Chapter004-FPGA学习之IP核相关功能【时钟、RAM、FIFO】

在之前STM32的学习中,认识到无论实现什么功能,有几个基础功能是必不可少的,缺失这些功能则无法将代码以我们想要的逻辑运行下去,STM32因为STM32CubeMX的存在,使得这些功能能够通过图形化配置,建立代码框架,但我们知道,FPGA是硬件电路代码化,其本身并没有已经固化好的功能,比如串口、IIC、SPI等,甚至连RAM和ROM都没有,但这也就是FPGA可以是任何东西的原因,其并未将功能固化到引脚上的同时,各个功能也没有了像STM32一样的引脚束缚。
但由于上述功能的概念大众较为认可,Vivado同样也集成了类似的图形化配置功能,其命名为IP核。
故该章主要讲述的就是IP核的三个大功能,分别是:

  • PLL锁相环【时钟相关】
  • RAM随机存储器【活动内存相关】
  • FIFO先进先出【数据传输相关】

IP核之MMCM/PLL

MMCM/PLL通俗的将就是将晶振的主频提高或降低的核心部件,为不同的功能提供不同的时钟信号,可以理解为STM32CubeMX的时钟树配置的部分,只是STM32CubeMX的时钟树需要兼顾多个部件的时钟供应,故存在诸多限制,但MMCM/PLL则不存在此限制,直接配置即可

目标功能

使用Clocking Wizard IP核产生4个时钟100MHz、100MHz_180deg、50M、25M,连接到U20、T20、P19、N18四个引脚。

IP核配置

新建Vivado项目后,点击Project Manager下的IP Catalog,即可进入IP核的配置界面
在这里插入图片描述
在IP核配置界面搜索clock,找到Clocking Wizard
在这里插入图片描述
首先配置时钟源,时钟源为FPGA的板上晶振提供的时钟信号,我是用的板子时钟为50MHz晶振,则将时钟源配置为50MHz
在这里插入图片描述
配置完成时钟源后,进行输出时钟配置,我们的配置目标是100MHz、100MHz_180deg、50M、25M4个时钟,其中180deg的意义为相位后移180°
在这里插入图片描述
Clock_Wizard的IP核存在一个控制信号为locked,在Port Renaming中可对此信号重命名,若无特殊要求则默认即可
在这里插入图片描述
MMCM Settings为而配置总览
在这里插入图片描述
完成上一步后,若确认无异常,则可直接点击OK,点击后会出现Generate Output Products界面,直接点击Generate即可
在这里插入图片描述
之后在Source串口的IP Source菜单即可找到clk_wiz_0.veo,双击打开后可找到clk_wiz_0的例化接口。
在这里插入图片描述
接口如下:

clk_wiz_0 instance_name
   (
    // Clock out ports
    .clk_out1_100m(clk_out1_100m),     // output clk_out1_100m
    .clk_out2_100m_180(clk_out2_100m_180),     // output clk_out2_100m_180
    .clk_out3_50m(clk_out3_50m),     // output clk_out3_50m
    .clk_out4_25m(clk_out4_25m),     // output clk_out4_25m
    // Status and control signals
    .reset(reset), // input reset
    .locked(locked),       // output locked
   // Clock in ports
    .clk_in1(clk_in1));      // input clk_in1

代码编辑

为验证内核功能,需要建立一个verilog文件将ip_wiz_0功能例化,名称为MMCM_PLL.v内容如下:

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2022/07/11 23:13:37
// Design Name: 
// Module Name: MMCM_PLL
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module MMCM_PLL(
    input       sys_clk     ,
    input       sys_rst_n   ,
    
    output      clk_100m    ,
    output      clk_100m_180deg,
    output      clk_50m     ,
    output      clk_25m
    );
    
/***************************************************
                    main code
***************************************************/

wire        locked;

