MIPS汇编总结

一、汇编指令

1.为了简化处理器的设计,MIPS处理器采用了固定结构的汇编指令:每个指令由4个部分组成:1个操作符+3个操作数

  指令格式:指令代码 操作数1,操作数2,操作数3

2.在汇编指令中,寄存器没有数据类型,由运算符确定将寄存器的内容当作什么数据来处理

3.MIPS既提供了检测溢出的加(add)、减(sub)指令,也停供了不检测溢出的加(addu)、减(subu)指令

以适用不同高级语言的需求

 

 

二、寄存器

1.为了是使硬件设计更简单,MIPS处理器的汇编语言中,算术运算指令的操作数只能是寄存器

2.在MIPS计算机中设计了32个32位的通用寄存器来作为汇编指令的操作数,分别编号位0-31.

既可以通过编号也可以通过寄存器名来访问指定的寄存器

3.MIPS定义了一个特殊的处理器$S0,该寄存器的值永远都是0

4.由于计算机运算速度很快,对于需要延时的程序。可以有一条不做任何处理,仅延时一个周期的指令noop,

该指令没有任何操作数:add $0,$0,$0

 

三、立即数

1、立即数在代码中可立即获得,不必先放到寄存器中再从寄存器中取出

2、可以通过加负常数来实现减正常数,因此在MIPS中没有立即数减法指令

 

四、内存

MIPS算术指令不能直接操作内存,仅能直接操作寄存器,因此要操作内存中数据必须先将其从内存中装入到存储器中,

然后再对寄存器中的数据进行运算

一、数据交换:内存到寄存器

1、内存地址为寄存器(包含指向内存的指针)和数值偏移量(以字节为单位)之和

2、从内存取出数据的指令语法格式:

       1   2,3(4)

其中:1表示指令名字;2表示接受内存传入值的寄存器名;3表示数值偏移量(单位:字节)4是寄存器名,该寄存器中存储的是内存地址,其中括号表示地址

例如: lw $t0,12($s0)

表示:取出寄存器$s0中的指针与立即数12相加,将结果作为内存地址,从内存中取值,把趣得的值放入到$t0中

二、数据传送:寄存器到内存

1、把寄存器的值存储到内存中:

例如:sw $t0,12($t0)

表示:取出$s0中的指针,加上12字节,得到内存地址的值,然后把寄存器$t0中的值存储到该内存地址中

2、寄存器可以保存任意32位数值,可以是有符号整数、无符号整数、指针等,但不能混用

三、寻址模式

1、在现代计算机中,既要访问字节,也要访问字,主要采用的是字节寻址其相邻的两个32位(4字节)字地址相差4个字节

表示各个字的地址方式为:

memory[0],memory[4],memory[8]....

2、相邻字之间的地址相差4个字节,而不是一个字节,不能简单加1

3、对于lw、sw,基地址和偏移地址之和必须是4的倍数,即需要字对齐,如果字没有对齐,则读数据操作需要两次才能完成

四、字节数据的传送

1、除了传送字数据的指令lw,sw外,MIPS还有字节传送指令:lb(load byte)和sb(store byte),其格式于lw,sw相同

例如:lb $s0,3,($s1)表示:把位于($s1)+3内存地址的内容复制到寄存器s0中,但寄存器有32位,传送的数据只有八位,放在低字节中

2、对于无符号数,指令lbu(load byte unsigned)用来装入字节,并对高位数据进行零拓展。既装入8位数据到寄存器的低字节中,其余24位补0.

 

四、MIPS程序控制指令

一、基本的MIPS分支指令:

①beq register1,register 2,L1

其含义是:register1于register2相等,则跳转到标号L1处的语句,否者不执行;

对应于:if(register1==register2) goto L1

②bne register1,register 2,L1

对应于:if(register1!=register2) goto L1

③j label

该指令又称跳转指令,即不需要满足任何条件而之间跳转到指定的标号处

二、用分支指令实现循环控制

1、两个“逻辑”指令

逻辑左移指令sll(shift left logic)

例如:sll $s1,$s2,2    #s1=s2<<2表示:将寄存器$s2的值左移2位,并将结果存放到$s1中,右边空出来的位中补0,和C语言中的<<运算符等价

逻辑右移指令srl(shift right logic)

2、循环

以下为一段c语言循环程序:

do{
g=g+A[i];
i=i+j;
}while(i!=h);

要把它翻译成MIPS程序,首先要重写以上程序为条件语句的形式

Loop:
g=g+A[i];
i=i+j;
if(i!=h)
goto Loop;

然后使用以下映射关系:

g->$s1;    h->$s2;     i->$s3;     j->$s4;

则可以把以上语句翻译为以下MIPS代码:

Loop:
sll $t1,$s3,2   #$t1=4*i,乘4得字节地址
add $t1,$t1,$s5  #$t1=A的地址
lw $t1,0($t1)   #$t1=A[i]
add $s1,$s1,$t1 #g=g+A[i]
add $s3,$s3,$s4 #i=i+j
bne $s3,$s2,loop #if (i!=h)goto Loop

三、MIPS汇编中的不等式判断

1、MIPS设计过程中,通过提供一条指令来实现4种条件分支:slt(set on less than)

其语法为:slt reg1,reg2,reg3

与其对应的C语句是:reg1=(reg2<reg3);

 

利用slt指令可以实现小于分支,例如C语言中的小于分支语句:

if(g<h)goto Less;

变量映射为:g:$s0,h:$s1

可以翻译为MIPS代码:

slt $t0,$s0,$s1  #如果g<h,则$t0=1
bne $t0,$s0,Less  #if($t0!=0) goto Less

将bne改成beq即可实现大于等于的判断

