目前我正在了解具有三个扩展I、M和C扩展RISC-V(ISA)指令集架构。我几乎已经理解了I、M和C扩展的所有指令,但我还没有找到jumpsbranches指令是如何工作的当两个不同的计数器出现时,以及它们如何计算下一条指令的地址以及我们给出的标签的立即值。

注意:C-扩展中,程序计数器以+2递增,因为C意味着压缩并且它包含16-位指令。在I和M扩展中,程序计数器以+4递增,因为I和M包含32位指令.

我有两个例子,我想了解跳转分支如何计算下一条指令的地址以及给定标签的立即值。任何人都可以提供或解释当发生跳转或分支时计算指令的下一个地址的公式。我提供了两个 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 

请您参考如下方法:

bnebeq 是 32 位指令,允许 13 位立即字节偏移,仅需要 12 位来存储,因为低位始终为零因此不会被存储(所有指令都是 2 字节的倍数)。

13 位立即数用于 PC 相对寻址模式,因此当采用条件分支时,硬件计算:

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 

最高位是最高位,如果为 1 则表示该数字为负数。为了在加宽时保留该值(例如从 11 位到 32 位),请将较短字段中的 MSB 传播到所有额外宽度的位。


评论关闭
IT虾米网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!