Vivado版本:2019.2 MATLAB Modelsim版本:Modelsim SE-64 10.7
实验内容:通过MATLAB生成一个COE文件,文件内容为一个周期的正弦波与余弦波,长度为1024,振幅为1023,数据类型为10进制。通过控制地址偏移实现一个简单的DDS,在modelsim中仿真完成。
存储器的初始化可以使用默认数据或者通过内存文件(.coe)来完成,还可以两者搭配使用。通过COE文件可以定义单独内存位置的初始内容,而默认数据会直接定义所有位置的内存,两者搭配使用也就是COE文件初始化内存的一部分,默认数据填充剩余的内存空间。其中COE文件与默认数据的格式由端口A写入宽度(ROM的端口A读取宽度)有关。
COE文件是包含两个指定参数的文本文件:
(1)memory_initialization_radix:内存初始化基数,既初始化数据类型。有效值为2、10或16,既2进制、10进制与16进制。
(2)memory_initialization_vector:内存初始化向量,用来定义每个内存的内容,每一个值都是低字节对齐,该值按照memory_initialization_radix配置的基数完成初始化。
下面展示一个8位位宽,16进制,深度为16的初始化文件:
memory_initialization_radix = 16;
memory_initialization_vector =
12, 34, 56, 78, 9A, BC, DE, F0, 12, 34, 56, 78, 9A, BC, DE, F0;
内存向量可以用空格、逗号分隔,也可以用回车符在每行放置一个值,在BRAM IP核中可以创建或者选择文件方式加载初始化文件。
MATLAB生成coe文件的代码如下:
clc;close all;clear all;
Ac = 1023;
c = 0:1/1024:1-1/1024;
s_rom = round(Acsin(2pic));
c_rom = round(Accos(2pic));
file = fopen(‘sin.coe’,‘w’);
fprintf(file,‘memory_initialization_radix = 10;\n’);
fprintf(file,‘memory_initialization_vector = \n’);
for i = 1:length(s_rom)
if i == length(s_rom)
fprintf(file,’%d;\n’,s_rom(i));
else
fprintf(file,’%d, ‘,s_rom(i));
end
end
fclose(file);
file = fopen(‘cos.coe’,‘w’);
fprintf(file,‘memory_initialization_radix = 10;\n’);
fprintf(file,‘memory_initialization_vector = \n’);
for i = 1:length(c_rom)
if i == length(s_rom)
fprintf(file,’%d;\n’,c_rom(i));
else
fprintf(file,’%d, ',c_rom(i));
end
end
fclose(file);
figure;plot(s_rom);hold on;plot(c_rom,‘r’);
结果展示:
打开vivado软件,新建一个工程,配置芯片为xc7a75tfgg484-2:
进入工程,选择IP Catalog:
在IP Catalog界面搜索框中输入RAM,在Memories & storage Elements选项下有两种IP,一种是DRAM(Distributed Memory Generator),一种是BRAM(Block Memory Generator):
IP核命名为blk_mem_cos,类型选择单口ROM:
配置A口数据位宽为16位,深度为1024,使能端口为Always Enable,不加寄存器:
勾选导入初始化文件,点击Browse,选择刚刚通过MATLAB生成的cos.coe文件,点击Edit,查看添加的内容是否正确:
点击OK生成IP核。
以同样的步骤生成一个sin ROM IP核:
有了两个正余弦表,可以通过查表法生成不同频率的正弦波。频率通过频率控制字进行配置。频率控制字与频率的对应关系为:
W=(f_c2^N)/f_s
f_s为系统频率,f_c为要生成的频率,N为相位累加器的位宽,W为计算出的频率控制字,也就是相位累加器的累加值。
根据此公式,编写tb测试激励文件。设定系统频率为100MHz,生成一个3.125MHz的正弦波,累加器位宽为32位,可以得到频率控制字等于:
W=(3.125MHz2^32)/100MHz=134217728
通过tb测试激励实现一个简单的DDS,结构如下图所示:
在tb中实现框图中的内容,相位寄存器为32位,由于寄存器只有32位,所以不用考虑递增值超过32位后清零问题。ROM深度为1024,也就是10位,所以使用相位寄存器的高10位用于查表。
结果如下:
dout_sin与dout_cos两个数据线能够输出连续的正弦与余弦波。
添加两个游标,查看波形一个周期为320ns,也就是3.125MHz,与设计频率一致。
` timescale 1ns / 1ps module tb_ram(); // clock reg clk; initial begin clk = 'b0; forever #(5) clk = ~clk; end // synchronous reset reg srstb; initial begin srstb <= 'b0; repeat(10)@(posedge clk); srstb <= 'b1; end // (*NOTE*) replace reset, clock, others wire clka; wire [ 9:0] addra; wire [15:0] dout_sin; wire [15:0] dout_cos; parameter W = 32'd134217728; reg [31:0] add = 0; always @(posedge clk) begin if (srstb == 1'b0) begin // reset add <= 0; end else begin add <= add + W; end end assign clka = clk; assign addra = add[31:22]; blk_mem_sin inst_blk_mem_sin ( .clka (clka ), // input wire clka .addra (addra ), // input wire [9 : 0] addra .douta (dout_sin ) // output wire [15 : 0] douta ); blk_mem_cos inst_blk_mem_cos ( .clka (clka ), // input wire clka .addra (addra ), // input wire [9 : 0] addra .douta (dout_cos ) // output wire [15 : 0] douta ); endmodule
链接:https://pan.baidu.com/s/15xZyyhOSotBV8xUsD1-B8A
提取码:cwum
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_38828382/article/details/117122658