用移位寄存器实现同步FIFO

用移位寄存器实现同步FIFO,带空满判断-LMLPHP

        如图所示,同步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次。


波形图

用移位寄存器实现同步FIFO,带空满判断-LMLPHP

 

04-06 13:47