作者:李西銳??校對(duì):陸輝
大俠好,歡迎來(lái)到FPGA技術(shù)江湖。本系列將帶來(lái)FPGA的系統(tǒng)性學(xué)習(xí),從最基本的數(shù)字電路基礎(chǔ)開(kāi)始,最詳細(xì)操作步驟,最直白的言語(yǔ)描述,手把手的“傻瓜式”講解,讓電子、信息、通信類專業(yè)學(xué)生、初入職場(chǎng)小白及打算進(jìn)階提升的職業(yè)開(kāi)發(fā)者都可以有系統(tǒng)性學(xué)習(xí)的機(jī)會(huì)。
系統(tǒng)性的掌握技術(shù)開(kāi)發(fā)以及相關(guān)要求,對(duì)個(gè)人就業(yè)以及職業(yè)發(fā)展都有著潛在的幫助,希望對(duì)大家有所幫助。本次帶來(lái)Vivado系列,ROM使用教程。話不多說(shuō),上貨。
ROM使用教程
ROM的英文全稱為Read-Only Memory,即只讀存儲(chǔ)器??梢詮娜我獾刂飞献x取數(shù)據(jù),但是不能寫(xiě)入。那么我們ROM中的數(shù)據(jù),就需要我們提前存放進(jìn)去,在IP核中,我們可以通過(guò).coe文件進(jìn)行數(shù)據(jù)存放,文件格式我們可以參考Xilinx官方標(biāo)準(zhǔn)。
數(shù)據(jù)文件的格式是固定的,我們?cè)谔畛鋽?shù)據(jù)時(shí),需要嚴(yán)格按照官方的格式進(jìn)行書(shū)寫(xiě)。
在示例文件中,第一行規(guī)定了數(shù)據(jù)的格式,此處規(guī)定的是二進(jìn)制,那么下面的數(shù)據(jù),我們必須用二進(jìn)制的形式。大家在寫(xiě)的時(shí)候,規(guī)定什么進(jìn)制就用什么進(jìn)制。數(shù)據(jù)與數(shù)據(jù)之間用逗號(hào)隔開(kāi),最后一個(gè)數(shù)據(jù)用分號(hào)結(jié)尾。
了解了數(shù)據(jù)文件格式之后,接下來(lái)我們提前準(zhǔn)備一個(gè)數(shù)據(jù)文件,以便于后續(xù)我們調(diào)用IP核去使用。寫(xiě)數(shù)據(jù)文件的方法有很多,在此給大家介紹一種:MATLAB。
我們打開(kāi)MATLAB之后,首先先選擇一下工作路徑,以便于我們?nèi)フ业轿覀兩傻奈募约氨4嫖覀兊拇a。如圖:
打開(kāi)如圖所示的圖標(biāo)之后,選擇好工程路徑。
選擇好之后,我們新建腳本文件,然后寫(xiě)入代碼。
1 data = 0:1:255;
2 fid = fopen('sin_data.coe','w');
3 fprintf(fid,'memory_initialization_radix = 10;n');
4 fprintf(fid,'memory_initialization_vector = n');
5 for i = 1:1:1024
6 fprintf(fid,'%d',round(127*sin(2*pi/1024*i)+127));
7
8 if i == 1024
9 fprintf(fid,';');
10 else
11 fprintf(fid,',');
12 end
13
14 if mod(i,1) == 0
15 fprintf(fid,'n');
16 end
17 end
18 fclose(fid);
寫(xiě)好代碼,點(diǎn)擊運(yùn)行,即可生成我們想要的.coe文件。數(shù)據(jù)文件準(zhǔn)備好之后,接下來(lái)我們就可以調(diào)用IP核了。
首先我們新建一個(gè)工程
在第二步選擇路徑
第三步直接跳過(guò),第四步選擇我們的芯片,芯片型號(hào)為XC7A35TFGG484-2。
選中型號(hào)之后,點(diǎn)擊Next。
工程新建完成之后,開(kāi)始新建文件。
首先我們先新建IP核,打開(kāi)IP Catalog,在窗口搜索block
找到如圖所示選項(xiàng),然后雙擊打開(kāi)。
我們?cè)诳蜻x的選項(xiàng)中,選擇Single Port ROM。這個(gè)選項(xiàng)中總共有五個(gè)選項(xiàng)。第一個(gè)為單端口RAM,第二個(gè)為偽雙端口RAM,第三個(gè)為真雙端口RAM,第四個(gè)為單端口ROM,第五個(gè)為真雙端口ROM。我們此次使用的是單端口ROM。
圖中框選出了四處,第一處需要我們修改一下數(shù)據(jù)的位寬以及深度,位寬我們默認(rèn)使用8bit,深度為1024。因?yàn)槲覀冊(cè)谇懊孀隽艘粋€(gè)數(shù)據(jù)量為1024的.coe文件,所以這里深度改為1024。第二處為數(shù)據(jù)輸出使能,在此我們選擇為Always Enabled。使我們的輸出使能一直有效。第三處為輸出寄存器,輸出會(huì)在時(shí)鐘下輸出,導(dǎo)致結(jié)果會(huì)慢一拍,在此處我們不需要這個(gè)選項(xiàng),因此取消勾選。第四處為ROM復(fù)位的設(shè)置,如果有需要,可以進(jìn)行勾選,此處,我沒(méi)有使用復(fù)位信號(hào),大家在使用時(shí)自行選擇。
此處我們需要勾選中加載初始化文件的選項(xiàng),然后點(diǎn)擊Browse找到我們提前生成好的數(shù)據(jù)文件。選擇好之后點(diǎn)擊OK,生成IP核。
直接點(diǎn)擊Generate。
IP核生成好之后,我們新建文件,寫(xiě)一下我們的地址控制模塊。代碼如下:
1 module addr_ctrl(
2
3 input wire clk,
4 input wire rst_n,
5 output reg [9:0] addr
6 );
7
8 always @ (posedge clk, negedge rst_n)
9 begin
10 if(rst_n == 1'b0)
11 addr <= 10'd0;
12 else if(addr == 10'd1023)
13 addr <= 10'd0;
14 else
15 addr <= addr + 1'b1;
16 end
17
18 endmodule
然后我們新建頂層文件。寫(xiě)好端口之后,我們將IP核與地址控制模塊例化到頂層當(dāng)中。
點(diǎn)擊Next,選擇Create File,新建頂層開(kāi)始寫(xiě)代碼。
打開(kāi)IP核例化的頭文件。
復(fù)制粘貼到頂層當(dāng)中。地址控制模塊也同樣進(jìn)行例化。頂層代碼如下:
1 module rom(
2
3 input wire clk,
4 input wire rst_n,
5 output wire [7:0] q
6 );
7
8 wire [9:0] addr;
9
10 addr_ctrl addr_ctrl_inst(
11
12 .clk (clk),
13 .rst_n (rst_n),
14 .addr (addr)
15 );
16
17 blk_mem_gen_0 blk_mem_gen_0_inst (
18 .clka(clk), // input wire clka
19 .addra(addr), // input wire [9 : 0] addra
20 .douta(q) // output wire [7 : 0] douta
21 );
22
23 endmodule
代碼寫(xiě)好之后,保存編譯,沒(méi)有錯(cuò)誤,那么我們寫(xiě)一下仿真看一下仿真波形。
選中新建仿真文件,點(diǎn)擊Next輸入名字。
點(diǎn)擊OK,開(kāi)始寫(xiě)代碼。仿真代碼如下:
1 `timescale 1ns / 1ps
2
3 module rom_tb;
4
5 reg clk;
6 reg rst_n;
7 wire [7:0] q;
8
9 initial begin
10 clk = 0;
11 rst_n = 0;
12 #105;
13 rst_n = 1;
14 #10000;
15 $stop;
16 end
17
18 always #10 clk = ~clk;
19
20 rom rom_inst(
21
22 .clk (clk ),
23 .rst_n (rst_n ),
24 .q (q )
25 );
26
27 endmodule
代碼寫(xiě)好之后,打開(kāi)仿真。
波形窗口打開(kāi)后,點(diǎn)擊run all讓波形繼續(xù)運(yùn)行
然后看到如圖所示波形。
然后選中輸出q,右鍵選擇wavaform style,然后選擇analog就可以看到我們的數(shù)字信號(hào)就變成了模擬信號(hào)。
但是此時(shí)波形只有一部分,我們?cè)俅吸c(diǎn)擊run all ,然后點(diǎn)擊break
就可以看到完整的正弦波。
我們的數(shù)據(jù)文件就是做的正弦波,仿真顯示正確。