//MMCM-PLL example
clk_wiz_0 clk_wiz_0
(
// Clock out ports
.clk_out1_100m      (clk_100m),             // output clk_out1_100m
.clk_out2_100m_180  (clk_100m_180deg),      // output clk_out2_100m_180
.clk_out3_50m       (clk_50m),              // output clk_out3_50m
.clk_out4_25m       (clk_25m),              // output clk_out4_25m
// Status and control signals
.reset              (~sys_rst_n),           // input reset
.locked             (locked),               // output locked
// Clock in ports
.clk_in1            (sys_clk)               // input clk_in1
);      
    
endmodule

除了逻辑代码外,还需要添加约束代码【用于堆芯逻辑输出和硬件物理引脚】
在这里插入图片描述
约束文件命名为MMCM_PLL.xdc
在这里插入图片描述
若各位码哥有逻辑分析仪,则直接生成代码下载测试,如果没有的话则需要在Vivado或者Modelsim中进行仿真,仿真的玩法基本一致,这里图方便就在Vivado实现了;

仿真配置

首先建立仿真verilog文件:
在这里插入图片描述
将新建立的仿真文件命名为tb_MMCM_PLL
在这里插入图片描述

需要建立一个verilog文件进行仿真,名称为tb_MMCM_PLL.v,代码如下:

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2022/07/11 23:27:08
// Design Name: 
// Module Name: tb_MMCM_PLL
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module tb_MMCM_PLL();

reg     sys_clk;
reg     sys_rst_n;

wire    clk_100m;
wire    clk_100m_180deg;
wire    clk_50m;
wire    clk_25m;

always #10 sys_clk = ~sys_clk;

initial begin
    sys_clk = 1'b0;
    sys_rst_n = 1'b0;
    #200
    sys_rst_n = 1'b1;
end

MMCM_PLL u_MMCM_PLL(
    .sys_clk        (sys_clk    ),
    .sys_rst_n      (sys_rst_n  ),
    
    .clk_100m       (clk_100m           ),
    .clk_100m_180deg (clk_100m_180deg    ),
    .clk_50m       (clk_50m    ),
    .clk_25m       (clk_25m    )
);

endmodule

该仿真程序的核心就是仿真出时钟信号sys_clk和复位信号sys_rst_n。

接下来就是进行仿真,首先左键点击项目管理的Run Simulation,在弹出的菜单中点击第一项RUN Behavioral Simulation即可开始仿真
在这里插入图片描述
在这里插入图片描述
按照下图红框中配置好仿真的时长,并开始仿真
在这里插入图片描述
由图可见生成的各个时钟的波形,与预期一致,到此,IP的内核功能已经实现!

IP核之RAM

RAM随机存储器,它可以随时把数据写入任一指定地 址的存储单元,也可以随时从任一指定地址中读出数据,其读写速度是由时钟频率决定的。可以理解为STM32在编写代码时,定义的变量在赋值或使用时所对应的硬件地址所在的存储表。

目标功能

定义一块RAM空间,对RAM空间内的数据进行写入的读取;仅使用时钟输入和复位输入;

IP核配置

新建Vivado工程,在IP核的配置界面搜索Block Memory
在这里插入图片描述
配置如下图所示,配置总线类型为Native、存储器类型为单端口RAM【读写只能通过一个端口实现】
在这里插入图片描述
接下来配置端口A,读取数据宽度8bit深度32,写入数据宽度8bit深度32,读写模式使用不变模式No Change【不允许同时读写】,取消Primitives Output Register,防止在仿真时,数据后滞一个时钟周期,不利于学习过程的分析,选中该选项是打开输出流水寄存器,可改善时序性能,正常使用时一般选择打开;
在这里插入图片描述
Other Options在该实验暂时不用修改,故跳过,之后在Summary中进行全局检查,无问题则直接点击OK。
在这里插入图片描述
跳出生成界面直接点击生成(Generate)即可
在这里插入图片描述
在与MMCM_PLL的IP核相同的位置可找到RAM的例化端口
在这里插入图片描述
复制例化端口后进行编码;

//----------- Begin Cut here for INSTANTIATION Template ---// INST_TAG
blk_mem_gen_0 your_instance_name (
  .clka(clka),    // input wire clka
  .ena(ena),      // input wire ena
  .wea(wea),      // input wire [0 : 0] wea
  .addra(addra),  // input wire [4 : 0] addra
  .dina(dina),    // input wire [7 : 0] dina
  .douta(douta)  // output wire [7 : 0] douta
);
// INST_TAG_END ------ End INSTANTIATION Template ---------

代码编辑

建立使用RAM的功能模块,命名为ram_rw.v,该模块和IP核为同层级;
在这里插入图片描述
代码如下:

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2022/07/12 22:40:36
// Design Name: 
// Module Name: ram_rw
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module ram_rw(
    input       clk     ,//时钟信号
    input       rst_n   ,//复位信号,低电平有效
    
    output      ram_en  ,//ram 使能信号
    output      ram_wea ,//ram 读写选择
    output reg [4:0] ram_addr   ,//ram 读写地址
    output reg [7:0] ram_wr_data,//ram 写数据
    input       [7:0] ram_rd_data //ram 读数据
    );
    
//reg define
reg [5:0] rw_cnt;

/*****************************************
                main code
******************************************/    

//控制RAM使能信号
assign ram_en = rst_n;

//rw_cnt计数器在0~31写入数据,32~63读取数据
assign ram_wea = (rw_cnt <= 6'd31 && ram_en == 1'b1) ? 1'b1 : 1'b0;    
    
