-
- 读数据:
- module r_ctrl (
- input wire r_clk,//读时钟
- input wire rst_n,
- input wire r_en,//读使能
- input wire [8:0] w_gaddr,//写时钟域中的写地址指针
- output reg r_empty,//读空标志
- output wire [8:0] r_addr,//读地址二进制
- output wire [8:0] r_gaddr//读格雷码地址
- );
- reg [8:0] addr;
- reg [8:0] gaddr;
- wire [8:0] addr_wire;
- wire [8:0] gaddr_wire;
- reg [8:0] w_gaddr_d1,w_gaddr_d2;
- wire r_empty_wire;
- //打两拍进行时钟同步
- always @(posedge r_clk or negedge rst_n)
- if(rst_n == 1'b0)
- {w_gaddr_d2,w_gaddr_d1} <= 18'd0;
- else
- {w_gaddr_d2,w_gaddr_d1} <= {w_gaddr_d1,w_gaddr};
- //二进制的读地址
- assign r_addr = addr;
- always @(posedge r_clk or negedge rst_n)
- if(rst_n == 1'b0)
- addr <=9'd0;
- else
- addr <= addr_wire;
- assign addr_wire = addr + ((~r_empty)&r_en);
- //格雷码的读地址
- assign r_gaddr = gaddr;
- assign gaddr_wire = (addr_wire >>1 )^ addr_wire;
- always @(posedge r_clk or negedge rst_n)
- if(rst_n == 1'b0)
- gaddr <= 9'd0;
- else
- gaddr <= gaddr_wire;
-
- //读空标志的产生
- assign r_empty_wire =(gaddr_wire == w_gaddr_d2);
- always @(posedge r_clk or negedge rst_n)
- if(rst_n == 1'b0)
- r_empty<=1'b1;
- else //if(gaddr_wire == w_gaddr_d2)//根据仿真验证一下打两拍对空满标志的影响???
- r_empty <= r_empty_wire;
- //else
- //r_empty <= 1'b0;
- endmodule
- 下面是fifo_mem实现:
- module fifomem(
- input wire w_clk,
- input wire r_clk,
- input wire w_en,//来自于FIFO的写控制模块
- input wire w_full,//来自于FIFO的写控制模块
- input wire [7:0] w_data,//来自于外部数据源
- input wire [8:0] w_addr,//来自于FIFO的写控制模块
- input wire r_empty,//来自于FIFO的读控制模块
- input wire [8:0] r_addr,//来自于FIFO的读控制模块
- input wire rst_n,
- output reg [7:0] r_data//读数据是从内部ram中读取
- );
- reg [7:0]data_mem[255:0];
- wire [7:0]w_addr_r;//定义写入地址
- wire [7:0]r_addr_r;//定义写入地址
- integer i;
- assign w_addr_r = w_addr[7:0];
- assign r_addr_r = r_addr[7:0];
- //写入数据
- always@(posedge w_clk or negedge rst_n)
-
- if(!rst_n)begin
-
- for(i = 0;i < 256;i = i + 1)begin
- data_mem[i] <= 8'b0;
- end
- end
-
- else if(w_en &&(!w_full))//防止写溢出,如果已经满了禁止写数据
- data_mem[w_addr_r] <= w_data;
- //读出数据
- always@(posedge r_clk or negedge rst_n)
- if(!rst_n)
- r_data <= 0;
- else
- r_data <=data_mem[r_addr_r];
- endmodule
- 下面是顶层模块:
- module ex_fifo(
- input wire w_clk,
- input wire r_clk,
- input wire rst_n,
- input wire w_en,
- input wire [7:0] w_data,
- output wire w_full,
- input wire r_en,
- output wire [7:0] r_data,
- output wire r_empty
- );
- wire [8:0] r_gaddr;
- wire [8:0] w_addr;
- wire [8:0] w_gaddr;
- wire [8:0] r_addr;
- w_ctrl w_ctrl_inst(
- .w_clk (w_clk),//写时钟
- .rst_n (rst_n),//复位
- .w_en (w_en),//写使能
- .r_gaddr (r_gaddr),//读时钟域过来的格雷码读地址指针
- .w_full (w_full),//写满标志
- .w_addr (w_addr),//256深度的FIFO写二进制地址
- .w_gaddr (w_gaddr)//写FIFO地址格雷码编码
- );
- fifomem fifomem_inst(
- .w_clk (w_clk),
- .r_clk (r_clk),
- .w_en (w_en),//来自于FIFO的写控制模块
- .w_full (w_full),//来自于FIFO的写控制模块
- .w_data (w_data),//来自于外部数据源
- .w_addr (w_addr),//来自于FIFO的写控制模块
- .r_empty (r_empty),//来自于FIFO的读控制模块
- .r_addr (r_addr),//来自于FIFO的读控制模块
- .r_data (r_data),//读数据是从内部ram中读取
- .rst_n(rst_n)
- );
- r_ctrl r_ctrl_inst(
- .r_clk (r_clk),//读时钟
- .rst_n (rst_n),
- .r_en (r_en),//读使能
- .w_gaddr (w_gaddr),//写时钟域中的写地址指针
- .r_empty (r_empty),//读空标志
- .r_addr (r_addr),//读地址二进制
- .r_gaddr (r_gaddr)//读格雷码地址
- );
- endmodule
- 下面是testbench:
- `timescale 1ns/1ns
- module tb_ex_fifo;
- reg r_clk,w_clk,rst_n;
- reg w_en;
- reg [7:0] w_data;
- reg r_en;
- wire w_full;
- wire r_empty;
- wire [7:0] r_data;
- parameter CLK_P=20;
- initial begin
- rst_n<=0;
- r_clk<=0;
- w_clk<=0;
-
- #200
- rst_n=1;
- end
- //写的初始化模块
- initial begin
- w_en=0;
- w_data=0;
- #300
- write_data(256);
- end
- //读的初始化模块
- initial begin
- r_en =0;
- @(posedge w_full);
- #40;
- read_data(256);
- end
- always #(CLK_P/2) r_clk =~r_clk;
- always #(CLK_P/2) w_clk =~w_clk;
- ex_fifo ex_fifo_inst(
- .w_clk (w_clk),
- .r_clk (r_clk),
- .rst_n (rst_n),
- .w_en (w_en),
- .w_data (w_data),
- .w_full (w_full),
- .r_en (r_en),
- .r_data (r_data),
- .r_empty (r_empty)
- );
- task write_data(len);
- integer i,len;
- begin
- for (i=0;i<len;i=i+1)
- begin
- @(posedge w_clk);
- w_en=1'b1;
- w_data=i;
- end
- @(posedge w_clk);
- w_en = 1'b0;
- w_data =0;
- end
- endtask
- task read_data(len);
- integer i,len;
- begin
- for (i=0;i<len;i=i+1)
- begin
- @(posedge r_clk);
- r_en=1'b1;
- end
- @(posedge r_clk);
- r_en = 1'b0;
- end
- endtask
- endmodule
- 自己用modelsim仿真脚本如下:
- quit -sim
- .main clear
- vlib work
- vlog ./tb_ex_fifo.v
- vlog ./../design/*.v
- vsim -voptargs=+acc work.tb_ex_fifo
- add wave tb_ex_fifo/*
- add wave tb_ex_fifo/ex_fifo_inst/*
- add wave -divider {w}
- add wave tb_ex_fifo/ex_fifo_inst/w_ctrl_inst/*
- add wave -divider {R}
- add wave tb_ex_fifo/ex_fifo_inst/r_ctrl_inst/*
- run 25us