標籤:

如何編寫一個硬體模擬器?

比如說虛擬機,或者 http://circuit.io 的 Arduino 模擬器之類。


話題太大,不喜打字,簡單說點

要寫一個硬體模擬器,首先你得有那個硬體(逃,當然,這麼說其實沒啥意義,有一個spec就可以了,當然也有隻有硬體,幾乎或者根本沒有spec的時候。

一般的計算機系統,主要有這麼幾塊要模擬:CPU,memory,IO,stor,gfx。

首先是CPU,看手冊,把CPU的各種模式,GPR,MSR等等都搞明白,每一條指令都模擬下來,中斷處理寫好,基本就能用了,MMU也別忘了,TLB一般可以省掉。CPU一般都是可以得到手冊的,所以寫這個模擬只是一個體力活。

然後是Memory,這個一般就是new一塊內存,或者硬編碼一個數組(你應該祈禱被模擬的硬體內存不要太大,或者說memoryspace不要太大,否則處理起來很麻煩)。

IO模擬花樣繁多,這裡就不細說了,舉個例子,有的遊戲機是用mail slot reg來執行IO的,這時候你的代碼只要在寫這個reg的時候,讀reg的值就知道該做什麼了。當然這裡花樣多於是情況就要複雜得多,比如真實的硬體是需要時間才對的,你模擬一個光碟機,如果沒模擬延遲,有時候就會一塌糊塗。

stor一般都屬於IO,如果要提高模擬的速度,就要特殊處理,這裡不細表了。

gfx模擬比較有技巧,一種是完全比著spec自己擼一個gfx管線,這樣的效果就是模擬很精確,代價就是慢,無以倫比的慢。另一種就是做一個到現代API的map,比如把gfx指令翻譯成opengl,運氣好的話,比如你要在pc做一個gles的模擬,那可就簡單多了。

ok,上面都是入門,下面說一點hardcore的

首先,沒有spec怎麼辦。總所周知模擬遊戲機,遊戲機是不可能給你詳細的spec的,這就要用各種逆向的方法,首先你可以用搜索引擎找廠商的專利,這裡面會有一些硬體spec的蛛絲馬跡。其次找SDK,SDK裡面的手冊起碼會把執行環境介紹一下。

然後就是最hardcore的工作了,最暴力的方法是用LA,也就是邏輯分析儀接到遊戲機的或者什麼玩意的pcb上,前提是你能找到你要的匯流排,或者猜測,然後分析各種信號時序,這樣很多外設的連接方式和匯流排協議就知道了,可以著手開始這類設備的模擬了。

其次是逆向SDK,把裡面的lib之類的用IDA之類的反彙編,看看官方是怎麼在最底層和硬體通信的,這個工作量相當大,而且有時候靜態是看不出太多信息的,不過總比什麼都沒有強。

再其次是用SDK寫一些spy code,在真實硬體上run,試一下reg的功能之類的,這需要極大的耐心。以上就是硬體逆向的基本工作,當然還有別的懶得寫了。

還有最後一個,就是模擬的速度,上面說的一切都是暴力模擬,每一條cpu指令,每一個硬體功能都要用很多行c代碼,老慢了,慢到什麼程度?可能只有真實硬體的幾十分之一甚至萬分之一。

這種情況就需要用一些高級的技巧,比如HLE,HLE就是high level emu,簡單的說有這麼幾種:

函數級HLE,比如著名的N64模擬器Ultra64,做到了SDK級函數識別,模擬的時候遇到crt會用自己的函數換掉,這樣就飛快。硬體級HLE,比如模擬BIOS,你別管BIOS裡面怎麼工作的,你把BIOS的介面實現出來就行了,光碟機神馬的同理。

另外一個最著名的就是處理器的JIT了,也就是把異質架構的處理器指令流翻譯成本地指令流執行,可能會快10到幾百倍,這個過程比較複雜,說起來夠寫一本書,這裡不廢話了,以後有機會再說。


首先硬體模擬器按照精確度來說分為以下幾類:

1. 功能級模擬器,這個應該是題主所說的硬體模擬器。

此類模擬器實現硬體的功能,能夠像真實硬體一樣運行上層的軟體。例如在PC上開發安卓就需要arm的模擬器,在x86上運行arm程序,當前安卓模擬器是基於開源模擬器QEMU實現的。

2. 時序精確級模擬器,此類模擬器不僅能夠實現硬體的功能,還能夠模擬硬體內部的時序。在進行晶元和SOC架構探索的時候需要用到此類模擬器,用於評估、分析硬體架構的性能。設計階段之所需使用模擬器是因為一方面晶元的流片周期很長、成本高昂(百萬級),

另一方面在真實晶元上缺少調測定位的手段。

猜測題主所說的模擬器應該指的是功能級模擬器,這裡對功能機模擬器做大概的介紹:

實現一個功能機模擬器主要包含以下幾大塊:

1. 處理器模擬

模擬處理器其實主要做的就是使用軟體實現硬體的指令。處理器的模擬其實跟晶元內部的大概流程很類似。以ARM的模擬器為例,經過ARM的編譯器編譯出來一個ARM程序,需要在我們的模擬器上運行:

首先要按照ARM可執行程序的格式(linux下同意為ELF格式文件)解析可執行文件--&>從ELF文件中讀取指令--&>按照ARM的指令集說明對讀取的二進位指令進行解碼--&>執行解析出的指令--&>獲取下一條指令--&>循環

這裡的主要工作就是要對ARM的每條指令進行實現,例如add加法指令、load/store內存操作指令、乘法指令等。。。

2. 內存模擬

處理器運行時需要不停對外部IO進行操作,最多就是load/store仿寸,我們必須模擬處理器的內存。對於功能機模擬器來說只需要malloc一塊內存,映射給處理器即可。當然,如果硬體設計有MMU時還需要對實現MMU功能。Cache一般不需要進行模擬。

3. 外設模擬

如果要整個系統運行起來,還需要對外設進行模擬,例如ARM程序用到了DMA,那麼我們就需要對DMA部件進行模擬,硬體規格會定義出DMA寄存器的行為,我們需要對這些行為進行模擬。

4. 匯流排的模擬

OK,假設處理器,內存,外設我們都模擬好了,接下來我們還需要將這些部件進行互聯。系統會對每個部件在系統中的地址進行定義,我們需要正確的進行地址映射,如此一個store指令我們才能根據地址說這條指令是訪問了內存還是DMA。

其次需要對中斷進行互聯,例如DMA完成了,需要通過中斷告訴CPU,我們就需要通過句柄等是DMA能夠更新CPU的狀態(中斷寄存器)。

此時,我們純手工版的模擬器就OK了,開發工作兩肯定不小。基於開源模擬器做模擬器能夠更為快速的構建自己的模擬器。

當前的開源模擬器有QEMU、GEM5、Asim等。

QEMU使用了JIT技術(具體可以參看Java的JIT),模擬速度能達到幾百百萬條指令每秒,而且提供了ARM、Power PC、MIPS、x86等幾乎所有的處理器架構的模擬器,還支持串口、網卡等硬體外設。

GEM5模擬器是一個核和內存子系統的時序精確級開源模擬器,能夠模擬核和cache、內存的時序。

提起模擬器還要說的是SystemC語言,SystemC是使用C/C++語言用於系統設計的語言,提供了時鐘、信號等基本的模塊,提供了抽系那個能夠在較高層次上對硬體進行描述。基於SystemC還發展出了一套TLM協議,設計TLM協議的目標是通過一套規範的介面實現模擬模塊間的解耦。通過TLM不同模塊只要滿足規範,就可以進行互聯成為一個整體,降低硬體的複雜度。

此外還有一些商業的模擬器,例如simics(當前已被Intel收購),提供了更為高級的模型描述語言DML,能夠在更高層次上對硬體進行建模,快速開發模擬器。系統也提供了一套解耦,實現模塊間解耦。而且支持使用python腳本語言實現整體的互聯,進一步降低系統的複雜度。

最後要說的是:在當前軟硬體協同設計的背景下,對模擬器的一個主要挑戰是如何快速構建精確級的模擬器和與之配套的編譯器工具鏈,用以評估驗證硬體開發人員的設計和idea。目前看到有Coware解決方案,能夠快速生成硬體模擬器和編譯器,給出性能數據。


我來提供一個入門級的教程...

ICS2015 Programming Assignment

南京大學《計算機系統基礎》的PA,跟著它可以從Linux下開發環境搭建開始,一步一步把ISA層次中的指令系統, 存儲管理, 中斷/異常, I/O知識都運用起來,最後實現一個簡單的x86模擬器。

PA還提供了把《仙劍奇俠傳》移植到你所做模擬器上的附加題~

只需一步:

git clone https://github.com/nju-ics/ics2015

你就能得到框架代碼,然後開始新的旅途了...

當然,鑒於國內本科教育的現狀,你不會像本校學生那樣有TA的支持,可能會很辛苦。但既然有了一個提高的機會,為什麼不把握呢?加油!

PS.最新的PA是2015版的,還在更新當中...心急的話可以搜2014版的

還要感謝之前諸位答主的回答,讓我更系統地理解相關概念~


看到「Arduino」,估計題主是不想做硬體而直接用計算機模擬一個硬體系統出來,然後寫軟體程序?

而我們做EE的在沒有硬體的情況下,會使用Protues、Multisim等專業的EDA模擬軟體來測試調試電路和MCU程序。如:

不過我現在已經很少用模擬軟體了,都是直接焊實際電路。以前用過的軟體好像都沒有ARM系列的晶元,不知現在的新版是否有。


因為模擬有不同抽象層次之分,相應的實現的複雜程度也有天壤之別。

行為級的模擬抽象層次比較高,實現起來簡單,只要黑箱模型實現即可。

函數級的模擬就要進—步,需要實現系統響應的內部子流程。

硬體級的模擬更需要了解信號傳播的時間特性。

具體來說,如果要實現虛擬機,只到函數級,把虛擬機讀入的每條指令以函數形式實現即可;如果要實現系統中處理器的時序模擬,最笨的辦法是把處理器內每個子部件的運轉時間特性都模擬出來;往往也可以簡化到函數級,只要把每條機器指令的執行時間和數據在內外匯流排的傳遞時間模擬出來就足夠了。


這裡有個文檔我覺得很有用

HOWTO: Writing a Computer Emulator

不讓複製只讓給連接...

裡邊也提到了一些社區

我覺得找不到文檔的時候可以去碰碰運氣


第一步也是最最重要的一步應該是對模擬對象有徹底的了解,完全清楚實際邏輯流程。其次,需要用事件驅動來模擬實際流程。然後,需要對模擬器進行反覆的validation。再之後,就是各種bug的修改,版本的改進了。精確又易用的模擬器實現真不是容易的事,知名的cpu模擬器像marssx86,gem5都是很多研究組/公司經過幾代積累完成的,內存模擬器DRAMSim看起來要比CPU簡單的多,但依然耗費了20 student-year。


EDA級別模擬很多,真要寫模擬器估計挺難.


推薦閱讀:

像QQ遊戲這樣的界面應該用什麼框架開發比較好?
作為一枚程序猿,你有或見過哪些奇葩的編程習慣?
開發人員買 MacBook Pro 好還是 MacBook Air 好?
工作中,在linux平台怎麼開發軟體?
程序員需要達到什麼水平才能順利拿到20k無壓力?

TAG:軟體開發 |