试图了解跳转指令如何在存在不同程序计数器时计算地址
Trying to understand how jump instruction calculate the address when different Program counter present
目前我正在理解 RISC-V(ISA) 指令集架构,具有三个扩展 I、M 和 C 扩展。我几乎理解了 I、M 和 C 扩展 的所有指令,但我还没有发现 jumps
和 branches
指令在 2 个不同的情况下如何工作counter 呈现,以及它们如何计算下一条指令的地址和我们给出的标签的立即值。
注意:在C-extension中程序计数器递增+2
,因为C意味着压缩并且它包含16-bit
说明。在 I 和 M 扩展 中,程序计数器递增 +4
因为 I 和 M 包含 32-bit
指令。
我有两个例子,我想了解 jumps
和 branches
如何计算下一条指令的地址和给定标签的立即值。谁能提供或解释一下发生跳转或分支时计算指令下一个地址的公式。我提供了两个 RISC-V 汇编的例子。请帮助我。提前致谢。
示例 1:
0x0 addi x5,x0,12 #x5 = x0 + 12
0x4 c.addi x6,0 #x6 = x6 + 0
l1:
0x6 c.addi x8,6 #x8 = x8 + 6
0x8 c.jal end # ?
0xA c.li x7,2 #x7 = x7 + 2
end:
0xC c.mv x6,x8 #x6 = x8
0xE bne x5,x6,l1 # ?
0x12 c.add x7,x6 # x7 = x7 + x6
0x14 add x8,x5,x7 # x8 = x5 + x7
0x18 c.jal end # ?
示例 2:
0x0 addi x5,x0,12 #x5 = x0 + 12
0x4 c.addi x6,1 #x6 = x6 + 1
l1:
0x6 c.li x7,1 #x7 = x7 + 1
0x8 beq x6,x7,end # ?
0xC c.add x7,x6 #x7 = x7 + x6
end:
0xE add x8,x5,x7 #x8 = x5 + x7
0x12 c.jal l1 # ?
0x14 sub x9,x8,x6 #x9 = x8 + x6
不确定这是否是最好的方法
<p id="x"></p> // replace **{{c}}** blank element hence it will impact anything
调用成功后ajax
success: function(data){ // data will hold whatever is returned from the url
$("#x").html(data['c']); // This will populate the p element with your value
alert("Hello");
},
你也可以隐藏ment
bne
和 beq
是 32 位指令,允许 13 位立即字节偏移,只需要 12 位存储,因为低位始终为零,因此不存储(所有指令都是 2 字节的倍数)。
13位立即数用于pc-relative寻址模式,所以当条件分支发生时,硬件计算:
pc' := pc + signExtend(immediate12 ## 0)
其中pc'
是下一个pc,##
表示按位串联。当不采用分支时,它会计算通常的 pc' := pc + 4
这是顺序流。
进行符号扩展以将立即数解释为带符号的,这意味着立即数可以是负数或正数,分别向后或向前跳转。
13 位分支目标立即数的12 位分布存储在整个指令的多个字段中。选择这些字段是为了与其他立即数有良好的重叠,并允许寄存器字段相对于其他指令格式保留在同一位置。
c.jal
指令在16位指令中编码了12位立即数;立即数以 11 位编码(同样因为低位总是零,所以不需要在指令中表示它)。硬件采用 11 位编码的立即数,在末尾添加一个额外的 0 使其成为 12 位,然后符号扩展到全角(我们也可以说它首先符号扩展到全角,然后乘以 2 — 结果相同).操作是 pc' := pc + signExtend(imm11 ## 0)
其中 ##
是串联。
一旦我们知道了处理器如何计算分支目标 pc,pc'
,我们就可以在汇编指令时简单地逆向计算。减去目标标签(to)和当前pc(from)之间的差异,然后除以2并截断以适应字段宽度。
如果截断改变了数值,那么立即数对于指令的字段来说太大了,因此无法编码。
内联编码立即字段的值:
0x0 addi x5,x0,12 #x5 = x0 + 12
0x4 c.addi x6,0 #x6 = x6 + 0
l1:
0x6 c.addi x8,6 #x8 = x8 + 6
0x8 c.jal end # ? **(to-from)/2=(0xC-0x8)/2=2**
0xA c.li x7,2 #x7 = x7 + 2
end:
0xC c.mv x6,x8 #x6 = x8
0xE bne x5,x6,l1 # ? **(0x6-0xE)/2=-4**
0x12 c.add x7,x6 # x7 = x7 + x6
0x14 add x8,x5,x7 # x8 = x5 + x7
0x18 c.jal end # ? **(0xC-0x18)/2=-6**
0x0 addi x5,x0,12 #x5 = x0 + 12
0x4 c.addi x6,1 #x6 = x6 + 1
l1:
0x6 c.li x7,1 #x7 = x7 + 1
0x8 beq x6,x7,end # ? **(0xE-0x8)/2=3**
0xC c.add x7,x6 #x7 = x7 + x6
end:
0xE add x8,x5,x7 #x8 = x5 + x7
0x12 c.jal l1 # ? **(0x6-0x12)/2=-6**
0x14 sub x9,x8,x6 #x9 = x8 + x6
符号扩展用于将短符号字段变成全宽值。
一个 11 位编码的立即数,如 c.jal
,以 -6 和 +6 为例,在二进制中看起来像这样:
# Example using -6
* The bit under the * is the MSB
|
11111111010 # -6 in 11 bits
11111111111111111111111111111010 # -6 in 32 bits
********************* Copied from the MSB in 11 bits
# Example using +6
* The bit under the * is the MSB
|
00000000110 # 6 in 11 bits
00000000000000000000000000000110 # 6 in 32 bits
********************* Copied from the MSB in 11 bits
The Most Significant Bit 是最高位,如果为 1 则表示数字为负数。为了在加宽(例如从 11 位到 32 位)时保留值,将较短字段中的 MSB 传播到所有额外宽度的位。
目前我正在理解 RISC-V(ISA) 指令集架构,具有三个扩展 I、M 和 C 扩展。我几乎理解了 I、M 和 C 扩展 的所有指令,但我还没有发现 jumps
和 branches
指令在 2 个不同的情况下如何工作counter 呈现,以及它们如何计算下一条指令的地址和我们给出的标签的立即值。
注意:在C-extension中程序计数器递增+2
,因为C意味着压缩并且它包含16-bit
说明。在 I 和 M 扩展 中,程序计数器递增 +4
因为 I 和 M 包含 32-bit
指令。
我有两个例子,我想了解 jumps
和 branches
如何计算下一条指令的地址和给定标签的立即值。谁能提供或解释一下发生跳转或分支时计算指令下一个地址的公式。我提供了两个 RISC-V 汇编的例子。请帮助我。提前致谢。
示例 1:
0x0 addi x5,x0,12 #x5 = x0 + 12
0x4 c.addi x6,0 #x6 = x6 + 0
l1:
0x6 c.addi x8,6 #x8 = x8 + 6
0x8 c.jal end # ?
0xA c.li x7,2 #x7 = x7 + 2
end:
0xC c.mv x6,x8 #x6 = x8
0xE bne x5,x6,l1 # ?
0x12 c.add x7,x6 # x7 = x7 + x6
0x14 add x8,x5,x7 # x8 = x5 + x7
0x18 c.jal end # ?
示例 2:
0x0 addi x5,x0,12 #x5 = x0 + 12
0x4 c.addi x6,1 #x6 = x6 + 1
l1:
0x6 c.li x7,1 #x7 = x7 + 1
0x8 beq x6,x7,end # ?
0xC c.add x7,x6 #x7 = x7 + x6
end:
0xE add x8,x5,x7 #x8 = x5 + x7
0x12 c.jal l1 # ?
0x14 sub x9,x8,x6 #x9 = x8 + x6
不确定这是否是最好的方法
<p id="x"></p> // replace **{{c}}** blank element hence it will impact anything
调用成功后ajax
success: function(data){ // data will hold whatever is returned from the url
$("#x").html(data['c']); // This will populate the p element with your value
alert("Hello");
},
你也可以隐藏ment
bne
和 beq
是 32 位指令,允许 13 位立即字节偏移,只需要 12 位存储,因为低位始终为零,因此不存储(所有指令都是 2 字节的倍数)。
13位立即数用于pc-relative寻址模式,所以当条件分支发生时,硬件计算:
pc' := pc + signExtend(immediate12 ## 0)
其中pc'
是下一个pc,##
表示按位串联。当不采用分支时,它会计算通常的 pc' := pc + 4
这是顺序流。
进行符号扩展以将立即数解释为带符号的,这意味着立即数可以是负数或正数,分别向后或向前跳转。
13 位分支目标立即数的12 位分布存储在整个指令的多个字段中。选择这些字段是为了与其他立即数有良好的重叠,并允许寄存器字段相对于其他指令格式保留在同一位置。
c.jal
指令在16位指令中编码了12位立即数;立即数以 11 位编码(同样因为低位总是零,所以不需要在指令中表示它)。硬件采用 11 位编码的立即数,在末尾添加一个额外的 0 使其成为 12 位,然后符号扩展到全角(我们也可以说它首先符号扩展到全角,然后乘以 2 — 结果相同).操作是 pc' := pc + signExtend(imm11 ## 0)
其中 ##
是串联。
一旦我们知道了处理器如何计算分支目标 pc,pc'
,我们就可以在汇编指令时简单地逆向计算。减去目标标签(to)和当前pc(from)之间的差异,然后除以2并截断以适应字段宽度。
如果截断改变了数值,那么立即数对于指令的字段来说太大了,因此无法编码。
内联编码立即字段的值:
0x0 addi x5,x0,12 #x5 = x0 + 12
0x4 c.addi x6,0 #x6 = x6 + 0
l1:
0x6 c.addi x8,6 #x8 = x8 + 6
0x8 c.jal end # ? **(to-from)/2=(0xC-0x8)/2=2**
0xA c.li x7,2 #x7 = x7 + 2
end:
0xC c.mv x6,x8 #x6 = x8
0xE bne x5,x6,l1 # ? **(0x6-0xE)/2=-4**
0x12 c.add x7,x6 # x7 = x7 + x6
0x14 add x8,x5,x7 # x8 = x5 + x7
0x18 c.jal end # ? **(0xC-0x18)/2=-6**
0x0 addi x5,x0,12 #x5 = x0 + 12
0x4 c.addi x6,1 #x6 = x6 + 1
l1:
0x6 c.li x7,1 #x7 = x7 + 1
0x8 beq x6,x7,end # ? **(0xE-0x8)/2=3**
0xC c.add x7,x6 #x7 = x7 + x6
end:
0xE add x8,x5,x7 #x8 = x5 + x7
0x12 c.jal l1 # ? **(0x6-0x12)/2=-6**
0x14 sub x9,x8,x6 #x9 = x8 + x6
符号扩展用于将短符号字段变成全宽值。
一个 11 位编码的立即数,如 c.jal
,以 -6 和 +6 为例,在二进制中看起来像这样:
# Example using -6
* The bit under the * is the MSB
|
11111111010 # -6 in 11 bits
11111111111111111111111111111010 # -6 in 32 bits
********************* Copied from the MSB in 11 bits
# Example using +6
* The bit under the * is the MSB
|
00000000110 # 6 in 11 bits
00000000000000000000000000000110 # 6 in 32 bits
********************* Copied from the MSB in 11 bits
The Most Significant Bit 是最高位,如果为 1 则表示数字为负数。为了在加宽(例如从 11 位到 32 位)时保留值,将较短字段中的 MSB 传播到所有额外宽度的位。