2021.1.22ROM IP核(二)调用与仿真

一、验证
如何验证ROM IP核是否正常工作,首先满足两个要求。
第一:每个地址都对应一个数据
第二:能够根据clk产生随机数据地址,同时能够将对应地址中的内容提取出来

1、实验目标
(1)以生成的mif文件为例子,从地址0——255将其每个地址中间的内容读取出来,并将读取的数据在数码管上显示出来,将每个数据显示的时间定为200ms。再将数据与我们的mif文件进行对比观察数据的正确性
(2)验证随机变量的正确性,引入两个变量即两个按键k1、k2,当k1按下的时候给rom提供一个随机但是有效的地址A1,然后将A1存储的数据读取出来显示在数码管上。k2也是同理,产生一个随机数地址A2,并将A2地址对应的数据提取出来,将其显示在数码管上面。比如按下按键k1,产生随机地址A1之后,以A1为起始地址,255为最后的地址,将数据依次显示结束之后再从地址0开始进行循环

二、实现
1、框图
在这里插入图片描述

动态显示模块
在这里插入图片描述

rom控制模块
在这里插入图片描述

rom ip核模块
在这里插入图片描述

按键消抖模块
在这里插入图片描述

根据之前的学习,我们现在已经生成了按键消抖模块,动态显示模块、rom ip核模块。现在只差rom控制模块,以及功能的顶层模块

2、rom控制模块波形
(1)
在这里插入图片描述

使得每个地址对应一个数据,将数据在数码管上面显示出来,每个数据显示的时间为200ms,所以在每个200ms的周期内显示你每个数据,此时的两个按键都没有按下。

(2)
在这里插入图片描述

这个状态是按键1按下的时候,当按键1按下的时候,地址跳转到地址99,并将地址99中的数据显示在数码管上,当按键1再次按下的时候,地址会不断的自动加1,并将地址中的数据显示在数码管上面

(3)
在这里插入图片描述

这个状态是按键1按下的时候,当按键2按下的时候,地址跳转到地址199,并将地址199中的数据显示在数码管上,当按键2再次按下的时候,地址会不断的自动加1,并将地址中的数据显示在数码管上面

(4)
在这里插入图片描述

这种状态是显示按键1按下,数码管显示地址99中的数据,当下一时刻按下按键2,则数据会跳转到地址199所对应的数据上面。再次按下按键2的时候,数码管显示的数据会从地址199上面依次加1。同样还有第五种情况,可以根据状态4进行修改

3、程序
在这里插入图片描述

在rom中我们用到的模块,在之前都已经存在,只有rom_ctrl没有,在这里只单独写出其程序以及测试程序
(1)rom_ctrl程序

module  rom_ctrl
#(
    parameter   CNT_MAX =   9_999_999  //0.2s计数器最大值
)
(
    input   wire        sys_clk     ,   //系统时钟,频率50MHz
    input   wire        sys_rst_n   ,   //复位信号,低有效
    input   wire        key1  ,   //按键1消抖后有效信号
    input   wire        key2  ,   //按键2消抖后有效信号

    output  reg [7:0]   addr            //输出读ROM地址

);

//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//


//reg   define
reg             key1_en      ;   //特定地址1标志信号
reg             key2_en      ;   //特定地址2标志信号
reg     [23:0]  cnt_200ms       ;   //0.2s计数器

//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//

//0.2s循环计数
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_200ms    <=  24'd0;
    else    if(cnt_200ms == CNT_MAX || key1_en == 1'b1 || key2_en == 1'b1)
        cnt_200ms   <=  24'd0;
    else
        cnt_200ms   <=  cnt_200ms + 1'b1;


//产生特定地址1标志信号
always@(posedge sys_clk or  negedge sys_rst_n)
    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;

//产生特定地址2标志信号
always@(posedge sys_clk or  negedge sys_rst_n)
    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;


