nand2teris - hack assembler

已经把nand2teris的part1学完了,如今才写的缘由是终于到了software hierarchy部分了,project是正式的coding..而不是讨厌的HDL了hhh(其实HDL也很是有意思。)。project6写这个hack machine code的assembler我以为是一个承上启下的unit,因此从这里概括一下往下的hardware和开始以后的top layer,以后的software hierarchy对大多数人实际上是更有用的,因此以后的每一个project都会记录一下。git

github:https://github.com/Lunaticf/n...github

1. what is nand2teris and the part1

nand2teris官网: https://www.nand2tetris.org编程

nand2teris是一门教你from the ground up从一个nand逻辑门开始造一台计算机的课程,分为硬件和软件两个part。Cousera上学起来比较方便,可是project和其余资源彻底开放,不看视频彻底没问题,甚至能够节省至关多的时间,干货都在pdf和project。而且这门课对初学者很是友好,甚至不要求你有编程经验,在project6写汇编器的时候甚至提供了非编程的版本,让你手动翻译程序到binary code也能够过(虽然我以为这样也太蠢了....)。这门课另外一个好处在于模块划分很是清晰和独立,按部就班,而且打造了至关好的多个可视化工具,帮助你理解和实践。而且整个HDL硬件编程语言和CPU的指令集都是从新设计的简化版,很是友好,能够想象投入了很是大的精力,天然这门课也是好评如潮,两个老师也很萌,每一个week最后的perspective最爱看了。架构


part1的各个项目:编程语言

  • Boolean Logic 用与非门设计And,Or,Not,Multiplexor等基本逻辑门
  • Boolean Arithmetic 设计半加器、全加器和ALU等
  • Sequential Logic 以上都是combinational的chip,不能维护状态,构建寄存器和RAM
  • Machine Language 用汇编先写一点程序
  • Computer Architecture 设计CPU,这里用的是程序和数据分离的哈佛架构
  • Assembler 将汇编程序转化为binary code

我在完成part1的各个project的过程当中感觉就是学到了如何从一个简单的逻辑门一步一步搭建到各个模块,体会用基础的逻辑门实现多路复用等逻辑,再从各个小的模块构建到更大的模块好比ALU,RAM,很是深的体会了Abstract这一计算机科学的核心,在实现high level的chip的时候用到小的chip,彻底不用care里面的细节,只须要focus其输入输出。另外就是重温了一下硬件编程,刚上手的时候就想起来本科的时候数电的时候曾经写过的verilog,而且当即就想起了怎么用真值表来构造表达式,算出这个chip所须要的逻辑门组合,而后天然而然就过渡到化简更方便的卡诺图等,固然也要感谢这门课设计的精简的hdl,让我忘记了被verilog支配的恐惧。另一个很深的感触就是学过的知识确实是有用的,在你的mind里其实会创建索引,可能索引指向的数据会忘掉,可是可让你往后有这种deja vu(似曾相识的)的感受,立刻就能按图索骥拾起来。工具

我以为每一个CS的新生均可以学一下这门课,创建起down to top的对计算机体系的总体的感性认识,这样以后再去学数电、操做系统和编译原理等专业课的时候会有必定的帮助,研究各个系统的detail。spa

2. the hack assembler

在完成了part1以后,咱们就能够过渡到software hierarchy啦~看到图中下面已经变成一个Hack chip了,这意味着咱们已经完成对Hardware一整层的Abstract了,只须要把它当成一个能运行Binary code的computer。操作系统

用Java快速写了一个很laji的版本,https://github.com/Lunaticf/n...
须要注意的是这里Project只要求翻译正确的汇编程序,也就是提供的须要转换的汇编程序语法上是正确的,也下降了必定的难度,毕竟不是Compiler的课程。
实现的核心就是根据Binary code的规范来将汇编程序.asm转换为.hack二进制代码。,指令集也是很是简单的,照着提供的大体流程写就好了。主要有Parser和Generator两个核心类,Parser用于返回每个有效line,在调用hasNext的时候跳过空行与注释,同时也要对语句进行trim和判断是否有行尾注释。主类调用Parser返回每一行有效的汇编语句后,调用Genertor生成bianry code,指令集很简单,只有A指令和C指令两种指令,转译便可。另外就是SymbolTable的概念,汇编语言天然须要定义本身的symbol来更方便的编程,那么咱们须要定义一个SymbolTable,这里我直接用Java的HashMap来实现,首先预约义一些symbol好比Screen、Keyboard这些键,值就是其内存起始地址。咱们的汇编器须要对程序进行两遍的扫描,first pass来扫诸如(xxx)这样的label,主要是由于这类label可能会出如今定义其label的语句以前就被调用,咱们没有办法扫描的时候就给出symbol的value,因此须要two pass。翻译

初学者须要注意一些细节,好比在A指令定义一个新的symbol的时候,是从内存的16开始存放,你可能会以为那程序中若是用到过@1六、@17的语句,那么不是重复使用这一个Byte了么,其实这里也仍是简化了,在论坛中发现助教回答诸如如下@常量的语句后面跟的都是:设计

@18
D=A

这些数字不用作内存地址的reference,而是只是用来赋值常量的。
另外就是在first pass的时候统计行号的时候注意不要统计label这一行。

单独写一个很快速的版本过test是比较简单的,py写的话能够不到100行,其实还有不少能够完善的点,好比检测语法错误、重复的label、D+A能够写成A+D等等,使其更加robust,还能够用js直接写一个网页的可视化版本,可是完成课程要求的已经足够理解基本原理了,Keep moving!

相关文章
相关标签/搜索