Algorithm 如何为';等式';对于Hack汇编语言?
我在读书和学习,但有一点我被困住了。示例章节跳过接下来的5条说明 无论如何,我正在尝试实现一个虚拟机(或一个字节码到汇编转换器),但我在跳过下一个5指令一点上卡住了 您可以找到汇编符号 目标是实现一个转换器,将特定的字节码转换为该汇编代码 我成功完成的一个例子是字节码Algorithm 如何为';等式';对于Hack汇编语言?,algorithm,assembly,bytecode,interpreter,nand2tetris,Algorithm,Assembly,Bytecode,Interpreter,Nand2tetris,我在读书和学习,但有一点我被困住了。示例章节跳过接下来的5条说明 无论如何,我正在尝试实现一个虚拟机(或一个字节码到汇编转换器),但我在跳过下一个5指令一点上卡住了 您可以找到汇编符号 目标是实现一个转换器,将特定的字节码转换为该汇编代码 我成功完成的一个例子是字节码 push constant 5 翻译成: @5 D=A @256 M=D @5 D=A @256 M=D @98 D=A @257 M=D @5 D=A @256 M=D @98 D=A @257 M=D @257 //
push constant 5
翻译成:
@5
D=A
@256
M=D
@5
D=A
@256
M=D
@98
D=A
@257
M=D
@5
D=A
@256
M=D
@98
D=A
@257
M=D
@257 // Here starts the translation for 'add' // Load top of stack to A
D=M // D = M[A]
@256 // Load top of stack to A
A=M // A = M[A]
D=D+A
@256
M=D
正如我所说,Hack的汇编语言可以在我提供的链接中找到,但基本上:
@5 // Load constant 5 to Register A
D=A // Assign the value in Reg A to Reg D
@256// Load constant 256 to Register A
M=D // Store the value found in Register D to Memory Location[A]
这是非常直接的。根据定义,内存位置256是堆栈的顶部。所以
push constant 5
push constant 98
将翻译为:
@5
D=A
@256
M=D
@5
D=A
@256
M=D
@98
D=A
@257
M=D
@5
D=A
@256
M=D
@98
D=A
@257
M=D
@257 // Here starts the translation for 'add' // Load top of stack to A
D=M // D = M[A]
@256 // Load top of stack to A
A=M // A = M[A]
D=D+A
@256
M=D
这很好
我还想再举一个例子:
push constant 5
push constant 98
add
翻译为:
@5
D=A
@256
M=D
@5
D=A
@256
M=D
@98
D=A
@257
M=D
@5
D=A
@256
M=D
@98
D=A
@257
M=D
@257 // Here starts the translation for 'add' // Load top of stack to A
D=M // D = M[A]
@256 // Load top of stack to A
A=M // A = M[A]
D=D+A
@256
M=D
我想这很清楚
但是我不知道如何翻译字节码
eq
组装。eq的定义如下:
其中三个命令(eq、gt、lt)返回布尔值。虚拟机
将true和false表示为正如我在上一条注释中所写的,有一种无分支的方法,因此您需要直接计算操作数的返回值 现在让我们来做一些简单的操作,比如
eq
- 如果我做对了
类似于eqa,d
a=(a==d)
- true为
,false为0xFFFF
0x0000
- 因此,如果
那么a==d
这可以直接使用a-d==0
- 计算
a=a-d
- 计算
或
a的所有位的级联
- 如果结果为0,则返回0
- 如果结果为1,则返回0xFFFF
- 这可以通过表格或
0-或\u级联(a)
级联或
- 我在您的描述中没有看到任何位移位操作
- 因此,您需要使用
而不是a+a
a1)|(a>>2)|……|(a>>15))&1
a=0-a代码>
- 您只需要将其编码到程序集中
- 由于您没有直接支持的部门或轮班制,这可能会更好
a=a-d代码>
a=(a |)(a似乎还有另一章更明确地定义了黑客CPU。它说: 黑客CPU由第2章和第3章中规定的ALU组成 称为数据寄存器(D)、地址寄存器(A)和程序的寄存器 计数器(PC).D和A是通用16位寄存器,可以 由算术和逻辑指令操作,如A=D-1,D=D | A ,等等,遵循第章中指定的Hack机器语言 4.虽然D寄存器仅用于存储数据值,但A寄存器的内容可以用三种不同的方式解释, 取决于指令的上下文:作为数据值,作为RAM 地址,或作为ROM地址 很明显,M访问是由A控制的RAM位置。这里有我丢失的间接寻址。现在所有的东西都点击了 随着困惑的消除,现在我们可以处理OP的问题了(要容易得多) 让我们从使用堆栈实现子例程调用开始
并调用“推送常数”例程: 将值从堆栈弹出到D寄存器的子例程:; subroutine calling sequence @returnaddress ; sets the A register D=A @subroutine 0 ; jmp returnaddress: ... subroutine: ; D contains return address ; all parameters must be passed in memory locations, e.g, R1-R15 ; ***** subroutine entry code ***** @STK AM=M+1 ; bump stack pointer; also set A to new SP value M=D ; write the return address into the stack ; **** subroutine entry code end *** <do subroutine work using any or all registers> ; **** subroutine exit code **** @STK AM=M-1 ; move stack pointer back A=M ; fetch entry from stack 0; jmp ; jmp to return address ; **** subroutine exit code end ****
现在,要进行OP最初要求的“EQ”计算:popD: @R15 ; save return address in R15 M=D ; we can't really use the stack,... @STK AM=M-1 ; decrement stack pointer; also set A to new SP value D=M ; fetch the popped value @R15 A=M 0 ; jmp
总而言之:EQ: ; compare values on top of stack, return boolean in D @R15 ; save return address M=D @EQReturn1 D=A @PopD 0; jmp @EQReturn1: @R2 M=D ; save first popped value @EQReturn2 D=A @PopD 0; jmp @EQReturn2: ; here D has 2nd popped value, R2 has first @R2 D=D-M @EQDone equal; jmp @AddressOfXFFFF D=M EQDone: ; D contains 0 or FFFF here @R15 A=M ; fetch return address 0; jmp
此时,OP可以生成代码将D推送到堆栈上:@5 ; push constant 5 D=A @R2 M=D @returnaddress1 D=A @pushR2 0 ; jmp returnaddress1: @X ; now push X D=M @R2 M=D @returnaddress2 D=A @pushR2 0 ; jmp returnaddress2: @returnaddress3 ; pop and compare the values D=A @EQ 0 ; jmp returnaddress3:
@<constant> ; sets A register D=A ; save the constant someplace safe @STK AM=M+1 ; bump stack pointer; also set A to new SP value M=D ; write the constant into the stack
或者,他可以生成代码,根据D的值进行分支:@R2 ; push D onto stack M=D @returnaddress4 D=A @pushR2 0 ; jmp returnaddress4:
@jmptarget EQ ; jmp
事实上,看起来您确实有任意的跳转,请检查到jmp指令。您可以使用它创建两个分支,其中一个将1加载到目标寄存器中,另一个加载0@NiklasB.谢谢您的回复。但是我怎么知道跳转到哪里呢?JMP指令将跳转到加载到寄存器A的步骤n是,我如何创建会说“跳转4条指令”或“跳转8条指令”的汇编代码?1.字节码到汇编?…汇编源代码是程序的文本表示形式(助记符)这被编译成字节…通常是代码二进制。2.在我接触过的所有体系结构上,通过减法和设置标志
来比较指令,有些还包括条件分支(主要是MCU)因此Z,C
通常会执行CMPA,b
操作,但会将结果扔掉,只留下标志。现在进入条件(无论是跳转指令还是其他指令)a-b
…我怎么知道要跳转到哪个指令?将条件分支编码到符号标签。手册中有示例,我在回答中也对这样的示例进行了编码。(如果您正在生成二进制代码,您知道分支指令的位置;“跳过5条指令”表示“分支到分支的二进制位置,+5”。)nand2Tetris网站有一个问答部分。似乎这个问题需要一个非常具体的背景,所以这可能是一个很好的地方。我相信这就是你想要的:这也是我的第一个意见,但我想我遗漏了一些东西。谢谢你的回答。但还有一个问题:我该在哪里陈述没有间接寻址吗?@KorayTugay:你没有。你提供了一份文档副本;我看了原件,这就是我最初拥有的所有数据。你唯一的“罪恶”指向一个似乎只有关于指令集信息的文档。请重新阅读关于您的问题的评论,以了解思考是如何演变的。我向该书的作者发送了一条消息,说拆分指令集文档不是一件好事。PS:我实际上查看了Jack生成的代码,以便进行转换我自己equal=(Z)、greater=(NC)、lower(C)