论文参考:The Design and Verification of a Synchronous First-In First-Out

博客参考:【原创】异步FIFO设计原理详解 (含RTL代码和Testbench代码)_锤王马加爵的博客-CSDN博客_fifo testbenchFIFO在硬件上是一种地址依次自增的Single Dul RAM,按读数据和写数据工作的时钟域是否相同分为同步FIFO和异步FIFO,其中同步FIFO是指读时钟和写时钟为同步时钟,常用于数据缓存和数据位宽转换;异步FIFO通常情况下是指读时钟和写时钟频率有差异,即由两个异步时钟驱动的FIFO,由于读写操作是独立的,故常用于多比特数据跨时钟域处理。本文仅讨论异步FIFO的设计。 因为FIFO的硬件本质是一块Single Dul RAM,无论它的内部结构和原理如何复杂,最核心的...https://blog.csdn.net/qq_40807206/article/details/109555162

代码中省略了转为格雷码的步骤,读者可自行添加。

1.write_control.v

//FIFO parameters
`define FIFO_DEPTH 64
`define FIFO_MEM_ADDR_WIDTH 6
`define FIFO_HALFFULL 4

module write_control (
    input reset,
    input clk_write_logic,
    input wire [`FIFO_MEM_ADDR_WIDTH:0] read_pointer,
    input write_request,
    output reg w_enable,
    output reg write_ack,
    output reg [`FIFO_MEM_ADDR_WIDTH:0] write_pointer,
    output reg full_fifo_status,
    output reg halffull_fifo_status,
    input wire wc_scan_in0,// test scan mode data input
    // wc_scan_en, // test scan mode enable
    // wc_test_mode, // test mode select
    // output wc_scan_out0, // test scan mode data,
    output wire [`FIFO_MEM_ADDR_WIDTH-1:0] mem_addr_read,
    output reg [`FIFO_MEM_ADDR_WIDTH:0] rd_ff1,            // 读地址同步寄存器1
    output reg [`FIFO_MEM_ADDR_WIDTH:0] rd_ff2,            // 读地址同步寄存器2
    input reg init_done
    );

wire [`FIFO_MEM_ADDR_WIDTH-1:0] mem_addr_write;

assign mem_addr_read = read_pointer [`FIFO_MEM_ADDR_WIDTH-1:0];
    assign mem_addr_write = write_pointer [`FIFO_MEM_ADDR_WIDTH-1:0];
    
    //full_fifo_status = (111 111=63) && (1),这是写满?出现(read_pointer=7'h66 write_pointer=7'h3f)、(7'h28 7'h7f)等为写满的情况
    //assign full_fifo_status = ((mem_addr_write == `FIFO_DEPTH - 1) && (read_pointer[`FIFO_MEM_ADDR_WIDTH] ^ write_pointer[`FIFO_MEM_ADDR_WIDTH]));

// 读地址同步至写时钟域
    always @(posedge clk_write_logic or posedge reset) begin
        if(!reset) begin
            rd_ff1 <= 'b0;
            rd_ff2 <= 'b0;
        end
        else begin
            rd_ff1 <= read_pointer;
            rd_ff2 <= rd_ff1;
        end
    end

//写使能判断
    // assign w_enable = (write_request && (full_fifo_status==0))?1:0;
    always @(*) begin
        // 写数据
        if(init_done) begin
            if(write_request == 1'b1 && full_fifo_status == 1'b0)begin
                w_enable = 1;
            end
            else begin
                w_enable = 0;
            end
        end
    end

// 写地址自加一
    always@(posedge clk_write_logic or posedge reset) begin
        if(!reset) begin
            write_pointer <= 0;
            write_ack <= 0;
        end
        else begin
            //将满也不是64-mem_addr_write[5:0],应该是本地写指针减去同步过来的读指针
            //halffull_fifo_status = ((`FIFO_DEPTH - mem_addr_write)<=(`FIFO_HALFFULL))?1:0;//逻辑小于等于
            // $display("halffull_fifo_status=%b",halffull_fifo_status);
            if(w_enable==1'b1 && full_fifo_status==1'b0) begin
                write_ack <= 1;
                write_pointer <= write_pointer + 1'b1;
            end
            else
                write_ack <= 0;
        end
    end

