專案 | 用 VHDL 寫的 Forth SoC |
---|---|
作者 | 理查德·詹姆斯·豪 |
版權 | 2013-2019 理查德·豪 |
執照 | 麻省理工學院/LGPL |
電子郵件 | [email protected] |
該專案實作了一個基於 J1 CPU 定制的小型堆疊計算機,用於執行 Forth。該處理器已從 Verilog 以 VHDL 重寫,並略有擴展。
該專案的目標如下:
這三項都已完成。
H2 處理器與 J1 一樣,是基於堆疊的處理器,執行特別適合 FORTH 的指令集。
目前的目標是 Nexys3 板,帶有 Xilinx Spartan-6 XC6LX16-CS324 FPGA,未來將針對新板,因為該板即將達到其使用壽命。 VHDL 以通用方式編寫,硬體組件被推斷而不是明確實例化,這應該會使程式碼相當可移植,儘管 Nexys3 板組件的介面特定於該板上的周邊。
可以在此處查看該項目在硬體上的實際運行影片:
SoC也可以用C語言寫的模擬器來仿真,如下圖所示:
系統架構如下:
該項目使用的許可證是混合的,並且基於每個文件。對於我的程式碼,我使用 MIT 許可證 - 所以請隨意使用它。使用的其他許可證是 LGPL 和 Apache 2.0 許可證,它們僅限於單個模組,因此如果您對 LGPL 程式碼有一些厭惡,可以將其刪除。
目前唯一可用的目標板是 Nexys3,這應該會在未來發生變化,因為該板目前已達到其生命週期的終點。我希望支援的下一個主機板是它的後繼產品 Nexys 4 和 myStorm BlackIce (https://mystorm.uk/)。 myStorm 板使用完全開源的工具鏈進行綜合、佈局佈線以及位元檔案產生。
該建置已在 Debian Linux 版本 8 下進行了測試。
您將需要:
硬體:
Xilinx ISE 可以(或可能)免費下載,但需要註冊。 ISE 需要出現在您的路徑上:
PATH=$PATH:/opt/Xilinx/14.7/ISE_DS/ISE/bin/lin64;
PATH=$PATH:/opt/Xilinx/14.7/ISE_DS/ISE/lib/lin64;
製作基於 C 的工具鏈:
make embed.hex
製作可以燒寫到目標板的位檔:
make simulation synthesis implementation bitfile
將位元檔上傳到目標板:
make upload
查看「make模擬」產生的波形:
make viewer
基於 C 的 CLI 模擬器可以透過以下方式呼叫:
make run
這將彙編 H2 Forth 原始檔 embed.fth,並在啟動偵錯器的情況下在 H2 模擬器下執行彙編的目標檔案。圖形模擬器可以透過以下方式運作:
make gui-run
這需要 freeglut 以及 C 編譯器。
原始 J1 項目位於:
該專案針對原始 J1 核心並提供 eForth 實作(使用 Gforth 編寫,用於 J1 核心的元編譯/交叉編譯)。它也為用 C 編寫的系統提供了模擬器。
元編譯器所基於的 eForth 解釋器可以在以下位置找到:
H2 處理器和相關週邊裝置現在相當穩定,但原始程式碼始終是關於指令和周邊行為以及暫存器對映的權威指南。
J1 CPU 有一些修改,其中包括:
H2 CPU 的行為與 J1 CPU 非常相似,可以閱讀 J1 PDF 以更好地了解該處理器。此處理器是 16 位元的,指令佔用時鐘週期。大多數原始 Forth 字也可以在單一週期中執行,一個值得注意的例外是 store(“!”),它被分成兩個指令。
CPU 內部有以下狀態:
載入並儲存到保存 H2 程式的區塊 RAM 中,丟棄最低位,所有其他記憶體操作都使用較低位元(例如跳轉以及載入和儲存到輸入/輸出週邊)。這樣應用程式在存取程式 RAM 時可以使用最低位元進行字元操作。
指令集的解碼方式如下:
+---------------------------------------------------------------+
| F | E | D | C | B | A | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+---------------------------------------------------------------+
| 1 | LITERAL VALUE |
+---------------------------------------------------------------+
| 0 | 0 | 0 | BRANCH TARGET ADDRESS |
+---------------------------------------------------------------+
| 0 | 0 | 1 | CONDITIONAL BRANCH TARGET ADDRESS |
+---------------------------------------------------------------+
| 0 | 1 | 0 | CALL TARGET ADDRESS |
+---------------------------------------------------------------+
| 0 | 1 | 1 | ALU OPERATION |T2N|T2R|N2A|R2P| RSTACK| DSTACK|
+---------------------------------------------------------------+
| F | E | D | C | B | A | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+---------------------------------------------------------------+
T : Top of data stack
N : Next on data stack
PC : Program Counter
LITERAL VALUES : push a value onto the data stack
CONDITIONAL : BRANCHS pop and test the T
CALLS : PC+1 onto the return stack
T2N : Move T to N
T2R : Move T to top of return stack
N2A : STORE T to memory location addressed by N
R2P : Move top of return stack to PC
RSTACK and DSTACK are signed values (twos compliment) that are
the stack delta (the amount to increment or decrement the stack
by for their respective stacks: return and data)
所有 ALU 操作都替換 T:
價值 | 手術 | 描述 |
---|---|---|
0 | 時間 | 堆疊頂 |
1 | 氮 | 將 T 複製到 N |
2 | 時間+N | 添加 |
3 | 泰恩 | 按位與 |
4 | T 或 N | 按位或 |
5 | ^N | 按位異或 |
6 | ~T | 按位取反 |
7 | T=N | 平等測試 |
8 | N < T | 簽名比較 |
9 | N >> T | 邏輯右移 |
10 | T-1 | 遞減 |
11 | 右 | 返回棧頂 |
12 | [T] | 從地址載入 |
13 | N << T | 邏輯左移 |
14 | 深度 | 堆疊深度 |
15 | N u < T | 無符號比較 |
16 | 設定CPU狀態 | 啟用中斷 |
17 號 | 取得CPU狀態 | 中斷打開了嗎? |
18 | 深度 | 返回深度 stk |
19 號 | 0= | T==0? |
20 | CPU ID | CPU識別符 |
21 | 文字 | 內部指令 |
帶有“o”前綴的寄存器是輸出寄存器,帶有“i”前綴的寄存器是輸入寄存器。暫存器分為暫存器的輸入和輸出部分,且輸入和輸出暫存器的位址並非在所有情況下都彼此對應。
VHDL SoC 中已實現以下週邊,以便與 Nexys3 板上的裝置連接:
SoC 還具有一組可啟用或停用的有限中斷。
輸出暫存器映射:
登記 | 地址 | 描述 |
---|---|---|
奧雅特 | 0x4000 | 串口暫存器 |
VT100 | 0x4002 | VT100 終端機寫入 |
OLED | 0x4004 | LED輸出 |
o定時器Ctrl | 0x4006 | 定時器控制 |
記憶體輸出 | 0x4008 | 記憶體資料輸出 |
記憶體控制 | 0x400A | 記憶體控制/高位址 |
記憶體位址低位 | 0x400C | 記憶體低位址 |
o7SegLED | 0x400E | 4 x LED 7 段顯示器 |
遮罩 | 0x4010 | CPU中斷屏蔽 |
串口波特率 | 0x4012 | UART Tx 波特率時鐘設置 |
串口波特率 | 0x4014 | UART 接收波特率時鐘設置 |
輸入暫存器:
登記 | 地址 | 描述 |
---|---|---|
藝術 | 0x4000 | 串口暫存器 |
iVT100 | 0x4002 | 終端狀態和 PS/2 鍵盤 |
i開關 | 0x4004 | 按鈕和開關 |
定時器Din | 0x4006 | 當前定時器值 |
iMemDin | 0x4008 | 記憶體資料輸入 |
應依序閱讀以下暫存器的描述,並描述週邊裝置的工作原理。
SoC 上有一個具有固定波特率和格式(115200、8 位元、1 個停止位)的 UART。 UART 在 RX 和 TX 頻道上都有一個深度為 8 的 FIFO。 UART 的控制分為 oUart 和 iUart。
若要將值寫入 UART,請置位 TXWE,同時將資料放入 TXDO。可以透過查看 iUart 暫存器來分析 FIFO 狀態。
要從 UART 讀取值:可以檢查 iUart 以查看 FIFO 中是否存在數據,如果在 oUart 寄存器中置位 RXRE,則在下一個時脈週期,數據將存在於 iUart 暫存器中。
UART的波特率可以透過重建VHDL工程來改變,位長、奇偶校驗位和停止位只能透過修改uart.vhd來改變
+-------------------------------------------------------------------------------+
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-------------------------------------------------------------------------------+
| X | X |TXWE| X | X |RXRE| X | X | TXDO |
+-------------------------------------------------------------------------------+
TXWE: UART TX Write Enable
RXRE: UART RX Read Enable
TXDO: UART TX Data Output
VGA 文字裝置模擬一個終端,使用者可以透過寫入 oVT100 暫存器來與之對話。它支援 VT100 終端功能的子集。此介面的行為非常類似於使用相同的忙碌訊號和控制訊號寫入 UART。輸入來自板上可用的 PS/2 鍵盤,其行為類似於 UART 的 RX 機制。
+-------------------------------------------------------------------------------+
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-------------------------------------------------------------------------------+
| X | X |TXWE| X | X |RXRE| X | X | TXDO |
+-------------------------------------------------------------------------------+
TXWE: VT100 TX Write Enable
RXRE: UART RX Read Enable
TXDO: UART TX Data Output
在 Nexys3 板上,開關旁邊有一組 LED,可以透過寫入 LEDO 來開啟 (1) 或關閉 (0) 這些 LED。這裡的每個 LED 都對應到它旁邊的開關。
+-------------------------------------------------------------------------------+
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-------------------------------------------------------------------------------+
| X | X | X | X | X | X | X | X | LEDO |
+-------------------------------------------------------------------------------+
LEDO: LED Output
定時器由 oTimerCtrl 暫存器控制,它是一個以 100MHz 運行的 13 位元定時器,它可以選擇產生中斷,並且可以使用 iTimerDin 暫存器讀回目前定時器內部計數。
一旦 TE 位元被置位,定時器就會開始計數,一旦定時器達到 TCMP 值,它就會回繞,並且可以選擇透過置位 INTE 來產生中斷。這也會切換來自定時器並路由到板上引腳的 Q 和 NQ 線(有關引腳,請參閱約束檔 top.ucf)。
可以透過寫入 RST 來重設定時器。
+-------------------------------------------------------------------------------+
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-------------------------------------------------------------------------------+
| TE | RST|INTE| TCMP |
+-------------------------------------------------------------------------------+
TE: Timer Enable
RST: Timer Reset
INTE: Interrupt Enable
TCMP: Timer Compare Value
H2 核心具有中斷機制,必須透過指令啟用或停用中斷。每個中斷都可以透過 IMSK 中的一位來屏蔽,以啟用該特定中斷。 IMSK 中的一位中的「1」啟用該特定中斷,如果在其中啟用了中斷,則該中斷將被傳送到 CPU。
+-------------------------------------------------------------------------------+
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-------------------------------------------------------------------------------+
| X | X | X | X | X | X | X | X | IMSK |
+-------------------------------------------------------------------------------+
IMSK: Interrupt Mask
此暫存器僅用於設定傳輸的波特率和取樣時脈頻率。
+-------------------------------------------------------------------------------+
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-------------------------------------------------------------------------------+
| BTXC |
+-------------------------------------------------------------------------------+
BTXC: Baud Clock Settings
此暫存器僅用於設定接收的波特率和取樣時脈頻率。
+-------------------------------------------------------------------------------+
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-------------------------------------------------------------------------------+
| BRXC |
+-------------------------------------------------------------------------------+
BRXC: Baud Clock Settings
當 oMemControl 中發出寫入使能 (WE) 時,資料將輸出到選取的位址。
+-------------------------------------------------------------------------------+
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-------------------------------------------------------------------------------+
| Data Ouput |
+-------------------------------------------------------------------------------+
此暫存器包含 Nexys3 板上板載記憶體的控制暫存器。該板包含三個儲存設備、兩個非揮發性儲存設備和一個基於揮發性 RAM 的設備。可透過簡單 SRAM 介面存取的兩個裝置(一個易失性 M45W8MW16,一個非揮發性 - NP8P128A13T1760E)均可存取,第三個是基於 SPI 的儲存裝置 NP5Q128A13ESFC0E),但目前無法存取。
+-------------------------------------------------------------------------------+
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-------------------------------------------------------------------------------+
| OE | WE | RST|WAIT| RCS| FCS| Address Hi |
+-------------------------------------------------------------------------------+
OE: Output Enable - enable reading from current address into iMemDin
WE: Write Enable - enable writing oMemDout into ram at current address
RST: Reset the Flash memory controller
RCS: RAM Chip Select, Enable Volatile Memory
FCS: Flash Chip Select, Enable Non-Volatile Memory
Address Hi: High Bits of RAM address
OE 和 WE 是互斥的,如果兩者都設定了則沒有效果。
記憶體控制器正在積極開發中,其介面可能會發生變化。
這是 RAM 的低位址位元。
+-------------------------------------------------------------------------------+
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-------------------------------------------------------------------------------+
| Address Lo |
+-------------------------------------------------------------------------------+
Nexys3 板上有一組 7 段顯示器,具有小數點(實際上是 8 段),可用於數位輸出。 LED 段無法直接定址。相反,L8SD 中儲存的值會對應為十六進位顯示值(或 BCD 值,但這需要重新產生 SoC 並修改 VHDL 中的通用值)。
值「0」對應於 LED 段上顯示的零,「15」對應於「F」等。
連續有 4 個顯示器。
+-------------------------------------------------------------------------------+
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-------------------------------------------------------------------------------+
| L7SD0 | L7SD1 | L7SD2 | L7SD3 |
+-------------------------------------------------------------------------------+
L7SD0: LED 7 Segment Display (leftmost display)
L7SD1: LED 7 Segment Display
L7SD2: LED 7 Segment Display
L7SD3: LED 7 Segment Display (right most display)
iUart 暫存器與oUart 暫存器搭配使用。 iUart 暫存器中提供緩衝位元組傳輸和接收的 FIFO 的狀態以及任何接收到的位元組。
+-------------------------------------------------------------------------------+
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-------------------------------------------------------------------------------+
| X | X | X |TFFL|TFEM| X |RFFL|RFEM| RXDI |
+-------------------------------------------------------------------------------+
TFFL: UART TX FIFO Full
TFEM: UART TX FIFO Empty
RFFL: UART RX FIFO Full
RFEM: UART RX FIFO Empty
RXDI: UART RX Data Input
iVT100 暫存器與 oVT100 暫存器搭配使用。 iVT100 暫存器中提供緩衝位元組傳輸和接收的 FIFO 的狀態以及任何接收到的位元組。它的工作原理與 iUart/oUart 暫存器相同。
+-------------------------------------------------------------------------------+
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-------------------------------------------------------------------------------+
| X | X | X |TFFL|TFEM| X |RFFL|RFEM| 0 | ACHR |
+-------------------------------------------------------------------------------+
TFFL: VGA VT100 TX FIFO Full
TFEM: VGA VT100 TX FIFO Empty
RFFL: PS2 VT100 RX FIFO Full
RFEM: PS2 VT100 RX FIFO Empty
ACHR: New character available on PS2 Keyboard
此暫存器包含定時器計數器的目前值。
+-------------------------------------------------------------------------------+
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-------------------------------------------------------------------------------+
| X | X | X | TCNT |
+-------------------------------------------------------------------------------+
TCNT: Timer Counter Value
iSwitches 包含來自多個來源的輸入線。這些按鈕(BUP、BDWN、BLFT、BRGH 和 BCNT)對應於 Nexys3 板上的方向鍵。開關 (TSWI) 是 oLed 中提到的開關,每個開關旁邊都有一個 LED。
開關和按鈕已在硬體中進行去抖處理,因此從這些暫存器讀入後無需進一步處理。
+-------------------------------------------------------------------------------+
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-------------------------------------------------------------------------------+
| X | X | X | BUP|BDWN|BLFT|BRGH|BCNT| TSWI |
+-------------------------------------------------------------------------------+
BUP: Button Up
BDWN: Button Down
BLFT: Button Left
BRGH: Button Right
BCNT: Button Center
TSWI: Two Position Switches
記憶體輸入,來自 SRAM 或快閃記憶體,由 oMemControl 和 oMemAddrLow 索引。當從閃存讀取時,這實際上可能是狀態資訊或來自查詢表的資訊。
+-------------------------------------------------------------------------------+
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-------------------------------------------------------------------------------+
| Data Input |
+-------------------------------------------------------------------------------+
定義了以下中斷服務例程:
姓名 | 數位 | 描述 |
---|---|---|
沒有 | 0 | 未使用 |
isrRxFifo不為空 | 1 | UART RX FIFO 不為空 |
isrRxFifoFull | 2 | UART RX FIFI 已滿 |
isrTxFifoNotEmpty | 3 | UART TX FIFO 不為空 |
isrTxFifoFull | 4 | UART TX FIFO 已滿 |
isrKbd新 | 5 | 新 PS/2 鍵盤字符 |
定時器 | 6 | 定時器計數器 |
isrDPad按鈕 | 7 | 任何方向鍵按鈕更改狀態 |
當發生中斷並且在處理器內啟用中斷時,就會執行對記憶體中位置的呼叫 - 該位置與 ISR 編號相同。例如,編號為「4」的 ISR 將執行對記憶體中位置「4」的呼叫(而不是跳轉)。
中斷在執行之前至少有 4-5 個週期的延遲,中斷請求處理程序中有兩到三個週期的延遲,然後必須呼叫記憶體中的 ISR 位置,然後呼叫實現 ISR 本身的字。
如果兩個中斷同時發生,則按照從最低中斷號到最高中斷號的順序進行處理。
當發生相同編號且尚未處理的中斷時,中斷將會遺失。
H2 的反組譯程式和基於 C 的模擬器位於單一程式中(請參閱 h2.c)。此模擬器是 VHDL 測試平台 tb.vhd 的補充,而不是取代它。元編譯器在 eForth 解釋器之上運行,它包含在檔案 embed.c 和 embed.blk 中。元編譯器(交叉編譯器的 Forth 說法)是一個 Forth 程序,用於建立在目標上執行的 eForth 映像。
該工具鏈目前正在不斷變化,未來 h2.c 和 embed.c 之間可能會有更多集成,同時將 Embed 虛擬機更改為更類似於 H2 CPU 的虛擬機,其長期目標是創建自託管系統。
要建置兩者,需要一個 C 編譯器,建置目標“h2”將建置可執行文件,h2,“embed”將建置元編譯器:
make h2 embed
它可以使用 make 目標在原始檔 embed.fth 上運行:
make run
不需要 make 檔:
Linux:
cc -std=c99 h2.c -o h2 # To build the h2 executable
cc -std=c99 embed.c -o embed # To build the embed VM executable
./embed embed.blk embed.hex embed.fth # Create the target eForth image
./h2 -h # For a list of options
./h2 -r embed.hex # Run the assembled file
Windows:
gcc -std=c99 h2.c -o h2.exe # Builds the h2.exe executable
gcc -std=c99 embed.c -o embed.exe # Builds the embed.exe executable
embed.exe embed.blk embed.hex embed.fth # Create the target eForth iamge
h2.exe -h # For a list of options
h2.exe -r embed.hex # Run the assembled file
可用的命令列選項清單:
- stop processing options, following arguments are files
-h print a help message and exit
-v increase logging level
-d disassemble input files (default)
-D full disassembly of input files
-T Enter debug mode when running simulation
-r run hex file
-L # load symbol file
-s # number of steps to run simulation (0 = forever)
-n # specify NVRAM block file (default is nvram.blk)
file* file to process
該程式是在 MIT 許可下發布的,請隨意使用並根據需要進行修改。透過最小的修改,它應該能夠為原始 J1 核心彙編程式。
元編譯器運行在嵌入虛擬機器之上,它是一個最初源自 H2 CPU 的 16 位元虛擬機器。該專案包括一個元編譯方案,允許 eForth 映像產生經過修改的新 eForth 映像。該系統已適應 H2 的使用,取代了用 C 編寫的交叉編譯器,從而可以創建 H2 的第一個映像。
元編譯器是一個普通的 Forth 程序,它包含在 embed.fth 中。然後使用元編譯器 Forth 程式建立能夠在 H2 目標上運行的 eForth 映像。
有關 Forth 中元編譯的更多信息,請參閱:
反組譯器取得包含組譯器的文字文件,該文件由 16 位元十六進位數字組成。然後它嘗試反彙編指令。它還可以提供一個符號文件,該符號文件可以由彙編器生成,並嘗試找到跳轉和調用指向的位置。
GTKwave 呼叫的 tcl 腳本使用反彙編器,它將 H2 的指令追蹤從一系列數字轉換為它們代表的指令和分支目的地。這使得 VHDL 的調試變得更加容易。
紫色痕跡顯示了反彙編的指令。
C 語言的模擬器實作了 H2 核心和大部分 SoC。模擬器的 IO 不是周期精確的,但可用於運行和調試程序,其結果與硬體的行為非常相似。這比重建用於快閃 FPGA 的位元檔案要快得多。
該模擬器還包括一個調試器,其設計類似於 DOS 中的 DEBUG.COM 程式。調試器可用於反彙編記憶體部分、檢查外設的狀態並將記憶體部分轉儲到螢幕。它還可用於設定斷點、單步執行並運行程式碼直到命中斷點。
要運行偵錯器,必須提供十六進位檔案或來源檔案:
# -T turns debugging mode on
./h2 -T -r file.hex # Run simulator
兩種操作模式都可以透過符號檔案擴展,該檔案列出了變數、標籤和函數在組裝核心中的位置。
當給出“-T”選項時,將在執行模擬之前進入調試模式。應出現提示,命令列應如下所示:
$ ./h2 -T -R h2.fth
Debugger running, type 'h' for a list of command
debug>
斷點可以透過符號方式設置,也可以透過程式位置設置,「b」指令用來設定斷點:
數字可以八進制(數字前綴為“0”)、十六進制(前綴為“0x”)或十進制形式輸入。例如,以下三個偵錯指令都在同一位置設定斷點:
debug> b 16
debug> b 0x10
debug> b 020
'k' 可用於列出目前設定的斷點:
debug> k
0x0010
這會在函數“key?”時設定斷點。稱為:
debug> b key?
函數和標籤都可以停止,這需要在命令列上指定符號文件,或彙編並運行以在來源文件(而不是十六進位文件)上使用。符號檔案可用於來源檔案或十六進位檔案。
要單步執行,可以使用 's' 命令,但如果關閉追蹤(預設情況下追蹤是關閉的),則不會發生太多情況。可以使用“t”命令開啟或關閉追蹤:
debug> s
debug> s
debug> t
trace on
debug> s
0001: pc(089a) inst(4889) sp(0) rp(0) tos(0000) r(0000) call 889 init
debug> s
0002: pc(0889) inst(807a) sp(0) rp(1) tos(0000) r(089b) 7a
debug> s
0003: pc(088a) inst(e004) sp(1) rp(1) tos(007a) r(089b) 6004
建議在運行時發出“c”或繼續命令時關閉跟踪。
這 '。命令可用於顯示 H2 內核內部狀態:
debug> .
Return Stack:
0000: 0000 08aa 0883 017b 0000 031b 0000 ffb0 0000 02eb ffb5 0210 0167 0167
0167 0167
0010: 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
0000 0000
Variable Stack:
tos: 0000
0001: 0000 0000 0000 0001 0004 0005 0000 ffb0 0000 0000 0000 0000 0000 0000
0000 0000
0011: 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
0000 0000
pc: 0538
rp: 0001
dp: 0000
ie: false
'p'指令可用來顯示模擬週邊裝置的狀態:
debug> p
LEDS: 00
VGA Cursor: 0005
VGA Control: 007a
Timer Control: 8032
Timer: 001b
IRC Mask: 0000
UART Input: 6c
LED 7seg: 0005
Switches: 00
LFSR: 40ba
Waiting: false
有關命令的完整列表,請使用“h”命令。
進入偵錯模式的其他方法包括將“.break”彙編程式指令放入原始程式碼中(這僅在原始檔上使用彙編和運行命令時有效,而不是在十六進位檔案上使用),以及在模擬器運行時點擊轉義字元。
可以在Linux和Windows下編譯、測試單獨的程式。這模擬了 SoC 所連接的 Nexys3 板外設,但提供了圖形環境,與命令列實用程式不同。與設備互動並查看其正在執行的操作更容易,但調試會話的控制較少。它需要自由的過剩。
下面是 GUI 模擬器中正在運行的會話的圖像:
建築可以透過
make gui
並運行:
make gui-run
或者:
./gui h2.hex (on Linux)
gui.exe h2.hex (on Windows)
當系統上安裝了免費 glut 的開發包時,Linux 建置應該可以工作,Windows 建置可能需要更改建置系統和/或手動安裝編譯器、函式庫和標頭。
目前的鍵位圖是:
Up Activate Up D-Pad Button, Release turns off
Down Activate Down D-Pad Button, Release turns off
Left Activate Left D-Pad Button, Release turns off
Right Activate Right D-Pad Button, Release turns off
F1 - F8 Toggle Switch On/Off, F1 is left most, F8 Right Most
F11 Toggle UART/PS2 Keyboard Input
F12 Toggle Debugging Information
Escape Quit simulator
所有其他鍵盤按鍵都重定向到 UART 或 PS/2 鍵盤輸入。
可以單擊開關和方向鍵按鈕將其打開,左鍵單擊打開開關,右鍵單擊關閉開關。點擊頂部的方向鍵按鈕即可打開,在螢幕上的任何位置釋放按鍵即可關閉。
此系統中使用的 VHDL 元件被設計為可在不同的工具鏈和供應商之間重複使用和移植。硬體組件(例如區塊 RAM)是推斷出來的,而不是明確實例化的。這些組件也被設計得盡可能通用,其中大多數都具有可選的寬度。這可能會走向極端,但不幸的是許多供應商仍然不支援VHDL-2008標準。
文件 | 執照 | 作者 | 描述 |
---|---|---|---|
實用工具.vhd | 麻省理工學院 | 理查德·J·豪 | 通用組件的集合 |
h2.vhd | 麻省理工學院 | 理查德·J·豪 | H2第四個CPU核心 |
串口vhd | 麻省理工學院 | 理查德·J·豪 | UART TX/RX(運行時可自訂) |
vga.vhd | LGPL 3.0 | 哈維爾·V·加西亞 | 文字模式 VGA 80x40 顯示屏 |
理查德·J·豪 | (和 VT100 終端模擬器) | ||
KBD文件 | ??? | 史考特·拉爾森 | PS/2 鍵盤 |
上面描述了用作彙編程式的類偽 Forth 語言,實際在 Forth 核心上運行的應用程式本身就是一個 Forth 解釋器。本節介紹在 H2 Core 上運行的 Forth 解釋器,它包含在 embed.fth 中。
待辦事項:
整個專案使用了多種語言,所有這些語言都彼此截然不同,並且需要自己的一套編碼標準和風格指南。
常用訊號名稱:
clk - The system clock
rst - A reset signal for the module
we - Write Enable
re - Read Enable
di - Data In
din - Data In
do - Data Out
dout - Data Out
control - Generally an input to a register, the documentation
for the module will need to be consulted to find out
what each bit means
signal_we - The write enable for 'signal'
signal_i - This is an input signal
signal_o - This is an output signal
一般來說,不使用“_i”和“_o”後綴,模組保持簡短,並且選擇名稱,以便其含義顯而易見。一旦專案發展,這條規則可能會被重新審視。
組件應該:
constant N: positive := 4;
signal a: std_logic_vector(N - 1 downto 0) := (others => '1');
而不是:
signal a: std_logic_vector(3 downto 0) := x"F";
樣式規則如下:
格式化指南的範例,描述了一個簡單的任意寬度暫存器:
-- Lots of comments about what the unit does should go
-- here. Describe the waveforms, states and use ASCII
-- art where possible.
library ieee, work;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all; -- numeric_std not std_logic_arith
entity reg is -- generic and port indented one tab, their parameters two
generic (
N: positive); -- Generic parameters make for a generic component
port (
clk: in std_logic; -- standard signal names
rst: in std_logic; --
we: in std_logic;
di: in std_logic_vector(N - 1 downto 0);
do: out std_logic_vector(N - 1 downto 0)); -- note the position of ");
end entity; -- "end entity", not "end reg"
architecture rtl of reg is
signal r_c, r_n: std_logic_vector(N - 1 downto 0) := (others => '0');
begin
do <= r_c;
process(rst, clk)
begin
if rst = '1' then -- asynchronous reset
r_c <= (others => '0');
elsif rising_edge(clk) then -- rising edge, not "clk'event and clk = '1'"
r_c <= r_n;
end if;
end process;
process(r_c, di, we)
begin
r_n <= r_c;
if we = '1' then
r_n <= di;
end if;
end process;
end; -- "end" or "end architecture"
此專案中使用了相當多的C程式碼,用於為H2核心製作工具鏈並模擬系統。
這裡的 C 程式碼沒有什麼太令人驚訝的,因此應該處理一些異常。
static const char *alu_op_to_string(uint16_t instruction) {
/* notice also that the 'case' clauses are inline with the
* switch selector */
switch (ALU_OP(instruction)) {
case ALU_OP_T: return "T";
case ALU_OP_N: return "N";
case ALU_OP_T_PLUS_N: return "T+N";
case ALU_OP_T_AND_N: return "T&N";
case ALU_OP_T_OR_N: return "T|N";
case ALU_OP_T_XOR_N: return "T^N";
case ALU_OP_T_INVERT: return "~T";
case ALU_OP_T_EQUAL_N: return "N=T";
case ALU_OP_N_LESS_T: return "T>N";
case ALU_OP_N_RSHIFT_T: return "N>>T";
case ALU_OP_T_DECREMENT: return "T-1";
case ALU_OP_R: return "R";
case ALU_OP_T_LOAD: return "[T]";
case ALU_OP_N_LSHIFT_T: return "N<N";
case ALU_OP_ENABLE_INTERRUPTS: return "seti";
case ALU_OP_INTERRUPTS_ENABLED: return "iset?";
case ALU_OP_RDEPTH: return "rdepth";
case ALU_OP_T_EQUAL_0: return "0=";
case ALU_OP_CPU_ID: return "cpu-id";
default: return "unknown";
}
}
if (foo)
bar();
else
baz();
picocom --omap delbs -b 115200 -e b /dev/ttyUSB1