Chapter2-2-2 MIPS Architecture

Posted by LvKouKou on October 12, 2022

2-2-2 MIPS Architecture

image-20221010163213107

Review: MIPS Instructions

一般算数指令符号扩展,逻辑指令零扩展

Category Instr OPCode Example meaning 备注
Arithmetic (R & I format) add 0 & 20 add s1 ,s2, s3 s1 = s2 + s3  
  subtract 0 & 22 sub s1, s2, s3 s1 = s2 - s3  
  add immediate 8 addi s1, s2, 4 s1 = s2 + 4 做符号扩展
逻辑左移 shift left logical 0 & 00 sll s1, s2, 4 s1 = s2 « 4 在空出的地方补0(零扩展)
逻辑右移 shift right logical 0 & 02 srl s1, s2, 4 s1 = s2 » 4 (fill with zeros) 在空出的地方补0(零扩展)
算数右移 shift right arithmetic 0 & 03 sra s1, s2, 4 s1 = s2 » 4 (fill with sign bit) 在空出的地方做符号扩展
  and 0 & 24 and s1, s2, s3 s1 = s2 & s3  
  or 0 & 25 or s1, s2, s3 s1 = s2|s3  
  nor 0 & 27 nor s1, s2, s3 s1 = not (s2|s3) 或非
  and immediate c andi s1, s2, ff00 s1 = s2 & 0xff00  
  or immediate d ori s1, s2, ff00 s1 = s2 | 0xff00  
  load upper immediate f lui s1,0xffff s1 = 0xffff0000 后一步载入低16位时,用无符号数相加指令 addiu 或者 ori 逻辑指令,因为ori是0扩展,而addi是符号扩展
  异或   xor s2,s1,s0 s2=s1⊕s0  
Data transfer (I format) load word 23 lw s1 100(s2) s1=Memory(s2+100)  
  store word 2b sw s1, 100(s2) Memory(s2+100)=s1  
  load byte 20 lb s1, 101(s2) s1=Memory(s2+101) 对高位进行符号扩展
  store byte 28 sb s1, 101(s2) Memory(s2+101)=s1 对高位进行符号扩展
  load half 21 lh s1, 101(s2) s1=Memory(s2+102) 对高位进行符号扩展
  store half 29 sh s1, 101(s2) Memory(s2+102)=s1 对高位进行符号扩展
Cond. branch (I & R format) br on equal 4 beq s1, s2, L if (s1==s2) go to L 1.往前跳为负偏移,往后跳为正偏移;2.跳转目标规定的是相对于它的下⼀条指令的偏移;3.偏移量(加上 2 个低位零,即×4) 符号扩展后与(更新的) PC相加, 得到⽬标地址
  br on not equal 5 bne s1, s2, L if (s1 !=s2) go to L 4.跳转范围被限制在离分⽀指令⼤约正负 32K 条指令 (正负 128K 字节(±2^17=±131072 约等于128k))的范围。
  set on less than immediate a slti s1, s2, 100 if (s2<100) s1=1; else s1=0  
  set on less than 0 & 2a slt s1, s2, s3 if (s2<s3) s1=1; else s1=0  
Uncond. jump jump 2 j 2500 go to 10000 绝对地址的形成 :指令中低26位,后面加两个零把PC+4的高4位与上面的28位合并为32位绝对地址,即跳转范围为距离当前地址高4位2^28≈256M的地方
  jump register 0 & 08 jr t1 go to t1  
  jump and link 3 jal 2500 go to 10000; ra=PC+4 ==跳转的最远的是jr和jalr,因为他们跳转的地址是寄存器中存的,即有32位,而jal和j只有28位,beq只有17位(因为是16位左移2位变18位,但beq是I型指令,imm中第一位是符号位)==
  MULT instruction 0 & 0x18 mult rs, rt   ⾼ 32 bits 存于 hi 中, 低 32 bits 存于 lo 中
  DIV instruction 0 & 0x1a div rs, rt   商存储在 lo 中, 余数存储在 hi中
  move from hi 0 & 0x10 mfhi rd move the 32-bit half result from hi to rd  
  move from lo 0 & 0x12 mflo rd move the 32-bit half result from lo to rd  

MIPS指令汇总

1
https://www.likecs.com/show-203940020.html?sc=3400.3359375

32 个寄存器的使用约定

