TA的每日心情 | 怒 2018-11-20 13:41 |
---|
签到天数: 3 天 连续签到: 1 天 [LV.2]偶尔看看I
|
写在前面的话
在项目设计中,我们通常需要使用一些固定的数据。如果是使用单片机,那么在数据量比较大的情况下,这些数据就必须存储在外挂的存储芯片中。那么,使用FPGA呢?在数据量不是特别大的情况下,我们可以将这些数据存储到FPGA片内的存储器中,这样既节约了板级成本,又可以保证数据不容易受到外界干扰。那么本节,梦翼师兄和大家一起学习FPGA只读存储器IP核-ROM的设计。
项目需求
设计一个ROM控制器,该控制器负责输出0-255递增的地址数据,将此地址总线连接到ROM地址输入端,查看ROM输出的数据是否正确
操作步骤
由于ROM是只读存储器,也就是说,我们不能对其内部写入外部数据,那么,我们就需要创建一个ROM的数据初始化文件mIF文件(mif文件用来存放初始数据)
定义位宽和深度(这里我们选择位宽为8位,深度为256)
填充数据(在这里我们用软件自带的一种的填充数据的方式,填充上0到255,大家自己在项目中应用的时候,应该填充上自己所需要的初始值)。
mif文件建立成功(地址从0到255,数据从0开始,每次增加1,所以此时的mif文件中存放的是0到255)。
在右侧的IP核搜索的编辑区,输入rom,在菜单栏找到并双击rom(在这里我们使用单端口的rom,双端口的rom,自己感兴趣的话,可以自己调用试一试)。
选择语言类型为Verilog,同时为该IP核命名,然后点击【OK】
进入rom的设置向导,设置深度和字节的宽度(rom的深度和字节宽度必须要和建立的mif文件保持一致),然后点击【NEXT】。
把输出端口的寄存器去掉(如果不去掉的话,就会使输出延迟一拍。这里我们不需要延迟这一拍,所以去掉),然后点击【NEXT】
进入如下界面,点击【browse···】(找到我们之前建立的mif文件,添加进来),点击【NEXT】
一直点击【NEXT】,直到出现如下界面,把my_rom_inst.v选择上,然后点击【finish】(完成rom的设置)
顶层架构设计
Rom是只读存储器,需要我们指定地址,它才能输出对应地址的数据。
模块功能介绍
模块名
| 功能描述
| Rom_control
| ROM控制模块,产生递增的地址信号
| My_rom
| ROM存储器IP核
| Rom
| 系统顶层模块,负责子模块级联
|
端口和内部连线描述
顶层模块端口介绍
端口名
| 端口说明
| Clk
| 系统时钟输入
| Rst_n
| 系统复位
| q
| 数据输出
|
系统内部连线介绍
连线名
| 连线说明
| addr
| Rom_control产生的地址信号
|
代码解释
Rom_control模块的代码
/****************************************************
* Engineer : 梦翼师兄
* QQ : 761664056
* The module function: 输出有效地址
*****************************************************/
01 module rom_control (
02 clk, //系统时钟输入
03 rst_n, //系统复位
04 addr //地址输出
05 );
06 // 系统输入
07 input clk; //系统时钟输入
08 input rst_n; //系统复位
09
10 output reg [7:0] addr; //地址输出
11
12 // 产生地址电路
13 always @ (posedge clk or negedge rst_n)
14 begin
15 if (!rst_n)
16 addr <= 0; // 复位的时候地址是0;
17 else
18 if (addr < 255) // 让地址在0到255循环
19 addr <= addr + 1;
20 else
21 addr <= 0;
22 end
23
24 endmodule
|
本模块只是产生了有效的地址信号,让地址信号在0到255之间循环,用于rom的输入,遍历rom全部存储空间,验证rom是否能够正确地输出对应地址的数据。
Rom模块代码
/****************************************************
* Engineer : 梦翼师兄
* QQ : 761664056
* The module function: 顶层连接
*****************************************************/
01 module rom (
02 clk, //系统时钟输入
03 rst_n, //系统复位
04 q //有效数据输出
05 );
06 //系统输入
07 input clk; //系统时钟输入
08 input rst_n; //系统复位
09 //系统输出
10 output [7:0] q; //有效数据输出
11 //定义中间连线
12 wire [7:0] addr; //定义地址信号
13 //实例化rom_control
14 rom_control rom_control (
15 .clk(clk), //系统时钟输入
16 .rst_n(rst_n), //系统复位
17 .addr(addr) //地址输出
18 );
19 //IP核--rom的调用
20 my_rom my_rom_inst (
21 .address ( addr ), // 地址输入
22 .clock ( clk ), // 时钟输入
23 .q ( q ) //有效数据输出
24 );
25
26 endmodule
|
本模块只是用于做连接,没有任何的逻辑。编写完可综合代码之后,查看RTL视图如下:
由RTL视图可以看出,代码综合以后得到的电路和我们设计的系统框图一致,接下来,编写 测试代码如下:
/****************************************************
* Engineer : 梦翼师兄
* QQ : 761664056
* The module function: 顶层测试
*****************************************************/
01 `timescale 1ns/1ps //时间单位和精度定义
02 module rom_tb;
03
04 //系统输入
05 reg clk; //系统时钟输入
06 reg rst_n; //系统复位
07 //系统输出
08 wire [7:0] q; //有效数据输出
09
10 initial begin
11 clk = 1;
12 rst_n = 0;
13 # 200.1
14 rst_n = 1;
15 end
16
17 always # 10 clk = ~clk; //50MHz时钟
18
19 rom rom (
20 .clk(clk), //系统时钟输入
21 .rst_n(rst_n), //系统复位
22 .q(q) //有效数据输出
23 );
24
25 endmodule
|
仿真分析
当复位信号拉高以后,addr(地址)开始发生变化,q(rom的输出)开始输出有效数据,并且是每一拍都会输出一个有效数据。地址和数据之间存在一拍的延迟是由于rom内部结构导致的。
在地址循环的同时,对应地址的有效数据也循环输出,证明我们的ip核使用正确。
|
|