一旦我們構建了一臺計算機,下一步就是開發一種匯編語言,然后是一個可以匯編我們程序的匯編器。
?
在我之前的專欄中,我們介紹了在計算機內存中存儲多字節(或在我們的例子中是多 nybble)數據塊的大端與小端方式的概念。我們還概述了計算機設計者可能決定支持的一些尋址模式。現在是時候開始為我們的 4 位 HRRG 計算機考慮匯編語言和匯編程序了。
作為我們討論的起點,讓我們進行一個簡單的思想實驗。假設我們剛剛完成了 4 位 HRRG 計算機的構建。我們還假設它是地球上的第一臺計算機;也就是說,沒有任何其他計算機,或編程語言,或者……嗯,任何東西,真的。
讓我們對自己大方一點,假設我們還開發了一些輸入和輸出設備——看起來有點像 QWERTY 鍵盤、VT100 終端和紙帶閱讀器/寫入器——并且我們已經將它們連接到了一些 HRRG輸入和輸出端口,但我們還沒有創建任何代碼來驅動小流氓。
在繼續本專欄的其余部分之前,為什么不暫停片刻來思考您的下一步是什么。
以機器代碼捕獲和輸入程序
作為快速提醒,HRRG 有 16 個寄存器并支持 16 條指令,如下所示(關于各種指令執行其魔法的方式的更詳細討論在我們的“指令集”和“指令權衡”列)。
我們的首要任務是創建一個非常非常簡單的程序,只是為了確保這個野獸能夠正常工作。如果我們決定使用鉛筆和紙來繪制帶有相關注釋的流程圖來捕捉該程序的意圖,我不會感到驚訝,如下圖所示:
下一步將是計算出我們想要將哪些操作碼和操作數加載到計算機內存中以實現我們的程序。再一次,這可能涉及鉛筆和紙以及一些皺眉和撓頭,導致如下所示:
這種類型的表示被稱為“機器代碼”,因為這些是我們的計算機(機器)將執行(處理)的二進制代碼。
最后但并非最不重要的一點是,我們希望將機器代碼加載到我們的計算機中并運行程序,但我們將如何做到這一點?好吧,我們可能會構建一個開關面板并將其連接到計算機。至少,這將涉及 12 個用于表示地址的撥動開關,4 個用于表示數據的撥動開關,以及幾個控制開關和按鈕,如下圖所示。
為了進入程序,我們將“Program/Run”開關設置為“Program”,在地址開關上設置一個地址,在數據開關上設置一個相應的操作碼或操作數,然后按下“Load”按鈕將此值加載到內存中。我們將對構成我們程序的所有 nybbles 重復此過程。上圖顯示我們準備將 $C(跳轉)操作碼輸入到內存位置 $106。
輸入程序后,我們將地址開關設置為指向程序的起始地址(本例中為 100 美元),然后將“程序/運行”開關切換到“運行”。
用匯編語言捕獲程序
許多設計原始計算機的團隊認為,為了獲得最佳結果,有必要盡可能靠近機器。也就是說,他們的理念是以盡可能接近機器內部表示的形式編寫程序;即機器碼。
然而,正如您可能想象的那樣,以機器代碼捕獲和輸入程序是耗時的、容易出錯的,并且——最終——在下面的區域中是一種痛苦。抽象階梯的下一步是用稱為匯編語言的低級符號編程語言捕獲程序,其中程序語句和計算機的機器代碼指令之間存在非常強的對應關系。(英國數學家 Kathleen Booth 根據她 1947 年開始的理論工作發明了匯編語言的概念。)
當然,擁有匯編語言與擁有匯編程序不同,匯編程序一詞是指將匯編源代碼轉換為可執行機器代碼的實用程序。在我們的思想實驗中,我們仍處于使用鉛筆和紙捕捉程序的階段。
假設我們已經定義了 HRRG 匯編語言(我們將在下一篇專欄中更詳細地討論這種語言)。在這種情況下,我們可以使用鉛筆和紙以匯編語言捕獲我們的程序,并將其手動組裝成機器代碼。讓我們考慮一下在我們的原始測試程序的情況下這可能是什么樣子,如下圖所示:
非常有用的一件事是將標簽與關鍵指令的地址相關聯,例如標記循環開始的 LOOP 標簽。在執行程序時,我們將構建一個標簽及其地址的交叉引用表,如上圖右上角所示。
對于我們的簡單程序,我們在使用標簽之前聲明了它們,這讓我們的生活變得輕松。在一個更復雜的程序中,我們可能會在聲明它之前引用一個標簽(例如,跳轉到一個標簽位于程序下方的子程序)。在這種情況下,我們將對源代碼執行多次遍歷,其中第一次遍歷允許我們確定所有標簽的地址,第二次遍歷允許我們解析第一次不知道的任何地址-時間循環。
通過我們的引導來提升自己
這就是事情開始變得有趣的地方。首先,我們將創建幾個簡單的低級實用程序,以允許我們監控鍵盤并使用我們的紙帶閱讀器/寫入器。我們將通過用鉛筆和紙捕獲源代碼,將其手工組裝成機器代碼,然后使用我們的開關面板將機器代碼加載到計算機的內存中來做到這一點(請注意,我們可以將多個程序存儲在記憶)。
大約在這個時候,我們還將創建一個低級監控程序。這樣的程序提供了一個簡單的用戶界面——通常基于單字符命令——以允許用戶執行檢查和更改內存、讀取或寫入 I/O 端口以及將控制權轉移到內存中的其他程序等操作。再一次,該程序將使用鉛筆和紙捕獲,手工組裝,并使用開關面板加載到計算機的內存中。
接下來,我們將創建一個簡單的匯編程序,僅支持我們最終希望擁有的功能的一個子集。和以前一樣,這個簡單的匯編程序將使用鉛筆和紙來捕獲,手工組裝,然后使用開關面板加載到計算機的內存中。
現在我們準備好搖滾了,因為我們可以使用類似電傳終端的東西來捕獲我們的第一遍匯編器支持的匯編語言子集中的程序,并將這些源代碼程序寫入紙帶。接下來,我們可以使用監控程序和我們的實用程序從紙帶中讀取此源代碼并將其存儲在計算機內存的一個區域中。然后我們可以使用我們的第一遍匯編器將這個源代碼匯編成可執行的機器代碼并將其存儲在另一個內存區域中。此時,我們可以對存儲在計算機內存中的可執行機器代碼做兩件事:
例如,交叉匯編器是一種匯編器,它可以將指令轉換為計算機的機器代碼,而不是運行它的計算機。我在 HRRG 上的同謀,EEWeb 專家 Joe Farr,創建了一個在 PC 上運行的 HRRG 交叉匯編器,它采用 HRRG 的匯編語言編寫的程序,并生成可執行的機器/目標代碼以在 HRRG 上運行。下面的兩張圖片顯示了同一程序片段的源代碼和目標代碼版本。
?
HRRG 交叉匯編源代碼查看(來源:Joe Farr)
?
?
HRRG 交叉匯編器目標代碼視圖(來源:Joe Farr)
?
更棒的是,HRRG的匯編器是一個宏匯編器,它是一個可以進行宏替換和擴展的匯編器。這允許我們定義由一個或多個語句組成的宏,然后在程序中稍后使用這些宏名稱,從而避免重寫語句。
舉個簡單的例子,HRRG 的指令集不包含 HALT 指令。但是,我們可以在 HRRG 的匯編語言中將這樣的指令實現為宏,如下所示:
.MACRO HALT
OR %0010, S1
.ENDMACRO
現在,我們可以將前面程序示例中的 OR 指令替換為 HALT,這有助于使程序更易于理解。此外,我們可以將所有宏捆綁到一個單獨的文件中,我們可以使用 .INCLUDE 指令將其導入到我們的程序中。
在我的下一篇專欄中,我們將研究 HRRG 的匯編語言,我們還將考慮如何使用宏來實現 HRRG 本身不支持的一堆指令,例如 ADD、SUB、ROL、ROR、ASHL 、ASHR、LSHL 和 LSHR。與此同時,我一如既往地歡迎您提出意見和問題。
審核編輯 黃昊宇
評論
查看更多