秦國鋒, 秦家豪, 鄒劍煌, 劉 鯤, 胡 岳
(同濟大學計算機科學與技術系,上海201804)
計算機系統實驗課程是計算機類專業課程的配套動手實踐實驗課程,它通過設置與計算機重點專業知識相適配的實驗,達到幫助學生們更全面、更深入地理解計算機系統的基本組成和運作原理,培養學生們設計與開發個人計算機系統的能力。在之前“計算機系統結構”理論課程設置的基于MIPS 指令集的靜態和動態流水線CPU設計與實現的同步實驗中,學生們很好地完成了流水線CPU的設計與實現[1]。然而,在實際的計算機系統中不僅是CPU和內存模塊的交互,需要主存、緩存和輔存形成的三級存儲系統來與CPU進行數據交互,以此達到計算機的高效運行。因此,本文在實驗課程中提出了一種基于Artix-7 FPGA系統的三級存儲體系的設計與實現方案,該方案采用自頂向下的層次模塊化設計方法,使用verilog 硬件邏輯語言進行描述。
計算機存儲體系中,“三級存儲”指的是高速緩沖存儲器、主存儲器、輔助存儲器。高速緩沖存儲器用來改善主存儲器與中央處理器的速度匹配問題;輔助存儲器用于擴大存儲空間。三級存儲系統解決存儲器速度、容量和價格三者的矛盾,并且提升了CPU 訪存速度,改善了系統的總體性能。在FPGA系統中,共有位于FPGA 系統的片內內存,位于片外的DDR 存儲,以及屬于外設的SD 卡3 種存儲模塊,分別在三級存儲實驗中可以模擬對應主存儲器、高速緩沖存儲器和輔助存儲器[2]。
基于FPGA系統的三級存儲體系實驗的總體框架分為SD 卡、DDR 和FPGA 片內內存三級,如圖1 所示。系統一通電,會先執行SD 中初始部分的引導代碼,從而將存儲在SD中的CPU 二進制流遷移到DDR緩存中,在以此調入主存供CPU 執行,同時會將位于SD中的系統或用戶程序目標代碼遷移到DDR中等待CPU調用執行。

圖1 三級存儲總體框架
一臺市場上商業發售的計算機都在它的核心硬盤(基本上都命名為C 盤)的初始地址空間固化有一段用于加載和遷移存儲,在核心硬盤上的用于維護系統啟動和運行的系統程序和用戶程序的固定程序,常被稱為BootLoader程序[3],這一加載的啟動機制借助三級存儲體系保證了計算機系統啟動的快速和準確。
實驗設計的基于Artix-7 FPGA的三級存儲體系中也設計有適用于自主啟動運行系統的BootLoader 程序。其實現方法是將BootLoader 程序用匯編語言和C語言聯合開發,通過gcc 交叉編譯后將其加載到irom里,類比于一般計算機的核心硬盤。當FPGA 板通上電后,會加載.bit 文件,然后執行irom 里的BootLoader程序[4-10]。
如圖2 所示,被執行的BootLoader 程序首先會將存儲于SD卡中的用戶程序指令加載到iram 中(即圖1 中的DDR緩存組件中),然后搬遷進板內等待被執行;在完成加載任務后修改PC 寄存器中的指令地址信息,讓其指向剛被加載到板內的用戶程序所在的地址空間,然后CPU按照PC 寄存器所指的指令地址空間執行該用戶程序,完成一個簡易計算機的啟動和運行。

圖2 BootLoader啟動過程
CPU在執行用戶程序時指令和數據的流向如圖3所示。首先CPU通過讀取PC寄存器中的待執行指令地址信息,然后結合指令地址映射模塊,找到存在于irom或iram地址空間的指令內容,將其加載到板內,供CPU執行。同理,在CPU 執行指令時會發生對于內存的讀寫需求,結合數據地址映射模塊,找到存在于dram和SD卡地址空間的數據內容,將其讀取到板內或者寫入到這些地址空間。通過多級儲存器之間相互協作,實現和保證了一臺簡易計算機處理效率和性能。

圖3 執行程序時的指令和數據流
在整個執行過程中,代碼段地址和存儲器地址進行統一編址,所有的代碼、數據和存儲器都在邏輯地址空間中有一個32 位的地址,C語言編寫的就是對這些地址的操作。
BootLoader存儲于irom 地址空間,地址為0x0000 0000,如圖4 所示。在執行完BootLoader程序后,需要將PC寄存器內容改為0x00400000,指向存儲加載而來的用戶程序的iram地址空間中,于是在編譯時需要在0x00000000 附近加上一段跳轉指令到BootLoader的main 函數,以及返回時跳轉回0x00400000,具體代碼實現如下:
.org 0x00000000
.global _start
.set noat
.start
Lui $at,0x1000
Ori $at,$at,0x1F00
Add $sp,$zero,$at
Jal main
Nop
Lui $at,0x40 #0040 0000
Jr $at
Nop

