計算機要素--第四章 Hack機器語言規範詳述

計算機系統要素,從零開始構建現代計算機(nand2tetris)
如果完成了本書所有的項目 你將會獲得以下成就

  • 構建出一臺計算機(在模擬器上運行)
  • 實現一門語言和相應的語言標準庫
  • 實現一個簡單的編譯器

而且,這本書的門檻非常低,只要你能熟練運用一門編程語言即可。本課程綜合了數字電路,計算機組成原理,計算機體系架構,操作系統,編譯原理,數據結構等的主要內容,搭建了計算機平臺的構建的框架,並未深入細節,如果需要了解細節,可由本書作爲主線,逐步完善的知識體系。

QQ交流羣(含資料):289682057
課程連接
項目地址Github


本章要完成的內容

  • 乘法程序:該程序的輸入值存儲在R0和R1中。程序計算R0*R1的值並將其存入R2。
  • I/O處理程序:這個程序是個無限循環程序,它偵測鍵盤的輸入。當按下任一鍵時,程序將屏幕變黑,即將“black”寫入每個像素。當沒有鍵按下時,屏幕應該被清屏。你以任何空間順序來選擇屏幕的變黑和清屏,只要連續地按一個鍵足夠長時間,屏幕就會全黑,長時間不按鍵就會清屏。

內容詳解

實現乘法操作

比如:2*3操作,在底層實現上,將其作爲3個2相加來實現,因爲我們前面已經實現了加法操作。可以通過僞代碼來描述 一下這個過程,這個過程比較簡單。

	R0,R1;
	initialize sum = 0;
	while(R1>0){
		R1--;
		sum=sum+a;
	}

實現一個簡單的I/O處理程序

這個I/O程序比較簡單,只需要在屏幕上打印黑色像素即可。項目中關於本程序的描述是這樣的:Runs an infinite loop that listens to the keyboard input. When a key is pressed (any key), the program blackens the screen, i.e. writes “black” in every pixel; the screen should remain fully black as long as the key is pressed. When no key is pressed, the program clears the screen, i.e. writes “white” in every pixel; the screen should remain fully clear as long as no key is pressed.
書中關於本程序的描述:這個程序是個無限循環程序,它偵測鍵盤的輸入。當按下任一鍵時,程序將屏幕變黑,即將“black”寫入每個像素。當沒有鍵按下時,屏幕應該被清屏。你以任何空間順序來選擇屏幕的變黑和清屏,只要連續地按一個鍵足夠長時間,屏幕就會全黑,長時間不按鍵就會清屏。
看完兩端,便會有一個幾個問題:
1、如何定義無限循環?
2、什麼意味着監聽到按鍵?
3、監聽到按鍵後,如何將屏幕變黑?
4、如何清屏?
實際上這些問題並不難,重點理解這個過程。首先需要注意的是SCREEN和KBD被預定義爲表示屏幕內存映像和鍵盤內存映像的基地址。
接下來我們逐個解決這些問題:
如何定義無限循環?
定義無限循環很簡單,重點在於結束時候的跳轉,只要我們保證,它總是跳轉到起始位置即可,代碼如下:

(LOOP)
...
...
@LOOP
0;JMP

什麼意味着監聽到按鍵?
如果有按鍵,那麼鍵盤內存映像中一定不能爲0,所以只要判斷基地址KBD中的內容是否大於零即可。由於程序是在無限循環執行,所以只要按鍵不停,那麼KBD的內容就不爲零,程序就會一直檢測到有按鍵,然後會一直在屏幕上打印。如果鍵盤內存映像中的值爲0,說明沒有按鍵,此時,應該去執行清屏操作(跳轉過去的方式有多種,這裏只列出了一種)。所以這個功能的代碼如下:

@KBD
D=M    // get the basic address of th keyboard memory-map
@FILL
D;JGT  // if D is greater than zero, jump to FILL
@CLEAR // if D is not greater than zero, jump to CLEAR
0;JMP

如何將屏幕變黑?
實際上這就是前面程序代碼中FILL實現的功能。首先我麼得確定,將那個單元變黑,實際上就是將該單元存儲的值置爲-1(參考補碼的內容理解細節)。因此,我們要判斷屏幕內存映像中第一個可用單元(當前單元)是什麼,因此,我們需要一個單元來存儲當前單元的地址,不妨存儲在M[0]中,接着,如何判斷屏幕內存映像是否已滿,即屏幕已經全部置黑。這可以通過將當前單元地址與屏幕內存映像的最大單元地址進行比較,因此,我們需要來存儲最大單元地址,不妨用M[1]。需要注意的是,當前單元表示的是第一個可用單元。如果沒有可用單元的話,那麼M[1]-M[0]<0,如果等於零,則表示,最後一個單元可用。現在完成了是否已滿的判斷,如果滿,那麼我們無法寫入黑色像素,直接返回LOOP,如果未滿,則繼續在當前單元寫入黑色像素,寫完之後返回LOOP。如果按鍵不停的話,那麼循環會一直檢測到按鍵,也就會一直執行FILL模塊,每執行一次會填充一各單元的黑色像素,因此,在屏幕上看到的像素顯示應該是有時間差距的,而不是連續的。本模塊的代碼如下:

/* 這段代碼應該定義在LOOP之前 */
@SCREEN
D=A    // get the basic address of the screen memory-map
@0
M=D    // store the basic address in the M[0]
@24575
D=A    // get the max address of the screen memory-map
@1
M=D    // store the max address in the M[1]
/**************************/
(FILL)
@1    
D=M    // get the max address of the screen memory-map
@0
D=D-M  // get the current address of the screen memory-map, and let the max address minus the current address
@LOOP
D;JLT  // if the result of this minus operation is lower then zero, jump to LOOP

@0
D=M   // get the current address of the screen memory-map
A=D   // store the current address in the A register
M=-1  // let the value of the current address is "black"
@0    
D=M   // get the current address of the screen memory-map
D=D+1 // add the current address
M=D
@LOOP
0;JMP // return to the LOOP

如何清屏?
這個問題類似於第三個問題的反過程。當程序檢測到沒有按鍵時,就會進入清屏的子程序。然後進行清屏操作。如果要清屏,我們只需要獲得程序當前地址,對它減一,然後與SCREEN比較是否小與SCREEN(因爲小與SCREEN意味着清屏結束),如果大於或等於那麼我們就將當前地址中的內容置零,也就是清屏。那麼結束條件,前面已經提到了,就是小與SCREEN一位置結束。在這種彙編程序中,通過是將兩數相減,然後跟零比較來判斷兩數的大小。代碼如下:

(CLEAR)
@0
D=M     // get the current address
D=D-1   // do the minus operation
@SCREEN // get the basic address
D=D-A   // let current address minus basic address
@LOOP
D;JLT   // do just, if D is lower than zero, jump to LOOP
@0      
D=M     // get the current address
A=D     // store the current address in the A register
M=0     // clear the "black", in another word
@LOOP
0;JMP   // return to LOOP

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章