//将满判断
    // assign full_fifo_status = (rd_ff2[`FIFO_MEM_ADDR_WIDTH]!=write_pointer[`FIFO_MEM_ADDR_WIDTH]) && (rd_ff2[`FIFO_MEM_ADDR_WIDTH-1:0]==write_pointer[`FIFO_MEM_ADDR_WIDTH-1:0])?1:0;
    always @(*) begin
        if(write_pointer[`FIFO_MEM_ADDR_WIDTH]==0 && rd_ff2[`FIFO_MEM_ADDR_WIDTH]==1)begin
            halffull_fifo_status = (`FIFO_DEPTH - (write_pointer + 2*`FIFO_DEPTH - rd_ff2)<=(`FIFO_HALFFULL))?1:0;
            $display("half_01=%b",halffull_fifo_status);
        end
        else begin
            halffull_fifo_status = (`FIFO_DEPTH - (write_pointer - rd_ff2)<=(`FIFO_HALFFULL))?1:0;
            $display("half=%b",halffull_fifo_status);
        end
        
    end

//写满判断
    always @(*) begin
        if((rd_ff2[`FIFO_MEM_ADDR_WIDTH]!=write_pointer[`FIFO_MEM_ADDR_WIDTH]) && (rd_ff2[`FIFO_MEM_ADDR_WIDTH-1:0]==write_pointer[`FIFO_MEM_ADDR_WIDTH-1:0])) begin
            full_fifo_status = 1'b1;
        end
        else begin
            full_fifo_status = 1'b0;
        end
    end
endmodule

2.read_control.v

//FIFO parameters
`define FIFO_DEPTH 64
`define FIFO_MEM_ADDR_WIDTH 6
`define FIFO_HALFEMPTY 4module read_control (input reset,input clk_read_logic,input wire [`FIFO_MEM_ADDR_WIDTH:0] write_pointer,input read_request,output reg r_enable,output reg read_ack,output reg [`FIFO_MEM_ADDR_WIDTH:0] read_pointer,output reg empty_fifo_status,output reg halfempty_fifo_status,input wire rc_scan_in0,input wire rc_scan_en,input wire rc_test_mode,output rc_scan_out0,output reg [`FIFO_MEM_ADDR_WIDTH:0] wr_ff1,          // 写地址同步寄存器1output reg [`FIFO_MEM_ADDR_WIDTH:0] wr_ff2,            // 写地址同步寄存器2input reg init_done);wire [`FIFO_MEM_ADDR_WIDTH-1:0] mem_addr_read;wire [`FIFO_MEM_ADDR_WIDTH-1:0] mem_addr_write;assign mem_addr_read = read_pointer [`FIFO_MEM_ADDR_WIDTH-1:0];assign mem_addr_write = write_pointer [`FIFO_MEM_ADDR_WIDTH-1:0];// always @(*) begin//     $display("$time=%p, mem_addr_read=%h", $time, mem_addr_read);//     $display("$time=%p, mem_addr_write=%h",$time, mem_addr_write);// endalways@(posedge clk_read_logic or posedge reset) beginif(!reset) beginread_pointer <= 0;read_ack <= 0;end// else begin//halfempty_fifo_status = ((mem_addr_read)<=(`FIFO_HALFEMPTY))?1:0;//读指针自加1if(r_enable) beginread_ack <= 1;read_pointer <= read_pointer + 1'b1;endelseread_ack <= 0;// endend// 写地址同步至读时钟域always @(posedge clk_read_logic or posedge reset) begin// rdclk是wrclk的两倍,因为写要快点,所以时间短节奏快,波形密if(!reset) beginwr_ff1 <= 'b0;wr_ff2 <= 'b0;endelse beginwr_ff1 <= write_pointer;wr_ff2 <= wr_ff1;endend//读使能判断// assign r_enable = (read_request && (empty_fifo_status==0))?1:0;always @(*) begin//读数据if(init_done) beginif( read_request == 1'b1 && empty_fifo_status == 1'b0 )beginr_enable = 1;endelse beginr_enable = 0;endendend//将空判断always @(*) beginhalfempty_fifo_status = ((wr_ff2 - read_pointer)<=(`FIFO_HALFEMPTY))?1:0;end//读空判断// assign empty_fifo_status = ((mem_addr_read == 0) && (mem_addr_write == 0) && read_pointer[`FIFO_MEM_ADDR_WIDTH] == write_pointer[`FIFO_MEM_ADDR_WIDTH])?1:0;always @(*) beginif( wr_ff2==read_pointer ) beginempty_fifo_status = 1'b1;endelse beginempty_fifo_status = 1'b0;endendendmodule

3.memory_array.v

 //FIFO parameters
`define MEM_ADDR_WIDTH 6
`define MEM_DEPTH 64
`define MEM_DATA_WIDTH 16module memory_array (input reset,input clk_write_logic,input clk_read_logic,input [`MEM_ADDR_WIDTH-1:0] w_addr,input [`MEM_ADDR_WIDTH-1:0] r_addr,input w_enable,input r_enable,input reg [`MEM_DATA_WIDTH-1:0] w_data,input reg mem_scan_in0,input reg mem_scan_en,input reg mem_test_mode,output reg [`MEM_DATA_WIDTH-1:0] r_data,output mem_scan_out0);reg [`MEM_DATA_WIDTH-1:0] memory [0:`MEM_DEPTH-1];always @(posedge clk_write_logic) beginif(w_enable)memory[w_addr] <= w_data;// $display("memory = 'p%p", memory);//64*16endalways @(posedge clk_read_logic or posedge reset) beginif(!reset)r_data <= 'b0;else if(r_enable)r_data <= memory[r_addr];endendmodule

4.SFIFO.v

`define FIFO_DEPTH 64
`define FIFO_MEM_ADDR_WIDTH 6
`define FIFO_MEM_DATA_WIDTH 16
`define FIFO_HALFEMPTY 4
`define FIFO_HALFFULL 4`include "write_control.v"
`include "read_control.v"
`include "memory_array.v"
module SFIFO (input reset,// system resetinput wire init_done,clk_write_logic,clk_read_logic,read_request,write_request,halffull_fifo_status,//it is input or output?write_ack,input wire [`FIFO_MEM_DATA_WIDTH-1:0] w_data,input wire scan_in0, // test scan mode data inputinput wire scan_en, // test scan mode enableinput wire test_mode, // test mode selectoutput wire [`FIFO_MEM_DATA_WIDTH-1:0] r_data,output wire read_ack,output w_enable,output r_enable,output empty_fifo_status,output wire halfempty_fifo_status,output full_fifo_status,output wire scan_out0, // test scan mode data output,output wire [`FIFO_MEM_ADDR_WIDTH:0] rd_ff1,         // 读地址同步寄存器1output wire [`FIFO_MEM_ADDR_WIDTH:0] rd_ff2,           // 读地址同步寄存器2output wire [`FIFO_MEM_ADDR_WIDTH:0] wr_ff1,           // 写地址同步寄存器1output wire [`FIFO_MEM_ADDR_WIDTH:0] wr_ff2            // 写地址同步寄存器2);wire [`FIFO_MEM_ADDR_WIDTH:0] read_pointer;wire [`FIFO_MEM_ADDR_WIDTH:0] write_pointer;wire [`FIFO_MEM_ADDR_WIDTH-1:0] w_addr;wire [`FIFO_MEM_ADDR_WIDTH-1:0] r_addr;assign w_addr = write_pointer [`FIFO_MEM_ADDR_WIDTH-1:0];assign r_addr = read_pointer [`FIFO_MEM_ADDR_WIDTH-1:0];read_control READ_CONTROL_MOD (.reset                  (reset),.clk_read_logic         (clk_read_logic),.write_pointer          (write_pointer),.read_request           (read_request),.r_enable               (r_enable),.read_ack               (read_ack),.read_pointer           (read_pointer),.empty_fifo_status      (empty_fifo_status),.halfempty_fifo_status  (halfempty_fifo_status),.rc_scan_in0            (scan_in0),.rc_scan_en             (scan_en),.rc_test_mode           (test_mode),.rc_scan_out0           (scan_out0),.wr_ff1                 (wr_ff1),.wr_ff2                 (wr_ff2),.init_done              (init_done));write_control WRITE_CONTROL_MOD (.reset                  (reset),.clk_write_logic        (clk_write_logic),.read_pointer           (read_pointer),.write_request          (write_request),.w_enable               (w_enable),.write_ack              (write_ack),.write_pointer          (write_pointer),.full_fifo_status       (full_fifo_status),.halffull_fifo_status   (halffull_fifo_status),.wc_scan_in0            (scan_in0),// .wc_scan_en             (scan_en),// .wc_test_mode           (test_mode),// .wc_scan_out0           (scan_out0),.rd_ff1                 (rd_ff1),.rd_ff2                 (rd_ff2),.init_done              (init_done));memory_array MEM_ARRAY_MOD (.reset              (reset),.clk_write_logic    (clk_write_logic),.clk_read_logic     (clk_read_logic),.w_addr             (w_addr),.r_addr             (r_addr),.w_enable           (w_enable),.r_enable           (r_enable),.w_data             (w_data),.r_data             (r_data),.mem_scan_in0       (scan_in0),.mem_scan_en        (scan_en),.mem_test_mode      (test_mode),.mem_scan_out0      (scan_out0));endmodule

5.test_tb.v

// `timescale 1ns / 1ns
`timescale 1ns/100ps
`include "SFIFO.v"module SFIFO_tb;parameter DATA_WIDTH = 16               ;reg                 reset               ;// 写时钟域tb信号定义reg                    clk_write_logic     ;reg                    write_request       ;reg[DATA_WIDTH-1:0]    w_data              ;wire               full_fifo_status    ;// 读时钟域tb信号定义reg                   clk_read_logic      ;reg                    read_request        ;wire[DATA_WIDTH-1:0]r_data             ;wire               empty_fifo_status   ;// testbench自定义信号reg                   init_done           ;       // testbench初始化结束// FIFO初始化initial  begin// 输入信号初始化reset                 = 1   ;clk_write_logic      = 0  ;clk_read_logic           = 0  ;write_request         = 0 ;read_request          = 0 ;w_data                = 'b0 ;init_done             = 0  ;// FIFO复位#30 reset             = 0   ;write_request     = 0  ;read_request      = 0 ;#30 reset             = 1   ;write_request     = 1   ;read_request      = 1 ;// 初始化完毕#30 init_done         = 1   ;if (init_done)beginrepeat(1000)begin             #4 read_request  = 1;write_request = 1;                                   #8 read_request  = 0;//读请求 高两周期 低一周期 循环1000次write_request = 0;//写请求 高两周期 低一周期 循环1000次endrepeat(1000)begin#8 write_request = 1;                      read_request  = 1;//写读请求 一直高两周期 循环1000次endrepeat(1000)begin             #4 read_request  = 0;write_request = 0;                                   #8 read_request  = 1;//读请求 低两周期 高一周期 循环1000次write_request = 1;//写请求 低两周期 高一周期 循环1000次endrepeat(1000)begin#8 write_request = 1;#4 write_request = 0;//写请求 高一周期 低两周期 读请求一直高电平 循环1000次endrepeat(1000)beginwrite_request = 1;//写请求80次,一次4nsread_request  = 0;#320 read_request  = 1;//读请求35次write_request = 0;#140 write_request = 1;//写请求10次read_request  = 0;#40  read_request  = 1;//读请求10次write_request = 0;#40  write_request = 1;//写请求35次read_request  = 0;#140 read_request  = 1;//读请求160次write_request = 0;#640;endrepeat(1000)begin     write_request   = 1;//写请求一直高电平#4 read_request    = 1;#8 read_request    = 0;//读请求 高两周期 低一周期  循环1000次endendend// 写时钟 写快读慢always#2 clk_write_logic = ~clk_write_logic;// 读时钟always#4 clk_read_logic = ~clk_read_logic;//再开一个initial write_request和read_request会乱// repeat(10)begin//     if (init_done)//        if(clk_write_logic)//           write_request = 1;//           read_request = 1;//            #8; //          write_request = 0;//写请求 高两周期 低两周期 循环1000次//            read_request = 0;//读请求 高两周期 低两周期 循环1000次           //          #4; // end// read_request = 1;// end// 写入数据自增always @(posedge clk_write_logic) beginif(init_done) beginif( write_request==1'b1 && full_fifo_status == 1'b0 )beginw_data <= w_data + 1;// $display("w_data = 'h%h", w_data);endelsew_data <= w_data;endelse beginw_data <= 'b0;endendSFIFO SFIFO_inst1 (.reset                 (reset                 ),.clk_write_logic       (clk_write_logic       ),.clk_read_logic        (clk_read_logic        ),.read_request          (read_request          ),.w_data                (w_data                ),.write_request         (write_request         ),.r_data                (r_data                ),.read_ack              (read_ack              ),.w_enable              (w_enable              ),.r_enable              (r_enable              ),.empty_fifo_status     (empty_fifo_status     ),.halfempty_fifo_status (halfempty_fifo_status ),.full_fifo_status      (full_fifo_status      ),.halffull_fifo_status  (halffull_fifo_status  ),.write_ack             (write_ack             ),.scan_in0              (scan_in0              ),.scan_en               (scan_en               ),.test_mode             (test_mode             ),.scan_out0             (scan_out0             ),.init_done             (init_done             ));
endmodule

异步fifo设计及验证verilog代码相关推荐

  1. 异步FIFO设计:各个模块的作用及Verilog代码详解

    实现原理参考:异步FIFO---Verilog实现_alangaixiaoxiao的博客-CSDN博客_异步fifo 代码参考:IC基础(一):异步FIFO_MaoChuangAn的博客-CSDN博客 ...

  2. 02【Verilog实战】异步FIFO设计(附源码RTL/TB)

    脚 本:makefile 工 具:vcs 和 verdi 文 章:1. 同步FIFO的设计和功能验证(附源码)     2. Verilog的亚稳态现象和跨时钟域处理方法 写在前面 这个专栏的内容记录 ...

  3. 异步FIFO基本原理(基于Verilog的简单实现)

    参考文献: [1]彭莉, 秦建业, 付宇卓. 异步FIFO的设计与验证[J]. 计算机工程与应用, 2005, 41(3):4. [2]魏芳, 刘志军, 马克杰. 基于Verilog HDL的异步FI ...

  4. 基于FPGA的异步FIFO设计

    今天要介绍的异步FIFO,可以有不同的读写时钟,即不同的时钟域.由于异步FIFO没有外部地址端口,因此内部采用读写指针并顺序读写,即先写进FIFO的数据先读取(简称先进先出).这里的读写指针是异步的, ...

  5. 【FIFO】异步 FIFO 设计

    目录 写在前面 简介 传递多个异步信号 同步 FIFO 指针 异步FIFO指针 二进制 FIFO 指针注意事项 FIFO测试问题 格雷码计数器 ‑ 样式 #1 格雷码模式 格雷码计数器基础 额外的格雷 ...

  6. 异步FIFO设计详解

    目录 一.FIFO介绍 二.FIFO的"空"/"满"检测 三.同步化分析 四.异步FIFO设计与结构 一.FIFO介绍 FIFO存储器概念介绍_的博客-CSDN ...

  7. 异步fifo_【推荐】数字芯片异步FIFO设计经典论文

    之前有一篇文章我已经推荐过了数字芯片跨时钟域设计的经典论文 ([推荐]数字芯片跨时钟域设计经典论文 ),希望看过的读者都有一定的收获.不过有点遗憾的是那片论文中虽然提到了异步FIFO,却没有讲具体的原 ...

  8. 异步fifo_异步FIFO设计

    由于知乎编辑器对markdown支持性问题,本文为直接上传markdown文档,格式混乱且图像不全,格式完整版请移步个人博客 异步FIFO设计​qiankun214.github.io 1.设计目标 ...

  9. 基于 FPGA 的高级数字电路设计(7)单口 RAM、同步 FIFO、异步 FIFO 设计

    一.单口 RAM 设计 module BRAM_PORTA( input clka, input ena, input wea, input [3:0] addra, input [15:0] din ...

最新文章

  1. linux下helloworld的简单编译过程
  2. SQLSERVER拆分字符串的函数(表值函数)
  3. bzoj1070: [SCOI2007]修车
  4. 听说你想去大厂看妹子,带你看看字节跳动数据挖掘面试是啥样?
  5. 10+ commonly using find command switches with example Unix/Linux
  6. java 整数溢出检测,Java如何处理整数下溢和溢出以及如何检查它?
  7. 关于cp命令中拷贝所有的写法
  8. spring cloud 入门系列七:基于Git存储的分布式配置中心--Spring Cloud Config
  9. 安卓应用安全指南 4.6.3 处理文件 高级话题
  10. 什么是lambda(函数)?
  11. c语言中isdigit函数_在C / C ++中使用isdigit()
  12. 架构 简述负载均衡和CDN技术
  13. 【技术白皮书】第四章:信息抽取技术产业应用现状及案例(下)
  14. eclipse php使用方法,Eclipse PHPEclipse 配置的具体步骤
  15. QQ群排名优化规则-学会后10分钟全国排名第一
  16. Choerodon猪齿鱼1.0先行版已发布!
  17. 优锘科技:数字孪生如何与新基建摩擦出智慧火花
  18. Java打造RPC框架(二):11个类实现简单Java RPC
  19. 使用Pixelmator Pro修饰照片
  20. YBTOJ反素数洛谷P1463(数论)

热门文章

  1. 利用快递100来获取快递信息-java
  2. 农夫过河狼羊白菜Java开放封闭_农夫过河——狼羊菜问题
  3. 《Web安全之机器学习入门》笔记:第九章 9.4 支持向量机算法SVM 检测DGA域名
  4. java服务器下载jpg等静态资源方法
  5. Java——线程插队_join ()方法来实现“插队功能”
  6. python输出宽度是什么意思_python字符串格式化输出的时候类似{0:.3f}是什么意思?...
  7. 【论文--文献格式】
  8. 使用隐含Trace参数诊断Oracle Data Pump(expdp)故障
  9. 智能照明系统优势与特点
  10. Unity Shader学习笔记 - 用UV动画实现沙滩上的泡沫