從零開始的模擬器(1)

 關於模擬器

這裏說的模擬器,是經過軟件模擬CPU、外設、存儲系統等硬件的行爲,來虛擬出一臺設備,並在其上運行操做系統及應用程序。好比 Android 模擬器。其實和日常用的虛擬機沒太大區別,不過虛擬機一般是模擬 x86 架構,速度很快;而這裏我打算模擬 MIPS 架構,與 x86 差別很大,速度慢。這也是 Android 模擬器慢的緣由。git

簡易 CPU

原理

《計算機組成與設計(硬件/軟件接口)》2.1-2.10節
CPU 經過執行指令來完成操做,所以咱們應首先看看指令長什麼樣子:
圖片描述github

R型指令,經常使用於計算架構

圖片描述

I型指令,經常使用於訪存、分支函數

圖片描述

J型指令,經常使用於跳轉
MIPS 採用了定長的指令結構,全部指令都是32位長,經過識別 op 就能肯定指令的類型(在咱們要實現的 MIPS 核心指令集上,R型的 opcode 都爲0,J型的有兩個 j(0x2)、jal(0x3)),進而就能肯定每一位的含義。
再看看都有哪些指令:
圖片描述spa

操做都比較簡單,畢竟這是計算機中最底層的語言了。操作系統

實現

爲了執行指令,咱們還須要模擬寄存器和存儲器。
MIPS 寄存器有32個:
圖片描述設計

int regs[32];

就能夠模擬。另外還須要模擬 $pc 寄存器指示當前指令的地址。該寄存器不能被直接操做,因此沒有列在上面。本來超快速的寄存器放到內存中模擬,速度必然被拖慢了。
存儲器直接 malloc 申請一段空間就行了。
利用循環不斷取指令,直接用 switch 語句判斷 op 字段來譯碼,用相應的 C 語句模擬指令行爲,咱們的 CPU 就運行起來了。code

是否是太簡單了?
確實是,用軟件模擬省略了大量的硬件實現細節,咱們作的只是描述 MIPS 指令的行爲,並讓編譯器和彙編器幫咱們轉化成 x86 指令執行,這其中必然引入了大量沒必要要的操做。blog

一個更接近真實 CPU 的模型

原理

《計算機組成與設計(硬件/軟件接口)》4.1-4.4節
這裏就是要模擬傳說中的硬佈線控制器。
圖片描述接口

重點是中間的主控單元,經過對 op 字段的分析,肯定每一個控制信號有效/無效(即高電位/低點位)。好比 RegWrite 有效,則寄存器堆就會把 WriteData 端口的值寫入 Write Register 端口輸入的寄存器號中, 無效則執行讀取操做;RegDst 有效,則會將 rd 字段輸入 Write Register 端口,不然將 rt 字段輸入該端口。每一個部件都按照指定的方式工做,指令也就被執行了。
此外,每一個單元還有一個時鐘信號輸入(即矩形波),在時鐘的上升沿/降低沿,單元的狀態改變。PC 寄存器每一個週期都會自增,這樣就能不斷讀入新的指令並執行。

實現

通常來講,這種邏輯設計應該使用 Verilog 語言描述。這裏我用了一種比較奇葩的方法,使用 C 語言來描述。
每一個單元用一個函數模擬,參數就是輸入端口上的值,返回值就是輸出端口上的值,控制信號做爲全局變量,函數調用時的實參就起到了多選器的做用。按上圖設計就行了。
須要注意的是,C 語句有前後順序:必須先執行指令存儲器,再執行寄存器,等等。可是在硬件中指定好控制信號,在一個週期內就會達到想要的狀態,並無人爲指定前後順序,有點像原子操做。用 C 模擬仍是有點不三不四的感受。

這裏我模擬了 lw、 sw、 beq、 add、 sub、 and、 or、 slt、 j 指令。其實這一部分徹底沒有必要,只會增長程序的複雜度。不過經過這樣的練習,咱們對處理器的認識也會更加深入些。

具體過程看代碼吧:https://github.com/hduhxc/echovm

相關文章
相關標籤/搜索