從零開始設計一套指令集及其虛擬機


前言

在半年前,我萌生了創造一門獨特的編程語言的想法。大約三個月前,腦中的這個想法逐漸變得清晰,我想實現一種可以不用鍵盤就能編寫代碼的語言。比較准確得說應該是一門圖形化編程語言,不完全是像藍圖腳本那樣,而是結合代碼和圖形的優點。

設想中它是一門高級解釋型語言,所以我先命名它為“H”語言,意為高級。但我能力和水平非常有效,在實現的准備過程中就被絆倒了,於是我開始考慮將它實現為靜態編譯語言,先編譯為中間代碼,再解釋執行。

這篇文章介紹的就是這當中的中間代碼,因為它層次比"H"低,所以我命名為“L”語言

 這段時間我暫時放下之前GBA上的光線追蹤,開始設計L語言的指令集和虛擬機。現在虛擬機可以高效的運行指令字節碼,並調用系統函數,實現輸入輸出等功能。這篇文章記錄了目前的進度。

指令設計的基礎應該是虛擬機的架構,因此我先簡要說明虛擬機特點,然后是指令集特點,最后詳細介紹指令設計過程。


 

虛擬機

通過中間代碼在不同架構,不同平台的系統上運行程序的方法大概叫虛擬機技術,例如JAVA和.NET都是運行各自指令集的虛擬機。

我的虛擬機設計的目標是為了方便運行我的H語言,我將他稱為LVM,意為低級虛擬機(和LLVM名字很像 : D 我也是事后發現的)。

          

學過計算機架構的也許知道基於棧的虛擬機和基於寄存器的虛擬機,我的LVM是基於寄存器的,但有它自己的特點。

在現代計算機中,函數調用需要保存寄存器,移動寄存器和壓棧出棧,會占用很多時間。這是因為寄存器的數量有效,而在虛擬機的設計中,完全可以不考慮寄存器的限制,例如可以給每個函數調用分配一組內存模擬的虛擬寄存器,這樣就不必保存和恢復現場。

我則采用了一種寄存器指針的方法,寄存器指針指示寄存器窗口的位置,調用函數會移動窗口位置,且原窗口和新窗口位置存在重疊,用於傳遞參數

 

結合此圖,函數調用的過程為

  1. 調用者把參數放到寄存器窗口的末尾。
  2. 調用者將窗口后移,使原來的末尾變成開頭.
  3. 調用者把PC保存到窗口前之前。
  4. 調用函數(PC跳轉)。
  5. 被調用函數執行完后,從窗口前讀取PC,回到調用前位置。
  6. 最后將窗口移回原位。

通過這種方法既可以不用保存現場,也不用移動寄存器。在寫這篇文章時,我才查到這種方法在我之前就已提出,名稱是重疊寄存器窗口技術,用於精簡指令集處理器中,其中的范例是SPARC。因此我的虛擬機也可稱為基於重疊寄存器窗口技術的虛擬機

截至目前為止,虛擬機的結構如下:

 可以看到:

  • 寄存器窗口有16個寄存器,而虛擬寄存器有一萬多個。這就是軟件虛擬的好處,是SPARC等硬件處理器不能做到的。
  • 雖然現在留有SP寄存器,但實際上除了寄存器列,並沒有棧,因此也沒有棧指令,我想先探究依靠靈活的寄存器窗口和寄存器列能否替代棧。
  • 指令譯碼后儲存為VL字節碼,加載到內存后由vcode指針連接到虛擬機。
  • 沒有使用標志位(或者叫程序狀態字)

 附帶一提寄存器統一是32位或64位,目前按32位設計指令。


 

指令集

很隨意的命名為VL指令集,代表變長低級指令集。此外編譯器已經寫好,可以將其對應的LASM匯編語言編譯到VL字節碼。

目前指令約80條,包含寄存器移動、內存讀取儲存、加減乘除、移位、位運算、跳轉、分支、寄存器窗口操作和系統指令。

個人感覺VL指令集功能應該在精簡和復雜指令集之間。

正如前面所說,指令是依附於機器的,所以指令的Call和Return的操作都比較特殊,還有特殊的寄存器窗口移動指令,但沒有棧操作指令

因為面向的是軟件層面,且是實時解釋執行的,這些指令的字節碼都盡量比較規整,例如操作碼是1字節的,兩個寄存器各4bit拼一起也是1字節,盡量避免讀取譯碼的額外操作。指令不是像大多精簡指令集一樣定長,而是以字節為單位,長度在1-6字節之間。這會導致指令執行增加一點變數,速度受到影響,但節約了大量的空間所以也不用心疼。

這是一些字節碼的安排(靠右為低字節):

 


 

設計指令集

指令集的組成和設計指令集的過程我放到下一篇文章中詳細說明。

下下篇文章,我會繼續介紹LVM虛擬機的實現過程和優化心得。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM