目录
模块划分
设计总共包含五个文件,分别是参数定义文件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
仿真结果