fud*_*din 30 assembly mips machine-code
我是汇编语言的新手.我正在阅读有关MIPS架构的内容,我遇到了跳转目标地址和分支目标地址以及如何计算它们.
emr*_*azi 66
在MIPS分支指令中,只有16位偏移量来确定下一条指令.我们需要一个寄存器添加到这个16位值来确定下一条指令,这个寄存器实际上是由架构暗示的.它是PC寄存器,因为PC在获取周期期间被更新(PC + 4),因此它保存下一条指令的地址.
(在下图中,PC是分支延迟槽的地址,而不是分支指令本身.但在文中,我们将说PC + 4.)
我们还将分支距离限制为-2^15 to +2^15 - 1来自(指令后)分支指令的指令.然而,这不是真正的问题,因为无论如何大多数分支都是本地的.
所以一步一步:

对于跳转指令,Mips只有26位来确定跳转位置.此外,跳转与MIPS中的PC相关.像分支一样,立即跳转值需要字对齐;因此,我们需要将26位地址乘以4.
再一步一步:
换句话说,将取出的指令的低26位替换为PC + 4的低28位,向左移位2位.

跳转是相对于分支延迟槽的区域,不一定是分支本身.在上图中,PC在跳转计算之前已经进入分支延迟槽.(在经典RISC 5阶段流水线中,BD在同一周期内被提取,跳转被解码,因此PC + 4下一个指令地址已经可用于跳转和分支,并且相对于跳转自己的地址计算需要额外的工作来保存该地址.)
资料来源: Bilkent大学CS 224课程幻灯片
use*_*653 19
通常您不必担心计算它们,因为汇编程序(或链接程序)将采取正确的计算方法.假设你有一个小功能:
func:
  slti $t0, $a0, 2
  beq $t0, $zero, cont
  ori $v0, $zero, 1
  jr $ra
cont:
  ...
  jal func
  ... 
当将上述代码转换为二进制指令流时,汇编程序(或链接器,如果你第一次组装成目标文件)将确定函数将驻留在内存中的哪个位置(让我们暂时忽略位置无关代码).它在内存中的位置通常在ABI中指定,或者在您使用模拟器时给予您(如SPIM加载代码0x400000- 注意链接也包含对过程的良好解释).
假设我们正在谈论的SPIM情况下,我们的作用是先在内存中,该slti指令将驻留在0x400000中,beq在0x400004等.现在我们快到了!对于beq指令,分支目标地址是cont(0x400010)查看MIPS指令引用的地址,我们看到它被编码为相对于下一条指令的16位有符号立即数(除以4,因为所有指令必须位于4字节无论如何都要对齐地址).
那是:
Current address of instruction + 4 = 0x400004 + 4 = 0x400008
Branch target = 0x400010
Difference = 0x400010 - 0x400008 = 0x8
To encode = Difference / 4 = 0x8 / 4 = 0x2 = 0b10
编码 beq $t0, $zero, cont
0001 00ss ssst tttt iiii iiii iiii iiii
---------------------------------------
0001 0001 0000 0000 0000 0000 0000 0010
如您所见,您可以分支到-0x1fffc .. 0x20000字节内.如果由于某种原因,你需要进一步跳跃,你可以使用蹦床(无条件跳转到放置在给定限制内的真实目标).
跳转目标地址是,不像分支目标地址,使用所述编码的绝对地址(再除以4).由于指令编码使用6位作为操作码,因此只留下26位用于地址(实际上28位,因为最后2位将为0)因此在形成地址时使用PC寄存器的4位最高有效位(除非你打算跨越256 MB边界,否则无关紧要).
回到上面的例子,编码jal func是:
Destination address = absolute address of func = 0x400000
Divided by 4 = 0x400000 / 4 = 0x100000
Lower 26 bits = 0x100000 & 0x03ffffff = 0x100000 = 0b100000000000000000000
0000 11ii iiii iiii iiii iiii iiii iiii
---------------------------------------
0000 1100 0001 0000 0000 0000 0000 0000
您可以快速验证这一点,并使用我遇到的这个在线MIPS汇编程序来处理不同的指令(例如slti,注意它不支持所有操作码,所以我只是将其改为slt此处):
00400000: <func>    ; <input:0> func:
00400000: 0000002a  ; <input:1> slt $t0, $a0, 2
00400004: 11000002  ; <input:2> beq $t0, $zero, cont
00400008: 34020001  ; <input:3> ori $v0, $zero, 1
0040000c: 03e00008  ; <input:4> jr $ra
00400010: <cont>    ; <input:5> cont:
00400010: 0c100000  ; <input:7> jal func