RAM的coe文件与简单DDS实现

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’);

1.png

结果展示:

2.png

3.png

打开vivado软件,新建一个工程,配置芯片为xc7a75tfgg484-2:

4.png

5.png


进入工程,选择IP Catalog:

在IP Catalog界面搜索框中输入RAM,在Memories & storage Elements选项下有两种IP,一种是DRAM(Distributed Memory Generator),一种是BRAM(Block Memory Generator):

6.png

IP核命名为blk_mem_cos,类型选择单口ROM:

7.png

配置A口数据位宽为16位,深度为1024,使能端口为Always Enable,不加寄存器:

8.png

勾选导入初始化文件,点击Browse,选择刚刚通过MATLAB生成的cos.coe文件,点击Edit,查看添加的内容是否正确:

9.png

点击OK生成IP核。


以同样的步骤生成一个sin ROM IP核:

10.png

有了两个正余弦表,可以通过查表法生成不同频率的正弦波。频率通过频率控制字进行配置。频率控制字与频率的对应关系为:

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,结构如下图所示:

11.png

在tb中实现框图中的内容,相位寄存器为32位,由于寄存器只有32位,所以不用考虑递增值超过32位后清零问题。ROM深度为1024,也就是10位,所以使用相位寄存器的高10位用于查表。
结果如下:
dout_sin与dout_cos两个数据线能够输出连续的正弦与余弦波。

12.png

添加两个游标,查看波形一个周期为320ns,也就是3.125MHz,与设计频率一致。

13.png

实验完成。

附:tb测试激励代码

` 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 

最新文章

最新文章