赞
踩
ROM 是只读存储器(Read-Only Memory)的简称,是一种只能读出事先所存数据的固态半导体存储器。其特性是一旦储存资料就无法再将之改变或删除,且资料不会因为电源关闭而消失。而事实上在FPGA 中通过 IP 核生成的 ROM 或 RAM调用的都是 FPGA 内部的 RAM 资源,掉电内容都会丢失(这也很容易解释, FPGA 芯片内部本来就没有掉电非易失存储器单元)。用 IP 核生成的 ROM 模块只是提前添加了数据文件(.coe 格式),在 FPGA 运行时通过数据文件给 ROM 模块初始化,才使得 ROM 模块像个“真正”的掉电非易失存储器;也正是这个原因, ROM 模块的内容必须提前在数据文件中写死,无法在电路中修改。
Xilinx 推出的 ROM IP 核分为两种类型:单端口 ROM(Single-Port Rom)和双端口ROM(Dual-Port ROM)。对于单端口 ROM 提供一个读地址端口和一个读数据端口,只能进行读操作;双端口 ROM 与单端口 ROM 类似,区别是其提供两个读地址端口和两个读数据端口,基本上可以看做两个单口 RAM 拼接而成。
单端口ROM如下图所示:
双端口ROM:
关于IP核的配置如下图所示:
首先打开IP选型
然后搜索block
然后双击,我们选择单端口ROM
这里选择8位宽,深度256,总是使能。
定义了一个0-255的.coe文件,然后并添加
在Summary界面可以看到自己的配置
然后点击OK,我们的但端口ROM IP核就创建完成了。
本次实验任务是参考野火征途Pro系列开发指南,设计一个ROM 的初始化数据是 0~255,也就是存入数据0~255。然后每隔 0.2s 我们从 0 地址开始往下读取数据显示在数码管上,我们再利用两个按键信号来读取指定地址的数据,每按一个按键就读取一个地址的数据显示在数码管上。再次按下按键后,以当前地址继续以 0.2s 的时间间隔往下读取数据并显示出来。
根据实验任务我们可以知道,本次实验需要使用到的外设有按键以及数码管。按键的话肯定需要消抖模块,数码管的话是需要数码管驱动模块。在按键跟数码管中间的数据传输时通过ROM IP进行传输,所以还需要设计一个rom控制模块。模块框图大致如下:
消抖模块、rom控制模块以及rom IP的系统时钟以及系统复位端口没有画出来,正常都应该有的,这里需要注意一下。
按键消抖模块代码如下:
- `timescale 1ns / 1ps
-
- module key_filter(
- input sys_clk ,
- input sys_rst_n ,
- input key ,
- output reg key_flag
- );
-
- parameter CNT_MAX = 20'd999_999;
-
- reg [19:0] cnt_20ms;
-
-
- //20ms cnt
- always@(posedge sys_clk or negedge sys_rst_n) begin
- if(sys_rst_n == 1'b0)
- cnt_20ms <= 20'd0;
- else if(key == 1'b1)
- cnt_20ms <= 20'd0;
- else if(cnt_20ms == CNT_MAX && key == 1'b0)
- cnt_20ms <= cnt_20ms;
- else
- cnt_20ms <= cnt_20ms + 20'd1;
- end
-
- //key_flag
- always@(posedge sys_clk or negedge sys_rst_n) begin
- if(sys_rst_n == 1'b0)
- key_flag <= 1'd0;
- else if(cnt_20ms == (CNT_MAX - 20'd1))
- key_flag <= 1'd1;
- else
- key_flag <= 1'd0;
- end
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
消抖设置了一个20ms的计数器,当按键按下时间小于20ms就认为按键在抖动时间,根据消抖模块可以看一下仿真代码及波形图如下:
- `timescale 1ns / 1ns
-
- module tb_key_filter(
- );
-
-
- reg sys_clk ;
- reg sys_rst_n;
- reg key1 ;
- reg key2 ;
-
- wire key1_flag;
-
- initial begin
- sys_clk = 1'b1;
- sys_rst_n <= 1'b0;
- key1 <= 1'b1;
- key2 <= 1'b1;
- #201
- sys_rst_n <= 1'b1;
- #200
- //key1
- key1 <= 1'b0;
- #20
- key1 <= 1'b1;
- #80
- key1 <= 1'b0;
- #120
- key1 <= 1'b1;
- #20
- key2 <= 1'b0;
- #20
- key2 <= 1'b1;
- #20
- key2 <= 1'b0;
- #100
- key1 <= 1'b0;
- #500
- key1 <= 1'b1;
- #500
- key1 <= 1'b0;
- #400
- key1 <= 1'b1;
- end
-
- always #10 sys_clk <= ~sys_clk;
-
- defparam key_filter_inst1.CNT_MAX = 19;
- defparam key_filter_inst2.CNT_MAX = 19;
-
- key_filter key_filter_inst1(
- .sys_clk (sys_clk ),
- .sys_rst_n (sys_rst_n),
- .key (key1 ),
-
- .key_flag (key1_flag )
- );
-
- key_filter key_filter_inst2(
- .sys_clk (sys_clk ),
- .sys_rst_n (sys_rst_n),
- .key (key2 ),
-
- .key_flag (key2_flag )
- );
-
- endmodule
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
接下来我们开始设计rom控制模块,代码如下:
- `timescale 1ns / 1ps
-
- module rom_ctrl(
- input sys_clk ,
- input sys_rst_n ,
- input key1 ,
- input key2 ,
-
- output reg [7:0] addr
- );
-
-
-
- parameter CNT_MAX = 9_999_999; //0.2s计数器
- parameter ADDR_MAX = 8'd255; //最大地址
- reg key1_en;
- reg key2_en;
- reg [23:0] cnt_200ms;
-
- //key1_en
- always@(posedge sys_clk or negedge sys_rst_n) begin
- if(sys_rst_n == 1'b0)
- key1_en <= 1'b0;
- else if(key2 == 1'b1)
- key1_en <= 1'b0;
- else if(key1 == 1'b1)
- key1_en <= ~key1_en;
- end
-
- //key2_en
- always@(posedge sys_clk or negedge sys_rst_n) begin
- if(sys_rst_n == 1'b0)
- key2_en <= 1'b0;
- else if(key1 == 1'b1)
- key2_en <= 1'b0;
- else if(key2 == 1'b1)
- key2_en <= ~key2_en;
- end
-
- //0.2s cnt
- always@(posedge sys_clk or negedge sys_rst_n) begin
- if(sys_rst_n == 1'b0)
- cnt_200ms <= 24'd0;
- else if(key1_en == 1'b1 || key2_en == 1'b1 || cnt_200ms == CNT_MAX)
- cnt_200ms <= 24'd0;
- else
- cnt_200ms <= cnt_200ms + 24'd1;
- end
-
- //地址
- always@(posedge sys_clk or negedge sys_rst_n) begin
- if(sys_rst_n == 1'b0)
- addr <= 8'd0;
- else if(addr == ADDR_MAX && cnt_200ms == CNT_MAX)
- addr <= 8'd0;
- else if(key1_en == 1'b1)
- addr <= 8'd99;
- else if(key2_en == 1'b1)
- addr <= 8'd199;
- else if(cnt_200ms == CNT_MAX)
- addr <= addr + 8'd1;
- end
-
- endmodule
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
仿真代码:
- `timescale 1ns / 1ns
-
- module tb_rom_ctrl();
-
- reg sys_clk ;
- reg sys_rst_n;
- reg key1 ;
- reg key2 ;
-
- wire [7:0] addr ;
-
- initial begin
- sys_clk = 1'b1;
- sys_rst_n <= 1'b0;
- key1 <= 1'b0;
- key2 <= 1'b0;
- #201
- sys_rst_n <= 1'b1;
- #2000
- //key1
- key1 <= 1'b1;
- #20
- key1 <= 1'b0;
- #2000
- key1 <= 1'b1;
- #20
- key1 <= 1'b0;
- #700
- //key2
- key2 <= 1'b1;
- #20
- key2 <= 1'b0;
- #2500
- key2 <= 1'b1;
- #20
- key2 <= 1'b0;
- #500
- //key1&key2
- key1 <= 1'b1;
- #20
- key1 <= 1'b0;
- #2000
- key2 <= 1'b1;
- #20
- key2 <= 1'b0;
- #2000
- key2 <= 1'b1;
- #20
- key2 <= 1'b0;
-
- end
-
- always #10 sys_clk <= ~sys_clk;
-
- defparam rom_ctrl_inst.CNT_MAX = 19;
-
- rom_ctrl rom_ctrl_inst(
- .sys_clk (sys_clk ),
- .sys_rst_n (sys_rst_n),
- .key1 (key1 ),
- .key2 (key2 ),
-
- .addr (addr )
- );
- endmodule
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
数码管例程就不展示了,大家可以随便使用一个数码管驱动模块,也可以参考野火的数码管例程
最后将这三个模块例化到一起,再进行一个仿真验证:
仿真结果跟我们要实现的任务要求是一致的,说明代码没有问题,这边就不展示上板验证的效果了,下一章介绍RAM的使用。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。