【问题标题】:Definition question in Assembly (RiscV), help me understand大会(RiscV)中的定义问题,帮助我理解
【发布时间】:2020-12-13 18:31:57
【问题描述】:

学习 RiscV 我的讲师定义了一个名为 Load Upper Immediate (lui) 的新命令,如下所示:

lui rt, imm

将立即 imm 的下半字加载到上半字中 寄存器 rt。寄存器的低位设置为0。

以下图片:

但有几件事我无法理解:

  1. “加载立即数的下半字”是什么意思?我认为如果我们在 imm 中有 32 位,那么它会加载前 16 位,对吗?

  2. 图像是否正确?前半部分不应该全为零并且定义提到了吗?为什么我们有那些 0xf, 0, rt 以及 rt 是从哪里来的?

  3. 给定以下命令:lui S0, 0x1234
    它会做什么?不知道内存中1234位置的值...

【问题讨论】:

  • immediate = 作为编码指令一部分的数字常量。也称为数字 0x1234。不代表地址,它只是一个数字。
  • 而且图像只是显示了指令编码(如果你用汇编程序编写这条指令,这些字节将按此顺序出现在生成的二进制文件中......),没有什么是对或错的那里。除非你在其中发现了一些错误。
  • @dratenik 所以 3 会在 S0 中节省 1234/2?另外 0x1234 不是十六进制的数字吗?我完全糊涂了
  • 引用 Erik 的回答“s0 变为 0x12340000”。是的,这是一个十六进制数字。
  • 您得到的答案是正确的,并且尽可能简单。现在轮到你看笔记,复习基础知识并尝试理解你被告知的内容。我仍然觉得您不理解带有指令编码的图像的含义,因此请特别确保您理解您在其中看到的内容。

标签: assembly mips riscv machine-code immediate-operand


【解决方案1】:

图像是否正确?前半部分不应该全为零并且定义提到了吗?为什么我们有那些 0xf, 0, rt 以及 rt 是从哪里来的?

是的,没错;但是,该图像向我们显示它是 MIPS 指令,而不是 RISC V1

0xf 是lui 的 MIPS 操作码。有一个未使用的 5 位(零)字段和一个寄存器字段以及 16 位立即数。

lui 不是内存引用指令——它只是将指令中存储的常量加载到寄存器中。

给定以下命令:lui S0, 0x1234 它会做什么?

lui s0, 0x1234     ; s0 becomes 0x12340000

您可以在MIPS green sheet 中查找。

可以这么说,使用 2 条指令我们可以形成一个 32 位的常量值(数据值或内存地址)。第一条指令 lui 形成 32 位值的高 16 位,第二条指令使用普通的 oriaddi 提供低 16 位。

Load Upper Imm.        lui rt,imm      I-Type        R[rt] = {imm, 16’b0}

这一条指令相当于2条指令序列:

ori rt, r0, imm         ; load 16-bit constant
sll rt, rt, 16          ; shift left by 16 bits

脚注 1:这是LUI 的 RISC V 版本:

 31    12 11   7 6       0
+-------------------------+
|  imm   |  rd  |  opcode |
+-------------------------+
    20       5        7

如您所见:立即数是 20 位长(不是 MIPS 的 16 位),当然,操作码在右边(7 位而不是 MIPS 的 6 位)。 (也没有浪费的零。)

【讨论】:

  • 嗨,对不起,这并没有回答我的任何问题另外这是我教授的定义
  • 我无法改变现实。
  • @ErikEidt:为了清楚起见,asm 语法并没有告诉我们它是 MIPS。这是机器代码布局和立即宽度。
  • @PeterCordes,是的,这就是我展示 RISC V 对应物的原因。
  • 我的想法是让答案的早期句子这么说。我进行了编辑以显示我的意思。当我第一次阅读您的答案时,这句话似乎可以理解为 LUI 完全是 MIPS 指令,而不仅仅是那个定义。 (特别是因为我跳过了问题的引用部分)。只是一个小问题:P
【解决方案2】:

在尝试阅读或编写汇编语言之前,您需要获取文档。对于您使用的指令集,这是 MIPS 问题(您发布的图像)还是标题文本中记录的 risc-v 问题等?

假设 risc-v 访问 risc-v.org 并点击文档链接,他们非常容易找到。

risc-v 中的 LUI 是这样定义的

33222222222211111111 11
10987654321098765432 10987 6543210
     imm[31:12]        rd   opcode

bits 31:12 of the instruction are the immediate
bits 11:7  of the instruction are the destination register
bits 6:0   of the instruction are the opcode

