一、汇编指令
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
④从栈中恢复值