What & How & Why

差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录前一修订版
后一修订版
前一修订版
cs:comp_n_arch:courses:fnti_i:week_6 [2025/05/19 08:37] – [Translating C-instructions] codingharecs:comp_n_arch:courses:fnti_i:week_6 [2025/05/19 14:24] (当前版本) – [Developing a Hack Assembler] codinghare
行 56: 行 56:
     * Label     * Label
 ====Instruction Handling==== ====Instruction Handling====
 +===外部总逻辑===
 +对于 ROM 所有的指令:
 +  * 首先对其进行解析,并将其拆分为指定的部分
 +  * 其次根据指令的类型,来进行对应的转换
 +  * 将所有转化的结果组合起来,并输出到对应的文件中
 ===Translating A-instructions=== ===Translating A-instructions===
 A 指令的结构表现为: ''@ + value'' ,因此将 A 指令转化为二进制取决于: A 指令的结构表现为: ''@ + value'' ,因此将 A 指令转化为二进制取决于:
行 73: 行 78:
   - C 指令中 ''15-13'' 这三位永远都是 ''111'',可以将其先填入   - C 指令中 ''15-13'' 这三位永远都是 ''111'',可以将其先填入
   - 对 ''comp'' 这部分 ''12..6''(''a'' 和 ''comp'')进行翻译。这部分通过对照 C 指令的 table 来获取二进制代码。比如例子中的计算部分 ''D+1'',对应的 ''a'' 是 ''0'',对应的六位 ''comp'' 是 ''011111'',那么这一部分对应的代码就是 ''0011111''   - 对 ''comp'' 这部分 ''12..6''(''a'' 和 ''comp'')进行翻译。这部分通过对照 C 指令的 table 来获取二进制代码。比如例子中的计算部分 ''D+1'',对应的 ''a'' 是 ''0'',对应的六位 ''comp'' 是 ''011111'',那么这一部分对应的代码就是 ''0011111''
-  - 对 ''dest'' 这部分 ''5-3'' 进行翻译。这部分的翻译也是通过查表:比如例子中的 ''MD'',对应的是 ''011'' +  - 对 ''dest'' 这部分 ''5..3'' 进行翻译。这部分的翻译也是通过查表:比如例子中的 ''MD'',对应的是 ''011'' 
-  - 对 ''jump'' 这部分 ''2-0'' 进行翻译,同样也是通过查表:本例中没有跳转部分(null),对应的 bits 是 ''000''+  - 对 ''jump'' 这部分 ''2..0'' 进行翻译,同样也是通过查表:本例中没有跳转部分(null),对应的 bits 是 ''000''
   - 最后得到的翻译结果是 ''111 0011111 011 000''   - 最后得到的翻译结果是 ''111 0011111 011 000''
 +
 +====Symbols Handling====
 +之前介绍过,根据 symbol 的内容,可以将 symbol 划分为三种类型:
 +  * //varible symbol//:代表着用于数据操作的**内存位置**,该地址映射由汇编器管理
 +  * //label symbol//:代表着 ''goto'' 跳转的**指令位置**
 +  * //pre-defined symbols//:代表着系统占用的特殊内存位置
 +===pre-defined symbols===
 +由于这些 symbol 只会在 A 指令中出现,因此只需要根据对照表,将 symbol 转化为对应的地址值即可:比如 
 +<code nand2tetris-hdl>
 +// R1 corresponds address 1
 +@R1->@1
 +</code>
 +===Label symbols===
 +label 类型的 symbol 主要用于:
 +  * 标记 goto 命令的终点,比如 ''@loop''。这类 symbol 会被直接替换成其值(与 pre-defined symbol 类似),比如下面例子中的 ''LOOP'' 会被替换为 ''16''
 +  * 对应的伪代码声明,比如 ''(loop)'':这类 label 通常不会进行翻译,但汇编器遇到这类 label 时,会将其对应的 symbol 与其起始行关联起来。比如:
 +<code nand2tetris-hdl>
 +@i // line 0
 +M=1
 +@sum
 +M=0
 +
 +(LOOP) // not a instruction line
 +    @i // line 4
 +    ...
 +    @LOOP //line 16
 +</code>
 +这里的 ''(LOOP)'' 标签,对应的 block 起始行为 ''4'';这个关系将会使用一张表来维护:
 +^Symbol^value^
 +|LOOP|4|
 +===Variable symbols===
 +变量类型的 symbol 指非提前定义的,且没有使用 driective 在别处进行定义的(比如 ''LOOP'')的 symbol。上面例子中的 ''@i'',''@sum'' 都是变量类型的 symbol。之前提到过,这类 symbol 都会被存储在一个独特地址的内存单元中(地址从 ''16'' 开始)。因此这类 symbol 对应的值,是他们所在内存单元的地址:
 +^Symbol^value^
 +|i|16|
 +|sum|17|
 +由于变量可能会被多次用到,当第一次用到时,该变量 symbol 和其对应地址会被加入到映射表中;之后再使用时,汇编器会从映射表中查找到该对应关系,并把 symbol 翻译为对应的地址。
 +===Symbol table===
 +可以看到的是,上述的所有翻译都依赖于一种数据结构://Symbol table//,用于建立翻译的映射关系。Hack 计算机的 Symbol table 通过几个阶段进行构造:
 +  * 初始化:这个阶段会建立一张空表,并将 pre-defined symbol 的映射关系写入表中
 +  * 寻找 label 声明:这个阶段(//first pass//)会扫描整个指令序列,将所有的 label 声明找出来
 +    * 当遇到 ''('' 的时候,就识别为 label 的声明
 +    * 同时维护一个计数器,对行数计数。记录的是**已经扫描过的行数**:比如之前的 ''(LOOP)'',其对应的数据是之前已经扫描过的行数 ''4''
 +    * 然后接着扫描,直到遇到下一个 ''('' 开头的 label 声明,重复上面的过程,直到构建出整个 Symbol table 中的 label 声明数据
 +  * 变量处理(//second pass//):这个阶段会再次扫描指令序列,寻找**变量**,再将其与 RAM地址关联,并写入关系到 //Symbol table// 中:
 +    * 新变量会直接加入 symbol table
 +    * 已存在的变量会直接读取 symbol table 中的对应映射关系
 +
 +===Assembly process===
 +<code cpp>
 +// 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
 +</code>
 +