摘 要:設(shè)計(jì)了一款面向嵌入式控制領(lǐng)域的16位堆棧處理器,該處理器包含兩個(gè)堆棧:執(zhí)行數(shù)學(xué)表達(dá)式的數(shù)據(jù)堆棧和支持子程序調(diào)用的返回堆棧,其指令集含35條堆棧指令.詳細(xì)給出了該堆棧處理器的體系結(jié)構(gòu)及設(shè)計(jì)方法;不僅采用簡單有效的指令編碼方式縮小了代碼體積,同時(shí)給出了單周期操作多個(gè)堆棧元素的解決方法.該處理器采用FPGA實(shí)現(xiàn),在XC5VLX110T芯片上的運(yùn)行時(shí)鐘頻率最高達(dá)到146.7MHz。最后給出了設(shè)計(jì)的軟件仿真與硬件綜合結(jié)果。
1 引言
Forth是由Charles H.Moore在1960年代發(fā)明的一種基于堆棧、可擴(kuò)展、具有簡單哲學(xué)思想的計(jì)算機(jī)編程語言[1],特別適合于軟件代碼在千行數(shù)量級的中規(guī)模嵌入式系統(tǒng)中應(yīng)用,并且已經(jīng)被國外廣泛應(yīng)用于天文、軍事、航空航天、工業(yè)自動(dòng)化、圖形、儀器儀表等領(lǐng)域。
Forth語言既可以被看作匯編語言又可以被看作高級語言,它與傳統(tǒng)語言最大的區(qū)別在于它是基于堆棧的和可擴(kuò)展性。Forth語言本質(zhì)上定義了一種雙堆棧體系結(jié)構(gòu)。這種體系結(jié)構(gòu)的主要思想是基于兩個(gè)不同的堆棧,一個(gè)是用來執(zhí)行數(shù)學(xué)表達(dá)式的數(shù)據(jù)堆棧,另一個(gè)是用來支持子程序調(diào)用的,即保存子程序返回地址的返回堆棧,指令的所有操作都是針對這兩個(gè)堆棧的一個(gè)或者幾個(gè)棧頂元素[2]。
Forth語言定義的這種雙堆棧體系結(jié)構(gòu)清晰明了,復(fù)雜度低,并且其主要面向的是嵌入式控制領(lǐng)域。在這種背景下,結(jié)合FPGA的靈活性,本文設(shè)計(jì)并實(shí)現(xiàn)了一種基于FPGA 的16位堆棧處理器,相比基于RISC體系結(jié)構(gòu)的嵌入式處理器,具有以下幾點(diǎn)優(yōu)勢:
① 很大程度上避免了處理器進(jìn)行上下文切換帶來的開銷,因?yàn)樘幚砥鞯倪\(yùn)行不依賴于大量的通用寄存器;
② 處理器的尋址方式非常簡單,幾乎所有指令都是0操作數(shù)指令.這樣不僅系統(tǒng)復(fù)雜度顯著降低,速度得到提升,代碼體積也大大減?。?/p>
③ 處理器在運(yùn)行具有深度嵌套特征的程序時(shí)有更加明顯的優(yōu)勢,因?yàn)榫哂袑iT的硬件堆棧來執(zhí)行子程序調(diào)用與返回。
2 設(shè)計(jì)與實(shí)現(xiàn)
2.1 堆棧處理器體系結(jié)構(gòu)概覽
處理器的結(jié)構(gòu)如圖1所示,為了能夠清晰地展示其結(jié)構(gòu),部分信號并未顯示或直接連接.處理器包含的主要模塊見表1。
需要說明的是,表中的數(shù)據(jù)堆棧由棧頂寄存器T、次棧頂寄存器N1、第三棧頂寄存器N2以及深度為32的堆棧存儲(chǔ)器構(gòu)成;返回堆棧由棧頂寄存器R以及深度為32的堆棧存儲(chǔ)器構(gòu)成。
2.2 指令集
2.2.1 指令集設(shè)計(jì)
處理器實(shí)現(xiàn)了四種類型共35條指令,具體如下表2所示。
表中大部分指令遵從了Forth語言的原語命名規(guī)則與功能.比如,其中的‘>r’表示將數(shù)據(jù)堆棧棧頂寄存器T的內(nèi)容彈出到返回堆棧棧頂寄存器R,‘r>’則表示相反的功能.另外,‘@’表示從存儲(chǔ)器讀數(shù)據(jù)到數(shù)據(jù)堆棧,而‘!’表示將數(shù)據(jù)堆棧的內(nèi)容存儲(chǔ)到存儲(chǔ)器中.下面分別簡述各種類型指令的功能。
① 堆棧操作:主要是對數(shù)據(jù)堆?;蛘叻祷囟褩5囊粋€(gè)或者多個(gè)棧頂元素的操作.例如,swap指令交換T與N1的內(nèi)容;one和zero指令分別將T的所有bit位置1和0;drop指令彈出T中內(nèi)容并拋棄.所有的堆棧操作類型指令都在一個(gè)周期內(nèi)完成。
② 數(shù)學(xué)運(yùn)算:數(shù)學(xué)運(yùn)算指令的操作數(shù)均為T和N1中內(nèi)容.邏輯運(yùn)算指令包括or、xor和and;移位指令包括asr、lsr和lsl;1plus和1min分別將數(shù)據(jù)堆棧棧頂元素加1和減1.所有數(shù)學(xué)運(yùn)算類型指令都在一個(gè)周期內(nèi)完成。
為了節(jié)省硬件資源,堆棧處理器沒有實(shí)現(xiàn)硬件支持的乘法器[3]和除法器[4],因此沒有直接的乘法和除法指令,取而代之的是mpp和shld指令.這兩條指令分別完成了乘法器和除法器在一個(gè)時(shí)鐘周期中完成的操作.mpp指令執(zhí)行時(shí)需要同時(shí)操作寄存器T、N1和N2.N1與N2中分別存放初始的乘數(shù)與被乘數(shù),T的初始值為0;最終乘積結(jié)果的高低16位分別存放于T與N1.mpp指令的執(zhí)行分成兩步.第一步判斷N1最低位是否為1:如果為1,將N2與T中內(nèi)容相加;否則不做操作.第二步將T做高位、N1做低位,對其內(nèi)容進(jìn)行邏輯右移.這樣連續(xù)執(zhí)行完16條mpp指令后,T與N1中存放的分別為乘積的高低16位.這16條mpp指令再配合其他幾條指令便可以完成正常的乘法操作,完整的乘法操作耗費(fèi)19個(gè)時(shí)鐘周期.除法的實(shí)現(xiàn)與乘法類似,完整的除法操作耗費(fèi)21個(gè)時(shí)鐘周期.下面給出了乘法操作的程序示例,其詳細(xì)解釋將在3.1節(jié)的仿真分析中給出:
litc?。?∥將0壓入堆棧
mpp ∥第1條mpp指令
…
mpp ∥第16條mpp指令
rot ∥乘法結(jié)束后,清理掉
drop ∥位于N2的被乘數(shù)
③ 訪存:堆棧處理器支持按字節(jié)和按字兩種訪存方式.指令集中的litc、c@和c!指令為字節(jié)訪存指令;而lit、@和!為按字訪存指令.這里簡要說明按字訪存指令的功能,按字節(jié)訪存與之類似.lit將一個(gè)字常量壓入數(shù)據(jù)堆棧;@將T的內(nèi)容彈出送入地址寄存器A,按A中地址訪存取得數(shù)據(jù)后壓入數(shù)據(jù)堆棧;!指令將T中的內(nèi)容彈出送入地址寄存器A,再將當(dāng)前棧頂T的數(shù)據(jù)彈出存入A 中地址.除litc指令的其他指令需要兩個(gè)周期執(zhí)行,litc指令在設(shè)計(jì)時(shí)被優(yōu)化為不需要訪存,因此只需要一個(gè)周期執(zhí)行。
④ 程序轉(zhuǎn)移:call為子程序調(diào)用指令,它將當(dāng)前PC寄存器值壓入返回堆棧,同時(shí)將子程序地址送入PC寄存器;ret為子程序返回指令,它將返回堆棧的棧頂值彈出,送入PC寄存器;jmp為無條件跳轉(zhuǎn)指令;jz和jc為有條件跳轉(zhuǎn)指令,跳轉(zhuǎn)條件分別是數(shù)據(jù)堆棧棧頂T的內(nèi)容是否為0和ALU進(jìn)位標(biāo)志位是否為0;drjne將返回堆棧棧頂R的內(nèi)容減1,然后判斷R中內(nèi)容是否為0,如果不為0則跳轉(zhuǎn).除call與ret以外的其他指令都需要先訪存取得16位跳轉(zhuǎn)地址,然后壓入堆棧,因此需要兩個(gè)周期執(zhí)行;ret與call指令只需要一個(gè)周期執(zhí)行。
2.2.2 指令集編碼優(yōu)化
存儲(chǔ)器是嵌入式控制系統(tǒng)中的一種稀缺資源,因此在設(shè)計(jì)堆棧處理器時(shí),采用了一種簡單但是有效的編碼方式進(jìn)行指令編碼,不僅大大減小了代碼體積,還在一定程度上可以降低系統(tǒng)的復(fù)雜度,提高系統(tǒng)效率。
在堆棧處理器上執(zhí)行的程序一般都通過大量子程序調(diào)用進(jìn)行模塊化設(shè)計(jì)以減小代碼尺寸,這樣才能充分利用硬件支持的返回堆棧.因此,在典型的堆棧處理器程序中25%的時(shí)間花費(fèi)在子程序調(diào)用上[5],這就要求在實(shí)現(xiàn)堆棧處理器時(shí)必須高效地實(shí)現(xiàn)call指令.一方面,如果call指令占用的bit位較少,便能減小代碼體積;另外一方面,如果call指令的執(zhí)行能在一個(gè)周期完成,將大大加快程序的執(zhí)行速度.因此指令集采用了兩種不同的編碼方式實(shí)現(xiàn)。
對于除call以外的其他指令,每條指令占8位且最高位均為0.處理器每次訪存取出的16位數(shù)據(jù)中,高低8位各為一條指令.采用這種設(shè)計(jì)方案后,一方面,每次訪存可以取出兩條指令.這在處理器和存儲(chǔ)器之間形成了一個(gè)處理器速度兩倍于存儲(chǔ)器速度的緩沖,可以在一定程度上避免Cache的引入,降低嵌入式系統(tǒng)的復(fù)雜度;另一方面,每條指令占用8位而不是16位可以大大減小代碼體積。
all指令采用了另外一種實(shí)現(xiàn)方式,如果訪存取出的16位數(shù)據(jù)中最高位為1,那么這16位不再被解釋為兩條指令,最高位被解釋為call指令,剩下的15位經(jīng)邏輯左移1位后作為子程序地址.相對于采用與其他類型指令相同的8位實(shí)現(xiàn)方式,這種實(shí)現(xiàn)方式使得call指令僅占1位,可以進(jìn)一步減小代碼體積。
另外,call指令執(zhí)行時(shí)的子程序地址不需要通過訪存取得,因此其執(zhí)行將只耗費(fèi)一個(gè)周期.當(dāng)然,這樣的方案會(huì)讓call指令只能調(diào)用位于偶地址的子程序,但是好的設(shè)計(jì)來源于適當(dāng)?shù)恼壑?,這種損失相對于獲得的效率和性能提升是值得的。
2.3 控制模塊
控制器本質(zhì)上是如圖2所示的一個(gè)五狀態(tài)的有限狀態(tài)機(jī)。InstrF為其初始狀態(tài),即取指令狀態(tài)。Slot0和Slot1為執(zhí)行狀態(tài),Slot0_M 和Slot1_M 為訪存狀態(tài)。Slot0與Slot0_M 對應(yīng)于低8位指令地執(zhí)行與訪存,Slot1與Slot1_M 對應(yīng)于高8位指令地執(zhí)行與訪存。
處理器在InstrF狀態(tài)訪存取出16位數(shù)據(jù)后進(jìn)入Slot0狀態(tài),先判斷數(shù)據(jù)的最高位是否為1:若為1,則最高位被解釋為call指令,低15位經(jīng)邏輯左移1位后作為子程序地址,執(zhí)行子程序調(diào)用后下一狀態(tài)進(jìn)入InstrF;若為0,則執(zhí)行低8位指令.如果低8位指令為單周期指令,下一狀態(tài)進(jìn)入Slot1執(zhí)行高8位指令;如果低8位指令為雙周期指令,下一狀態(tài)進(jìn)入Slot0_M 進(jìn)行訪存,訪存結(jié)束后下一狀態(tài)進(jìn)入Slot1執(zhí)行高8位指令。
處理器在進(jìn)入Slot1狀態(tài)后,執(zhí)行高8指令.如果高8位指令為單周期指令,下一狀態(tài)進(jìn)入InstrF繼續(xù)取指令;如果高8位為雙周期指令,下一狀態(tài)進(jìn)入Slot1_M 訪存,訪存結(jié)束后下一狀態(tài)進(jìn)入InstrF繼續(xù)取指令。
在InstrF狀態(tài)可以響應(yīng)外部中斷.如果此時(shí)檢測到中斷請求信號intreq為高電平,則給出中斷響應(yīng)信號intack,并且將中斷向量intvec送入PC,下一狀態(tài)依然為InstrF狀態(tài)。
2.4 堆棧實(shí)現(xiàn)
本文設(shè)計(jì)的堆棧處理器包含兩個(gè)硬件支持的堆棧:數(shù)據(jù)堆棧和返回堆棧.由于所有指令都是對這兩個(gè)堆棧的操作,因此堆棧的實(shí)現(xiàn)方式對于堆棧處理器的效率和性能是至關(guān)重要的.堆棧的實(shí)現(xiàn)不僅要最大程度上避免溢出,還要保證在訪問時(shí)能夠非常高效。
2.4.1 堆棧溢出問題
關(guān)于硬件堆棧溢出問題存在多種解決方法,主要有:請求式單元素堆棧管理器、頁式堆棧管理以及
聯(lián)合Cache等.其實(shí)Charles H.Moore曾經(jīng)做過統(tǒng)計(jì),在典型的堆棧程序執(zhí)行過程中,當(dāng)堆棧深度超過32時(shí),幾乎所有的程序都不會(huì)發(fā)生堆棧溢出問題。因此堆棧處理器WISC和EP32直接將堆棧深度設(shè)置為256,以求完全避免堆棧溢出問題。
相對于采用其他硬件方式來避免溢出問題,直接增加堆棧深度更加簡單有效,因此本文論述的處理器直接將堆棧存儲(chǔ)器深度設(shè)置為32(不包括棧頂寄存器在內(nèi)).這對于一般的應(yīng)用已經(jīng)足夠,由于是采用FPGA實(shí)現(xiàn),在需要的情況下可以很方便地將堆棧深度增加。
2.4.2 指令的單周期堆棧操作
指令集中的很多指令,如swap和rot指令,需要同時(shí)操作堆棧的兩個(gè)甚至三個(gè)棧頂元素.如果采用普通的堆棧存儲(chǔ)器,想同時(shí)訪問棧頂?shù)亩鄠€(gè)元素,就需要訪問堆棧多次,這樣那些需要操作多個(gè)棧頂元素的指令在執(zhí)行時(shí)需要耗費(fèi)多個(gè)周期.這對于堆棧處理器將是極大的性能損失。
因此,為了保證所有指令的堆棧操作都能夠在單周期內(nèi)完成,在堆棧設(shè)計(jì)上采用了圖1中所示的棧頂寄存器加堆棧存儲(chǔ)器的方式.對于數(shù)據(jù)堆棧,由于在最多的情況下(rot指令的執(zhí)行)需要同時(shí)訪問棧頂?shù)娜齻€(gè)元素,因此設(shè)置了三個(gè)棧頂寄存器T、N1和N2.這樣數(shù)據(jù)堆棧的真正棧頂元素就是T,而不是堆棧存儲(chǔ)器的棧頂元素.返回堆棧的設(shè)計(jì)與此類似,設(shè)置了一個(gè)棧頂寄存器R。
3 仿真與綜合
本文設(shè)計(jì)采用Verilog進(jìn)行RTL級描述,仿真軟件為ModelSimSE6.5C,綜合軟件為SynplifyPro9.6.1,目標(biāo)芯片為Xilinx公司的Virtex-5 XC5VLX110T。
3.1 仿真分析
圖3中給出了2.2.1節(jié)中的乘法程序的仿真波形圖,圖中state與nextstate信號給出了有限狀態(tài)機(jī)的狀態(tài)轉(zhuǎn)移情況;instr_exec表示當(dāng)前正在執(zhí)行的指令;I與PC則分別為指令寄存器與程序計(jì)數(shù)器;T、N1和N2為數(shù)據(jù)堆棧的三個(gè)棧頂寄存器;result表示ALU的運(yùn)算結(jié)果。
從圖中可以看出,在70~110ns,執(zhí)行了兩條lit指令(指令編碼為40H),這兩條指令將乘數(shù)與被乘數(shù)003H與0011H壓入數(shù)據(jù)堆棧.在這之后開始執(zhí)行2.2.1節(jié)中給出的乘法運(yùn)算程序.在120~130ns,執(zhí)行了一條litc(指令編碼為50H)指令,將00H擴(kuò)展為0000H 壓入數(shù)據(jù)堆棧.此時(shí),可以查看堆棧寄存器T、N1和N2里的內(nèi)容分別為0000H、0011H和0003H.在140~370ns期間連續(xù)執(zhí)行了16條mpp完成在mpp指令操作后的一些堆棧清理操作.最后,在第400ns時(shí)查看數(shù)據(jù)堆棧的棧頂寄存器T與N1,發(fā)現(xiàn)內(nèi)容分別為0000H 與0033H,其中0000H 為乘法結(jié)果的高16位,而0033H 則為低16位,與預(yù)期結(jié)果一致。
3.2 綜合分析
使用Xilinx公司的XC5VLX110T作為目標(biāo)芯片時(shí),片上資源利用率不超過3%,堆棧處理器的最高頻率可以達(dá)到146.7MHz.表3中給出了本設(shè)計(jì)在不同芯片上與不同文獻(xiàn)中同類設(shè)計(jì)進(jìn)行的主頻性能對比.從表中數(shù)據(jù)可以看出,本設(shè)計(jì)在主頻性能上與前三種同類設(shè)計(jì)相比有較明顯的提升.值得注意的是,與文獻(xiàn)[8]中的MSL16處理器相比較而言,本文處理器主頻略有下降,這是因?yàn)镸SL16處理器在設(shè)計(jì)中應(yīng)用了兩級流水線技術(shù).本文則側(cè)重于運(yùn)用較簡單的設(shè)計(jì)、較少的硬件資源以獲得較高的性能:一方面,流水線技術(shù)在堆棧處理器中的應(yīng)用無疑會(huì)大幅增加堆棧處理器的復(fù)雜度,這與本文的設(shè)計(jì)初衷不相符;另一方面,從性能提升率上看,流水線技術(shù)的應(yīng)用所帶來的頻率增加并非異常顯著。
4 結(jié)束語
本文以雙堆棧體系結(jié)構(gòu)為基礎(chǔ),設(shè)計(jì)了一種不同于RISC體系結(jié)構(gòu)的嵌入式堆棧處理器.該處理器結(jié)構(gòu)緊湊,系統(tǒng)復(fù)雜度低,代碼體積?。赬ilinx公司的XUPV5-LX110T開發(fā)板上實(shí)現(xiàn)后,其主頻達(dá)到了146.7MHz,片內(nèi)資源使用率不超過3%.仿真與綜合結(jié)果證明了設(shè)計(jì)的正確性,與同類設(shè)計(jì)相比較,主頻性能有較為明顯的提升.堆棧處理器較高的主頻與較低的資源使用率為后期以該處理器為核心構(gòu)建一個(gè)SoPC提供了基礎(chǔ)。
評論