上一节我们实现RAM的相关知识,也对比了RAM和FIFO的区别;FIFO:先进先出数据缓冲器,也是一个端口只读,另一个端口只写。但是FIFO与伪双口RAM的不同,FIFO为先入先出,没有地址线,不能对存储单元寻址;而伪双口RAM两个端口都有地址线,可以对存储单元寻址。但是FIFO内部的存储单元主要是由双口RAM(异步读写来实现的),在verilog 实现之RAM中已经讲过各种各样的RAM的实现。此时就要用双端口的RAM来实现FIFO。

  一、实现双口RAM(异步读写)

    

 

 

 

  1 `timescale 1ns / 1ps
  2 //////////////////////////////////////////////////////////////////////////////////
  3 // Company: 
  4 // Engineer: 
  5 // 
  6 // Create Date: 2020/06/25 20:46:14
  7 // Design Name: 
  8 // Module Name: synram_double_port
  9 // Project Name: 
 10 // Target Devices: 
 11 // Tool Versions: 
 12 // Description: 
 13 // 
 14 // Dependencies: 
 15 // 
 16 // Revision:
 17 // Revision 0.01 - File Created
 18 // Additional Comments:
 19 // 
 20 //////////////////////////////////////////////////////////////////////////////////
 21 
 22 
 23 module synram_double_port #(
 24 parameter DATA_WIDTH = 8,
 25 parameter ADDR_WIDTH = 8,
 26 parameter RAM_DEPTH = 1 << ADDR_WIDTH
 27 )(
 28 input [ADDR_WIDTH - 1 : 0] address_0 , // address_0 Input
 29 inout [DATA_WIDTH-1 : 0] data_0    , // data_0 bi-directional
 30 input cs_0      , // Chip Select
 31 input we_0      , // Write Enable/Read Enable
 32 input oe_0      , // Output Enable
 33 input [ADDR_WIDTH - 1 : 0] address_1 , // address_1 Input
 34 inout [DATA_WIDTH-1 : 0] data_1    , // data_1 bi-directional
 35 input cs_1      , // Chip Select
 36 input we_1      , // Write Enable/Read Enable
 37 input oe_1        // Output Enable
 38 ); 
 39  
 40 //--------------Internal variables---------------- 
 41 reg [DATA_WIDTH-1:0] data_0_out ; 
 42 reg [DATA_WIDTH-1:0] data_1_out ;
 43 reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1];
 44  
 45  
 46 //initialization
 47  
 48 // synopsys_translate_off
 49 integer i;
 50 initial begin
 51     for(i=0; i < RAM_DEPTH; i = i + 1) begin
 52         mem[i] = 8'h00;
 53     end
 54 end
 55 // synopsys_translate_on
 56  
 57  
 58 //--------------Code Starts Here------------------ 
 59 // Memory Write Block 
 60 // Write Operation : When we_0 = 1, cs_0 = 1
 61 always @ (address_0 or cs_0 or we_0 or data_0
 62 or address_1 or cs_1 or we_1 or data_1)
 63 begin : MEM_WRITE
 64   if ( cs_0 && we_0 ) begin
 65      mem[address_0] <= data_0;
 66   end 
 67   else if  (cs_1 && we_1) begin
 68      mem[address_1] <= data_1;
 69   end
 70 end
 71  
 72 // Tri-State Buffer control 
 73 // output : When we_0 = 0, oe_0 = 1, cs_0 = 1
 74 assign data_0 = (cs_0 && oe_0 && !we_0) ? data_0_out : 8'bz; 
 75  
 76 // Memory Read Block 
 77 // Read Operation : When we_0 = 0, oe_0 = 1, cs_0 = 1
 78 always @ (address_0 or cs_0 or we_1 or oe_0)
 79 begin : MEM_READ_0
 80   if (cs_0 && !we_0 && oe_0) begin
 81     data_0_out <= mem[address_0]; 
 82   end else begin
 83     data_0_out <= 0; 
 84   end
 85 end 
 86  
 87 //Second Port of RAM
 88 // Tri-State Buffer control 
 89 // output : When we_0 = 0, oe_0 = 1, cs_0 = 1
 90 assign data_1 = (cs_1 && oe_1 && !we_1) ? data_1_out : 8'bz; 
 91 // Memory Read Block 1 
 92 // Read Operation : When we_1 = 0, oe_1 = 1, cs_1 = 1
 93 always @ (address_1 or cs_1 or we_1 or oe_1)
 94 begin : MEM_READ_1
 95   if (cs_1 && !we_1 && oe_1) begin
 96     data_1_out <= mem[address_1]; 
 97   end else begin
 98     data_1_out <= 0; 
 99   end
100 end
101  
102 endmodule
View Code

 

  二、对RAM端口的实例化

 1 synram_double_port #(
 2         .DATA_WIDTH(DATA_WIDTH),
 3         .ADDR_WIDTH(ADDR_WIDTH),
 4         .RAM_DEPTH(RAM_DEPTH)
 5     ) inst_synram_double_port (
 6         .address_0 (wr_pointer),
 7         .data_0    (data_in),
 8         .cs_0      (wr_cs),
 9         .we_0      (wr_en),
10         .oe_0      (1'b0),
11         .address_1 (rd_pointer),
12         .data_1    (data_ram),
13         .cs_1      (rd_cs),
14         .we_1      (1'b0),
15         .oe_1      (rd_en)
16     );

  三、同步FIFO的实现

  同步FIFO的框图:

 

 

  同步FIFO读写原理:通常,FIFO是使用旋转指针实现的。 我们可以将FIFO的写入和读取指针称为数据区的头和尾。 最初,FIFO的读写指针将指向相同的位置,吸入所示:这是一个解释FIFO如何使用内存的示例。 这是长度为8的fifo,WP和RP是写指针和读指针指向的位置。 图中的阴影区域填充了数据。使用stutus_cnt记录FIFO RAM中的数据个数,等于0时,给出empty信号,等于RAM_DEPTH时,给出full信号。stutus_cnt写而未满时增加1,读而未空时减1。同时发生读写操作时,stutus_cnt。读写指针宽度与地址宽度相当,地址增加而溢出后,自动变成0。

 

 

 

 

 

 

 从同步FIFO的框图中。我们可以推理出同步FIFO的管脚图,同时这里所说的fifo 没有了地址,是因为用指针代替了地址。剩下的就是看图说话。

 

 

   四、实现的代码

RTL:

  1 `timescale 1ns / 1ps
  2 //////////////////////////////////////////////////////////////////////////////////
  3 // Company: 
  4 // Engineer: 
  5 // 
  6 // Create Date: 2020/06/25 20:42:22
  7 // Design Name: 
  8 // Module Name: syn_fifo
  9 // Project Name: 
 10 // Target Devices: 
 11 // Tool Versions: 
 12 // Description: 
 13 // 
 14 // Dependencies: 
 15 // 
 16 // Revision:
 17 // Revision 0.01 - File Created
 18 // Additional Comments:
 19 // 
 20 //////////////////////////////////////////////////////////////////////////////////
 21 
 22 module syn_fifo #(
 23 parameter DATA_WIDTH = 8,
 24 parameter ADDR_WIDTH = 8,
 25 parameter RAM_DEPTH = (1 << ADDR_WIDTH)
 26     )
 27 (
 28     input           wire                     clk            ,
 29     input            wire                     rst          ,
 30     //interfaces    
 31     input             wire                     wr_cs       ,//�--片�信�
 32     input             wire                    rd_cs        ,//�--片�信�
 33     input              wire [DATA_WIDTH-1:0]    data_in        ,//输入数据
 34     input           wire                    rd_en        ,//读是�
 35     input           wire                      wr_en       ,//写使�
 36     output            wire [DATA_WIDTH-1:0]    data_out    ,//数据输出
 37     output            wire                    empty        ,//空标�
 38     output          wire                     full
 39 
 40     );
 41 
 42 //========================================================================\
 43 // ################ Define Parameter and Internal signals ################ 
 44 //========================================================================/
 45 reg                [ADDR_WIDTH-1:0]        wr_pointer    ;//写指�
 46 reg                [ADDR_WIDTH-1:0]        rd_pointer    ;
 47 reg                [ADDR_WIDTH:0]            status_cnt    ;//状æ??
 48 reg             [DATA_WIDTH-1:0]        data_out_r    ;//数据计数
 49 wire               [DATA_WIDTH-1:0]        data_ram    ;
 50 
 51 //=============================================================================
 52 //+++++++++++++++++++++++++     Main Code    +++++++++++++++++++++++++++++++
 53 //=============================================================================
 54 
 55 assign     full   =   (status_cnt==RAM_DEPTH)?1'b1 :1'b0 ;
 56 assign     empty  =      (status_cnt==0)?1'b1:1'b0;
 57 
 58 //wr_pointer
 59 always @(posedge clk or posedge rst) begin
 60     if (!rst) begin
 61         wr_pointer  <= 0 ;        
 62     end
 63     else if (wr_cs && wr_en) begin
 64         wr_pointer  <= wr_pointer + 1;
 65     end 
 66 end
 67 
 68 //rd_pointer
 69 always @(posedge clk or posedge rst) begin
 70     if (!rst) begin
 71         rd_pointer   <=   0    ;
 72     end
 73     else if (rd_cs && rd_en) begin
 74         rd_pointer   <= rd_pointer + 1'b1 ;
 75     end
 76 end
 77 //data_out_r
 78 
 79 always @(posedge clk or posedge rst) begin
 80     if (!rst) begin
 81         data_out_r    <=   0 ;
 82         
 83     end
 84     else if (rd_cs && rd_en) begin
 85         data_out_r   <=  data_ram ;
 86     end
 87 end
 88 assign   data_out   =  data_out_r ;
 89 
 90 //status_cnt
 91 always @(posedge clk or posedge rst) begin
 92     if (!rst) begin
 93         
 94         status_cnt   <=   0; //只读不写
 95     end
 96     else if ((rd_cs && rd_en) && !(wr_cs && wr_en) && (status_cnt!=0)) begin
 97         status_cnt     <= status_cnt - 1'b1 ;//只读不写
 98     end
 99     else if(!(rd_cs && rd_en) && (wr_cs && wr_en) && (status_cnt!=RAM_DEPTH))begin
