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!

相關文章
相關標籤/搜索