assembly - 了解教授对装配作业的回答
问题描述
我的教授将此作为家庭作业问题的答案之一发布。谁能帮我分解一下?我不明白他在用 CON1 - CON4 做什么以及 >> 和 0x0FFF 是什么意思。
CON1: EQU 6000
CON2: EQU 6245
CON3: EQU 10000
CON4: EQU 10245
A: DM 4 ; DM is Define Memory
addi t1, x0, A ; t1 = &A
lui t0, (CON1>>12) + ((CON1 & 0x0800)>>11)
addi t0, t0, CON1&0xFFF
sd t0, 0(t1) // Cut and paste from last question of Quiz1
// Blank line between groups of statements
lui t0, (CON2>>12) + ((CON2 & 0x0800)>>11)
addi t0, t0, CON2&0xFFF
sd t0, 8(t1)
lui t0, (CON3>>12) + ((CON3 & 0x0800)>>11)
addi t0, t0, CON3&0xFFF
sd t0, 16(t1)
lui t0, (CON4>>12) + ((CON4 & 0x0800)>>11)
addi t0, t0, CON4&0xFFF
sd t0, 24(t1)
// We need this to avoid the NO INSTRUCTION error
ebreak x0, x0, 0 ; Suspend program.
任何帮助将不胜感激,谢谢。我们正在使用 RISC-V
解决方案
在 RISC-V 基本指令集中,每条指令都以 32 位编码。这意味着立即操作数的空间仅限于几位。因此,要将更大的常数放入寄存器(RV32G/RV64G 也是 32 位或 64 位宽),您需要将其拆分并使用多条指令移动部件,即 RV32G 为 2 个,RV64G 为最多 8 个。
使用 32 位 RISC-V (RV32G),可以使用加载上立即数( lui
) 和添加立即数( addi
) 指令加载更大的常量。的立即操作数lui
为 20 位宽,而addi
允许立即操作数为 12 位。因此,它们足以加载最多使用 32 位的常量。
lui
符号扩展其直接操作数并将其左移 12 位并将结果加载到目标寄存器中。因此得名。addi
还在添加它之前对它的直接操作数进行符号扩展。
因此,对于 RV32G,要加载一个更大的常数,lui
后跟一个必须采用高 20 位,将它们逻辑右移 12 位,以便抵消addi
12 位左移。lui
然后屏蔽低 12 位以获取addi
.
addi
如果不对直接操作数进行符号扩展,这就足够了。如果是因为最高位设置为 1,我们必须增加lui
操作数,以便在加法中再次将多余的符号位清零。
假设我们用 表示常量的高部分,x
用表示h
低部分l
,因为 RISC-V 实现了二进制补码和寄存器溢出时的算术换行,我们可以使用模运算来看到:
h + l = x # taking register widths into account:
=> (h + l) % 2**32 = x % 2**32 # in case l is sign extended:
=> (h + l + e + c) % 2**32 = x % 2**32 # replace e with the additional sign bits:
<=> (h + l + 4294963200 + c) % 2**32 = x % 2**32 # eliminate c:
<=> (h + l + 4294963200 + 4096) % 2**32 = x % 2**32
<=> (h + l) % 2**32 + (4294963200 + 4096) % 2**32 = x % 2**32
<=> (h + l) % 2**32 + 0 = x % 2**32
因此,当且仅当 的立即操作数是符号扩展时,我们必须将 1 添加到lui
立即操作数(左移 12 位后等于 4096) 。addi
在您的汇编示例中,>>
表示右移、<<
左移和&
逻辑与。它们用于实现所描述的拆分和算术,例如在
lui t0, (CON1>>12) + ((CON1 & 0x0800)>>11)
addi t0, t0, CON1&0xFFF
其中CON1 & 0x0800
屏蔽了 12 位,即addi
立即操作数的符号位。如果它被设置,则((CON1 & 0x0800)>>11)
评估为 1,从而抵消由以下addi
指令添加的多余符号位。CON1&0xFFF
屏蔽最低 12 位。
在标准 RISC-V 汇编中,所有这些繁琐的位管理都可以通过使用load immediate ( li
) 伪指令来避免,例如:
li t1, 6245
汇编器自动将其转换为最佳指令序列(例如使用 objdump 检查):
lui t1, 0x2
addi t1, t1,-1947
或者,使用 GNU 作为汇编器,也有将操作数分成上下部分的指令:
lui a1, %hi(6245)
addi a1, a1, %lo(6245)
可以说,这也比代码段中的混乱更具可读性。
这也适用于 GNU 中的符号,例如:
.set CON2, 6245
li a1, 6245
lui a2, %hi(CON2)
addi a2, a2, %lo(CON2)
li a3, CON2
# => a1 == a2 == a3
推荐阅读
- sql - 从 JOIN 表中返回一次结果
- dask - 将延迟对象中的 dask 系列添加到 dask 数据帧
- tinymce - TinyMCE 在设计模式下禁用链接导航
- sandbox - authorized.net 中 LIVE MODE 与 TEST MODE 之间的区别
- javascript - 检测 AMP 页面上的滚动方向并根据它显示或隐藏元素
- python - 根据一个列值组合多行,并根据 Pandas 中的其他列值添加额外的列
- c# - 在 C# 中异步加载属性的最佳方法是什么
- dataframe - Pyspark,如何将原始数据转换为 SVMLight 格式
- python - 如何在 matplotlib 的范围之间绘制数据?
- python - 将变量传递给正则表达式 exact pandas