ROM为只读存储器。可以从任意地址上读取数据,但是不能写入。所以ROM中的数据,就需要提前存放进去。在IP核中,可以通过.coe文件进行数据存放,文件格式可以参考Xilinx官方标准。
使用matlab生成.coe文件,数据为正弦波波形数据
% 1. 定义一个数据数组,范围从0到255
data = 0:1:255;% 2. 打开一个名为'sin_data.coe'的文件以供写入
fid = fopen('sin_data.coe','w');% 3. 写入COE文件的头部信息,表示数据是十进制的
fprintf(fid,'memory_initialization_radix = 10;\n');% 4. 写入COE文件的头部信息,表示接下来的数据向量
fprintf(fid,'memory_initialization_vector = \n');% 5. 开始循环,生成1024个数据点
for i = 1:1:1024% 6. 计算sin函数值并将其舍入到整数,然后写入文件fprintf(fid,'%d',round(127*sin(2*pi/1024*i)+127));% 8-9. 检查是否到达数据末尾,如果是,写入分号,否则写入逗号if i == 1024fprintf(fid,';');elsefprintf(fid,',');end% 14-16. 每打印1个数据点后,检查是否需要换行if mod(i,1) == 0fprintf(fid,'\n');end
end% 18. 关闭文件
fclose(fid);
成功生成coe文件
建立vivado工程
新建IP核,打开IP Catalog,在窗口搜索block
双击打开
选择单端口ROM,修改一下数据的位宽以及深度,位宽默认使用8bit,深度为1024。因为前面做了一个数据量为1024的.coe文件,所以这里深度改为1024。数据输出使能选择为Always Enabled。使输出使能一直有效。输出寄存器:输出会在时钟下输出,导致结果会慢一拍,在此处我们不需要这个选项,因此取消勾选。ROM复位的设置,如果有需要,可以进行勾选。此处,没有使用复位信号,在使用时可自行选择。
新建顶层文件
写入代码
module rom(input wire clk,
input wire rst_n,
output wire [7:0] q
);wire [9:0] addr;addr_ctrl addr_ctrl_inst(.clk (clk),
.rst_n (rst_n),
.addr (addr)
);blk_mem_gen_0 blk_mem_gen_0_inst (
.clka(clk), // input wire clka
.addra(addr), // input wire [9 : 0] addra
.douta(q) // output wire [7 : 0] douta
);endmodule
写地址控制模块:
module addr_ctrl(input wire clk,
input wire rst_n,
output reg [9:0] addr
);always @ (posedge clk, negedge rst_n)
begin
if(rst_n == 1'b0)addr <= 10'd0;
else if(addr == 10'd1023)addr <= 10'd0;
elseaddr <= addr + 1'b1;
endendmodule
编写testbench代码
module rom_tb;reg clk;reg rst_n;
wire [7:0] q;initial begin
clk = 0;
rst_n = 0;
#105;
rst_n = 1;
#10000;
$stop;
endalways #10 clk = ~clk;rom rom_inst(.clk (clk ),
.rst_n (rst_n ),
.q (q )
);endmodule
进行仿真
选中输出q,右键选择wavaform style,然后选择analog就可以看到数字信号变成了模拟信号。