module gm_fifo_pingpang(
input wire clk ,
input wire rst_n ,
input wire [7:0] data_in ,
input wire wr_en ,
output reg fifo1_wr_en ,
output reg fifo2_wr_en ,
output reg fifo1_rd_en ,
output reg fifo2_rd_en ,
output wire [7:0] data_out
);
wire [8:0] fifo_cnt1;
wire [8:0] fifo_cnt2;
wire [7:0] data_out1;
wire [7:0] data_out2;
parameter idle = 4'b0000,
start = 4'b0001,
ping = 4'b0010,
pang = 4'b0100;
reg[3:0]state;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
state <= idle;
fifo1_wr_en <= 1'b0;
fifo2_wr_en <= 1'b0;
end
else
begin
case(state)
idle:begin
fifo1_wr_en <= 1'b0;
fifo2_wr_en <= 1'b0;
fifo1_rd_en <= 1'b0;
fifo2_rd_en <= 1'b0;
if(wr_en)
state <= start;
else
state <= idle;
end
start:begin
fifo1_wr_en <= 1'b1;
fifo2_wr_en <= 1'b0;
fifo1_rd_en <= 1'b0;
fifo2_rd_en <= 1'b1;
if(fifo_cnt1 == 500)
state <= ping;
else
state <= start;
end
ping:begin
fifo1_wr_en <= 1'b0;
fifo2_wr_en <= 1'b1;
fifo1_rd_en <= 1'b1;
fifo2_rd_en <= 1'b0;
if(fifo_cnt2 == 500)
state <= pang;
else
state <= ping;
end
pang:begin
fifo1_wr_en <= 1'b1;
fifo2_wr_en <= 1'b0;
fifo1_rd_en <= 1'b0;
fifo2_rd_en <= 1'b1;
if(fifo_cnt1 == 500)
state <= ping;
else
state <= pang;
end
default :begin
state <= idle;
fifo1_wr_en <= 1'b0;
fifo2_wr_en <= 1'b0;
fifo1_rd_en <= 1'b0;
fifo2_rd_en <= 1'b0;
end
endcase
end
end
gm_syn_fifo u_fifo1(
.clk (clk ),
.rst_n (rst_n ),
.wr_en (fifo1_wr_en ),
.rd_en (fifo1_rd_en ),
.data_in (data_in ),
.data_out (data_out1 ),
.fifo_cnt (fifo_cnt1 )
);
gm_syn_fifo u_fifo2(
.clk (clk ),
.rst_n (rst_n ),
.wr_en (fifo2_wr_en ),
.rd_en (fifo2_rd_en ),
.data_in (data_in ),
.data_out (data_out2 ),
.fifo_cnt (fifo_cnt2 )
);
assign data_out = fifo1_rd_en ? data_out1 : data_out2;
endmodule
module gm_syn_fifo(
input wire clk ,
input wire rst_n ,
input wire wr_en ,
input wire rd_en ,
input wire [7:0] data_in ,
output reg [7:0] data_out ,
output reg [8:0] fifo_cnt ,
output wire wr_full ,
output wire rd_empty
);
reg [8:0] rd_ptr ;
reg [8:0] wr_ptr ;
reg [7:0] fifo[0:512];
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
rd_ptr <= 0;
wr_ptr <= 0;
end
else if(!rd_empty && rd_en)
begin
if(rd_ptr == 500)
rd_ptr <= 0;
else
rd_ptr <= rd_ptr + 1'b1;
end
else if(!wr_full && wr_en)
begin
if(wr_ptr == 500)
wr_ptr <= 0;
else
wr_ptr <= wr_ptr + 1'b1;
end
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
fifo_cnt <= 0;
else if( (!rd_empty && rd_en) && (!wr_full && wr_en) )
fifo_cnt <= fifo_cnt;
else if(!rd_empty && rd_en)
fifo_cnt <= fifo_cnt - 1'b1;
else if(!wr_full && wr_en)
fifo_cnt <= fifo_cnt + 1'b1;
else
fifo_cnt <= fifo_cnt;
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
data_out <= 0;
else if(!rd_empty && rd_en)
data_out <= fifo[rd_ptr];
else if(!wr_full && wr_en)
fifo[wr_ptr] <= data_in;
end
assign wr_full = (fifo_cnt == 500) ? 1'b1 : 1'b0;
assign rd_empty = (fifo_cnt == 0 ) ? 1'b1 : 1'b0;
endmodule
`timescale 1ns/1ns
module tb();
reg clk ;
reg rst_n ;
reg [7:0] data_in ;
reg wr_en ;
wire fifo1_wr_en;
wire fifo2_wr_en;
wire fifo1_rd_en;
wire fifo2_rd_en;
wire [7:0] data_out ;
gm_fifo_pingpang u_pingpang(
.clk (clk ),
.rst_n (rst_n ),
.data_in (data_in ),
.wr_en (wr_en ),
.fifo1_wr_en (fifo1_wr_en),
.fifo2_wr_en (fifo2_wr_en),
.fifo1_rd_en (fifo1_rd_en),
.fifo2_rd_en (fifo2_rd_en),
.data_out (data_out )
);
always
always
initial begin
clk <= 1'b1;
rst_n <= 1'b0;
data_in <= 8'd0;
#50 rst_n <= 1'b1;
wr_en <= 1'b1;
$stop;
end
endmodule