img

  • 还有2个32位乘、商寄存器 Hi 和L0
  • 乘法时分别存放64位乘积的高、低 32位;除法时分别存放余数和商。

image-20221010094600176

MIPS的模型

image-20221010094700827

MIPS的内存

MIPS 使用字节内存地址. 指令是32位的, 占4个字节(一个字) 地址,指令之间差4个字节地址

32bits = 4Bytes = 1Word

MIPS为大端存储

image-20221010095048940

指令剖析

image-20221010095234668

计算机中指令的表示

image-20221010095400134

MIPS指令格式

MIPS只有3种指令格式, 32位固定⻓度指令格式

  • R(Register) 类型指令: 两个寄存器操作数计算, 结果送寄存器
  • I(Immediate) 类型指令: 使⽤1个16位⽴即数作操作数;
  • J(Jump) 类型指令: 跳转指令, 26位跳转地址

  • 对于Load/Store指令, 单⼀寻址模式: Base+Displacement ➢ 没有间接寻址 ➢ 16位⽴即数 ➢ 简单转移条件(与0⽐较, 或者⽐较两个寄存器是否相等) ➢ ⽆条件码

img


R型指令

image-20221010100023934

  • shamt:此字段包含移位指令的移位数量。 将⼀个 32 位字移位超过 31 是没有意义,所以这个字段只有 5 位(它可以表示数字 0-31)
  • 除移位指令外, 该字段均设置为 0
  • R型指令的op都是 000 000,所以区别R型指令的是funct部分的编码,即最后六位

1. add rd ,rs ,rt

Reg[rd] = Reg[rs] + Reg[rt] 将 rs 的内容与 rt 的内容相加,将结果存储在 rd中

OP Rs Rt Rd shamt funct
000000 Rs Rt Rd 00000 0x20

add和sub的op是相同的,区分他们的是funct

指令 格式 op rs rt rd shamt funct address
add R 0 reg reg reg 0 32(10) n.a.
sub R 0 reg reg reg 0 34(10) n.a.

2. sll rd, rt, shamt

Reg[rd] = Reg[rt] « shamt rt内容左移 shamt位; 结果存于rd中

逻辑左/右移:把一个字里所有的位都向左/右移动,并在空出的地方补0

OP Rs Rt Rd shamt funct
000000 00000 Rt Rd 左移位数 0x00

逻辑左移还有额外的好处,左移i位= 原数 × $2^i$ 如3(00011)左移3位变24(11000),即3×2^3=24

image-20221010102236390

3. sllv rd, rt, rs SLLV (SLL Variable), 左移位数存在寄存器RS中

Reg[rd] = Reg[rt] « Reg[rs] 将 rt 的内容左移 rs 的内容;将结果存储在 rd 中,即移位量不在指令中,而是在寄存器中

image-20221010103900243

注意每个寄存器作用

同时也有右移指令:srl 和 srlv,用法与sll 和sllv相同

还有sll和srl是逻辑移动,还有算数移动,如:sra和sla,区别是补位是符号扩展(算数左移右边多出来的空也是补0)


I型指令

image-20221010104907896

这些常数限定在16位,可表示范围:有符号数[-32768…32767] , 或⽆符号数 [0…65535]

如何存大于16位的常数

Example: 把32-bit 数值0x5678ABCD 存⼊ $5, 怎样处理?

解⼀ :

1
2
3
4
5
6
7
8
9
10
11
把⾼位的16 位 (0x5678) 先存⼊ $5
然后左移$5 内容16 位, (0x5678 0000)
再与低16 位相加“add” (0x5678 0000 + 0xABCD)
//错误
addi $5, $0, 0x5678
sll $5, $5, 16
addi $5, $5, 0xABCD
//正确
addiu $5, $0, 0x5678
sll $5, $5, 16
addiu $5, $5, 0xABCD

⼩问题:

  • addi 处理常数为有符号数, 会造成错误,因为算数指令进行符号扩展
  • 相加时要用无符号数相加指令 addiu 或者 ori 逻辑指令替代 (零扩展)

解二:

前⾯两步(addi + sll) 组合为lui:装入高16位立即数,16-bit立即数放⼊寄存器的前半部分

上面三行转为下列两行

1
2
lui $5, 0x5678
ori $5, $5, 0xABCD

1. addi rt, rs, imm