//让地址从0~255循环,其中两个按键控制两个特定地址的跳转
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        addr    <=  8'd0;
    else    if(addr == 8'd255 && 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 + 1'b1;

endmodule

(2)tb_rom_ctrl测试模块

`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;
        #30
        sys_rst_n <= 1'b1;
        #700_000
//仿真设置的为99,即100个时钟周期,每个时钟周期为20ns,总共100*20=2000ns,
//表示仿真过程中每个数据显示的时间为2000ns,在rom ip核中共有256个数据,2000*256=51200,即延时时间不能小于这个数
//key1
        key1 <= 1'b1;
        #20
        key1 <= 1'b0;
        #20000
        key1 <= 1'b1;
        #20
        key1 <= 1'b0;
        #60000
//key2
        key2 <= 1'b1;
        #20
        key2 <= 1'b0;
        #20000
        key2 <= 1'b1;
        #20
        key2 <= 1'b0;
        #60000
//按下key1一次,按下key2两次
        key1 <= 1'b1;
        #20
        key1 <= 1'b0;
        #20000
        key2 <= 1'b1;
        #20
        key2 <= 1'b0;
        #20000
        key2 <= 1'b1;
        #20
        key2 <= 1'b0;
    end
always #10 sys_clk = ~sys_clk;


rom_ctrl
#(
    .CNT_MAX (24'd99)  //0.2s计数器最大值
)
rom_ctrl_inst
(
    .sys_clk    (sys_clk),   //系统时钟,频率50MHz
    .sys_rst_n  (sys_rst_n),   //复位信号,低有效
    .key1       (key1)   ,   //按键1消抖后有效信号
    .key2       (key2 )   ,   //按键2消抖后有效信号

    .addr       (addr)    //输出读ROM地址

);
endmodule

(3)总模块

module rom
(
    input wire  sys_clk,
    input wire  sys_rst_n,
    input wire  key1,
    input wire  key2,
    
    output wire stcp,
    output wire shcp,
    output wire ds,
    output wire oe

);

wire key1_flag;
wire key2_flag;
wire [7:0]  addr;
wire [7:0]  data;

key_filter
#(
    .CNT_MAX (20'd999999)
)
key_filter_inst1
(
    .sys_clk   (sys_clk) ,
    .sys_rst_n (sys_rst_n) ,
    .key_in    (key1) ,

    .key_flag  (key1_flag)

);


key_filter
#(
    .CNT_MAX (20'd999999)
)
key_filter_inst2
(
    .sys_clk   (sys_clk) ,
    .sys_rst_n (sys_rst_n) ,
    .key_in    (key2) ,

    .key_flag  (key2_flag)

);

rom_ctrl
#(
    .CNT_MAX (24'd9999999)  //0.2s计数器最大值
)
rom_ctrl_inst
(
    .sys_clk      (sys_clk)  ,   //系统时钟,频率50MHz
    .sys_rst_n    (sys_rst_n)  ,   //复位信号,低有效
    .key1         (key1_flag)  ,   //按键1消抖后有效信号
    .key2         (key2_flag)  ,   //按键2消抖后有效信号
 
    .addr         (addr)   //输出读ROM地址

);

rom_8_256	rom_8_256_inst 
(
.address    ( addr ),
.clock      ( sys_clk ),
.q          ( data )
);

seg_595_dynamic seg_595_dynamic_inst
(
    .  sys_clk   (sys_clk) ,
    .  sys_rst_n (sys_rst_n) ,
    .  data      ({12'b0,data} ) ,//因为在动态显示模块里面的data是20位宽,而data是8位宽
    .  point     (6'b000_000) ,
    .  seg_en    (1'b1) ,
    .  sign      (1'b0) ,

    .  ds        (ds) , 
    .  shcp      (shcp) , 
    .  stcp       (stcp) , 
    .  oe        (oe)
    
 ); 

endmodule

(4)总测试模块

`timescale  1ns/1ns
module  tb_rom();

//wire  define
wire    stcp;
wire    shcp;
wire    ds  ;
wire    oe  ;

//reg   define
reg         sys_clk     ;
reg         sys_rst_n   ;
reg         key1         ;
reg         key2         ;
//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//

//对sys_clk,sys_rst赋初值,并模拟按键抖动
initial
    begin
            sys_clk     =   1'b1 ;
            sys_rst_n   <=  1'b0 ;
            key1         <=  1'b1;
            key2         <=  1'b1;
    #200    sys_rst_n   <=  1'b1 ;
//按下按键key1
    #700000     key1      <=  1'b0;//按下按键
    #20         key1      <=  1'b1;//模拟前抖动
    #20         key1      <=  1'b0;//模拟前抖动
    #20         key1      <=  1'b1;//模拟前抖动
    #20         key1      <=  1'b0;//模拟按下按键
    #200        key1      <=  1'b1;//松开按键
    #20         key1      <=  1'b0;//模拟后抖动
    #20         key1      <=  1'b1;//模拟后抖动
    #20         key1      <=  1'b0;//模拟后抖动
    #20         key1      <=  1'b1;//模拟后抖动
//按下按键key2
    #20000      key2      <=  1'b0;//按下按键
    #20         key2      <=  1'b1;//模拟抖动
    #20         key2      <=  1'b0;//模拟抖动
    #20         key2      <=  1'b1;//模拟抖动
    #20         key2      <=  1'b0;//模拟抖动
    #200        key2      <=  1'b1;//松开按键
    #20         key2      <=  1'b0;//模拟抖动
    #20         key2      <=  1'b1;//模拟抖动
    #20         key2      <=  1'b0;//模拟抖动
    #20         key2      <=  1'b1;//模拟抖动
//按下按键key2
    #20000      key2      <=  1'b0;//按下按键
    #20         key2      <=  1'b1;//模拟抖动
    #20         key2      <=  1'b0;//模拟抖动
    #20         key2      <=  1'b1;//模拟抖动
    #20         key2      <=  1'b0;//模拟抖动
    #200        key2      <=  1'b1;//松开按键
    #20         key2      <=  1'b0;//模拟抖动
    #20         key2      <=  1'b1;//模拟抖动
    #20         key2      <=  1'b0;//模拟抖动
    #20         key2      <=  1'b1;//模拟抖动

    end
    
//sys_clk:模拟系统时钟,每10ns电平取反一次,周期为20ns,频率为50Mhz
always  #10 sys_clk =   ~sys_clk;

//重新定义参数值,缩短仿真时间仿真
/* defparam    rom_inst.key1_filter_inst.CNT_MAX   =   5 ;
defparam    rom_inst.key2_filter_inst.CNT_MAX   =   5 ;
defparam    rom_inst.rom_ctrl_inst.CNT_MAX      =   99; */

//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//

//---------------rom_inst--------------
rom rom_inst
(
    .sys_clk     (sys_clk   ),   //系统时钟,频率50MHz
    .sys_rst_n   (sys_rst_n ),   //复位信号,低电平有效
    .key1         (key1       ),   //输入按键信号
    .key2           (key2),

    .stcp        (stcp      ), //输出数据存储寄时钟
    .shcp        (shcp      ), //移位寄存器的时钟输入
    .ds          (ds        ), //串行数据输入
    .oe          (oe        )  //输出使能信号

);

endmodule


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值