显然,每条指令都需要一些位让处理器解码才能知道 它是什么指令,只有一个可以使模式为零,所以有非零 大多数操作码中的位。同样,您需要一个目标寄存器,其中的值 被存储,也被编码在指令中。

LUI(加载上立即数)用于构建 32 位常量并使用 U 型格式。 LUI 将 U 立即数放在目的寄存器 rd 的高 20 位,低 12 位用 0 填充。

这条指令的工作原理非常明显。

我承认 risc-v 文档可以做得更好,找到操作码...0b0110111 或 0x37。

不确定人类如何阅读数字的困惑是什么

0b0110111 = 0x37 = 067 (octal) = 55 (decimal)

这些都描述了相同的值,它们都描述了指令中相同的位模式。

这意味着他们可以像其他人一样将其放入指令定义中。

33222222222211111111 11
10987654321098765432 10987 6543210
     imm[31:12]        rd  0110111

所以知道我们可以例如构造

.word 0x12345137

组装然后拆卸

Disassembly of section .text:

00000000 <.text>:
   0:   12345137            lui x2,0x12345

好的,让我们继续尝试:

.word 0x12345137
lui x2,0x12345

组装和拆卸

Disassembly of section .text:

00000000 <.text>:
   0:   12345137            lui x2,0x12345
   4:   12345137            lui x2,0x12345

所以我们开始了,指令编码解决了。

LUI(加载上立即数)用于构建 32 位常量并使用 U 型格式。 LUI 将 U 立即数放在目的寄存器 rd 的高 20 位,低 12 位用 0 填充。

所以在这种情况下,32 位常量很明显

0x12345000

在这种情况下存储在寄存器 x2 中。

所有指令的编码和操作都定义了,大部分应该很容易理解。编码非常简单易懂。

现在,如果这是一个 MIPS 问题而不是 risc-v 问题,那么在这种情况下它同样容易理解。 16 位立即数进入常量的 31:16 位,其中 15:0 位全部为零,并且该常量存储在指令中编码的寄存器中。连同一个操作码,这样处理器就可以知道这是什么指令。

【讨论】:

    【解决方案3】:

    首先,这是 MIPS 的 lui 版本,而不是 RISC-V。它们是相似的 ISA,但肯定有不同的机器代码和不同大小的立即数。

    请参阅@Erik 对您的部分问题和一些必要背景的回答,但是是的,图片中的措辞存在问题。

    “加载立即数的下半字”是什么意思?我想如果我们在 imm 中有 32 位,那么它会加载前 16 位,对吗?

    这部分图片解释得很糟糕;甚至可以说是错误的。图中的图表显示了整个 32 位指令字及其各个字段。 立即数指令字的低半字。“立即数的低半字是整个立即数,有没有上半字。以这种方式表达它是零意义的,并且具有高度误导性。

    放置在目标寄存器中的值是立即数左移 16,所以是的,立即数放置在 32 位寄存器的高半字中。


    给定以下命令:lui S0, 0x1234

    在 MARS 中单步执行,看看会发生什么。查看调试器中的寄存器值。我是0x1234 &lt;&lt; 16

    【讨论】:

    • 寄存器的值怎么可能是十六进制的?一个值总是二进制的...
    • @albert:是的,寄存器不包含一串 ASCII 十六进制数字,我从来没有说过它会。我在答案中使用十六进制来表示数值,就像您在 lui $s0, 0x1234 的 asm 源中所做的一样。十六进制是一种以文本格式写入数字的便捷方式,供其他人阅读,其基数与基数 2 一致,因此每个 4 位块映射到一个十六进制数字。 (与十进制相比,每个数字的值取决于所有高位)。我本可以写 0b0000'0000'0000'0000'0001'0010'0011'0100(使用 C++ 风格的分隔符),但这会更难阅读。
    • @albert:我也可以写成4660 &lt;&lt; 163053977600x12340000,因为这些表达式都表示相同的数字。显然,我的答案文本中没有包含原始的 32 位整数;它是文本,所以我只能使用可打印的字符。在我们的书写系统中表示数字的标准方法是使用某个基数的位值系统,最重要的数字在左边。
    • 知道了,但 lui 不期待 32 位输入吗?当我们写 0x1234 它是 16 位所以...
    • @albert:整个指令是32位;立即数是其中的下半部分。这就是我回答的重点。再读一遍,尤其是“立即数是指令字的低半字”部分。并查看将低 16 位标记为“imm”的图表。该图是正确的,只是图像中的文字具有误导性。 lui 是具有 16 位立即数的 I 型指令。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-22
    • 1970-01-01
    • 1970-01-01
    • 2013-01-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多