用移位寄存器实现同步FIFO
如图所示,同步FIFO带有push信号和pop信号,push代表往队列里面压入一个数据,pop代表往队列外面排出一个数据。
解题思路
同步FIFO的空满判断用一个计数器来判断,收到push信号计数器加1,收到pop信号时计数器减1,考虑同时push和pop的情况计数器不变,当计数器为0时,输出空,当计数器为DEPTH时,输出满。FIFO给出空满信号,空时不能读,满时不能写。具体代码如下:
always @(posedge clk)begin
if(!rstn)
counter <= 'd0;
else if(push && pop)
counter <= counter;
else if(push)
counter <= counter + 1'b1;
else if(pop)
counter <= counter - 1'b1;
end
assign empty = (counter == 'd0);
assign full = (counter == DEPTH);
数据的写入和读出,push数据就直接在移位寄存器的一端,用拼接符号把数据拼接在一起。pop数据输出DEPTH-counter位置的数据,因为我们位拼接是从高位开始拼接的,要注意读出的地址位置。
always @(posedge clk)begin
if(!rstn)
pop_data <= 'd;
else if(push && pop)begin
fifo_mem <= {push_data,fifo_mem[DEPTH-1:1]};
pop_data <= fifo_mem[DEPTH-counter];
end
else if(push)begin
fifo_mem <= {push_data,fifo_mem[DEPTH-1:1]};
end
else if(pop)begin
pop_data <= fifo_mem[DEPTH-counter];
end
end
代码
module shift_reg_fifo#(
parameter DEPTH = 8 ,
parameter DATA_W = 32
)(
input clk ,
input rstn ,
output empty ,
output full ,
input push ,
input [DATA_W-1:0] push_data ,
input pop ,
output reg [DATA_W-1:0] pop_data
);
reg [DATA_W-1:0] fifo_mem [DEPTH-1:0];
reg [$clog2(DEPTH)+1:0] counter;
always @(posedge clk)begin
if(!rstn)
pop_data <= 'd;
else if(push && pop)begin
fifo_mem <= {push_data,fifo_mem[DEPTH-1:1]};
pop_data <= fifo_mem[DEPTH-counter];
end
else if(push)begin
fifo_mem <= {push_data,fifo_mem[DEPTH-1:1]};
end
else if(pop)begin
pop_data <= fifo_mem[DEPTH-counter];
end
end
always @(posedge clk)begin
if(!rstn)
counter <= 'd0;
else if(push && pop)
counter <= counter;
else if(push)
counter <= counter + 1'b1;
else if(pop)
counter <= counter - 1'b1;
end
assign empty = (counter == 'd0);
assign full = (counter == DEPTH);
endmodule
testbench
`timescale 1ns/1ps
module tb#(
parameter DEPTH = 8 ,
parameter DATA_W = 32
)();
reg clk,rstn;
wire empty,full;
wire [DATA_W-1:0] pop_data;
reg push,pop;
reg [DATA_W-1:0] push_data;
initial begin
forever #5 clk = ~clk;
end
initial begin
clk = 1'b0;
rstn = 1'b0;
pop = 1'b0;
push = 1'b0;
push_data = 32'd0;
#10
rstn = 1'b1;
#16
repeat(8)begin
#10
push = 1'b1;
push_data = $random%32;
end
#10
push = 1'b0;
repeat(8)begin
#10
pop = 1'b1;
end
#10
pop = 1'b0;
repeat(3)begin
#10
pop = 1'b0;
push = 1'b1;
push_data = $random() % 10'd32;
#10
push = 1'b0;
pop = 1'b1;
end
#10
pop = 1'b0;
push = 1'b1;
push_data = $random() % 10'd32;
repeat(4)begin
#10
pop = 1'b1;
push = 1'b1;
push_data = $random() % 10'd32;
end
#10
pop = 1'b0;
push = 1'b0;
#50
$finish();
end
initial begin
$fsdbDumpfile("shift_fifo.fsdb");
$fsdbDumpvars(0);
end
shift_reg_fifo #(
.DEPTH (DEPTH ),
.DATA_W (DATA_W )
)u_shift_reg_fifo(
.clk (clk ),
.rstn (rstn ),
.empty (empty ),
.full (full ),
.push (push ),
.push_data (push_data ),
.pop (pop ),
.pop_data (pop_data )
);
endmodule
仿真部分,在深度为8的情况下,我们分别模拟了写入8个数据到写满,读出8个数据直到读空,接着连续写读3次,然后写入1个数据(保证下一步同时读写时,FIFO不为空,能读出数据)。再同时读写4次。
波形图