异步fifo设计(四)

时间:2022-11-21 23:32:39

这篇文章主要是上篇文章的verilog代码实现,现在将代码贴上:

module fifo #(parameter size_data=8,
parameter size_addr=4)
(input wr_inc,wr_clk,wr_rst,
input rd_inc,rd_clk,rd_rst,
input [size_data-1:0]wr_data,
output wr_full,rd_empty,
output [size_data-1:0]rd_data);

wire [size_addr-1:0] wr_addr,rd_addr;
wire [size_addr:0]wr_ptr,rd_ptr,wq2_rd_ptr,rq2_wr_ptr;


cmp m1(rd_ptr,wr_ptr,wr_rst,full_flag,empty_flag);
ram_fifo m2(wr_clk,wr_addr,wr_data,wr_inc,rd_addr,rd_data);
rd_empty m3(rd_clk,rd_inc,rd_rst,empty_flag,rd_empty,rd_ptr);
wr_full m4(wr_clk,wr_rst,wr_inc,full_flag,wr_ptr,wr_full);
endmodule

module fifo_ram(wr_clk,wr_addr,wr_data,wr_inc,rd_addr,rd_data);
parameter size_addr=4;
parameter size_data=8;
parameter depth=1<<size_addr;
input wr_clk;
input [size_addr-1:0] wr_addr;
input [size_data-1:0] wr_data;
input wr_inc;
input [size_addr-1:0] rd_addr;
output[size_data-1:0] rd_data;

wire [size_data-1:0] rd_data;
reg [size_data-1:0] ram[depth-1:0];
assign rd_data=ram[rd_addr];

always@(posedge wr_clk)
begin
if(wr_inc) ram[wr_addr]<=wr_data;//时序逻辑要用非阻塞赋值,要养成编码习惯
end

endmodule

module cmp(rd_ptr,wr_ptr,wr_rst,full_flag,empty_flag);
parameter size_addr=4;
parameter size_data=8;
parameter high=1;
input [size_addr-1:0]rd_ptr,wr_ptr;
input wr_rst;
output full_flag,empty_flag;
wire full_flag,empty_flag;

wire dir_set,dir_clr;
reg dir;
wire equal_ptr;

assign equal_ptr=(rd_ptr==wr_ptr);

assign dir_set=~(wr_ptr[size_addr-1]^rd_ptr[size_addr-2])& ~(wr_ptr[size_addr-2]^rd_ptr[size_addr-1]);
assign dir_dir=~((~(wr_ptr[size_addr-2]^rd_ptr[size_addr-1])&(wr_ptr[size_addr-1]^rd_ptr[size_addr-2]))|(!wr_rst));

always@(dir_set or dir_dir)
begin
if(!dir_set)dir=1;
else if(!dir_clr) dir=0;
else dir=high;
end

assign full_flag=~(dir&&equal_ptr);
assign empty_flag=~(~dir&&equal_ptr);
endmodule


module rd_empty (rd_clk,rd_inc,rd_rst,empty_flag,rd_empty,rd_ptr);
parameter size_addr=4;
parameter size_data=8;

input rd_clk,rd_inc,rd_rst;
input empty_flag;
output [size_addr-1:0]rd_ptr;
output rd_empty;
reg [size_addr-1:0]rd_ptr;
reg rd_empty;
reg rd_empty_temp;

reg [size_addr-1:0] rd_bin;
wire [size_addr-1:0] rd_bin_next,rd_grey_next;

assign rd_bin_next=rd_bin+(rd_inc&(!rd_empty));
assign rd_grey_next=rd_bin_next<<1 ^ rd_bin_next;

always@(posedge rd_clk or negedge rd_rst)
begin
if(!rd_rst)
begin
rd_ptr<=0;
rd_bin<=0;
end
else
begin
rd_bin<=rd_bin_next;
rd_ptr<=rd_grey_next;
end
end

always@(posedge rd_clk or negedge empty_flag)
begin
if(!empty_flag) {rd_empty,rd_empty_temp}<=2'b11;//空状态
else {rd_empty,rd_empty_temp}<={rd_empty_temp,~empty_flag};//同步器
end

endmodule


module wr_ful(wr_clk,wr_rst,wr_inc,full_flag,wr_ptr,wr_full);
parameter size_addr=4;
parameter size_data=8;
input wr_clk,wr_rst,wr_inc;
input full_flag;
output [size_addr-1:0] wr_ptr;
output wr_full;
reg [size_addr-1:0] wr_ptr;
reg wr_full;
reg wr_full_temp;

reg [size_addr-1:0] wr_bin;
wire[size_addr-1:0] wr_bin_next,wr_grey_next;

assign wr_bin_next=wr_bin+(wr_inc & (!wr_full));
assign wr_grey_next=wr_bin_next<<1 ^ wr_bin_next;

always@(posedge wr_clk or negedge wr_rst)
begin
if(!wr_rst)
begin
wr_bin<=0;
wr_ptr<=0;
end
else
begin
wr_bin<=wr_bin_next;
wr_ptr<=wr_grey_next;
end
end

always@(posedge wr_clk or negedge full_flag or negedge wr_rst)//注意不能忽略写复位
begin
if(!full_flag) {wr_full,wr_full_temp}<=2'b11;
else if(!wr_rst) {wr_full,wr_full_temp}<=2'b00;
else {wr_full,wr_full_temp}<={wr_full_temp,~full_flag};
end
endmodule