劉 靜,史彥芳,孔 黎
(西北工業(yè)大學(xué) 電子信息學(xué)院,陜西 西安 710072)
在構(gòu)建一個(gè)新系統(tǒng)時(shí),為了有效地測(cè)試和驗(yàn)證新系統(tǒng)的行為和正確性,通常需要對(duì)此新系統(tǒng)進(jìn)行仿真。系統(tǒng)仿真包括軟硬件結(jié)合仿真和軟件仿真,其中,軟件仿真由于其具有脫離具體的硬件,便于調(diào)試的優(yōu)點(diǎn),而得到廣泛的應(yīng)用。
所謂軟件仿真是指通過(guò)軟件的執(zhí)行來(lái)模擬硬件行為的一種方法。軟件仿真器是在宿主機(jī)上運(yùn)行并能模擬目標(biāo)機(jī)器行為的一種軟件系統(tǒng)。
利用軟件仿真器,硬件生產(chǎn)廠商可以在構(gòu)建系統(tǒng)之前就對(duì)其正確性及性能進(jìn)行驗(yàn)證,從而使得軟件開(kāi)發(fā)商可以在硬件生產(chǎn)出來(lái)之前進(jìn)行軟件開(kāi)發(fā)使得軟硬件可以同時(shí)面世,從而大大降低了開(kāi)發(fā)時(shí)間。
與此同時(shí),軟件仿真器具有執(zhí)行速度低的缺點(diǎn),因此如何提高指令集仿真器的執(zhí)行速度成為指令集仿真器的一個(gè)研究課題。文中首先介紹了指令集仿真的實(shí)現(xiàn)策略,并對(duì)基于ZWFcore的DSP指令集仿真器具體設(shè)計(jì)與實(shí)現(xiàn)做了闡述。
指令集仿真器是最基本的軟件仿真器。目前最流行的指令集仿真器實(shí)現(xiàn)策略[1]有3種:基于解釋的指令集仿真策略、基于編譯的指令集仿真策略和混合指令集仿真策略。
解釋型指令集仿真器是基于解釋的指令集仿真策略來(lái)實(shí)現(xiàn)的仿真器。它通過(guò)在內(nèi)存中建立一個(gè)數(shù)據(jù)結(jié)構(gòu)來(lái)模擬目標(biāo)處理器的狀態(tài),然后進(jìn)入一個(gè)循環(huán),循環(huán)體包括取值、譯碼、路由、執(zhí)行4個(gè)基本的步驟。如圖1所示。
圖1 解釋型指令集仿真Fig.1 Interpreted instruction set simulator
其中取值是從內(nèi)存中將一條指令字取出,譯碼是通過(guò)相應(yīng)的掩碼取出指令字中的操作數(shù)和操作碼,然后通過(guò)路由根據(jù)操作碼選擇到相應(yīng)的執(zhí)行函數(shù),再有對(duì)應(yīng)的執(zhí)行函數(shù)完成對(duì)操作數(shù)的操作。從而完成對(duì)一條指令的的仿真。其優(yōu)點(diǎn)是,設(shè)計(jì)簡(jiǎn)單且靈活性好,但完成一個(gè)周期的時(shí)間較長(zhǎng)。
編譯型指令集仿真器[2-4]是基于編譯型指令集仿真策略來(lái)實(shí)現(xiàn)的仿真器。它在程序執(zhí)行之前,首先對(duì)程序進(jìn)行編譯處理,把每一條目標(biāo)機(jī)指令轉(zhuǎn)譯成一組宿主機(jī)指令,在實(shí)際運(yùn)行時(shí)直接使用那一組宿主機(jī)的指令代替那條目標(biāo)機(jī)的指令來(lái)完成處理器狀態(tài)的修改,如圖2所示。編譯型指令集仿真器具有較高的模擬速度,但它對(duì)宿主機(jī)過(guò)分依賴使得其通常只用于宿主機(jī)和目標(biāo)機(jī)體系結(jié)構(gòu)相近的模擬器中。
圖2 編譯型指令集仿真Fig.2 Compiled instruction set simulator
解釋型指令集仿真器能夠精確地模擬指令執(zhí)行過(guò)程中各個(gè)部件的狀態(tài),具有良好的擴(kuò)展性,因此可以方便地在模擬器外部擴(kuò)充調(diào)試其和程序分析器。另外,由于指令解釋部分采用高級(jí)語(yǔ)言的函數(shù)來(lái)實(shí)現(xiàn),使得模擬器便于向其他宿主機(jī)移植,故本文采用解釋型指令仿真策略來(lái)模擬指令的讀取、譯碼和執(zhí)行過(guò)程。
ZWFcore是一款高性能通用DSP核,支持多種片上系統(tǒng)(SOC)。其主要應(yīng)用于通信、圖像處理及視頻處理領(lǐng)域。DSP指令集仿真器(ZWISS)是運(yùn)行在ZWFcore平臺(tái)之上,基于解釋型指令集仿真策略對(duì)ZWFcore指令集進(jìn)行仿真的仿真器。其首先在內(nèi)存中建立一個(gè)數(shù)據(jù)結(jié)構(gòu)來(lái)代表目標(biāo)處理器的狀態(tài),并將可執(zhí)行的指令加載到內(nèi)存開(kāi)辟的存儲(chǔ)結(jié)構(gòu)中,然后進(jìn)入一個(gè)處理循環(huán)。它有效地對(duì)ZWFcore的存儲(chǔ)器、及存儲(chǔ)器的訪問(wèn)、指令集流水線及中央處理單元進(jìn)行了模擬,并通過(guò)設(shè)計(jì)server模塊,在server上完成了對(duì)ZWFcore上的開(kāi)發(fā)程序的調(diào)試。
為實(shí)現(xiàn)上述功能,基于ZWFcore的DSP指令集仿真器[5](ZWISS)主要可以分為7個(gè)模塊,分別為:初始化模塊、加載模塊、譯碼模塊、路由模塊、中央處理單元模塊、多級(jí)存儲(chǔ)器模塊、MMU模塊、MPS模塊、PMA模塊和調(diào)試代理rsp_server模塊。其中MMU模塊、MPS模塊和PMA模塊是可選的模塊。根據(jù)硬件的設(shè)計(jì)需求來(lái)決定是否啟用相應(yīng)的模塊。
2.2.1 初始化模塊
在啟動(dòng)zwiss時(shí),需要對(duì)多級(jí)存儲(chǔ)單元模塊的類中生成對(duì)象按照硬件啟動(dòng)時(shí)應(yīng)該具有的狀態(tài)進(jìn)行初始化設(shè)置,并且對(duì)其他各模塊進(jìn)行初始化,因此需要初始化模塊完成這個(gè)功能。
具體地,初始化模塊主要完成以下幾項(xiàng)任務(wù):
1)對(duì)多級(jí)存儲(chǔ)單元的初始化:多級(jí)存儲(chǔ)單元的初始化包括對(duì)寄存器的初始化和內(nèi)存的初始化,其可以通過(guò)通過(guò)加載模塊對(duì)elf頭文件中的信息進(jìn)行解析,獲得相應(yīng)的系統(tǒng)初始化的參數(shù)后,對(duì)多級(jí)存儲(chǔ)單元中的特殊寄存器和內(nèi)存的值分別進(jìn)行相應(yīng)的初始化,其他寄存器可以賦為0。
2)對(duì)譯碼模塊的初始化:主要是將配置文件中的信息存儲(chǔ)到向量表中,這樣可以使代碼的重用性大大提高。
3)對(duì)路由模塊的初始化就是對(duì)函數(shù)指針數(shù)組的初始化,由函數(shù)functionmap()來(lái)完成。
2.2.2 加載模塊
加載模塊[6]是在ZWFcore指令集仿真器初始化模塊運(yùn)行后,在譯碼模塊運(yùn)行之前運(yùn)行的模塊。加載模塊用于解析elf文件,提取相關(guān)信息包括其頭信息和此文件涉及的指令,將提取的信息存儲(chǔ)到多級(jí)存儲(chǔ)單元中。加載模塊是中微一號(hào)指令集仿真器運(yùn)行的基礎(chǔ),是后面譯碼、路由、執(zhí)行函數(shù)的先決條件,只有加載了信息后,中微一號(hào)指令集仿真器的運(yùn)行才有意義,才能夠驗(yàn)證指令仿真的正確性。
設(shè)計(jì)加載模塊前,首先要區(qū)分文件是否為ELF文件,根據(jù)文件的格式,提取指令信息。從ELF文件信息中分析出需要將指令信息加載到代碼區(qū)或者數(shù)據(jù)區(qū)的具體問(wèn)題,然后將提取出的信息加載到代碼區(qū)或者數(shù)據(jù)區(qū)中。
2.2.3 譯碼模塊
譯碼模塊實(shí)現(xiàn)對(duì)指令中操作碼和操作數(shù)的提取。從多級(jí)存儲(chǔ)單元中提取指令,然后經(jīng)過(guò)譯碼模塊的解釋,將操作數(shù)和操作碼提取出來(lái),根據(jù)操作碼定位到對(duì)應(yīng)的指令序號(hào),將操作數(shù)和指令序號(hào)存入到操作數(shù)結(jié)構(gòu)體中,為后面的指令的運(yùn)行提供了保證。
譯碼模塊主要完成以下工作:
1)將指令和指令掩碼按照順序依次進(jìn)行掩碼操作,判斷出指令的類別,然后根據(jù)指令的類別,和特征碼進(jìn)行匹配,如果特征碼相同,即完成了操作碼的定位,將其定位到特定的指令序號(hào)。
2)由于前面初始化的過(guò)程中已經(jīng)建立了操作數(shù)的初始化列表,并且定位了指令中具體的比特位的是第幾個(gè)操作數(shù)的比特位,所以可以根據(jù)這些定位從指令中提取出操作數(shù),并將操作數(shù)按照順序存放到定義的vector中。
譯碼模塊將操作數(shù)存在vector中,故定義如下的結(jié)構(gòu)體:
struct operand_struct
{
int instruction_index;//指令序號(hào)
vector
};
該結(jié)構(gòu)體包括指令序號(hào)和操作數(shù)列表信息。其中操作數(shù)列表中包含了從指令中提取的操作數(shù)的信息。
同時(shí)譯碼模塊定義了opcoder類,其流程圖如圖3所示。
圖3 譯碼流程圖Fig.3 Flow chart the decoder design
文中采用了基于決策森林的二進(jìn)制指令譯碼算法,其思想是先構(gòu)建一決策森林,當(dāng)一條待譯碼指令字進(jìn)入譯碼入口后,按照決策森林中的第一棵決策樹(shù)對(duì)應(yīng)的指令掩碼計(jì)算出其可能的指令決策碼,在決策樹(shù)中尋找,找到則識(shí)別完畢,譯碼成功退出,否則依次遍歷所有的決策樹(shù),直至譯碼成功退出,若還未匹配則說(shuō)明該指令字不合法,譯碼失敗退出。
2.2.4 路由模塊
路由模塊是緊跟譯碼模塊之后的模塊,主要根據(jù)譯碼所得的指令序號(hào),路由到中央處理單元的相應(yīng)處理函數(shù)來(lái)處理。
路由模塊的實(shí)現(xiàn)是通過(guò)定義一個(gè)函數(shù)指針數(shù)組,此數(shù)組的結(jié)構(gòu)如下:
Int(*function_map[765])(struct operand_struct&);
其中*function_map為定義的指針數(shù)組,765為指令的個(gè)數(shù),struct_operand_struct代表的是操作數(shù)結(jié)構(gòu)體。
2.2.5 中央處理單元模塊
中央處理單元模塊是整個(gè)仿真器的核心部分,其本質(zhì)是一個(gè)函數(shù)集,主要完成的是將ZWFcore所有的指令用C++語(yǔ)言的函數(shù)來(lái)實(shí)現(xiàn),每條指令根據(jù)指令集中給出的定義對(duì)相應(yīng)的多級(jí)存儲(chǔ)器進(jìn)行訪問(wèn)或修改。
為了方便整個(gè)系統(tǒng)的調(diào)用,中央處理單元針對(duì)每條向外部提供了接口,這些接口的命名如下:
int ins0(struct operand_struct operand&);
int ins1(struct operand_struct operand&);
……
由于這些函數(shù)采用了統(tǒng)一的參數(shù),即由譯碼模塊提供的指令操作數(shù),故使代碼的編寫更加規(guī)范,同時(shí)降低了出錯(cuò)概率。
2.2.6 內(nèi)存管理單元模塊
內(nèi)存管理單元(MMU)模塊是可選的模塊,其實(shí)現(xiàn)的是虛擬地址與物理地址的轉(zhuǎn)換功能(詳見(jiàn)圖4)。從而避免不同的指令執(zhí)行過(guò)程中訪問(wèn)同一物理地址。
MMU的實(shí)現(xiàn)主要是將虛擬頁(yè)表映射到物理頁(yè)表。通過(guò)查找TLBs來(lái)實(shí)現(xiàn)這種轉(zhuǎn)換。而TLBs是由操作系統(tǒng)填充的,用戶不能隨意更改。
2.2.7 存儲(chǔ)保護(hù)系統(tǒng)模塊
通過(guò)定義一對(duì)存儲(chǔ)器,用來(lái)存放可以讀寫的內(nèi)存的上下界的地址,從而來(lái)限定用戶訪問(wèn)的內(nèi)存范圍。它是一種基于地址的保護(hù),保障了系統(tǒng)的安全性。
圖4 虛擬地址轉(zhuǎn)換Fig.4 Virtual addressing translation
2.2.8 物理內(nèi)存屬性模塊
物理內(nèi)存屬性模塊(MPS),其主要功能是對(duì)內(nèi)存中的各個(gè)段進(jìn)行劃分,規(guī)定其特殊的屬性,包括外設(shè)屬性(Privileged Peripheral(P)),可緩存(Cacheable (C))
投機(jī)性(Speculative (S)),代碼可讀(Code Fetch (F)),數(shù)據(jù)可訪問(wèn)(Data Access(D))。這是一種基于段的保護(hù),防止對(duì)一些地址的非法訪問(wèn)。
2.2.9 多級(jí)存儲(chǔ)器模塊
多級(jí)存儲(chǔ)單元模塊主要完成的是對(duì)ZWFcore的寄存器組、主存和cache進(jìn)行管理。在指令仿真執(zhí)行的過(guò)程中通過(guò)調(diào)用該模塊完成對(duì)寄存器以及主存的修改與讀取。這里我們將其寄存器組合主存抽象成一個(gè)類,故對(duì)主存和寄存器的修改和讀取可以看作是對(duì)該類對(duì)象的相應(yīng)的操作。
在多級(jí)存儲(chǔ)器模塊中,ZWISS采用了虛擬頁(yè)表來(lái)仿真ZWFcore的主存,每個(gè)頁(yè)64 kB。由于ZWFcore的地址是32位,故我們將其告16位作為其頁(yè)地址,低16位為其頁(yè)內(nèi)地址。這種方式與單純使用“地址-值”的方式相比,具有查找次數(shù)少,用時(shí)短的優(yōu)點(diǎn)。
該模塊對(duì)外提供了很多接口,主要是完成其他模塊對(duì)寄存器和內(nèi)存的訪問(wèn)和修改。
這些接口的設(shè)計(jì)須滿足通用性、高效性、高內(nèi)聚和低耦合,并且應(yīng)在實(shí)現(xiàn)相應(yīng)功能基礎(chǔ)上,具有較好的擴(kuò)展性。
該類的設(shè)計(jì)表示如下所示:class MLSS
{
public:
//程序狀態(tài)字寄存器
unsigned int PSW;
//程序計(jì)數(shù)器
unsigned int PC;
…
private:
//資料寄存器
union reg data_reg;
//地址寄存器
union reg addr_reg;
//代碼區(qū)
std::map
//數(shù)據(jù)區(qū)
std::map
public:
int get_reg32bit (int reg_type, int reg_ID, unsigned int&val);//讀 32 位
int set_reg32bit (unsigned int val, int reg_type, int reg_ID);//寫 32 位
……
}
其中,在讀寫內(nèi)存時(shí),根據(jù)MMU、MPS、以及PMA的存在與否,來(lái)進(jìn)行對(duì)將要操作的地址進(jìn)行判斷,看其是否允許被操作,在進(jìn)行相應(yīng)的操作。其具體的操作如圖5所示。
圖5 地址的翻譯過(guò)程Fig.5 Progress of the addressing translation
2.2.10 調(diào)試代理模塊
調(diào)試代理模塊即server模塊,相當(dāng)于ZWISS仿真器與調(diào)試器GDB的接口。其用于解析調(diào)試器GDB發(fā)出的調(diào)試命令并調(diào)用仿真器進(jìn)行相應(yīng)的處理,同時(shí)將結(jié)果返回給調(diào)試器GDB。
Server模塊通過(guò)RSP協(xié)議與GDB進(jìn)行通信,針對(duì)RSP協(xié)議中的指令,在server模塊中設(shè)計(jì)了ZWDPI(中微一號(hào)調(diào)試編程接口)。在ZWDPI中提供最精簡(jiǎn)的調(diào)試編程方法,包括設(shè)置斷點(diǎn),移除斷點(diǎn),讀/寫全部寄存器,連接主機(jī)等。這些方法函數(shù)保證了server模塊通過(guò)方法的組合執(zhí)行GDB發(fā)出的所有命令。
2.2.11 陷阱模塊
陷阱模塊提供了各種陷阱的接口。其實(shí)現(xiàn)是通過(guò)定義一個(gè)類,在程序執(zhí)行過(guò)程中,當(dāng)發(fā)生陷阱時(shí)可以調(diào)用此模塊中的類成員函數(shù)來(lái)實(shí)現(xiàn)相應(yīng)的處理。
模擬器的好壞直接由各個(gè)模塊的性能決定,因此對(duì)各個(gè)模塊性能分析成為設(shè)計(jì)的一個(gè)主要部分,現(xiàn)對(duì)主要模塊的性能分析如下。
路由模塊主要是利用函數(shù)指針指向?qū)?yīng)的中央處理單元的執(zhí)行函數(shù),因此其具有較高的性能,時(shí)間復(fù)雜度僅為O(1)。
中央處理單元是整個(gè)模擬器的核心單元,其性能的好壞直接影響模擬器的正確性和執(zhí)行速度,故其是否能準(zhǔn)確的解釋指令,并且用最短的時(shí)間來(lái)實(shí)現(xiàn)指令,成為我們關(guān)注的核心。在用C語(yǔ)言實(shí)現(xiàn)中央處理單元時(shí),要盡可能使用執(zhí)行速度高的編碼,如:盡量使用比較簡(jiǎn)單的移位操作而避免使用與或操作。這樣大大提高此單元的執(zhí)行速度和可靠性。
多級(jí)存儲(chǔ)單元在實(shí)現(xiàn)上,采用了動(dòng)態(tài)申請(qǐng)空間的方式而不是一次性申請(qǐng)所需的模擬大小的內(nèi)存空間,這使得多級(jí)存儲(chǔ)單元的空間復(fù)雜度大大降低,同時(shí),在對(duì)寄存器和內(nèi)存進(jìn)行讀寫操作時(shí),使用較少的循環(huán)操作,提高了多級(jí)存儲(chǔ)單元的時(shí)間復(fù)雜度。
文中實(shí)現(xiàn)對(duì)ZWFcore的仿真,在對(duì)其進(jìn)行指令集仿真的基礎(chǔ)上,通過(guò)對(duì)其體系結(jié)構(gòu)的升入分析,對(duì)其特殊模塊如MMU、MPS、PMA單元進(jìn)行了仿真,實(shí)現(xiàn)了對(duì)內(nèi)存的保護(hù)和更加真實(shí)的模擬了硬件的實(shí)現(xiàn)情況。同時(shí),增加了調(diào)試代理模塊為仿真器的調(diào)試提供了接口,便于掛接其他的調(diào)試模塊。
[1]俞甲子,石凡,潘愛(ài)民,等.程序員的自我修養(yǎng)[M].北京:電子工業(yè)出版社,2009.
[2]譚華.嵌入式系統(tǒng)軟件仿真器的研究與實(shí)現(xiàn) [D].成都:電子科技大學(xué),2005.
[3]Reshadi M,Mishra P,Dutt N.Instruction Set Compiled Simulation:A Technique for Fast and Flexible Instruction Set Simulation [C]//Design Automation Conference,2003:758-763.
[4]A Nohl et al.A Universal Technique for fast and Flexible Instruction-Set Architecture Simulation[J].IEEE Transaction on Computer-Aided Design ofIntegrated Circuitsand Systems,2002,123(12):1625-1639.
[5]S Pees et al.Using Static Scheduling Techniques for the Retargeting ofHigh Speed, Compiled Simulators for Embedded Processors from an Abstract Machine Description[C]//The 14th International Symposium on System Synthesis,2001:57-62.
[6]陶峰峰,付宇卓.DSP指令集仿真器的設(shè)與實(shí)現(xiàn)[J].計(jì)算機(jī)仿真,2005,22(9):225-228.TAO Feng-feng,F(xiàn)U Yu-zhuo.Design and implementation of DSP instruction simulator[J].Computer Simulation,2005,22(9):225-228.