slt $t0,$s0,$s1 #$t0=1 if a<b
beq $t0,$s0,GreatE #GreatE if(a>=b)

同理也可实现小于和小于等于的判断

2、另外,MIPS也设计了slt的立即数版本slti,用来和立即数比较

例如:

C语句:

if(g>=1) goto Loop

转化成MIPS为:

slti $t0,$s0,1 
beq $t0,$s0,Loop

3、同样还有针对无符号数的不等式判断指令:stlu,stliu

(寄存器中的数是二进制串,本身不存在有符号或无符号的定义,其含义取决于指令)

例如:$s0=FFFF FFFA  $s1=0000 FFFA

当看成无符号数时,$s0>$s1;看作有符号数时,$s0为负数,$s0<  $s1

4.在MIPS的指令中,无符号标识u具有不同的含义。对于装入字节lbu,是进行符号扩展;对于addu是不检测溢出,而sltu是进行无符号数比较

四、将switch语句编译成汇编指令

C语言:

switch(k)
{
case 0:f=i+j;break;
case 1:f=g+h;break;
case 2:f=g-h;break;
case 3:f=i-j;break;
}

先改写为if-else语句:

if(k==0) f=i+j;
else if(k==1) f=g+h;
else if(k==2) f=g-h;
else if(k==3) f=i-j;

使用以下映射:f:$s0;       g->$s1;       h->$s2;        i->$s3;        j->$s4;      k->$s5

    bne $s5,$0,L1    #branch k!=0
    add $s0,$s3,$s4  #k==0,f=i+j
    j Exit
L1:
    addi $t0,$s5,-1  #$t0=k-1
    bne $t0,$0,L2    #branch k!=1
    add $s0,$s1,$s2  #k==1,f=g+h
    j Exit
L2:
    addi $t0,$s5,-1  #$t0=k-2
    bne $t0,$t0,L3   #branch k!=2
    sub $s0,$s1,$s2  #k==2,f=g-h
    j Exit
L3:
    addi $t0,$s5,-3  #$t0=k-3
    bne $t0,$0,Exit  #branch k!=3
    sub $s0,$s3,$s4  #k==3,f=i-j
Exit:

五、函数调用

 

一、函数的跳转指令

地址跳转指令jr(jump to register):jr $ra #跳转到寄存器所指定的地址

由于调用过程需要两条指令:一条存储返回值,一条实现跳转

MIPS设计了一个专门的跳转指令jal(jump and link)

例如:

addi $ra,$zero,0x1010 #存储函数返回地址

 j sum #调用函数sum

可以替换为:

jal sum

其执行过程分为两步:

①link:保存下一指令的地址到$ra

②jump:跳转到给定标记处label

1在MIPS处理器中,所有指令都占4个字节,和数据一样存储在内存中

2、MIPS规定使用通用寄存器$ra来存储返回值地址。

3、约定:(也可以存放在栈中)

函数返回地址:$ra

函数参数:$a0,$a1,$a2,$a3

函数返回值:$v0,$v1

 

二、函数嵌套调用

1、MIPS通过通用寄存器$sp作为栈指针来指向栈的最后使用空间。在使用栈时,首先将栈指针下移,然后将信息填充到移出的空间中

2、函数嵌套调用流程:

①申请栈空间,保护主调函数返回地址以及后面可能用到的值到栈

②调用下级函数前,对下级函数形参进行必要的赋值

③使用跳转语句jal调用函数mult

④从栈中恢复值

  • 21
    点赞
  • 124
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
setjmp是一个C库中的函数,用于在程序执行时保存当前执行上下文,并在稍后的时间点从该点重新开始执行。在MIPS汇编中,可以使用jr指令来实现类似的功能。下面是一个示例程序: ``` #include <setjmp.h> #include <stdio.h> jmp_buf env; int f(jmp_buf env) { int val = setjmp(env); printf("f's val = %d\n", val); return val; } int main() { int val = f(env); printf("main's val = %d\n", val); if (val != 0) { printf("longjmp to f()\n"); longjmp(env, val+1); } return 0; } ``` 在这个程序中,我们定义了一个保存执行上下文的jmp_buf类型的变量env。在f函数中,我们调用setjmp函数来保存当前执行上下文,并返回一个值。在main函数中,我们调用f函数,并检查返回值是否为0。如果不是0,则说明在f函数中调用了longjmp函数,需要恢复f函数的执行上下文。我们使用longjmp函数来实现这个功能。 在实际的MIPS汇编代码中,我们需要使用jr指令来实现这个过程。具体实现方法如下: ``` .text setjmp: # Save register values and return address addi $sp, $sp, -12*4 sw $ra, 0($sp) sw $s0, 4($sp) sw $s1, 8($sp) addi $v0, $sp, 12*4 jr $ra longjmp: # Restore register values and return address lw $ra, 0($sp) lw $s0, 4($sp) lw $s1, 8($sp) addi $sp, $sp, 12*4 # Set return value addi $v0, $a1, 1 jr $ra ``` 在setjmp函数中,我们将寄存器中的值保存到堆栈中,并将堆栈指针减小12*4字节(因为我们保存了3个寄存器的值)。然后,我们返回一个指向保存执行上下文的堆栈位置的指针。在longjmp函数中,我们将堆栈中保存的值恢复到寄存器中,并将堆栈指针增加12*4字节。最后,我们将返回值设置为传入的参数值加1,并跳转到保存的返回地址处。这个返回地址就是执行setjmp函数时保存的返回地址。 使用setjmp和longjmp函数可能会导致程序的可移植性问题,因为不同的平台可能实现方式不同。因此,应该避免在生产代码中频繁使用这些函数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

路漫漫其修远兮?

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值