//读写控制计数器,计数范围0~63
always @ (posedge clk or negedge rst_n)begin
    if(rst_n == 1'b0)
        rw_cnt <= 1'b0;
    else if(rw_cnt == 6'd63)
        rw_cnt <= 1'b0;
    else
        rw_cnt <= rw_cnt + 1'b1;
end

//产生RAM写数据
always @ (posedge clk or negedge rst_n)begin
    if(rst_n == 1'b0)
        ram_wr_data <= 1'b0;
    else if(rw_cnt <= 6'd31)//对应数据随地址变化而变化
        ram_wr_data <= ram_wr_data + 1'b1;
    else
        ram_wr_data <= 1'b0;
end

//读写地址信号 0~31
always@(posedge clk or negedge rst_n)begin
    if(rst_n == 1'b0)
        ram_addr <= 1'b0;    
    else if(rw_cnt == 6'd31)
        ram_addr <= 1'b0;
    else
        ram_addr <= ram_addr + 1'b1;
end

endmodule

新建高层级的模块,调用IP核和刚刚写好的模块ip_ram.v,端口仅为时钟信号和复位信号,代码如下:

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2022/07/12 23:00:27
// Design Name: 
// Module Name: ip_ram
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module ip_ram(
    input sys_clk , //系统时钟
    input sys_rst_n //系统复位,低电平有效
    );
    
//wire define
wire ram_en ; //RAM 使能
wire ram_wea ; //ram 读写使能信号,高电平写入,低电平读出
wire [4:0] ram_addr ; //ram 读写地址
wire [7:0] ram_wr_data ; //ram 写数据
wire [7:0] ram_rd_data ; //ram 读数据

//*****************************************************
//**                    main code
//*****************************************************

//ram 读写模块例化
ram_rw u_ram_rw(
    .clk        (sys_clk    ),
    .rst_n      (sys_rst_n  ),
    
    .ram_en     (ram_en     ),
    .ram_wea    (ram_wea    ),
    .ram_addr   (ram_addr   ),
    .ram_wr_data(ram_wr_data),
    .ram_rd_data(ram_rd_data)
);

//ram ip核模块例化
blk_mem_gen_0 blk_mem_gen_0(
    .clka       (sys_clk    )   ,// input wire clka
    .ena        (ram_en     )   ,// input wire ena
    .wea        (ram_wea    )   ,// input wire [0 : 0] wea
    .addra      (ram_addr   )   ,// input wire [4 : 0] addra
    .dina       (ram_wr_data)   ,// input wire [7 : 0] dina
    .douta      (ram_rd_data)    // output wire [7 : 0] douta
);
    
endmodule

接下来建立约束文件,命名为ip_ram.xdc,代码如下:

set_property -dict {PACKAGE_PIN U18 IOSTANDARD LVCMOS33} [get_ports sys_clk]
set_property -dict {PACKAGE_PIN N16 IOSTANDARD LVCMOS33} [get_ports sys_rst_n]

仿真配置

RAM的读写由于与物理引脚无关,故需要进行仿真验证,确定RAM的IP核功能是否正确,新建访问文件为tb_ip_ram.v,具体代码如下:

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2022/07/12 23:09:44
// Design Name: 
// Module Name: tb_ip_ram
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module tb_ip_ram();

reg     sys_clk;
reg     sys_rst_n;

always#10 sys_clk = ~sys_clk;

initial begin
    sys_clk = 1'b0;
    sys_rst_n = 1'b0;
    #200
    sys_rst_n = 1'b1;
end

ip_ram u_ip_ram(
    .sys_clk        (sys_clk    ),
    .sys_rst_n      (sys_rst_n  )
);

endmodule

之后与仿真MMCM_PLL一样的操作进行仿真:
在这里插入图片描述
进行仿真
在这里插入图片描述
仿真结果放大后,结果如下:
在这里插入图片描述
当ram_wea信号拉高后进行写操作,写入数据与地址一一对应;
在这里插入图片描述
当ram_wea信号拉低后进行读操作,读取数据与地址一一对应;

至此测试完成。

IP核之FIFO

目标功能

使用异步方式将数据先写入FIFO区,再从FIFO区读取;
其大致思路如下图所示,建立一个FIFO的写入模块u_fifo_wr、建立一个FIFO的读取模块u_fifo_rd、建立一个FIFO的IP核fifo_generator_0,若要下载到FPGA测试则还需要建立一个虚拟逻辑分析仪IP核ila_0:
在这里插入图片描述

IP核配置

与之前的IP核方法一样,在IP核搜索栏搜索FIFO,找到FIFO_Generator
在这里插入图片描述
选在Native接口的独立时钟块的RAM“Independent Clocks Block RAM”
在这里插入图片描述
对FIFO接口进行配置,本次实验读写数据为8位,故数据宽度都为8位,数据深度暂定为256,读取写入每次都顺序操作255个数据,由于仅观察FIFO读写,故ResetPin可以取消勾选。
在这里插入图片描述
状态标记配置需要把快满和快空的标记勾选上
在这里插入图片描述
配置数据计数器,读写数据计数器均使能,且宽度定义为8
在这里插入图片描述
完成上述操作后直接点击OK,则会跳出IP核生成器,直接点击生成即可;
FIFO的IP核例化端口可在下图所示位置实现
在这里插入图片描述
在这里插入图片描述

代码编辑

顶层模块代码文件命名为ip_fifo.v,代码如下:

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2022/07/13 20:48:50
// Design Name: 
// Module Name: ip_fifo
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module ip_fifo(
    input       sys_clk,
    input       sys_rst_n
    );

wire        fifo_wr_en  ;
wire        fifo_rd_en  ;
wire  [7:0] fifo_din    ;
wire  [7:0] fifo_dout   ;
wire        almost_full ;
wire        almost_empty;
wire        fifo_full   ;
wire        fifo_empty  ;
wire  [7:0] fifo_wr_data_count;
wire  [7:0] fifo_rd_data_count;

//*****************************************************
//*******           mian code
//*****************************************************

//例化FIFO IP核
fifo_generator_0 fifo_generator_0(
    .wr_clk         (sys_clk        ),
    .rd_clk         (sys_clk        ),
    
    .wr_en          (fifo_wr_en     ),
    .rd_en          (fifo_rd_en     ),
    
    .din            (fifo_din       ),
    .dout           (fifo_dout      ),
    
    .almost_full    (almost_full    ),
    .almost_empty   (almost_empty   ),
    .full           (fifo_full      ),
    .empty          (fifo_empty     ),
    
    .wr_data_count  (fifo_wr_data_count),
    .rd_data_count  (fifo_rd_data_count)
);

//例化FIFO写入模块
fifo_wr u_fifo_wr(
    .clk ( sys_clk ), // 写时钟
    .rst_n ( sys_rst_n ), // 复位信号
    .fifo_wr_en ( fifo_wr_en ) , // fifo 写请求
    .fifo_wr_data ( fifo_din ) , // 写入 FIFO 的数据
    .almost_empty ( almost_empty ), // fifo 将空信号
    .almost_full ( almost_full ) // fifo 将满信号
);

//例化FIFO读取模块
fifo_rd u_fifo_rd(
    .clk            ( sys_clk ),        // 读时钟
    .rst_n          ( sys_rst_n ),      // 复位信号
    .fifo_rd_en     ( fifo_rd_en ),     // fifo 读请求
    .fifo_dout      ( fifo_dout ),      // 从 FIFO 输出的数据
    .almost_empty   ( almost_empty ),   // fifo 将空信号
    .almost_full    ( almost_full )     // fifo 将满信号
);

//例化ILA IP核,虚拟逻辑分析仪
ila_0 ila_0(
    .clk        (sys_clk        ),
    
    .probe0     (fifo_wr_en     ),
    .probe1     (fifo_rd_en     ),
    .probe2     (fifo_din       ),
    .probe3     (fifo_dout      ),
    .probe4     (fifo_empty     ),
    .probe5     (almost_empty   ),
    .probe6     (fifo_full      ),
    .probe7     (almost_full    ),
    .probe8     (fifo_wr_data_count),
    .probe9     (fifo_rd_data_count)
);

    
endmodule

新建约束文件,命名为ip_dido.xdc,代码如下:

create_clock -period 20.000 -name clk [get_ports sys_clk]
set_property -dict {PACKAGE_PIN U18 IOSTANDARD LVCMOS33} [get_ports sys_clk]
set_property -dict {PACKAGE_PIN N16 IOSTANDARD LVCMOS33} [get_ports sys_rst_n]

编写FIFO写入模块,命名为fifo_wr.v,代码如下:

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2022/07/13 21:04:32
// Design Name: 
// Module Name: fifo_wr
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module fifo_wr(
    input       clk     ,
    input       rst_n   ,
    
    input       almost_empty,
    input       almost_full ,
    output reg  fifo_wr_en  ,
    output reg [7:0]fifo_wr_data
    );
    
//reg define    
reg     [1:0]       state           ;
reg                 almost_empty_d0 ;
reg                 almost_empty_syn;
reg     [3:0]       dly_cnt         ;         
    
//*****************************************************
//**                main code 
//*****************************************************    

//将almost_empty同步到写时钟域
always@(posedge clk)begin
    if(!rst_n)begin
        almost_empty_d0 <= 1'b0;
        almost_empty_syn <= 1'b0;
    end
    else begin
        almost_empty_d0 <= almost_empty;
        almost_empty_syn <= almost_empty_d0;
    end
end

//向FIFO写入数据
always @(posedge clk)begin
    if(!rst_n)begin
        fifo_wr_en <= 1'b0;
        fifo_wr_data <= 8'b0;
        state <= 2'b0;
        dly_cnt <= 4'd0;
    end
    else begin
        case(state)
            2'd0:begin
                if(almost_empty_syn) begin //如果检测到 FIFO 将被读空(下一拍就会空)
                    state <= 2'd1; //就进入延时状态
                end
                else
                    state <= state;
            end
            
            2'd1:begin
                if(dly_cnt == 4'd10) begin //延时 10 拍,等待状态信号完成更新
                    dly_cnt <= 4'd0;
                    state <= 2'd2;          //开始写操作
                    fifo_wr_en <= 1'b1;     //打开写使能
                end
                else
                    dly_cnt <= dly_cnt + 4'd1;
            end
            
            2'd2:begin
                if(almost_full) begin   //等待 FIFO 将被写满(下一拍就会满)
                    fifo_wr_en <= 1'b0; //关闭写使能
                    fifo_wr_data <= 8'd0;
                    state <= 2'd0;      //回到第一个状态
                end
                else begin              //如果 FIFO 没有被写满
                    fifo_wr_en <= 1'b1; //则持续打开写使能
                    fifo_wr_data <= fifo_wr_data + 1'd1; //且写数据值持续累加
                end
            end
            default : state <= 2'd0;
        endcase
    end
end

endmodule

编写FIFO的读取模块,命名为fifo_rd.v,代码如下:

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2022/07/13 21:04:32
// Design Name: 
// Module Name: fifo_rd
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module fifo_rd(
    input       clk     ,
    input       rst_n   ,
    
    input  [7:0]fifo_dout,
    input       almost_full ,
    input       almost_empty,
    output reg  fifo_rd_en  
    );
    
//reg define    
reg     [1:0]       state           ;
reg                 almost_full_d0 ;
reg                 almost_full_syn;
reg     [3:0]       dly_cnt         ;         
    
//*****************************************************
//**                main code 
//*****************************************************    

//将almost_full同步到读时钟域
always@(posedge clk)begin
    if(!rst_n)begin
        almost_full_d0 <= 1'b0;
        almost_full_syn <= 1'b0;
    end
    else begin
        almost_full_d0 <= almost_full;
        almost_full_syn <= almost_full_d0;
    end
end

//向FIFO读取数据
always @(posedge clk)begin
    if(!rst_n)begin
        fifo_rd_en <= 1'b0;
        state <= 2'b0;
        dly_cnt <= 4'd0;
    end
    else begin
        case(state)
            2'd0:begin
                if(almost_full_syn) begin //如果检测到 FIFO 将被写满(下一拍就会满)
                    state <= 2'd1; //就进入延时状态
                end
                else
                    state <= state;
            end
            
            2'd1:begin
                if(dly_cnt == 4'd10) begin //延时 10 拍,等待状态信号完成更新
                    dly_cnt <= 4'd0;
                    state <= 2'd2;          //开始读操作
                end
                else
                    dly_cnt <= dly_cnt + 4'd1;
            end
            
            2'd2:begin
                if(almost_empty) begin   //等待 FIFO 将被读空(下一拍就会空)
                    fifo_rd_en <= 1'b0; //关闭读使能
                    state <= 2'd0;      //回到第一个状态
                end
                else                    //如果 FIFO 没有被写满
                    fifo_rd_en <= 1'b1; //则持续打开写使能
            end
            default : state <= 2'd0;
        endcase
    end
end

endmodule

因为读写FIFO的动作下载到FPGA上后,实验现象难以观测,故需要启动虚拟逻辑分析仪内核ILA实现。
首先还是在IP核中搜索ILA,选中下图所示的IP核
在这里插入图片描述
由于我们需要观测的数据为读写过程中的使能、数据、存满、读空、将满将空等数据,具体内容如下,则需要配置10路虚拟逻辑分析仪探针,数据深度设置为1024【深度越深,采集的过程信息越多,占用FPGA空间越多,需要适可而止】
在这里插入图片描述
对虚拟逻辑分析仪配置的10个端口的数据宽度,针对读取写入的具体数据需要配置的数据宽度为8,其余布尔量信号宽度为1即可。
在这里插入图片描述
配置完成之后直接点击OK,生成即可。

仿真配置

编辑仿真代码,命名为tb_ip_fifo.v,代码如下:

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2022/07/13 21:47:10
// Design Name: 
// Module Name: tb_ip_fifo
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module tb_ip_fifo();

reg sys_clk;
reg sys_rst_n;

ip_fifo u_ip_fifo(
    .sys_clk        (sys_clk),
    .sys_rst_n      (sys_rst_n)
);

parameter   PERIOD = 20;

always begin
    sys_clk = 1'b0;
    #(PERIOD/2) sys_clk = 1'b1;
    #(PERIOD/2);
end

initial begin
    sys_rst_n = 0;
    #100
    sys_rst_n = 1;
end
endmodule

完成代码编辑后在Vivado直接进行仿真,完成写操作位置为下图黄线所示位置;
在这里插入图片描述
完成读操作,下图黄线位置为写完成
在这里插入图片描述
故测试成功;

  • 6
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值