目录

Assembler Roadmap

Week 6 notes


Assembly Languages and Assemblers

Basic Assmbler Logic

汇编器重复以下的功能:

  1. 读取下一条汇编命令
  2. 将命令分解为几个部分
  3. 查找每部分对应的二进制代码
  4. 将这些代码组合为一整条机器语言命令
  5. 输出该机器语言命令
读取逻辑

以下面的汇编代码为例:

// Start processing the table
Load R1, 18

  1. 读取时,会按行读取。读取时会忽略掉 whitespace 内容,得到的内容会存到一个数组中
  2. 将读取的指令分为几个部分(字符串),比如:Load, R1, 18
  3. 通过command-opcode 的对照表来进行翻译(主要是命令),某些数字可以直接进行翻译
  4. 将所有的内容组合在一起,形成机器语言指令,并进行输出


Symbols

汇编语言中存在着 symbols,以便提高程序的可读性,比如:

symbol table

而在汇编器翻译的过程中,这些 symbols 都会被替代为其对应的地址,比如 loop 对应的是跳转后的指令地址,weight 对应的是在 RAM 里面的寄存器所属地址。这种翻译也是依赖对应的 map 来实现的:

allocation of variables

第一次进入 symbol table 的变量需要汇编器为其安排 table 中的位置。通常,汇编器会在 RAM 中找到第一个可用的内存单元(Unallocated memory cell)来存放该变量。

Labels

Label 需要处理额外的两件事:

Hack Assembly Language

Assembly program 中的元素

需要汇编器处理的元素有:

Instruction Handling

外部总逻辑

对于 ROM 所有的指令:

Translating A-instructions

A 指令的结构表现为: @ + value ,因此将 A 指令转化为二进制取决于:

Translating C-instructions

首先回顾一下,C 指令的机器语言组成如下图所示:


因此,如果希望翻译 C 指令,那么首先需要做的就是将汇编语言按照机器语言的组成来进行划分。通常这部分会由 Parser(解析器)来完成。以下面的汇编语句为例:

// 将 D + 1 的值存储到 M 和 D 寄存器中
MD = D + 1
接下来按如下的顺序进行翻译:

  1. C 指令中 15-13 这三位永远都是 111,可以将其先填入
  2. comp 这部分 12..6acomp)进行翻译。这部分通过对照 C 指令的 table 来获取二进制代码。比如例子中的计算部分 D+1,对应的 a0,对应的六位 comp011111,那么这一部分对应的代码就是 0011111
  3. dest 这部分 5..3 进行翻译。这部分的翻译也是通过查表:比如例子中的 MD,对应的是 011
  4. jump 这部分 2..0 进行翻译,同样也是通过查表:本例中没有跳转部分(null),对应的 bits 是 000
  5. 最后得到的翻译结果是 111 0011111 011 000

Symbols Handling

之前介绍过,根据 symbol 的内容,可以将 symbol 划分为三种类型:

pre-defined symbols

由于这些 symbol 只会在 A 指令中出现,因此只需要根据对照表,将 symbol 转化为对应的地址值即可:比如

// R1 corresponds address 1
@R1->@1

Label symbols

label 类型的 symbol 主要用于:

@i // line 0
M=1
@sum
M=0

(LOOP) // not a instruction line
    @i // line 4
    ...
    @LOOP //line 16
这里的 (LOOP) 标签,对应的 block 起始行为 4;这个关系将会使用一张表来维护:

Symbolvalue
LOOP4

Variable symbols

变量类型的 symbol 指非提前定义的,且没有使用 driective 在别处进行定义的(比如 LOOP)的 symbol。上面例子中的 @i@sum 都是变量类型的 symbol。之前提到过,这类 symbol 都会被存储在一个独特地址的内存单元中(地址从 16 开始)。因此这类 symbol 对应的值,是他们所在内存单元的地址:

Symbolvalue
i16
sum17

由于变量可能会被多次用到,当第一次用到时,该变量 symbol 和其对应地址会被加入到映射表中;之后再使用时,汇编器会从映射表中查找到该对应关系,并把 symbol 翻译为对应的地址。

Symbol table

可以看到的是,上述的所有翻译都依赖于一种数据结构:Symbol table,用于建立翻译的映射关系。Hack 计算机的 Symbol table 通过几个阶段进行构造:

Assembly process

// init
- construct an empty symbol table
- add the pre-defined symbols to the symbol table

// first pass
// adding label declaration to the symbol table
- scan the program
- For each instruction of the form(xxx):
    - add the pair(xxx, address) to the symbol table, where address is the number of the instruction following (xxx)

// second pass
// adding variable symbol to the symbol table
- scan the program
- For each instruction:
    - if the insturction is @symbol, look up the symbol in the table
        - if (symbol, value) is found, use value to complete the instruction's translation
        - if not found
            - add(symbol, n) to the symbol table
            - use n to complete the instruction translation
            - ++n
    - if the instruction is a C-instruction, complate the instruction translation
- write the translated instruction to the output file