寫在前面的話
在很多時候,我們需要將采集得到的數據先存儲起來,等到了需要的時候再調用。如果是這種情況,那么就要求我們的存儲器必須可讀可寫。本節,夢翼師兄就和大家一起學習FPGA可讀寫存儲器IP核-RAM的使用。
項目需求
設計一個RAM控制器,該控制器負責對RAM 進行讀寫操作,首先將數據寫入RAM,然后再將數據全部讀出。如果讀出的數據和寫入的數據完全一致,說明我們的操作和設計正確。
操作步驟
在右側的IP核搜索區,輸入ram,在菜單欄找到並雙擊【RAM:1-PORT】
選擇語言類型為Verilog,並命名,點擊【OK】
設置ram的存儲深度和每一個存儲空間的比特位數,然后點擊【NEXT】
把【q output port】前面的對鈎取消掉(如果不取消掉就會在輸出端口生成寄存器,輸出就會慢一拍,這里我們不需要它慢一拍),然后點擊【NEXT】
一直點擊【NEXT】,直到如下界面,選擇my_ram_inst.v,點擊【Finish】,完成對ram的設置
頂層架構設計
RAM是可讀寫的存儲器,我們用一個控制模塊向ram中寫入數據,然后讀出。
模塊功能介紹
模塊名 |
功能描述 |
Ram_control |
Ram控制器,對my_ram進行讀寫 |
My_ram |
ram存儲器IP核 |
ram |
系統頂層模塊,負責子模塊級聯 |
5.3.6 端口和內部連線描述
頂層模塊端口介紹
端口名 |
端口說明 |
Clk |
系統時鍾輸入 |
Rst_n |
系統復位 |
q |
數據輸出 |
系統內部連線介紹
連線名 |
連線說明 |
addr |
Ram_control產生的地址信號 |
data |
Ram_control產生的數據 |
wren |
Ram_control產生的讀寫控制信號(高電平為寫,低電平為讀) |
5.3.7代碼解釋
Ram_control模塊的代碼
/**************************************************** * Engineer : 夢翼師兄 * QQ : 761664056 * The module function:產生控制信號以及數據 *****************************************************/ 00 module ram_control ( 01 clk, //系統時鍾輸入 02 rst_n, //系統復位 03 wren, //讀寫信號 04 addr, //地址信號 05 data //有效數據 06 ); 07 // 模塊輸入 08 input clk; //系統時鍾輸入 09 input rst_n;//系統復位 10 // 模塊輸出 11 output reg wren; //讀寫信號 12 output reg [7:0] addr;//地址信號 13 output reg [7:0] data;//有效數據 14 //定義中間寄存器 15 reg state; //定義狀態寄存器 16 17 always @ (posedge clk or negedge rst_n) 18 begin 19 if (!rst_n) // 復位時,將所有的輸出清零。 20 begin 21 wren <= 0; 22 addr <= 0; 23 data <= 0; 24 state <= 0; 25 end 26 else 27 begin 28 case (state) 29 0 : begin 30 if (addr < 255)//使地址在0到255之間,讓寫信號有效 31 begin 32 addr <= addr + 1; 33 wren <= 1; 34 end 35 else 36 begin 37 addr <= 0;//轉到下一個狀態,讓地址清零,讓讀信號有效 38 state <= 1; 39 wren <= 0; 40 end 41 42 if (data < 255)// 給有效數據,使數據在0到255之間 43 data <= data + 1; 44 else 45 data <= 0; 46 47 end 48 49 1 : begin 50 if (addr < 255)//使地址在0到255之間,讓讀信號有效 51 begin 52 addr <= addr + 1; 53 wren <= 0; 54 end 55 else 56 begin 57 state <= 0; //轉到0狀態,地址清零 58 addr <= 0; 59 end 60 end 61 62 default : state <= 0; // 如果系統不穩定的時候直接進入0狀態 63 64 endcase 65 end 66 end 67 68 endmodule |
在本模塊中,數據和地址的數值大小是一樣的。
Ram的頂層代碼
/**************************************************** * Engineer : 夢翼師兄 * QQ : 761664056 * The module function:頂層模塊,負責連接各子模塊 *****************************************************/ 00 module ram ( 01 clk, //系統時鍾輸入 02 rst_n,//系統復位 03 q //輸出數據 04 ); 05 // 系統輸入 06 input clk; //系統時鍾輸入 07 input rst_n;//系統復位 08 // 系統輸出 09 output [7:0] q;//輸出數據 10 //定義中間連線信號 11 wire wren; //定義寫信號 12 wire [7:0] addr;// 定義地址信號 13 wire [7:0] data;//定義中間數據 14 // 調用ram_control 15 ram_control ram_control ( 16 .clk(clk), //系統時鍾輸入 17 .rst_n(rst_n), //系統復位 18 .wren(wren), //讀寫信號 19 .addr(addr), //地址信號 20 .data(data) //有效數據 21 ); 22 //調用IP核--ram 23 my_ram my_ram_inst ( 24 .address ( addr ), // 地址信號 25 .clock ( clk ), // 系統時鍾 26 .data ( data ), // 輸入數據 27 .wren ( wren ), //讀寫信號 28 .q ( q ) //輸出數據 29 ); 30 31 endmodule |
本模塊只負責連接各個子模塊,沒有任何的邏輯。代碼編寫完畢以后,查看RTL視圖如下:
由RTL視圖可以看出,電路綜合以后的結果和我們所設計的系統框圖一致,接下來編寫測試代碼如下:
/**************************************************** * Engineer : 夢翼師兄 * QQ : 761664056 * The module function:對ram進行測試 *****************************************************/ 00 `timescale 1ns/1ps //時間單位和精度定義 01 module ram_tb; 02 //系統輸入 03 reg clk; //系統時鍾輸入 04 reg rst_n; //系統復位 05 //系統輸出 06 wire [7:0] q; //輸出數據 07 08 initial begin 09 clk = 1; 10 rst_n = 0; 11 # 200.1 12 rst_n = 1; 13 end 14 15 always # 10 clk = ~clk; //50MHz時鍾 16 17 ram ram ( 18 .clk(clk), //系統時鍾輸入 19 .rst_n(rst_n), //系統復位 20 .q(q) //輸出數據 21 ); 22 23 24 endmodule |
仿真分析
復位結束之后,寫信號有效,同時給出數據和地址。Ram的q端在寫的過程中也會進行慢一拍的輸出,這不是錯誤,這是由Ram內部結構決定的。
注:寫數據的過程中,q端也會輸出,這是由altera RAM IP核的功能決定的,此處不需要深究。
當寫完數據之后,進行讀(寫信號拉低),同時給出地址,ram在下一拍給出對應地址中的數據。
經過上述的分析,證明我們的ram應用正確。