圖4 Bootloader 后指令跳轉
依據邏輯地址的排布表,通過宏定義編寫SD 卡控制管腳高低的宏函數,實現SD卡時鐘設置。
#define SD_CS 0x22000000
#define SD_CLK 0x22000001
#define SD_DATAIN 0x22000002
#define SD_DATAOUT 0x22000003
#define SD_HALF_CLK_LEN 0;
#define SD_CLK_UP()*((uchar *)SD_CLK)= 1;
#define SD_CLK_DOWN()*((uchar *)SD_CLK)= 0;
#define SD_DATAIN_UP()*((uchar*)SD_ DATAIN)= 1;
#define SD _ DATAOUT _ DOWN()*((uchar *)SD _DATAOUT)= 0;
#define SD_CS_UP()*((uchar *)SD_ CS)= 1;
#define SD_ CS_DOWN()*((uchar *)SD_ CS)= 0;
如此,就可以用軟件方式一一對應地寫C 語言代碼,實現SD卡的協議。以時鐘為例如下:
Void SD_send_clk()
{
SD_CLK_DOWN();
DELAY_HALF_CLK();
SD_CLK_UP();
DELAY_HALF_CLK():
}
For (int i = 0;i <80;i + +)
SD_send_c
但僅進行上述的設置是不夠的,還需將對存儲單元寫入0 / 1 轉換成TTL高低電平的信號,通過設計的接口模塊來實現電平轉換,如圖5 所示。

圖5 SD卡接口模塊
對應的Verilog代碼實現如下:
module SD_soft(
input clk,/ /寫入時鐘
input rst,
input we,/ /寫使能
input [3:0]sel_i,/ /位選信號
input [31:0]data_i,/ /寫入數據
output [31:0]data_o,/ /將它視作一個4字節的輸出
/ / SD相關
output reg SD_cs,/ /片選,addr = 0
output reg SD_clk,/ /時鐘,addr = 1
output reg SD_datain,/ /數據輸入,addr = 2
input SD_dataout / /數據輸出,addr = 3
);
assign data_o = {7`b0,SD_cs,7`b0,SD_clk,7`b0,SD_datain,7`b0,SD_dataout};
always@(posedge clk or posedge rst)begin
if(rst)begin
SD_cs = 1`b0;
SD_clk = 1`b0;
SD_datain = 1`b0;
end
else if(we)begin
if(sel_i[3]= = 1`b1)begin
SD_cs <= (data_i[31:24]! = 8`b0);
end
if(sel_i[2]= = 1`b1)begin
SD_clk <= (data_i[23:16]! = 8`b0);
end
if(sel_i[1]= = 1`b1)begin
SD_datain <= (data_i[15:8]! = 8`b0);
end
end
end
SD卡作為三級存儲器中離CPU最遠段的一級存儲器,要進行存儲塊和頁面的地址管理,在進行數據的讀寫時,需要先進行初始化[11]。
本次三級存儲體系的設計與實現采用的CPU 是“計算機系統結構”課程中自主設計與實現的靜態和動態流水線CPU[12-13]。整個三級存儲體系的設計和實現采用Xilinx公司提供的vivado[14]集成開發工具和verilog[15]開發語言完成,并在Xilinx Nexys 4 Artix-7[16]開發板上進行了下板測試。
首先將整個三級存儲體系實現代碼生成的.bit文件寫入到被格式化后的SD卡中,然后用WinHex在邏輯80 扇區(本次實驗采用的SD卡對應的物理扇區是8272)寫入用戶指令(右鍵,從剪貼板寫入,寫入方式為16 進制)。然后放置好FPGA 板上的跳線。之后UART口連接上電源,開始啟動,實現三級存儲體系成功運行。
實驗中,在BootLoader 程序中額外設置了開關控制Led燈的程序,以提示三級存儲的建立狀態,控制代碼如下:
assign led = sw[0]?(sw[1]?
{debug_once_was,debug_i_data[14:0]}:inst_addr[15:
0]):inst_addr[31:16];
當sw[1:0]= = 2 時,Led 燈顯示PC 寄存器內容的低16 位,sw[1:0]= = 1 時,Led 燈顯示PC 寄存器的高16 位。
為避免無限循環,在測試程序末尾加入無條件跳轉指令,該指令的指令代碼如表1 中黃色部分標識所示。

表1 部分指令的執行過程
成功下板后,兩種開關下數碼管的顯示如下:當sw[0]= 1,sw[1]= 0 時,Led燈顯示情況如圖6(a)所示,說明PC[15:0]= = 0x00a0。當sw[0]= 0,sw[1]= 1 時,Led 燈顯示情況如圖6(b)所示,說明PC[31:16]= = 0x0040。兩者拼接組合起來就是0x0040 _00a0,即為表1 所示執行J 指令的結果。該測試結果說明三級存儲體系設計與運行正確。

圖6 Led燈顯示情況
本文提出了一種基于Artix-7 FPGA的三級存儲體系設計與實現方法,該方法指導學生們完成三級存儲體系的設計與實現實驗。此外,通過該實驗,增強了學生們對于計算機的三級存儲體系的結構與工作機制的深入理解和認知,是貫通后續課程實驗的關鍵環節,為學生自主設計、實現更加完善的個人計算機系統奠定了堅實的基礎[17]。