MIPS学习第二章

寄存器:

在MIPS中,寄存器直接由硬件构成

$s0 - $s7:(保存寄存器)    映射到数字16-23(10进制数)

$t0 - $t9:(临时寄存器)      8-15

$zero:值恒为0

$a0 - $a3:传递参数的4个参数寄存器

$v0 - $v1:返回值的寄存器

$gp:全局指针

$fp:帧指针

$sp:栈指针

$ra:用于返回起始点的返回地址寄存器

$at:被汇编器保留,用于处理大的常数

存储器:

Memory [0],Memory [4], ...Memory [4294967292]

存储器只能通过数据传输指令访问(lw,sw)。MIPS使用字节编址,连续的字地址相差4。存储器用于保存数据结构,数组和溢出的寄存器。

一个字节(byte)包含8个bit,一个字为4个字节。(寄存器是以bit为最小存储单位而存储器是以字节为最小存储单位)(存储器是8位字节,A[0]是以字存储的,占了四个字节。)

操作数:

数据结构(数组和结构):

这种操作数存储在存储器当中------>存数和取数操作------->寄存器------>算术运算指令

立即数:

立即数也是存储在存储器当中,正常取数会需要取数,为避免麻烦,产生操作数为立即数的指令  addi

最低有效位:最右边   最高有效位:最左边

无符号数和有符号数:有符号数最高有效位代表正负------->有符号数的负数采用的是补码(要掌握补码与原码之间的转换,以及直接从补码转换到10进制)

对于有符号数和无符号数的取数指令是不相同的:

有符号数:取回有符号数后需要使用符号位填充寄存器的所有剩余位(符号拓展)

无符号数:用0填充

字节加载:(把32位的字加载到32位的寄存器中时无需讨论有无符号数----->已经完全填满了,只有在字节加载时讨论才有意义------>涉及到什么去填充空余的寄存器位数)

1.字节加载:lb  将字节看成有符号数,使用符号拓展填充寄存器右侧的24位

2.无符号整数加载:lbu 

指令:

R型指令:

6位操作码+5位寄存器(两个)+目标寄存器(5位)(注意这里寄存器的先后位置,目标寄存器在最后)+位移量(5位)+功能码(6位)

算术运算指令:

加法:  add  $s1, $s2, $s3

-------->机器语言:

op(操作码)       rs(源寄存器)      rt(源操作码)    rd(目标寄存器)    shamt(偏移量)    funct

  000000          10010($s2)           10011($s3)          10001($s1)              00000             100000

减法:  sub   $s1, $s2, $s3 

逻辑操作:

逻辑左移:sll  $t0, $s0, 4------->将$s0寄存器里的数向左移四位赋给$t0

------>机器语言:

   op               rs              rt                     rd                    shamt          funct

000000       00000    10000($s0)       01010($t0)          00100         000000

逻辑右移:srl

按位与:仅当两个操作数均为1时才为1 (and,andi)     

按位或:任意一位为1就为1(or,ori)

按位取反:将操作数中1变0,0变1(not)------->为保持三位操作数------->nor(或非)

nor    $s1, $s2, $s3 ( 其中$s3为0,相当于对$s2按位取反)

I型指令:

6位操作码+5位寄存器(两个)+16位地址偏移量(这里的偏移量是指字节偏移量----->即A[0]与A[1]之间的偏移量应为4,再转成2进制,即为所需要的机器指令)

这里的地址偏移量需要在进行符号拓展之后与  PC+4相加,原因:为什么MIPS处理器的数据通路中需要符号扩展单元和左移2位?_城外南风起的博客-CSDN博客_符号扩展单元

算术运算指令:

立即数加法:  addi  $s1, $s2, 20 

存取数指令:

取字:lw  $s1,20($s2)

存字:sw  $s1,20($s2) 

取半字:lh  $s1,20($s2)    (将半个字从内存中取到寄存器)(这里的半字是什么意思?)

取无符号半字:lhu  $s1,20($s2)

 存半字:sh $s1,20($s2)  将半个字从寄存器中存到内存中)

J型指令:

跳转和链接指令:jal ProcedureAddress   (跳转到某个地址的同时将下一条指令的地址保存在寄存器$ra中)

寄存器跳转指令:jr $ra

j 指令与 jr 有什么区别

决策指令:

判断指令:

if-then-else:

beq + 寄存器1 + 寄存器2 + 执行语句L1------>如果寄存器1等于寄存器2则执行语句L1

bne + 寄存器1 +  寄存器2 + 执行语句L1------->不相等则执行语句L1

L1在后文中定义

完整if语句形式:

beq/bne register1, register2, Else

j Exit

Else:+指令

Exit:

case/switch语句:

jr (寄存器跳转指令)

单纯判断大小指令:

slt   $s0, $s1, $s2------>如果$s1的值小于$s2的值,则给$s1赋值1,否则赋值0

slti---->立即数     sltiu---->无符号整数

循环指令:

Loop:(进入循环)

一系列的指令,其中必须有Exit的,否则就一直循环

j Loop(再跳到开始的循环指令中)

Exit:

计算机硬件对过程的支持

我的理解是相当于c语言中的函数

使用更多的寄存器

如果对于一个过程,需要使用超过4个参数寄存器和两个返回寄存器------>使用栈(后进先出)

栈指针:指向栈中最新分配的地址,以指示下一个过程放置换出寄存器的位置(以字为单位进行调整)栈指针指的是$sp

压栈:将数据放入栈中

出栈:从栈中移除数据

int leaf_example (int g, int h, int i, int j)

{

        int f;

        f=(g+h)-(i-j);

        return f;

}

利用MIPS写出:

参数变量g,h,i,j对应寄存器$a0,$a1,$a2和$a3,f对应$s0

leaf_example:

addi  $sp, $sp, -12     #这里是在栈中建立三个字的空间

sw     $t1,8($sp)         #这里是让三个寄存器入栈

sw     $t0,4($sp)

sw     $s0,0($sp)        #到这为止是建立栈的过程

add   $t1,$a0,$a1

add   $t0,$a2,$a3

sub   $s0,$t1,$t0

add   $v0,$s0,$zero     #这一步是将其复制到返回寄存器中

lw      $s0,0($sp)          #这里注意栈是后进先出的

lw      $t0,4($sp)

lw      $t1,8(sp)

addi   $sp,$sp,12    #这一步是将栈恢复

jr        $ra                #这里根据跳转寄存器里的地址进行跳转

如果在这个例子中,调用者不希望保存寄存器$t0与$t1的值,则在开始时不需要将其载入栈中

嵌套过程

这里包含调用指令:jal

可能出现问题:由于传递参数的寄存器只有$a0-$a3,则在调用过程A时,若A中也调用了过程B,则可能导致寄存器$a0中的值产生冲突

解决方案:将所有必须保留的寄存器压栈,同时调用者将所有调用后还需要的参数寄存器($a0-$a3)或临时寄存器($t0-$t9)压栈,被调用者将返回地址寄存器($ra)和被调用者使用的保留寄存器($s0-$s7)压栈.

int fact (int n)

{

        if (n<1) return (1);

                else return (n*fact(n-1));

}

参变量n对应参数寄存器$a0。

fact:

addi    $sp,$sp,-8

sw      $ra,4($sp)     #这里究竟为什么要将$ra压栈?

sw      $a0,0($sp)

slti      $t0,$a0,1       #判断n是不是小于1,如果是则$t0为1,否则为0

beq     $t0,$zero,L1   #若$t0为0,即 n>=1时,转到L1

add     $v0,$zero,1

addi    $sp,$sp,8          #如果这里调用的不是fact而是其他的,是不是要将参数寄存器等更新一下,那地址寄存器呢,应该怎么调整

jr         $ra

L1:   addi  $a0,$a0,-1

        jal fact

lw     $a0,0($sp)

lw     $ra,4($sp)

addi  $sp,$sp,8

mul   $v0,$a0,$v0

jr       $ra

在栈中为新数据分配空间

问题:在栈中需要存储的数据有可能并不能在寄存器中存储,例如结构体等

帧指针:指向过程帧的第一个字

人机交互(利用字节表示字符)

指令:

字节读取指令:lb   $t0,0($sp)     从内存中读取一个字节,并将其放在寄存器最右边的八位

字节存储指令:sb    $t0,0($gp)    把寄存器最右边的八位取出来写到内存中

void    stropy (char x[], char y[])

{

        int i;

        i=0;

        while ((x[i] =y[i] !='\0')

        i+=1;

}

假定数组x和y的基地址在$a0和$a1中,而i在$s0中

stropy:

        addi     $sp,$sp,-4

        sw       $s0,0($sp)

        add      $s0,$zero,$zero

Loop:                                               #这一步进入循环

        add      $t1,$a1,$s0       #这一步是的到y[i]的地址

        lbu        $t2,0($t1)           #这一步是将y[i]的值放入寄存器$t2中,这里之所以不用lw,是因为读取的是字节

        add       $t3,$a0,$s0

        sb         $t2,0($t3)

        beq      $t2,$zero,L2

       addi      $s0,$s0,1

        jr          Loop

L2:

       lw          $s0,0($sp)

       addi       $sp,$sp,4

      jr             $ra

MIPS指令即中还包含读取和存储半字命令: lhu(把半字看成无符号数),sh

MIPS中32位立即数和寻址

立即数

立即数比较长:

读取立即数高位指令:liu,允许后续指令设置常数的低16位

加载32位常量:

0000 0000 0011 1101 0000 1001 0000 0000

lui  $s0,61

ori  $s0,$s0,2304

分支和跳转中的寻址

问题:条件分支指令只保留了16位用于分支地址

解决办法:程序计算器=寄存器+分支地址

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值