异步FIFO verilog设计与仿真

目录

模块划分

代码设计

Modelsim仿真

模块划分

设计总共包含五个文件,分别是参数定义文件parameter.v,跨时钟同步模块synchronization.v,双口存储模块dual_ram.v,顶层模块fifo_asyn.v和仿真文件fifo_tb.v。

代码设计

parameter.v

`define DATA_WIDTH 8
`define ADDR_WIDTH 4
`define FREQUENCY_W 200000000
`define FREQUENCY_R 50000000

synchronization.v

`include "parameter.v"
module synchronization(
    input                       i_clk   ,
    input                       i_rst   ,
    input   [`ADDR_WIDTH : 0]   i_data  ,
    output  [`ADDR_WIDTH : 0]   o_data  );

/*--------------------------------parameter------------------------------*/

/*----------------------------------wire---------------------------------*/

/*----------------------------------reg----------------------------------*/
reg [`ADDR_WIDTH : 0] r_data_out;
reg [`ADDR_WIDTH : 0] r_data_delay;
/*---------------------------------assign--------------------------------*/
assign o_data = r_data_out;

/*---------------------------------always--------------------------------*/
always @(posedge i_clk or posedge i_rst) begin
    if (i_rst) begin
        r_data_delay <= {(`ADDR_WIDTH + 1){1'b0}};
        r_data_out   <= {(`ADDR_WIDTH + 1){1'b0}};
    end
    else begin
        r_data_delay <= i_data;
        r_data_out   <= r_data_delay;
    end
end

endmodule

dual_ram.v

`include "parameter.v"
module dual_ram(
    // 写信号
    input                           i_clk_write         ,
    input                           i_rst_write         ,
    input   [`DATA_WIDTH - 1 : 0]   i_data              ,   
    input   [`ADDR_WIDTH - 1 : 0]   i_addr_write        ,
    input                           i_write_en          ,
    // 读信号
    input                           i_clk_read          ,
    input                           i_rst_read          ,
    input   [`ADDR_WIDTH - 1 : 0]   i_addr_read         ,
    input                           i_read_en           ,
    output  [`DATA_WIDTH - 1 : 0]   o_data              ,
    // 空满信号
    input                           i_full              ,
    input                           i_empty             );
/*--------------------------------parameter------------------------------*/
integer i;

/*----------------------------------wire---------------------------------*/

/*----------------------------------reg----------------------------------*/
reg [`DATA_WIDTH - 1 : 0] mem [{`ADDR_WIDTH{1'b1}} : 0];
reg [`DATA_WIDTH - 1 : 0] r_data_out;

/*---------------------------------assign--------------------------------*/
assign o_data = r_data_out;

/*---------------------------------always--------------------------------*/
// 写fifo
always @(posedge i_clk_write or posedge i_rst_write) begin
    if (i_rst_write) begin
        for (i = 0; i < 2**`ADDR_WIDTH; i = i + 1) begin
            mem[i] <= `DATA_WIDTH'b0;
        end
    end
    else if ((!i_full) && i_write_en) begin // 非满就写
        mem[i_addr_write] <= i_data;
    end
end

// 读fifo
always @(posedge i_clk_read or posedge i_rst_read) begin
    if (i_rst_read) begin
        r_data_out <= `DATA_WIDTH'b0;
    end
    else if (i_read_en && (!i_empty)) begin// 非空就读
        r_data_out <= mem[i_addr_read];
    end
end

endmodule

fifo_asyn.v

`include "parameter.v"
module fifo_asyn(
    // 写信号
    input                           i_clk_write         ,
    input                           i_rst_write         ,
    input   [`DATA_WIDTH - 1 : 0]   i_data              ,   
    input                           i_write_en          ,
    // 读信号
    input                           i_clk_read          ,
    input                           i_rst_read          ,
    input                           i_read_en           ,
    output  [`DATA_WIDTH - 1 : 0]   o_data              ,
    // 空满信号
    output                          o_full              ,
    output                          o_empty             );

/*--------------------------------parameter------------------------------*/

/*----------------------------------wire---------------------------------*/
wire [`ADDR_WIDTH : 0] w_addr_write_gray;
wire [`ADDR_WIDTH : 0] w_addr_write_gray_syn;
wire [`ADDR_WIDTH : 0] w_addr_read_gray;
wire [`ADDR_WIDTH : 0] w_addr_read_gray_syn;                

wire w_full;
wire w_empty;

/*----------------------------------reg----------------------------------*/
reg [`ADDR_WIDTH : 0] r_addr_write;
reg [`ADDR_WIDTH : 0] r_addr_read;

/*---------------------------------assign--------------------------------*/
assign w_addr_write_gray = r_addr_write ^ (r_addr_write >> 1);
assign w_addr_read_gray  = r_addr_read  ^ (r_addr_read  >> 1);

assign w_full  = (w_addr_write_gray == {~w_addr_read_gray_syn[`ADDR_WIDTH : `ADDR_WIDTH - 1],w_addr_read_gray_syn[`ADDR_WIDTH - 2 : 0]}) ? 1'b1 : 1'b0;
assign w_empty = (w_addr_read_gray  == w_addr_write_gray_syn) ? 1'b1 : 1'b0;

assign o_full  = w_full;
assign o_empty = w_empty;

/*---------------------------------always--------------------------------*/
// 产生写地址
always @(posedge i_clk_write or posedge i_rst_write) begin
    if (i_rst_write) begin
        r_addr_write <= {(`ADDR_WIDTH + 1){1'b0}};
    end
    else if (i_write_en && (!w_full)) begin
        r_addr_write <= r_addr_write + 1;
    end
end

// 产生读地址
always @(posedge i_clk_read or posedge i_rst_read) begin
    if (i_rst_read) begin
        r_addr_read <= {(`ADDR_WIDTH + 1){1'b0}};
    end
    else if (i_read_en && (!w_empty)) begin
        r_addr_read <= r_addr_read + 1;
    end
end

/*----------------------------------inst---------------------------------*/
dual_ram ram(
    .i_clk_write    (i_clk_write                    ),
    .i_rst_write    (i_rst_write                    ),
    .i_data         (i_data                         ),
    .i_addr_write   (r_addr_write[0 +: `ADDR_WIDTH] ),
    .i_write_en     (i_write_en                     ),
    .i_clk_read     (i_clk_read                     ),
    .i_rst_read     (i_rst_read                     ),
    .i_addr_read    (r_addr_read[0 +: `ADDR_WIDTH]  ),
    .i_read_en      (i_read_en                      ),
    .o_data         (o_data                         ),
    .i_full         (w_full                         ),
    .i_empty        (w_empty                        ));

synchronization write_to_read(      
    .i_clk          (i_clk_read                     ),
    .i_rst          (i_rst_read                     ),
    .i_data         (w_addr_write_gray              ),
    .o_data         (w_addr_write_gray_syn          ));
synchronization read_to_write(      
    .i_clk          (i_clk_write                    ),
    .i_rst          (i_rst_write                    ),
    .i_data         (w_addr_read_gray               ),
    .o_data         (w_addr_read_gray_syn           ));

endmodule

Modelsim仿真

fifo_tb.v

`timescale 1ns/1ns
`include "parameter.v"
module fifo_tb();
reg                             i_clk_write ;
reg                             i_rst_write ;
reg     [`DATA_WIDTH - 1 : 0]   i_data      ;
reg                             i_write_en  ;
reg                             i_clk_read  ;
reg                             i_rst_read  ;
reg                             i_read_en   ;
wire    [`DATA_WIDTH - 1 : 0]   o_data      ;
wire                            o_full      ;
wire                            o_empty     ;

parameter CLK_WRITE = 1000000000/`FREQUENCY_W;
parameter CLK_READ = 1000000000/`FREQUENCY_R;


initial begin
    i_clk_write = 0;
    i_rst_write = 0;
    i_clk_read  = 0;
    i_rst_read  = 0;
    #10
    i_rst_write = 1;
    i_rst_read  = 1;
    #100
    i_rst_write = 0;
    i_rst_read  = 0;
end

initial begin
    i_write_en = 0;
    forever begin
        #({$random}%200) i_write_en = ~i_write_en;
    end
end

initial begin
    i_read_en = 0;
    forever begin
        #({$random}%200) i_read_en = ~i_read_en;
    end
end


initial begin
    i_data = 0;
    forever begin
        #({$random}%20) i_data = {$random}%256;
    end
end


always #CLK_WRITE i_clk_write = ~i_clk_write;
always #CLK_READ i_clk_read = ~i_clk_read;


fifo_asyn inst(
    .i_clk_write(i_clk_write),
    .i_rst_write(i_rst_write),
    .i_data     (i_data     ),
    .i_write_en (i_write_en ),
    .i_clk_read (i_clk_read ),
    .i_rst_read (i_rst_read ),
    .i_read_en  (i_read_en  ),
    .o_data     (o_data     ),
    .o_full     (o_full     ),
    .o_empty    (o_empty    ));

endmodule

仿真结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值