大家好,又到了每日學習的時間了,今天我們來聊一聊在FPGA設計中RAM的兩種使用方法,RAM是用來在程序運行中存放隨機變量的數據空間,使用時可以利用QuartusII的LPM功能實現RAM的定制。
軟件環境:QuartusII 11.0
操作系統:win7
實現方法一、利用LPM_RAM:
1.首先準備好存儲器初始化文件,即.mif文件。
如何生成mif文件?如下:
mif文件就是存儲器初始化文件,即memory initialization file,用來配置RAM或ROM中的數據。生成QuartusII11.0可用的mif文件,有如下幾種方式:
方法A:利用Quartus自帶的mif編輯器
優點:對于小容量RAM可以快速方便的完成mif文件的編輯工作,不需要第三方軟件的編輯;
缺點:一旦數據量過大,一個一個的輸入會使人崩潰;
使用方法:在quartus中,【file】/【new】,選擇Memory Initialization file,彈出如下窗口:
Number of words:可尋址的存儲單元數,對于8bit地址線,此處選擇256;
words size:存儲單元寬度,8bit;
然后點擊“OK”.
* 在表格中輸入初始化數據;
* 右鍵單擊左側地址值,可以修改地址和數據的顯示格式;
* 表中任一數據的地址=列值+行值,如圖中藍色單元的地址=24+4=28;
對每個單元填寫初始值之后,將文件保存即可。
方法B:利用mif軟件來生成
無論使用什么編輯器,必須保證mif文件的格式如下:冒號左邊是地址,右邊是數據;分號結尾;
DEPTH = 256;
WIDTH = 8;
ADDRESS_RADIX = HEX;
DATA_RADIX = HEX;
CONTENT
BEGIN
0000 : 0000;
0001 : 0000;
0002 : 0000;
……(此處省略一千字*.*)
00FA : 00FF;
00FB : 00FF;
00FC : 00FF;
00FD : 00FF;
00FE : 00FF;
00FF : 00FF;
END;
這里推薦一款mif生成器:Mif_Maker2010.exe,可以百度下載;軟件使用方法見如下:
1.打開軟件,【文件】/【新建】;
2.設置全局參數:
3.生成波形:
以生成正弦波為例:【設定波形】/【正弦波】
4.修改波形:
【手繪波形】/【線條】,鼠標左鍵選擇兩個起點,鼠標右鍵結束,即可繪制任意波形。
繪制完畢后,再次選擇【手繪波形】/【取消手繪】,結束繪制狀態;
5.保存文件。
方法C:使用高級語言
用C語言或者matlab語言等來生成,C語言生成代碼如下:本代碼生成一個正弦波的數據波形,保存在TestMif.mif中。
#include
#include
#define PI 3.141592
#define DEPTH 128 /*數據深度,即存儲單元的個數*/
#define WIDTH 8 /*存儲單元的寬度*/
int main(void)
{
int i,temp;
float s;
FILE *fp;
fp = fopen("TestMif.mif","w"); /*文件名隨意,但擴展名必須為.mif*/
if(NULL==fp)
printf("Can not creat file!
");
else
{
printf("File created successfully!
");
/*
* 生成文件頭:注意不要忘了“;”
*/
fprintf(fp,"DEPTH = %d;
",DEPTH);
fprintf(fp,"WIDTH = %d;
",WIDTH);
fprintf(fp,"ADDRESS_RADIX = HEX;
");
fprintf(fp,"DATA_RADIX = HEX;
");
fprintf(fp,"CONTENT
");
fprintf(fp,"BEGIN
");
/*
* 以十六進制輸出地址和數據
*/
for(i=0;i
/*周期為128個點的正弦波*/
s = sin(PI*i/64);
/*將-1~1之間的正弦波的值擴展到0-255之間*/
temp = (int)((s+1)*255/2);
/*以十六進制輸出地址和數據*/
fprintf(fp,"%x : %x;
",i,temp);
}//end for
fprintf(fp,"END;
");
fclose(fp);
}
}
驗證生成的數據是否正確:用記事本打開生成的mif文件,同時用Quartus打開mif文件,內容如下:
能成功導入,且數據一致,說明生成正確。
前面的推薦的軟件的使用方法以及mif文件生成完畢后,開始接下來的設計。
本文預先生成了一個正弦波的數據文件,TEST1.mif,可以在QuartusII中打開,以便查看內容:【file】/【open】,在文件類型中選擇memory files,打開TEST1.mif,內容如下:
2.生成LPM_RAM塊
1)在QuartusII中,【tools】/【megawizard plugin manager】,打開向導,選擇【memory compiler】文件夾下的RAM:這里選擇單口RAM,
即:RAM:1-PORT,命名為RAM1P:
2)設置存儲深度為128,數據寬度為8bit、選擇嵌入式M4K RAM實現、使用單時鐘方案:
3)取消選擇“數據輸出鎖存”,不需要時鐘使能端:
4)使用mif初始化該RAM塊、允許“在系統(In System)存儲器讀寫”,并將此RAM的ID設置為RAM1:
* 載入前面生成的存儲器初始化文件:TEST1.mif;
* ID主要用于多RAM系統時,對不同RAM的識別,此處命名為RAM1;
* 關于“在系統存儲器讀寫”的含義,后續會補一片文章,專門介紹該工具的使用;
經過以上設置,即可生成一個名字為RAM1P.v的文件,以后就可以對其進行例化和使用。
3.對RAM1P.v進行例化,就可以使用,例化方法如下:
module TEST(
input [6:0] address,
input clock,
input [7:0] data,
input wren,
output [7:0] q
);
RAM1P RAM1P_inst (
.address ( address ),
.clock ( clock ),
.data ( data ),
.wren ( wren ),
.q ( q )
);
endmodule
推薦使用verilog文本的方式進行例化,十分不贊成用原理圖的方式來例化各個模塊。
生成的RTL圖:
4.對該RAM塊進行仿真,以便了解端口的特性:
* 由于使用的時鐘方案為單時鐘(single clock),因此無論wren=0還是1,Q都輸出address指定的地址中的數據;可以從verilog描述中看出這是利用assign語句實現的(verilog代碼見下文)。
* 當wren=1時,將數據輸入端data的數據寫入到address指定的存儲單元內。
輸出的數據依次為0x80,0x86,0x8c,0x92……,對比前文所顯示的mif文件內容,可以驗證mif文件已經成功導入;
而接下來輸出的數據0x0c、0x0d、0x0c、0x0c,是在wren=1期間,由數據輸入端data寫入到地址04、05、06、07中的數據;
接下來繼續輸出0xb0、0xb6……,則仍然為mif中對應地址的初始化數據。
說明:在編譯過程中,如果使用cycloneII器件,可能會出現錯誤“Error: M4K memory block WYSIWYG primitive……”,解決辦法為:
【ASSIGNMENTS 】/【 SETTING】,找到如下位置,在name中輸入“CYCLONEII_SAFE_WRITE”,在DEFAULT SETTING中輸入“VERIFIED_SAFE”;
然后點擊add按鈕:
方法二、使用verilog純文本的描述方式:
生成同樣功能的RAM塊,代碼如下:
module RAM1P(
input [6:0] address,
input clock,
input [7:0] data,
input wren,
output [7:0] q
);
(* ram_init_file = "TEST1.mif " *) reg [7:0] mem[127:0];
always@(posedge clock)
if(wren) mem[address] <= data; ?/*在時鐘的上升沿寫入數據*/
assign q = mem[address];
endmodule
注意此時mif文件載入RAM的方法,是利用文本描述的方式實現的,此種方式有一個缺點,就是不能在modelsim中進行仿真:
(* ram_init_file = "TEST1.mif " *) reg [7:0] mem[127:0];
對比兩種方法的優缺點:
經過QuartusII的編譯報告可以看出,方法二比方法一相比,占用了很多的LE,同時還使用了1024個register,故方法二是十分不經濟的,這里給出只是提供一個參考,便于理解LPM_RAM的工作方式,平時應用時,建議使用方法一來構建RAM。
今天就聊到這里,各位, 加油。
-
FPGA
+關注
關注
1629文章
21754瀏覽量
604235
發布評論請先 登錄
相關推薦
評論