100         status_cnt     <= status_cnt + 1'b1 ;//只写不读
101     end
102 end
103 
104 
105 
106 synram_double_port #(
107         .DATA_WIDTH(DATA_WIDTH),
108         .ADDR_WIDTH(ADDR_WIDTH),
109         .RAM_DEPTH(RAM_DEPTH)
110     ) inst_synram_double_port (
111         .address_0 (wr_pointer),
112         .data_0    (data_in),
113         .cs_0      (wr_cs),
114         .we_0      (wr_en),
115         .oe_0      (1'b0),
116         .address_1 (rd_pointer),
117         .data_1    (data_ram),
118         .cs_1      (rd_cs),
119         .we_1      (1'b0),
120         .oe_1      (rd_en)
121     );
122 
123 endmodule
View Code

TB:

  1 `timescale 1ns / 1ps
  2 //////////////////////////////////////////////////////////////////////////////////
  3 // Company: 
  4 // Engineer: 
  5 // 
  6 // Create Date: 2020/06/25 23:12:58
  7 // Design Name: 
  8 // Module Name: syn_fifo_tb
  9 // Project Name: 
 10 // Target Devices: 
 11 // Tool Versions: 
 12 // Description: 
 13 // 
 14 // Dependencies: 
 15 // 
 16 // Revision:
 17 // Revision 0.01 - File Created
 18 // Additional Comments:
 19 // 
 20 //////////////////////////////////////////////////////////////////////////////////
 21 
 22 
 23 
 24 module syn_fifo_tb();
 25 
 26 parameter DATA_WIDTH = 8;
 27 parameter ADDR_WIDTH = 8;
 28 parameter RAM_DEPTH = (1 << ADDR_WIDTH);
 29     
 30 reg clk ;
 31 reg rst ;
 32 reg wr_cs ;
 33 reg rd_cs ;
 34 reg rd_en ;
 35 reg wr_en ;
 36 reg [DATA_WIDTH-1:0] data_in ;
 37 wire full ;
 38 wire empty ;
 39 wire [DATA_WIDTH-1:0] data_out ;
 40 
 41 
 42 initial begin
 43     clk = 0;
 44     forever
 45     #2 clk = ~clk;
 46 
 47 end
 48 
 49 integer i=0;
 50 initial begin
 51 
 52     rst = 0;
 53     wr_cs = 0;
 54     rd_cs = 0;
 55     wr_en = 0;
 56     rd_en = 0;
 57     data_in = 0;
 58     
 59     #8
 60     rst = 1;
 61     //write
 62     wr_cs = 1;
 63     wr_en = 1;
 64     
 65     for(i = 0; i < 256; i = i + 1) begin
 66         @(negedge clk) begin
 67             data_in = data_in + 1;
 68         end
 69         
 70     end
 71     
 72     //read
 73     
 74     //#8
 75     wr_cs = 0;
 76     wr_en = 0;
 77     rd_cs = 1;
 78     rd_en = 1;
 79 
 80 
 81 
 82 
 83 end
 84 
 85 syn_fifo #(
 86     .DATA_WIDTH(DATA_WIDTH),
 87     .ADDR_WIDTH(ADDR_WIDTH),
 88     .RAM_DEPTH(RAM_DEPTH)
 89 ) inst_syn_fifo (
 90     .clk      (clk),
 91     .rst      (rst),
 92     .wr_cs    (wr_cs),
 93     .rd_cs    (rd_cs),
 94     .data_in  (data_in),
 95     .rd_en    (rd_en),
 96     .wr_en    (wr_en),
 97     .data_out (data_out),
 98     .empty    (empty),
 99     .full     (full)
100     );
101 
102     
103     
104 endmodule
View Code