Reg[rt] = Reg[rs] + sxt(imm) 将rs的内容与常数相加;将结果存储在 rt中

OP Rs Rt imm
0x08 Rs Rt 补码,做符号扩展

2. addiu rt, rs, imm

Reg[rt] = Reg[rs] + (imm) 寄存器rs内容与⽆符号常数相加;结果存于rt中

OP Rs Rt imm
0x09 Rs Rt 符号扩展

逻辑操作指令的常数, 是“unsigned”, 符号扩展,总是⽆符号数


ADDI、 ADDIU: 加立即数,区别在于是否检测溢出。 无符号加 不检测溢出 (因为检测溢出需要看符号位有无进位)

ADD、 ADDU: 加寄存器, 区别在于是否检测溢出。 无符号加 不检测溢出 (因为检测溢出需要看符号位有无进位)

即, 在忽略溢出的前提下, ADDI与ADDIU等价, ADD与ADDU等价。 对于CPU来说, 有符号或者⽆符号都不重要。 他们的运算都是⼀样的, 不管有没有符号位, 都是从最低位加, 进位, ⼀直到最⾼位, 区别在于是否具有溢出检测


3. lw rt, imm(rs)

Reg[rt] = Mem[Reg[rs] + sign-ext(imm)] 将内存中数取出存到rt中

tips:load和store都是相对于内存而言

1
2
3
4
5
做如下操作:
• 取出寄存器$rs的值
• 与⽴即数(有符号数)相加
• 相加结果作为内存地址索引
• 相应地址中取出的值存⼊寄存器 $rt 中

#### 4. sw rt, imm(rs)

Mem[Reg[rs] + sign-ext(imm)] = Reg[rt] rt内容取出存到内存中

1
2
3
4
5
做如下操作:
• 取出寄存器$rs的值
• 与⽴即数(有符号数) 相加
• 相加结果作为内存地址索引
• 读出寄存器$rt 的内容写⼊到内存此地址单元中

lw 和 sw 指令读或写的内容是 32-bit ⼀个字, 内存中占4个字节地址,因此, 地址计算必须是4的倍数 ,即 Reg[rs] + sign-ext(imm) ⼆进制数的后两位必须是“00” ,因为不是的话一定不是4的倍数。

1
2
3
4
这类指令也有针对字节访问的指令
•lb (load byte)
•sb (store byte)
• ⼯作⽅式相同, 但它们的地址不必是 4 的倍数

5.lb和sb

1
2
3
lb $t0, 1($s3) #load byte from memory
sb $t0, 6($s3) #store byte to memory

  • load指令将内存中读出的字节放在⽬标寄存器的最右边 8 位
  • 寄存器中的其它位怎么办? LOAD指令对高位进⾏0扩展
  • store 指令从寄存器中的最右边8位取出⼀个字节,把它写⼊内存字节处

image-20221010130518097

6. 半字操作(16bits)

1
2
lh $t0, 1($s3) #load half word from memory
sh $t0, 6($s3) #store half word to memory

16 bits 内存取和写⼊内存

  • load 半字 从内存取出16位半字, 放在⽬标寄存器的最右边高位0扩展
  • store 半字, 从寄存器的右边取出16位, 写⼊内存半字, 占两个地址内存字的其它部分不变

7.条件跳转指令 MIPS Branch Instructions

OP Rs Rt 16-bits signed constant(offset)
0x04(beq)/0x05(bne) Rs Rt 往前跳为负偏移,往后跳为正偏移
beq rs, rt, label # Branch if equal
1
2
3
4
if (REG[RS] == REG[RT])
{
	PC = PC + 4 + 4*offset;
}
bne rs, rt, label # Branch if not equal
1
2
3
4
if (REG[RS] != REG[RT])
{
	PC = PC + 4 + 4*offset;
}
  • 注意内存地址必须是4的倍数, 目标地址也必须是4的倍数
  • 跳转目标规定的是相对于它的下⼀条指令的偏移 (默认取下⼀条指令)。 汇编器计算出相对于⽬标地址(通常⽤lable表示) 的偏移量, 偏移量常数字段16位限定了跳转范围 ==PC = PC + 4 + 4*offset==;

16 位分⽀偏移量通过以下公式转换为 32 位的值

1
16-bit 偏移量后⾯加两个0, 然后==符号扩展==为32-bit

跳转流程:

1
2
在取指bne后, PC 更新为下⼀条指令地址 (PC = PC + 4)
偏移量(加上 2 个低位零,相当于×4) 符号扩展后与(更新的) PC相加, 得到⽬标地址 

例子:

1
2
3
4
5
6
7
8
9
0x00001234:beq $s3,$s4,True
			sub $s0,$s1,$s2     #这里是PC+4
			add					#1
			sub					#2
			j Fin				#3
	   True:add					#4
       Fin....
 -------------------------------------------------------------------------------------------------------------------------------
 PC=PC+4+sign-ext(4*offset)=0x1234+4+16=0x1248

总结:

  • Branch 分⽀指令的跳转范围被限制在离分⽀指令⼤约正负 32K 条指令 (正负 128K 字节($2^{17}$=131072 约等于128k))的范围
  • 跳转目标规定的是相对于它的下⼀条指令的偏移 (默认取下⼀条指令)。

字节编址

  • Big Endian(⼤端存储) :存储字的最左边字节地址作为字地址
  • Little Endian(⼩端存储) :存储字的最右边字节地址作为字地址

J型指令

image-20221010145734443

绝对跳转(无条件跳转)


image-20221010150446130

指令(J型) OP 26-bit address
j 2 后面会默认补2个0,即imm*4
jal 3 后面会默认补2个0,即imm*4
指令(R型) OP Rs Rt Rd shamt funct
jr 2 Rs 0 0 0 8
jalr 3 Rs 0 Rd 0 9
1
2
3
4
j label 				# jump to label (PC = PC[31-28] || CONST[25:0]*4)
jal label 				# jump to label and store PC+4 in $31
jr $t0 					# jump to address specified by register’s contents
jalr $t0, $ra 	# jump to address specified by first register’s contentsand store PC+4 in second register

1. j label

jump 的目标地址怎样规定 ?绝对地址的形成

  1. 指令中低26位, 后面加两个零
  2. PC+4的高4位与上面的28位合并为32位绝对地址

例子:

image-20221010152658075

2. jal label

jal应该被称为 laj , “链接和跳转”:

  1. 第 1 步( link链接) : 将下⼀条指令的地址保存到 $ra,ra=pc+4(为什么是下⼀条指令? 为什么不是当前⼀条? )
  2. 第 2 步( jump跳转) : 跳转到给定的标签
  • 没⽤jal指令之前,只能用j指令
1
2
1008 addi ra,zero,1016  #$ra=1016 ,要存储j指令后一条指令的地址,等下才可以返回主程序
1012 j sum              #goto sum
  • 使用jal指令
1
2
1008 jal sum			# $ra=1012,goto sum
1012 ........

#### 3. jr $ra

jr 指令跳转的地址在寄存器$ra中

tips:指令是R型指令


Q:如果 branch 跳转⽬的地址远于它16位能表示的范围怎么办?

A:汇编器来救援 - 它插入⼀个无条件跳转到分⽀目标并反转条件

1
beq $s0, $s1, L1

变成

1
2
3
	bne $s0, $s1, L2
	j L1
L2:......


乘除指令

1. mult rs, rt

含义: 将寄存器 rs 和 ​rt 的内容相乘, 并将(64 位结果) 存储在⼀对特殊寄存器中{hi, lo}

t代表”结果临时存储“,也就是需要特殊寄存器hi/lo存储运算结果

  • ⾼ 32 bits 存于 hi 中, 低 32 bits 存于 lo 中

要访问结果, 使⽤两个新指令

mfhi: move from hi

1
mfhi rd 					#move the 32-bit half result from hi to $rd

mflo: move from lo

1
mflo rd 			#move the 32-bit half result from lo to $rd

2. div rs, rt

含义: 将寄存器 rs 的内容除以 ​rt, 并将商存储在 lo 中, 余数存储在 hi中

  • 访问结果, use mfhi and mflo

有两条对应的⽆符号数乘法和除法指令

  • multu
  • divu

比较指令

1. slt rd, rs, rt

slt = set-if-less-than 小于则置⼀

rd = (rs < rt) // “1” if true and “0” if false

2.slti rt, rs, imm

slti = set-if-less-than-immediate 小于立即数则置⼀

rt = (rs < sign-ext(imm) ) 做符号扩展


also unsigned flavors 对应两条⽆符号数⽐较指令

  • sltu
  • sltiu

