FPGA——ROM

ROM
ROM是只读存储器(only read memory)的简称,是一种只能读出事先所存储数据的固态半导体存储器。FPGA中是没有非易性存储器的,ROM ip核其实是使用到FPGA中的RAM资源。在 FPGA 运行时通过数据文件给 ROM 模块初始化,模拟成非易失存储器。
Altera 推出的 ROM IP 核分为两种类型:单端口 ROM 和双端口 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仿真结果

在这里插入图片描述

  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: FPGA是一种可编程逻辑器件,可以通过编程实现各种功能。而Verilog是一种硬件描述语言,用于描述FPGA中的电路。Verilog基础语法包括模块定义、端口定义、信号定义、赋值语句、条件语句、循环语句等。模块定义是Verilog中最基本的语法,用于定义一个电路模块。端口定义用于定义模块的输入输出端口。信号定义用于定义模块内部的信号。赋值语句用于给信号赋值。条件语句用于根据条件执行不同的代码。循环语句用于重复执行一段代码。掌握Verilog基础语法是学习FPGA编程的基础。 ### 回答2: FPGA是一种可编程逻辑器件,它可以通过硬件描述语言来编写自定义的逻辑电路来实现各种功能。其中,Verilog是一种常用的硬件描述语言,有助于实现FPGA的功能。 Verilog语言主要由模块、端口、信号、语句和运算符五个基本部分组成。模块是Verilog中的最基本的语法单元,类似于传统程序语言中的函数,模块之间可以通过实例化进行连接。端口则是与外部世界进行通信的接口,可以分为输入端口(input)和输出端口(output)两种类型。信号是Verilog中表示数字信号的基本单元,可以是位向量、整数或实数。语句则是Verilog中描述操作和行为的语言,常用的语句包括赋值语句、分支语句和循环语句。运算符则是Verilog中用于进行操作的符号,包括算数运算符、逻辑运算符和位运算符。 在Verilog语言中,还有一些常用的结构体和命令可以帮助我们更方便地实现FPGA的功能。其中,常用的结构体包括always语句、case语句和module归档,常用的命令包括initial语句、wire语句和reg语句。always语句可以在指定的触发条件下执行某一段代码,case语句可以根据不同的条件执行不同的代码段,module归档则可以将多个模块合并为一个模块。initial语句可用于在仿真开始前初始化某些信号,wire语句则用于声明并连接信号,reg语句则用于声明并存储信号。 总体而言,了解FPGA和Verilog基础语法可以帮助我们更好地理解FPGA技术的应用和实现。然而,理论知识只有结合实际操作和实验才能更好地掌握。所以,我们还需要结合实际项目来进行练习和实践,从而更好地掌握FPGA和Verilog基础语法。 ### 回答3: FPGA(可编程门阵列)是一种可编程逻辑器件,可以用来创建定制的数字电路。Verilog是一种硬件描述语言,用于描述数字电路的结构和行为。 Verilog基础语法有以下几个部分: 1.模块定义:Verilog代码以模块的形式进行组织,每个模块都有一个名称和端口列表。模块定义以module关键字开始,以endmodule关键字结束。 2.端口声明:模块的端口是输入和输出连接到其他模块或FPGA芯片的引脚。端口可以是输入(input)、输出(output)或双向(inout)。端口声明在模块定义中。 3.信号声明:信号是描述数字电路中状态的变量。可以是单个位(wire)或多位(reg),在模块中声明。 4.赋值语句:用来为信号赋值,包括非阻塞赋值(<=)、阻塞赋值(=)和连续赋值(assign)。 5.条件分支语句:if, else if和else语句是用来控制程序流程,实现条件判断。 6.循环语句:Verilog支持for、while、do while和forever等类型的循环语句,可以在程序中实现迭代操作。 7.模块实例化:用来将其他模块作为子模块嵌入到当前模块中,从而实现复杂的数字电路。 除上述基本语法外,Verilog还有其他常用语法,如always块、initial块和function定义等。需要深入了解和使用Verilog,可以参考相关资料和教程。掌握了Verilog语法,可以使用FPGA搭建各种个性化的数字电路,用于嵌入式系统、数字信号处理、计算机网络等各种应用领域。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值