胡世昌
(沈陽師范大學(xué) 軟件學(xué)院,沈陽 110034)
“不聞不若聞之,聞之不若見之,見之不若知之,知之不若行之。學(xué)至于行之而止矣。”在硬件課程教學(xué)中,人們一直在探索更好的實驗改革方案[1-3]。對于計算機(jī)組成原理課程教學(xué),“行之”的境界,應(yīng)該是能夠設(shè)計一臺簡單的計算機(jī)。這種設(shè)計應(yīng)該是從“0”和“1”開始,根據(jù)數(shù)字電路基礎(chǔ)知識,結(jié)合計算機(jī)組成原理課程的內(nèi)容,實現(xiàn)滿足要求的簡單計算機(jī),而不應(yīng)是半成品的簡單連接和驗證。這種實現(xiàn)同樣不應(yīng)該受限于任何教材,講解《計算機(jī)組成原理》時,有的講解順序是運算器→存儲器→控制器[4],有的講解順序是存儲器→運算器→控制器,先設(shè)計哪一個環(huán)節(jié),都不能影響最終設(shè)計出一個簡單計算機(jī)這樣的目標(biāo)。綜合考慮成本、方便性,logisim-evolution仿真軟件(https://github.com/reds-heig/logisim-evolution)是一個不錯的選擇。
機(jī)器的指令集選擇圖靈完備的單指令SUBLEQ[6]來實現(xiàn)算術(shù)運算和轉(zhuǎn)移,單指令集計算機(jī)[7-8]適合教學(xué)。為簡化設(shè)計,把減法指令分成有跳轉(zhuǎn)(SJ)和無跳轉(zhuǎn)(SN)2條指令,用與非指令(NA)實現(xiàn)邏輯運算[9],共需實現(xiàn)3條運算指令。
由于存儲系統(tǒng)具有地址線16根、數(shù)據(jù)線8根,如果采用直接尋址,2個操作數(shù)的地址就需要訪存4次才能取回對應(yīng)地址的4個字節(jié),為了減少存儲器的訪問次數(shù)、縮短運算指令的長度,采用基址尋址,為此需要增加設(shè)置基地址指令(BA)。
由此得到了必須具備的4條指令,需要2位二進(jìn)制碼對這4條指令進(jìn)行編碼,如表1所示。
表1 指令編碼
“無跳轉(zhuǎn)減”運算指令SN、“與非”運算指令NA的長度都是1個字節(jié),指令格式為pp aaa bbb, D7D6兩位(pp)表示操作碼,D5D4D3三位(aaa)是A操作數(shù)的形式地址,D2D1D0三位(bbb)是B操作數(shù)的形式地址,它們作為有效地址的低3位,與基地址共同構(gòu)成16位有效地址,基地址僅僅負(fù)責(zé)提供有效地址的高13位。“設(shè)置基地址”指令(BA)是3字節(jié)指令,它的3個字節(jié)分別是(x表示0或1):00xxxxxx,基地址低字節(jié),基地址高字節(jié)。Subleq A,B,C是3字節(jié)指令,它的3個字節(jié)分別是:01aaabbb,C地址低字節(jié),C地址高字節(jié)。
需要3個字節(jié),第1字節(jié)的二進(jìn)制表示為00xxxxxx,其中x表示該位取值0或1;采用低字節(jié)在前的方法表示數(shù)字,所以第2字節(jié)是00(H),第3字節(jié)是10(H)。于是得到設(shè)置基地址指令的十六進(jìn)制表示為00 00 10(H)。
指令目標(biāo)是1000地址單元的內(nèi)容和1001地址單元的內(nèi)容做減法,結(jié)果放在1001地址單元,不跳轉(zhuǎn)。它是1字節(jié)指令,對應(yīng)的二進(jìn)制表示為10 000 001,轉(zhuǎn)換成十六進(jìn)制表示為81(H)。
指令系統(tǒng)中沒有專門的停機(jī)指令,可跳到預(yù)先設(shè)定的某個循環(huán)地址,如0FFD,讓機(jī)器進(jìn)入無限循環(huán)。
2.3.1 設(shè)置基地址為0000
這是一個3字節(jié)指令,代碼為00 00 00(H)。
2.3.2 無條件跳轉(zhuǎn)到0FFD地址
利用Subleq指令實現(xiàn),具體方法是讓0000地址單元的內(nèi)容減去0000地址單元的內(nèi)容,這個結(jié)果顯然必定為零,從而發(fā)生跳轉(zhuǎn)。又因為0000地址單元在ROM中,所以不可能真正寫入,也就不會改變程序。指令所對應(yīng)的3個字節(jié)是:第1字節(jié)包含操作碼,其二進(jìn)制代碼為01 000 000,對應(yīng)十六進(jìn)制40(H);第2字節(jié)包含跳轉(zhuǎn)的低位地址,這里為FD(H);第3字節(jié)包含跳轉(zhuǎn)的高位地址,這里為0F(H)。于是得到無條件跳轉(zhuǎn)指令的十六進(jìn)制代碼為40 FD 0F(H)。
2.3.3 完整測試代碼
實現(xiàn)“(1000)-(1001)→ 1001功能,之后無限循環(huán)”的整個程序代碼由10個字節(jié)構(gòu)成,內(nèi)容是00 00 10 81 00 00 00 40 FD 0F(H)。
實現(xiàn)上述功能的算術(shù)邏輯單元只需8位減法器和8位與非門即可,運算方式選擇輸入端S0N1為0時做減法運算,為1時做與非運算;輸出F表示運算結(jié)果,狀態(tài)標(biāo)志leq在運算結(jié)果小于或等于0時置1。
這個ALU雖然簡單,但需要譯碼、尋址,所以能夠作為實現(xiàn)的例子來使用,而且給學(xué)生留下了更多的改進(jìn)空間,可以去實現(xiàn)更加復(fù)雜的ALU。
ALU需要2個輸入寄存器保存輸入數(shù)據(jù),分別稱為A和X,它們可以分別用來保存參與運算的2個操作數(shù)A和B。為保存Subleq的跳轉(zhuǎn)目的地址C,設(shè)置專用寄存器CL和CH,CL用于保存C的低字節(jié),CH用于保存C的高字節(jié),它們連接到程序計數(shù)器PC的數(shù)據(jù)輸入端,以便改變PC的值。
對應(yīng)設(shè)置基地址指令base,相應(yīng)設(shè)置了基址寄存器,基址寄存器的位數(shù)最少應(yīng)該是13位,與指令中所給出的低3位結(jié)合,才能訪問所有的內(nèi)存空間。為了設(shè)計上的方便,本CPU中采用16位基址寄存器(低3位不用),對應(yīng)2個8位寄存器BAL和BAH,其中BAL用于保存基地址的低字節(jié),BAH用于保存基地址的高字節(jié)。
有效地址的高13位來自寄存器BAL和BAH,低3位來自指令中的aaa和bbb部分。實現(xiàn)電路如圖2所示,有效地址的低3位由指令寄存器中直接給出,高13位則由BAL和BAH給出,共同形成A操作數(shù)和B操作數(shù)的有效地址。
這樣就需要6個寄存器:A、X、CL和CH、BAL和BAH。此外,還需要指令寄存器IR、程序計數(shù)器PC和內(nèi)存地址寄存器MAR。由于例題相對簡單,內(nèi)存數(shù)據(jù)寄存器MDR可以不用。
指令譯碼器是一個2線-4線譯碼器,指令寄存器(IR)的最高2位作為指令譯碼器的輸入,指令譯碼器的4個輸出分別代表BA、SJ、SN、NA指令,高電平有效。例如當(dāng)BA=1時,表明指令譯碼器中保存的是設(shè)置基地址指令。
完整的CPU如圖2所示,包括ALU、寄存器、指令譯碼器和控制單元CU(控制器)??刂茊卧妮斎氚◤?fù)位、時鐘、使能信號、指令譯碼器的輸出信號BA、SJ、SN、NA和ALU的狀態(tài)標(biāo)志leq,輸出是用于三態(tài)門和寄存器的控制信號。為控制數(shù)據(jù)的流動,添加了必要的三態(tài)門,并給各個寄存器提供寫使能控制信號,這些控制信號的來源是控制單元的輸出。
確定了輸入和輸出信號之后,就可以設(shè)計控制器??刂茊卧跁r鐘的控制下,根據(jù)不同的輸入信號,有序地輸出一系列相應(yīng)的控制信號,控制ALU、寄存器、存儲器和I/O設(shè)備去執(zhí)行一系列的動作(微操作),來完成輸入信號所規(guī)定的功能。所以設(shè)計控制單元的第一步,就是確定不同輸入信號所對應(yīng)的一系列微操作。
規(guī)定寄存器和RAM都由時鐘上升沿觸發(fā),所有控制信號都是高電平有效。
第1個時鐘(T0)上升沿之后,給出MARi信號,MAR寄存器準(zhǔn)備接受內(nèi)存地址輸入。
第2個時鐘(T1)上升沿之后,內(nèi)存地址寫入MAR,寫入后內(nèi)存地址才能出現(xiàn)在地址總線(AB)上。同時可以給出讀內(nèi)存命令(R1_W0=1,MEMREQ0=0)。
第3個時鐘(T2)上升沿之后,“讀內(nèi)存”命令發(fā)揮作用,內(nèi)存單元的內(nèi)容被讀出到數(shù)據(jù)總線(DB)上。需要注意的是,如果讀信號在第3個時鐘上升沿到來時已經(jīng)消失(R1_W0=0,MEMREQ0=0),將會變成“寫內(nèi)存”命令,所以必須確保第3個時鐘上升沿到來時,讀信號依然有效。解決方案是把讀命令加寬為2個時鐘周期,在第2、3節(jié)拍中都確保讀命令(R1_W0=0,MEMREQ0=0)有效。
本機(jī)只有取指和執(zhí)行2個階段,可用T觸發(fā)器構(gòu)成工作階段寄存器STG,當(dāng)STGi=1時,T觸發(fā)器翻轉(zhuǎn)。F0E1=0表示取指階段,F(xiàn)0E1=1表示執(zhí)行階段;經(jīng)1輸入2輸出譯碼器譯碼后,F(xiàn)E=1表示取指階段,EX=1表示執(zhí)行階段。對應(yīng)電路如圖3所示。
7.3.1 取指令第1字節(jié)
表2 取指周期-讀入第1個字節(jié)
7.3.2 根據(jù)指令操作碼確定后續(xù)操作
T2上升沿,指令碼進(jìn)入CPU內(nèi)部DB,還沒有進(jìn)入IR,此時不能譯碼;T3上升沿,指令碼才能進(jìn)入IR,所以在T3節(jié)拍才可以得到譯碼結(jié)果,并根據(jù)譯碼結(jié)果,從T3節(jié)拍開始執(zhí)行不同的微操作序列。
T3~T8節(jié)拍中各個指令的微操作如下:
1)設(shè)置基地址指令(BA):從內(nèi)存中取出2字節(jié)地址存入基址寄存器,之后進(jìn)入下一條指令的取指周期,如表3所示。
表3 取指周期-設(shè)置基地址
2)Subleq 指令(SJ):從內(nèi)存中取出2字節(jié)地址存入C寄存器,之后進(jìn)入執(zhí)行周期,完成減法運算(表4)。為了標(biāo)識CPU進(jìn)入了執(zhí)行周期,設(shè)置STGi來改變執(zhí)行階段寄存器STG的值。
表4 取指周期-Subleq
3)無跳轉(zhuǎn)減指令SN、與非指令NA:在T3~T8節(jié)拍中沒有具體操作,只需更改STG即可(表5)。
表5 取指周期-SN和NA
BA指令沒有執(zhí)行周期,SJ、SN、NA指令的執(zhí)行周期基本相同,如表6所示。
表6 執(zhí)行周期
綜合取指周期和執(zhí)行周期的微操作信號表,可得到控制信號的邏輯表達(dá)式,例如
STGi=FE·(SJ·T8+(SN+NA)·T8)+
EX·(SJ+SN+NA)·T8,
PCi=EX·SJ·T8·leq。
其他表達(dá)式不一一列舉。根據(jù)表達(dá)式,就可以得到相應(yīng)的組合邏輯電路圖,例如STGi以及設(shè)置指令周期狀態(tài)的寄存器如圖4所示。
首先根據(jù)前文分析中所得到的控制信號出現(xiàn)的先后順序,寫出控制存儲器中每一個地址單元的內(nèi)容,如表7所示。根據(jù)表中所列的控制信號,可知控制信號需要17位;因為控制存儲器的地址編號有27個(對應(yīng)表中的編號0~26),可知下地址字段需要5位;二者相加,可知控制存儲器的位寬應(yīng)該是22。
表7 微程序控制器的代碼
表中第2列表示指令當(dāng)前所處的工作階段,其中FE表示取指周期的第1階段(取指令的第1字節(jié))。組合邏輯控制器的FE階段只需要3個時鐘周期,微程序控制器的FE階段卻需要4個時鐘周期,這是因為組合邏輯電路可以在1個時鐘周期(T3)內(nèi)完成譯碼以及根據(jù)譯碼結(jié)果確定相應(yīng)微操作的工作,而微程序控制方案中則需要2個時鐘周期,前一時鐘周期完成譯碼并根據(jù)譯碼結(jié)果確定下一個微地址,在下一時鐘周期才能把所確定的微地址寫入控制存儲器CMAR(這是由存儲器的工作特性所決定的)。
下地址字段決定了下一條指令的地址,用來修改CMAR,其含義有如下幾類:(1)第3行表示根據(jù)指令寄存器中的操作碼字段的譯碼結(jié)果決定下地址,BA轉(zhuǎn)地址4,SJ轉(zhuǎn)地址10,SN轉(zhuǎn)地址17,SA轉(zhuǎn)地址18。(2)第26行表示如果當(dāng)前指令是SJ指令且計算結(jié)果小于等于0(leq),則轉(zhuǎn)地址16(給PC賦值,以便實現(xiàn)指令跳轉(zhuǎn));否則直接轉(zhuǎn)CMAR地址0(取下一條指令)。(3)轉(zhuǎn)下地址字段給定地址(當(dāng)前地址加1,或地址0、或地址19)。
控制存儲器(控存)的下一條指令地址來自CMAR寄存器,其來源有3個:(1)當(dāng)前地址為3時,選擇來自指令操作碼所決定的地址(4、10、17或18);(2)當(dāng)前地址為26、指令為SJ、且leq為真時,選擇地址16;(3)其余情況,直接來自控存的下地址字段。
當(dāng)前地址為3和26的兩種情況,需要借助硬件實現(xiàn),如圖5所示。
其余情況則直接使用下地址字段即可。由此可得控制存儲器每個單元內(nèi)容,如0地址單元的內(nèi)容為10 0100 0000 0000 0000 0001(B),或者240001(H);1地址單元的內(nèi)容為00 0011 0000 0000 0000 0010(B),或者030002(H);其他地址單元的內(nèi)容依次類推。把所得到的每個地址單元的內(nèi)容寫入控制存儲器,就完成了微程序控制器的設(shè)計。
各部件設(shè)計完畢以后,連接起來,就構(gòu)成了一臺具有CPU和存儲器的簡單的機(jī)器。在步驟3已經(jīng)設(shè)計好了測試方案,只需運行測試代碼即可驗證所設(shè)計的計算機(jī)是否正確。在0000地址單元的起始部分(這里是ROM)填入用十六進(jìn)制表示的指令序列00 00 10 81 00 00 00 40 FD 0F,并在1000地址單元存入數(shù)據(jù)A,1001地址單元存入數(shù)據(jù)B,運行程序,運行后應(yīng)該在1001地址單元得到A-B的結(jié)果。如果結(jié)果正確,就說明這個由10個字節(jié)組成的程序確實實現(xiàn)了(1000)-(1001)→1001這個功能;之后機(jī)器進(jìn)入無限循環(huán)。
本設(shè)計側(cè)重于介紹一種低成本的、直觀的方法,學(xué)會從基本邏輯電路開始,快速地設(shè)計一臺簡單計算機(jī),它服務(wù)于《計算機(jī)組成原理》課程的教學(xué),僅以計算機(jī)的設(shè)計和實現(xiàn)為目的,對運算程序在空間和時間上的資源消耗未加考慮。
在課程教學(xué)中,給了學(xué)生3種選擇:獨立設(shè)計(自行設(shè)計一個簡單的計算機(jī),指令集不要求完備)、讀懂老師給的設(shè)計并改進(jìn)、單純讀懂。要求不論是設(shè)計還是改進(jìn),都不能重復(fù)。43名學(xué)生中,在選擇環(huán)節(jié)有8名選擇了獨立設(shè)計,2名選擇改進(jìn),33名選擇了單純讀懂;最終完成時,有2名學(xué)生放棄了獨立設(shè)計。這說明,要求所有學(xué)生掌握計算機(jī)的設(shè)計還不現(xiàn)實,更加復(fù)雜的指令系統(tǒng)的設(shè)計暫時還不宜引入。
在計算機(jī)組成原理課程中,使用logisim-evlution設(shè)計簡單計算機(jī),有益且可行。在條件允許的情況下,本設(shè)計可以有更多改進(jìn)的地方,比如考慮使用多總線、更多的通用寄存器、RAM采用下降沿觸發(fā)、仿真cache的實現(xiàn)、增加指令等。在邏輯電路的實現(xiàn)過程中,會發(fā)現(xiàn)根據(jù)邏輯表達(dá)式畫邏輯圖這個步驟,可以借助自動化工具來完成,從而在時間允許的條件下引入硬件描述語言實現(xiàn)。