【问题标题】:How are the maximum single jump range of MIPS branch instructions calculated?MIPS 分支指令的最大单次跳转范围是如何计算的?
【发布时间】:2018-10-05 07:33:02
【问题描述】:

我正在学习计算机体系结构(MIPS 体系结构)并阅读以下陈述:

1. 分支指令有一个 16 位有符号字偏移字段,允许从当前位置分支到地址 + 或 -128kBytes (+0x1FFFC TO -0X20000)。

2.跳转指令指定程序计数器最高有效4位指定的当前256MByte(0x0FFFFFFC)区域内的地址。

我理解上述跳转范围的概念,但是如何使用“256Mbyte 的范围”和“+-128 kbytes 的范围”计算 0x0FFFFFFC、0x1FFFC 和 0X20000 这三个数字?

谢谢!

【问题讨论】:

标签: assembly mips


【解决方案1】:

其他答案并没有真正回答您关于如何计算/找到这些十六进制值的问题。所以这是我的答案。

在二进制中考虑这一点比在 HEX 中容易得多。因为 2 位左移对于理解这个概念很重要 2 位乘以 4。 由于简单的十六进制数字是 16 个值,因此不能很好地用十六进制表示。 但我还是想解释一下:

0x20000

1 分支指令使用 16 位立即数字段。 (5 位 RS,RT)(6 位操作码)== 32 位 (https://en.wikibooks.org/wiki/MIPS_Assembly/Instruction_Formats#I_Format)

这 16 位是有符号的。它们可以是正面的也可以是负面的。

这为您提供了-(2^15) == -32768 的有效范围

+(2^15 -1) == 32767

MIPS 将任何地址输入乘以 4。强制它们按字对齐。

所以你的最小值-(2^15) 乘以 4:-{2^15 *4} (4=2^2), {2^(15+2)} (15+2 == 17): 变成-(2^17) == -131072

二进制(有符号 2 的补码)。 1000 0000 0000 0000 <<2 == 10 0000 0000 0000 00[00]

将其转换为十六进制 10=2 (0000=0) gives 2 0 0 0 0 == 0x20000

这将在添加到 (PC+4) 之前进行符号扩展:

so for say, instruction #32770, PC=0x00420008 (PC+4)=0x0042 000C

0x0042000C - 0x20000 = 0x0040000C, instruction #3(请记住,偏移量基于 PC+4)

#32770+1 +-32768 == 3

0x1FFFC

最大值相同: (2^15 -1) 乘以 4:{(2^15 -1) *4} (4=2^2), {2^(15+2) -(1*4)} (15+2 == 17)

变成(2^17 -4) == 131068 0111 1111 1111 1111 <<2 == 01 1111 1111 1111 11[00]

将其转换为十六进制 01=1 (1111=F) (1100=C) gives 1 F F F C == 0x1FFFC

注意地址需要加到当前(Program Counter+4)

so for say, instruction #32770, PC=0x00420008 (PC+4)=0x0042000C

0x0042000C + 0x1FFFC= 0x440008, instruction #65538(请记住,偏移量基于 PC+4)

#32770+1 +32767 == 65538

0x0FFFFFFC

2 现在跳转使用 28 位地址。
另请注意,跳转使用绝对地址。不是偏移量。

最大 28 位值为 (2^26 -1) == 67108863, 0x03FFFFFF ``

移位 2 (*4) 变为 28 位。 {(2^26 -1) *4}, == {2^28 -4} ==268435452, 0x0FFFFFFC

但是那缺少的四位呢? ..它们来自PC - 在内存阶段,它已经增加到(PC+4)

对于指令#32770,PC=0x00420008 (PC+4)=0x0042000C 0x0042000C in binary is [0000] 0000 0100 0010 0000 0000 0000 1100

+0x0FFFFFFC in binary [####] 1111 1111 1111 1111 1111 1111 1100 它只有 28 (27:0) 位,缺少 31:28 位。

从 PC+4 获取数据。我们得到:

 0000 ---- ---- ---- ---- ---- ---- ---- (PC+4)
 ---- 1111 1111 1111 1111 1111 1111 1100 (Target-Address)
-----------------------------------------
 0000 1111 1111 1111 1111 1111 1111 1100 (Jump-Address)

(在这种情况下与符号扩展它的值相同)

更好地解释如何计算地址。 How to Calculate Jump Target Address and Branch Target Address?

【讨论】:

  • 根据您链接的How to Calculate Jump Target Address and Branch Target Address?j 指令替换了分支延迟槽地址的低 28 位,而不是 30。因此它保留了高 4 位,使其成为绝对段在 256MiB 段内。 (指令字有 26 个立即位,左移产生 28。我认为你应用了两次左移。MIPS 操作码字段为 6 位宽,为跳转目标留下 26 位。)
  • 感谢指正。我脑子里有 28,一定是 26 移位 2 得到 28。操作码是固定的 6 位。 32-6 = 26...呃
【解决方案2】:

您为什么不直接询问经过测试和调试的工具链,然后将其与文档进行比较?

所以.s

four:
nop
nop
nop
j one
nop
j two
nop
j three
nop
j four
nop
nop
nop
nop
nop
one:
nop
two:
nop
nop
three:
nop

构建和拆卸

mips-elf-as so.s -o so.o
mips-elf-objdump -D so.o

so.o:     file format elf32-bigmips


Disassembly of section .text:

00000000 <four>:
    ...
   8:   0800000f    j   3c <one>
   c:   00000000    nop
  10:   08000010    j   40 <two>
  14:   00000000    nop
  18:   08000012    j   48 <three>
  1c:   00000000    nop
  20:   08000000    j   0 <four>
  24:   00000000    nop
    ...

0000003c <one>:
  3c:   00000000    nop

00000040 <two>:
    ...

00000048 <three>:
  48:   00000000    nop

链接到某个地址并反汇编

00001000 <_ftext>:
    ...
    1008:   0800040f    j   103c <one>
    100c:   00000000    nop
    1010:   08000410    j   1040 <two>
    1014:   00000000    nop
    1018:   08000412    j   1048 <three>
    101c:   00000000    nop
    1020:   08000400    j   1000 <_ftext>
    1024:   00000000    nop
    ...

0000103c <one>:
    103c:   00000000    nop

00001040 <two>:
    ...

00001048 <three>:
    1048:   00000000    nop

所以跳转超级简单,那么分支呢?

four:
nop
nop
nop
beq $10,$11,one
nop
beq $10,$11,four
nop
nop
nop
one:
nop

组装和拆卸

00000000 <four>:
    ...
   8:   114b0006    beq $10,$11,24 <one>
   c:   00000000    nop
  10:   114bfffb    beq $10,$11,0 <four>
  14:   00000000    nop
    ...

00000024 <one>:
  24:   00000000    nop

一些经验在这里会有所帮助,首先是 0x24 - 0x8 = 0x1C。这些是固定的 32 位指令,因此它们不太可能需要浪费这两个位并缩小范围,因此 0x1C>>2 = 7。编码有 6。好吧,他们也很可能在考虑 pc 方面已经递增,或者另一种看待这个的方式是前面的 6(+1) 条指令。 0xC、0x10、0x14、0x18、0x1c、0x20、0x24。所以这意味着倒退是 (0x00 - (0x10+4))>>2 = (0x00-0x14)>>2 = 0xFFFF...FFFFEC>>2 = 0xFF...FFFB 果然这就是我们得到的。

所以对于你采取的分支

((destination - (current address + 4))/4)&0xFFFF = 
(((destination - current address)/4) + 1)&0xFFFF

对于立即跳转 = {pc[31:28],destination[28:2]}

您应该能够从该信息中找出范围。

编码的关键是指令固定为 32 位并在 32 位边界上对齐,因此两个 lsbit 以及与之相关的数学运算始终为零,那么为什么要将范围缩小 4 以存储零呢?你没有,你有效地将偏移量打包到立即数中。一些(固定长度)指令集不这样做,但通常有理由不作为设计的一部分。

一般来说,如果您可以访问一个经过调试的汇编程序,它将提供比指令集参考更多有用的信息,这是基于学习许多指令集的经验。如果您是第一个为某个处理器编写汇编程序的人,那么这意味着您在那里工作或可以直接联系处理器的设计人员,您可以简单地问他们数学,而不是依赖他们尚未编写的手册将在芯片流片后写入,这为时已晚,因为您/他们需要汇编程序来验证设计。所以电子邮件、Skype 和最重要的关于指令编码的白板讨论。您可能还可以访问芯片源代码和/或模拟器,这样您就可以运行您的代码,查看它在 sim 中的执行(检查波形)并查看它分支到的位置(它获取的位置),更改立即数,查看在它获取的地方。

基本上,您通常应该始终可以访问具有答案的资源,以帮助解释缺少一些细节的手册。当然有时你会得到一本很好的手册......(你仍然应该用资源来验证)。

【讨论】:

    猜你喜欢
    • 2016-07-26
    • 1970-01-01
    • 2014-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多