赞
踩
ROM
ROM是只读存储器(only read memory)的简称,是一种只能读出事先所存储数据的固态半导体存储器。FPGA中是没有非易性存储器的,ROM ip核其实是使用到FPGA中的RAM资源。在 FPGA 运行时通过数据文件给 ROM 模块初始化,模拟成非易失存储器。
Altera 推出的 ROM IP 核分为两种类型:单端口 ROM 和双端口 ROM。对于单端口ROM 提供一个读地址端口和一个读数据端口,只能进行读操作;双端口 ROM 与单端口ROM 类似,区别是其提供两个读地址端口和两个读数据端口。
一、单端口ROM
1.
本次采用matlab生成一个FPGA所需要的正弦波MIF文件,sin_wave_8x256.mif会生成在你的资源管理器中,把他添加到你的FPGA工程文件下
clc; %清除命令行命令 clear all; %清除工作区变量,释放内存空间 F1=1; %信号频率 Fs=2^8; %采样频率 P1=0; %信号初始相位 N=2^8; %采样点数 t=[0:1/Fs:(N-1)/Fs]; %采样时刻 ADC=2^7-1; %直流分量 A=2^7; %信号幅度 %生成正弦信号 s=A*sin(2*pi*F1*t + pi*P1/180) + ADC; plot(s); %绘制图形 %创建mif文件 fild = fopen('sin_wave_8x256.mif','wt'); %写入mif文件头 fprintf(fild, '%s\n','WIDTH=8;'); %位宽 fprintf(fild, '%s\n\n','DEPTH=256;'); %深度 fprintf(fild, '%s\n','ADDRESS_RADIX=UNS;'); %地址格式 fprintf(fild, '%s\n\n','DATA_RADIX=UNS;'); %数据格式 fprintf(fild, '%s\t','CONTENT'); %地址 fprintf(fild, '%s\n','BEGIN'); %开始 for i = 1:N s0(i) = round(s(i)); %对小数四舍五入以取整 if s0(i) <0 %负1强制置零 s0(i) = 0 end fprintf(fild, '\t%g\t',i-1); %地址编码 fprintf(fild, '%s\t',':'); %冒号 fprintf(fild, '%d',s0(i)); %数据写入 fprintf(fild, '%s\n',';'); %分号,换行 end fprintf(fild, '%s\n','END;'); %结束 fclose(fild);
2.
创建ROM IP,数据位宽为8,ROM深度为256
3.
添加初始化MIF文件
4.
生成例化文档
RTL代码
顶层模块rom
module rom ( input wire sys_clk , input wire sys_rst_n , output wire [7:0] rom_data ); wire [7:0] rom_addr; rom_ctrl rom_ctrl_inst ( .sys_clk (sys_clk), .sys_rst_n (sys_rst_n), .rom_addr (rom_addr) ); rom_sin rom_sin_inst ( .address ( rom_addr ), .clock ( sys_clk ), .q ( rom_data ) ); endmodule
rom_ctrl模块
module rom_ctrl
(
input wire sys_clk ,
input wire sys_rst_n ,
output reg [7:0] rom_addr
);
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rom_addr <= 8'd0;
else
rom_addr <= rom_addr + 1'b1;
endmodule
testbench
`timescale 1ns/1ns module tb_rom(); reg sys_clk; reg sys_rst_n; wire rom_data; initial begin sys_clk = 1'b0; sys_rst_n <= 1'b0; #30 sys_rst_n <= 1'b1; end always #10 sys_clk = ~sys_clk; rom rom_inst ( .sys_clk (sys_clk), .sys_rst_n (sys_rst_n), .rom_data (rom_data) ); endmodule
modelsim仿真结果
由仿真波形数据得正弦波的周期是5120ns,而ROM存储的一个完整正弦波周期也是256*20=5120ns。仿真结果正确
二、双端口ROM
在原来的基础,采用双端口ROM输出两路信号,一路正弦波一路方波。步骤与上诉类似
1.matlab产生MIF文件
clc; %清除命令行命令 clear all; %清除工作区变量,释放内存空间 F1=1; %信号频率 Fs=2^8; %采样频率 P1=0; %信号初始相位 N=2^8; %采样点数 t=[0:1/Fs:(N-1)/Fs]; %采样时刻 ADC=2^7 - 1; %直流分量 A=2^7; %信号幅度 s1=A*sin(2*pi*F1*t + pi*P1/180) + ADC; %正弦波信号 s2=A*square(2*pi*F1*t + pi*P1/180) + ADC; %方波信号 %创建mif文件 fild = fopen('wave_512x8.mif','wt'); %写入mif文件头 fprintf(fild, '%s\n','WIDTH=8;'); %位宽 fprintf(fild, '%s\n\n','DEPTH=512;'); %深度 fprintf(fild, '%s\n','ADDRESS_RADIX=UNS;'); %地址格式 fprintf(fild, '%s\n\n','DATA_RADIX=UNS;'); %数据格式 fprintf(fild, '%s\t','CONTENT'); %地址 fprintf(fild, '%s\n','BEGIN'); %开始 for j = 1:2 for i = 1:N if j == 1 %打印正弦信号数据 s0(i) = round(s1(i)); %对小数四舍五入以取整 fprintf(fild, '\t%g\t',i-1); %地址编码 end if j == 2 %打印方波信号数据 s0(i) = round(s2(i)); %对小数四舍五入以取整 fprintf(fild, '\t%g\t',i-1+N); %地址编码 end if s0(i) <0 %负1强制置零 s0(i) = 0 end fprintf(fild, '%s\t',':'); %冒号 fprintf(fild, '%d',s0(i)); %数据写入 fprintf(fild, '%s\n',';'); %分号,换行 end end fprintf(fild, '%s\n','END;'); %结束 fclose(fild);
RTL代码
顶层模块rom
module rom ( input wire sys_clk , input wire sys_rst_n , output wire [7:0] rom_data , output wire [7:0] sin_d , output wire [7:0] squ_d ); wire [7:0] rom_addr; wire [8:0] rom_sin_d; wire [8:0] rom_squ_d; rom_ctrl rom_ctrl_inst ( .sys_clk (sys_clk), .sys_rst_n (sys_rst_n), .rom_addr (rom_addr), .rom_sin_d (rom_sin_d), .rom_squ_d (rom_squ_d) ); rom_double rom_double_inst ( //双端口ROM .address_a ( rom_sin_d ), .address_b ( rom_squ_d ), .clock ( sys_clk ), .q_a ( sin_d ), .q_b ( squ_d ) ); rom_sin rom_sin_inst ( .address ( rom_addr ), .clock ( sys_clk ), .q ( rom_data ) ); endmodule
rom_ctrl模块
module rom_ctrl ( input wire sys_clk , input wire sys_rst_n , output reg [7:0] rom_addr , output reg [8:0] rom_sin_d , output reg [8:0] rom_squ_d ); localparam SQU_Z = 9'd256; always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) rom_addr <= 8'd0; else rom_addr <= rom_addr + 1'b1; always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) rom_sin_d <= 9'd0; else if(rom_sin_d == 9'd255) rom_sin_d <= 9'd0; else rom_sin_d <= rom_addr + 1'b1; always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) rom_squ_d <= SQU_Z; else rom_squ_d <= rom_addr + SQU_Z; endmodule
testbench
`timescale 1ns/1ns module tb_rom(); reg sys_clk; reg sys_rst_n; wire rom_data; wire rom_sin_d; wire rom_squ_d; initial begin sys_clk = 1'b0; sys_rst_n <= 1'b0; #30 sys_rst_n <= 1'b1; end always #10 sys_clk = ~sys_clk; rom rom_inst ( .sys_clk (sys_clk), .sys_rst_n (sys_rst_n), .rom_data (rom_data), .sin_d (rom_sin_d), .squ_d (rom_squ_d) ); endmodule
modelsim仿真结果
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。