6个稳定版本
1.0.5 | 2024年4月25日 |
---|---|
1.0.4 | 2024年4月24日 |
1.0.1 | 2024年4月22日 |
#3 in #computer
60KB
1K SLoC
rgsm 🦀
用Rust编写的Gheith ISA汇编器。
内容
简介
这是gasm项目的兄弟项目。
请注意,rgsm
是Gheith教授CS 429H计算机体系结构课程的最终项目的贡献。对于完成流水线的学生,建议使用gasm
和dasm
,因为它们包含更多与项目完成相关的功能。
rgsm
是作为Gheith工具链的一部分构建和维护的。
入门指南
rgsm
是一个简单的Rust二进制文件。它在Cargo(官方Rust包管理器)上发布,因此可以使用以下命令安装
安装
cargo install rgsm
先决条件
- Rust 2021
编写汇编
在本节中,您将学习如何编写Gheith汇编程序。
注释
可以使用前缀//
将注释放置在汇编程序的任何位置。解析器将在解析此令牌后忽略该行后面的其余部分。
部分
汇编程序分为两个主要“部分”——.text
和.data
。实际上,有效的汇编程序可以有任意数量的这些部分;然而,每个程序基本上都由这些部分组成。
.text
部分相当简单:它包含所有要执行的指令。
.text
main:
print #97
print #98
print #99
// ...
end
.data
部分将包含放置在内存中的数据。Gheith体系结构是16位的,因此每个条目可以表示 $2^{17} - 1$ 个值之一:{ $0$,$1$,... $2^{17} - 1$ }。
.data
a:
#97
b:
#98
c:
#99
// ...
注意,在这个示例和上面的示例中,每个数字都以前缀#
开头。这将在稍后进行解释,但每个数字(实际上,几乎所有东西)都必须将其自身标记为它所代表的。在这些情况下,这些数字是立即的十进制值。
标签定义
程序实际上只是存储在内存中的数据。因此,在汇编中,如果我们想引用一组指令(或者实际上是程序中的任何东西),我们必须通过使用某些唯一的标识符(标签)来这样做。
.text
my_program_starts_here:
// ...
这些标签实际上是数字——程序中特定部分将驻留的内存位置。您可以使用它们在任何您会使用另一个数字的情况中使用,如下所示
// @0 -> Memory location word 0
.text
my_program_starts_here:
// ...
// This instruction jumps to the beginning of the program!
j my_program_starts_here
// ...
标签定义的声明方式如上所示,随后使用 :
标记来指定它是一个定义。标签引用将省略此冒号。标签是唯一的,您不能有两个具有相同名称的标签来引用程序的不同部分。例如,以下代码将是无效的
// @12 -> Memory location word 12
label_1:
print #97 // <- label_1 references word 12
label_1:
print #98 // <- label_1 references word 13 (?)
// hopefully it is clear why this makes no sense
// ...
// just in case it isn't clear
j label_1 // where should this jump to?
// word 12 or 13?
只需记住,标签实际上只是代表其下指令/数据的内存位置。
指令
rgsm
支持扩展的 Gheith ISA。它支持的特定指令可以在支持文档中找到。
以下是指令的一般形式:<INSTRUCTION NAME> [F1] [F2] [F3]
。
指令最多有 3 个字段,其存在和类型由 ISA 文档规定。它们可以是三种类型之一:寄存器、立即数或标签。
寄存器引用
以下 add
指令为例
add r3, r4, r5
此操作将 r4
和 r5
的值相加,并将结果存储在 r3
中。
寄存器引用以字母 r
为前缀。Gheith 架构中有 16 个寄存器,即 r0
-r15
。它们的标识如下
寄存器编号。 | 标识 | 说明 |
---|---|---|
0 | 零/打印寄存器 | 将 x 写入此寄存器将打印 x |
1 | 返回/参数寄存器 | 不适用 |
2 | 双寄存器 | 此寄存器存储值 $2$ |
7 | 跳转位置寄存器 | 由跳转到标签覆盖 |
1-7 | 通用调用者保留 | 不适用 |
8-15 | 通用被调用者保留 | 不适用 |
14 | 链接寄存器 | 不适用 |
15 | SP 寄存器 | 初始化为 0xFFFF |
立即数
立即数是十进制值,其范围取决于指令。它们以 #
为前缀。这就是全部内容。
标签引用
标签可以在需要立即数的地方使用(尽管,在像 ldo
和 sto
指令中,这样做可能从语义上讲并不总是有意义的)。标签可以在定义前后引用,因为它们是预处理的。
伪指令
除了官方支持的扩展 Gheith ISA 指令外,rgsm
还支持一些“伪指令”,或者更易于阅读的指令,这些指令汇编为简单的 Gheith 指令。以下列出的是
指令名称 | 字段(s) | 功能 |
---|---|---|
print |
<ra: Register> | add r0,ra,r0 |
movlb |
<rt: Register>, <label: Label> | movl ra, label[7:0] , movh ra, label[15:8] |
j |
<rt: Register> | jz rt,r0 |
j |
<label: Label> | movl r7, 标签[7:0] ,movh r7, 标签[15:8] ,jz r7, r0 |
入口点
Geith 架构遵循冯·诺依曼架构的文本共享地址空间与数据的原理。rgsm 组织程序的方式遵循这一原则。
程序文本放置在内存地址 0,入口点是第一个 .text 节的第一条指令——这是将放置在地址 0 的指令。如果您查看汇编输出,您将看到
@0
// first instruction
// ... and so on ...
@0
指示以下块从地址 0 开始顺序排列。
.text 节被合并并首先放置在内存中,然后 .data 节被合并并最后放置。因此,生成的机器代码形式为
@0
// first instruction
// second instruction
// ...
// end of `.text`
// first data entry
// second data entry
// ...
// end of `.data`
骨架
有效汇编程序的骨架为
.data
// Place your relevant data here!
.text
// Place your instructions here!
end
依赖关系
~3.5–5MB
~87K SLoC