逻辑操作指令

Boolean operations 布尔操作: 所有32位按位操作

  • AND, OR, NOR, XOR
  • and, andi
  • or, ori
  • nor // Note: There is no nori! Why? 或非没有与立即数比较的指令
  • xor, xori

无i的都是R型指令,有i的都为i型指令

Review: MIPS Instructions

一般算数指令符号扩展,逻辑指令零扩展

Category Instr OPCode Example meaning 备注
Arithmetic (R & I format) add 0 & 20 add s1 ,s2, s3 s1 = s2 + s3  
  subtract 0 & 22 sub s1, s2, s3 s1 = s2 - s3  
  add immediate 8 addi s1, s2, 4 s1 = s2 + 4 做符号扩展
逻辑左移 shift left logical 0 & 00 sll s1, s2, 4 s1 = s2 « 4 在空出的地方补0
逻辑右移 shift right logical 0 & 02 srl s1, s2, 4 s1 = s2 » 4 (fill with zeros) 在空出的地方补0
算数右移 shift right arithmetic 0 & 03 sra s1, s2, 4 s1 = s2 » 4 (fill with sign bit) 在空出的地方做符号扩展
  and 0 & 24 and s1, s2, s3 s1 = s2 & s3  
  or 0 & 25 or s1, s2, s3 s1 = s2|s3  
  nor 0 & 27 nor s1, s2, s3 s1 = not (s2|s3) 或非
  and immediate c and s1, s2, ff00 s1 = s2 & 0xff00  
  or immediate d or s1, s2, ff00 s1 = s2 | 0xff00  
  load upper immediate f lui s1,0xffff s1 = 0xffff0000 后一步载入低16位时,用无符号数相加指令 addiu 或者 ori 逻辑指令,因为他们时0扩展,而addi是符号扩展
  异或   xor s2,s1,s0 s2=s1⊕s0  
Data transfer (I format) load word 23 lw s1 100(s2) s1=Memory(s2+100)  
  store word 2b sw s1, 100(s2) Memory(s2+100)=s1  
  load byte 20 lb s1, 101(s2) s1=Memory(s2+101) 对高位进行符号扩展
  store byte 28 sb s1, 101(s2) Memory(s2+101)=s1 对高位进行符号扩展
  load half 21 lh s1, 101(s2) s1=Memory(s2+102) 对高位进行符号扩展
  store half 29 sh s1, 101(s2) Memory(s2+102)=s1 对高位进行符号扩展
Cond. branch (I & R format) br on equal 4 beq s1, s2, L if (s1==s2) go to L 1.往前跳为负偏移,往后跳为正偏移;2.跳转目标规定的是相对于它的下⼀条指令的偏移;3.偏移量(加上 2 个低位零) 符号扩展后与(更新的) PC相加, 得到⽬标地址
  br on not equal 5 bne s1, s2, L if (s1 !=s2) go to L 4.跳转范围被限制在离分⽀指令⼤约正负 32K 条指令 (正负 128K 字节(±2^17=±131072 约等于128k))的范围。
  set on less than immediate a slti s1, s2, 100 if (s2<100) s1=1; else s1=0  
  set on less than 0 & 2a slt s1, s2, s3 if (s2<s3) s1=1; else s1=0  
Uncond. jump jump 2 j 2500 go to 10000 绝对地址的形成 :指令中低26位,后面加两个零把PC+4的高4位与上面的28位合并为32位绝对地址,即跳转范围为距离当前地址高4位2^28≈256M的地方
  jump register 0 & 08 jr t1 go to t1  
  jump and link 3 jal 2500 go to 10000; ra=PC+4 跳转的最远的是jr和jalr,因为他们跳转的地址是寄存器中存的,即有32位,而jal和j只有28位,beq只有17位(因为是16位左移2位变18位,但beq是I型指令,imm中第一位是符号位)
  MULT instruction 0 & 0x18 mult rs, rt   ⾼ 32 bits 存于 hi 中, 低 32 bits 存于 lo 中
  DIV instruction 0 & 0x1a div rs, rt   商存储在 lo 中, 余数存储在 hi中
  move from hi 0 & 0x10 mfhi rd move the 32-bit half result from hi to rd  
  move from lo 0 & 0x12 mflo rd move the 32-bit half result from lo to rd