FIFO实验


前言

本实验简单地使用 fifo 跨时钟域传输多 bit 数据,以 100M 的时钟依次向 fifo 中写入 1-200 这 200 个数,然后再以 200M 的时钟从 fifo 中把数据读出,验证数据是否写入,然后继续写入 1-200 这 200 个数,然后在继续读出 200 个数,如此这样读写循环。让我们初步理解 fifo 的时序。


创建FIFO IP核

1.在 IP Catalog 中搜索fifo,找到FIFO Generator,双击打开
2.配置 fifo ip 核的基本设置,选择Independent Clocks Block RAM
3.配置 ip 核的接口的模式以及位宽
在这里插入图片描述
4.将 fifo 写入数据和读出数据的端口都选上

在这里插入图片描述
5.本实验用涉及到跨时钟用到了 pll,pll 主要配置如下图
在这里插入图片描述

程序设计

Verilog代码

// 定义FIFO测试模块
module fifo_test(
    input clk,          // 时钟信号输入
    input rst_n         // 复位信号输入,低电平有效
);

// 定义最大计数器值
localparam CNT_MAX = 200 - 1;

// 声明内部信号
wire rst;             // 复位信号,高电平有效
wire fifo_rst;         // FIFO复位信号
wire wr_clk;           // 写时钟信号
wire rd_clk;           // 读时钟信号

reg wr_en;             // 写使能信号
wire[7:0]din;          // 数据输入端口
reg[7:0]wr_cnt;        // 写计数器
wire empty;            // FIFO空信号
wire[7:0]wr_data_count; // 写数据计数
wire wr_rst_busy;      // 写复位忙信号

reg rd_en;             // 读使能信号
wire[7:0]dout;         // 数据输出端口
reg[7:0]rd_cnt;        // 读计数器
wire full;             // FIFO满信号
wire[7:0]rd_data_count; // 读数据计数
wire rd_rst_busy;      // 读复位忙信号

// 复位信号处理
assign fifo_rst = wr_rst_busy | rd_rst_busy; // FIFO复位信号由写复位忙或读复位忙信号产生
assign rst = ~rst_n; // 复位信号,取反rst_n得到

// 实例化时钟模块,产生写时钟和读时钟
clock inst_clock(
    .clk_out1(wr_clk),
    .clk_out2(rd_clk),
    .reset(rst),
    .clk_in1(clk)
);

// 写时钟域的写使能信号生成
always @(posedge wr_clk or posedge fifo_rst) begin
    if (fifo_rst)
        wr_en <= 1'b0; // FIFO复位时,写使能置为0
    else if (wr_cnt == CNT_MAX)
        wr_en <= 1'b0; // 写计数器达到最大值时,写使能置为0
    else if (empty)
        wr_en <= 1'b1; // FIFO为空时,写使能置为1
end

// 写计数器逻辑
always @(posedge wr_clk or posedge fifo_rst) begin
    if (fifo_rst)
        wr_cnt <= 'd0; // FIFO复位时,写计数器清零
    else if (wr_en) begin
        if (wr_cnt == CNT_MAX)
            wr_cnt <= 'd0; // 写计数器达到最大值时,计数器清零
        else
            wr_cnt <= wr_cnt + 1'b1; // 写使能时,计数器加1
    end
    else
        wr_cnt <= 'd0; // 非写使能时,计数器清零
end

// 数据输入端口连接写计数器加1
assign din = wr_cnt + 1'b1;

// 实例化FIFO模块
dc_fifo dc_fifo(
    .wr_clk(wr_clk),
    .rd_clk(rd_clk),
    .din(din),
    .wr_en(wr_en),
    .rd_en(rd_en),
    .dout(dout),
    .full(full),
    .empty(empty),
    .rd_data_count(rd_data_count),
    .wr_data_count(wr_data_count),
    .wr_rst_busy(wr_rst_busy),
    .rd_rst_busy(rd_rst_busy)
);

// 读时钟域的读使能信号生成
always @(posedge rd_clk or posedge fifo_rst) begin
    if (fifo_rst)
        rd_en <= 1'b0; // FIFO复位时,读使能置为0
    else if (rd_data_count == 200)
        rd_en <= 1'b1; // 读数据计数达到200时,读使能置为1
    else if (rd_cnt == CNT_MAX)
        rd_en <= 1'b0; // 读计数器达到最大值时,读使能置为0
    else
        rd_en <= rd_en; // 保持当前读使能状态
end

// 读计数器逻辑
always @(posedge rd_clk or posedge fifo_rst) begin
    if (fifo_rst)
        rd_cnt <= 'd0; // FIFO复位时,读计数器清零
    else if (rd_en) begin
        if (rd_cnt == CNT_MAX)
            rd_cnt <= 'd0; // 读计数器达到最大值时,计数器清零
        else
            rd_cnt <= rd_cnt + 1'b1; // 读使能时,计数器加1
    end
    else
        rd_cnt <= 'd0; // 非读使能时,计数器清零
end

endmodule

仿真代码

`timescale 1ns / 1ps
module tb_fifo_test();
    reg clk;
    reg rst_n;
    fifo_test fifo_test(
        .clk(clk),
        .rst_n(rst_n)
    );
    
    initial begin
        clk=1;
        forever begin
            #10 clk=~clk;
        end
    end
    
    initial begin
        rst_n=0;
        repeat(20) @(posedge clk);
        rst_n=1;
    end

endmodule

仿真结果

在这里插入图片描述
向 fifo 中以 100M 的时钟写入 1-200 这 200 个数据;从 fifo 中以 200M 的时钟读出这 200 个数
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值