Algorithm 如何为';等式';对于Hack汇编语言?

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 //

我在读书和学习,但有一点我被困住了。示例章节跳过接下来的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  // 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为
    0xFFFF
    ,false为
    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的问题了(要容易得多)

      让我们从使用堆栈实现子例程调用开始

           ; 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 ****
      
      并调用“推送常数”例程:

      将值从堆栈弹出到D寄存器的子例程:

         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
      
      现在,要进行OP最初要求的“EQ”计算:

      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
      
      总而言之:

           @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:
      
      此时,OP可以生成代码将D推送到堆栈上:

           @<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
      
           @R2                ; push D onto stack
           M=D
           @returnaddress4 
           D=A
           @pushR2
           0 ; jmp
        returnaddress4:
      
      或者,他可以生成代码,根据D的值进行分支:

           @jmptarget
           EQ ; jmp
      

      事实上,看起来您确实有任意的跳转,请检查到jmp指令。您可以使用它创建两个分支,其中一个将1加载到目标寄存器中,另一个加载0@NiklasB.谢谢您的回复。但是我怎么知道跳转到哪里呢?JMP指令将跳转到加载到寄存器A的步骤n是,我如何创建会说“跳转4条指令”或“跳转8条指令”的汇编代码?1.字节码到汇编?…汇编源代码是程序的文本表示形式(助记符)这被编译成字节…通常是代码二进制。2.在我接触过的所有体系结构上,通过减法和设置标志
      Z,C
      来比较指令,有些还包括条件分支(主要是MCU)因此
      CMPA,b
      通常会执行
      a-b
      操作,但会将结果扔掉,只留下标志。现在进入条件(无论是跳转指令还是其他指令)
      equal=(Z)、greater=(NC)、lower(C)
      …我怎么知道要跳转到哪个指令?将条件分支编码到符号标签。手册中有示例,我在回答中也对这样的示例进行了编码。(如果您正在生成二进制代码,您知道分支指令的位置;“跳过5条指令”表示“分支到分支的二进制位置,+5”。)nand2Tetris网站有一个问答部分。似乎这个问题需要一个非常具体的背景,所以这可能是一个很好的地方。我相信这就是你想要的:这也是我的第一个意见,但我想我遗漏了一些东西。谢谢你的回答。但还有一个问题:我该在哪里陈述没有间接寻址吗?@KorayTugay:你没有。你提供了一份文档副本;我看了原件,这就是我最初拥有的所有数据。你唯一的“罪恶”指向一个似乎只有关于指令集信息的文档。请重新阅读关于您的问题的评论,以了解思考是如何演变的。我向该书的作者发送了一条消息,说拆分指令集文档不是一件好事。PS:我实际上查看了Jack生成的代码,以便进行转换我自己