• 【【verilog代码异步FIFO的设计解释+源码+tb】】


    异步FIFO的设计

    使用格雷码 判断 是否是真的满员
    用了很巧的办法
    使用gray码解决了一个问题,但同时也带来另一个问题,即在格雷码域如何判断空与满。
    对于“空”的判断依然依据二者完全相等(包括MSB);
    而对于“满”的判断,如下图,由于gray码除了MSB外,具有镜像对称的特点,当读指针指向7,写指针指向8时,除了MSB,其余位皆相同,不能说它为满。因此不能单纯的只检测最高位了,在gray码上判断为满必须同时满足以下3条:
    wptr和同步过来的rptr的MSB不相等,因为wptr必须比rptr多折回一次。
    wptr与rptr的次高位不相等,如上图位置7和位置15,转化为二进制对应的是0111和1111,MSB不同说明多折回一次,111相同代表同一位置。
    剩下的其余位完全相等。
    解释一下 :
    我们来看 7是 0_100 要是用原来的判别 我们会发现 下一个8 是 1_100 除了 第一位不同 但是很明显 我们并没有相差一圈
    接下来 我们 观察 15-7=8 其实 我们正需要的是这样的8 其实是我们设置的3位宽所能提供的最大的 深度 而我们将比照 格雷码
    才得出的首位相同 次高位不同 接下来都相同

    源码asychronous.v

    // asynchronous
    module asyn #(
        parameter   WIDTH       =   8               ,
        parameter   DEEPTH      =   16              ,    //  I  just try 16
        parameter   ADDR_WIDTH  =   clogb2(DEEPTH)  
        //  just give up  PROG_EMPTY
      )(
        input                               wr_clk          ,
        input                               rd_clk          ,
        input                               wr_en           ,
        input                               rd_en           ,
        input                               wr_rst_n        ,
        input                               rd_rst_n        ,
        input  [WIDTH-1 : 0 ]               din             ,
        output   reg                        wfull           ,
        output   reg                        wempty          ,
        output   reg  [WIDTH-1 : 0 ]        dout
      );
    
    
    
      // ===================================================================================//
      //             define parameter and internal  signals                                 //
      //====================================================================================//
      reg    [WIDTH-1 : 0]    ram[DEEPTH-1 : 0]      ;    // this is ram
      reg    [ADDR_WIDTH : 0] wr_addr                ;    // we must set more bit wode  add exact bit + address
      reg    [ADDR_WIDTH : 0] rd_addr                ;    // we must set more bit wode
      wire   [ADDR_WIDTH - 1 : 0] wr_addr1           ;
      wire   [ADDR_WIDTH - 1 : 0] rd_addr1           ;
      assign wr_addr1 = wr_addr[ADDR_WIDTH - 1 : 0]  ;    //  we must put  address and addr_pointer together
      assign rd_addr1 = rd_addr[ADDR_WIDTH - 1 : 0]  ;
    
      // gray
      wire  [ADDR_WIDTH : 0] wr_addr_gray            ;
      wire  [ADDR_WIDTH : 0] rd_addr_gray            ;
      // B 2 Gray code
      assign wr_addr_gray = wr_addr ^ (wr_addr >> 1) ;
      assign rd_addr_gray = rd_addr ^ (rd_addr >> 1) ;
    
      //synchronous
      reg  [ADDR_WIDTH : 0] wr_addr_gray1            ;
      reg  [ADDR_WIDTH : 0] wr_addr_gray2            ;
      //synchronous
      reg  [ADDR_WIDTH : 0] rd_addr_gray1            ;
      reg  [ADDR_WIDTH : 0] rd_addr_gray2            ;
    
    
    
    
    
      //======================================================================================//
      //                            next is main code                                         //
      //========================================================================================//
      function  integer clogb2  ;
        input [31:0] value  ;
        begin
          value = value - 1 ;
          for( clogb2 = 0 ; value > 0 ; clogb2 = clogb2 + 1)
            value = value >>1 ;
        end
      endfunction
    
      //-----------------------------------------------------------------  wr_addr
      //--the  pointer is another thing
      always@(posedge wr_clk or negedge wr_rst_n)
      begin
        if(wr_rst_n == 0)
        begin
          wr_addr <= 0 ;
        end
        else if( wr_en && !wfull)
        begin
          wr_addr <= wr_addr + 1'b1 ;
        end
        else
          wr_addr <= wr_addr ;
      end
    
      //----------------------------------------------------------------------- rd_addr
      always@(posedge rd_clk or negedge rd_rst_n)
      begin
        if(rd_rst_n == 0)
        begin
          rd_addr <= 0;
        end
        else if( rd_en && !wempty)
        begin
          rd_addr <= rd_addr + 1'b1 ;
        end
        else
          rd_addr <= rd_addr ;
      end
    
      //-------------------------------------------------------------------------- write to ram
      //    wr_addr1
      always@(posedge wr_clk or negedge wr_rst_n)
      begin
        if(wr_rst_n == 0 )
        begin
          ram[wr_addr1] <= 0 ;
        end
        else if(wr_en && !wfull)
        begin
          ram[wr_addr1] <= din ;
        end
        else
        begin
          ram[wr_addr1] <= ram[wr_addr1] ;
        end
      end
    
      //------------------------------------------------------------------------------read to ram
      //  rd_addr1  [ADDR_WIDTH-1 : 0]  this is used to  which need reed
      always@(posedge rd_clk or negedge rd_rst_n)
      begin
        if(rd_rst_n == 0)
        begin
          dout <= 0 ;
        end
        else if( rd_en && !wempty)
        begin
          dout <= ram[rd_addr1] ;
        end
        else
        begin
          dout <= dout ;
        end
      end
    
      //----------------------------------------------------------------------------------this is what sysnchronus need
      //----------------------------------------------------------------------------------------------------
      //--  next is change to gary   and send to the same time clock //
      //------------------------------------------------------------------------------------------------------\
    
      //synchronous
      //reg  [ADDR_WIDTH : 0] wr_addr_gray1            ;
      //reg  [ADDR_WIDTH : 0] wr_addr_gray2            ;
      //synchronous
      //reg  [ADDR_WIDTH : 0] rd_addr_gray1            ;
      // reg  [ADDR_WIDTH : 0] rd_addr_gray2            ;
    
      //  this is pointer point
      // full use reed synchronous write
      // empty use write synchronous read
    
      //------------------------------------------------------------------------------------------------------\
    
    
      // write pointer  synchronous read clk     -----  empty
      always@(posedge rd_clk or negedge rd_rst_n)
      begin
        if( rd_rst_n == 0)
        begin
          wr_addr_gray1 <= 0 ;
          wr_addr_gray2 <= 0 ;
        end
        else
        begin
          wr_addr_gray1 <= wr_addr_gray  ;
          wr_addr_gray2 <= wr_addr_gray1 ;
        end
      end
    
    
      // read pointer sunchronous write clk    -----  full
      always@(posedge wr_clk or negedge wr_rst_n)
      begin
        if( wr_rst_n == 0)
        begin
          rd_addr_gray1 <= 0 ;
          rd_addr_gray2 <= 0 ;
        end
        else
        begin
          rd_addr_gray1 <= rd_addr_gray  ;
          rd_addr_gray2 <= rd_addr_gray1 ;
        end
      end
    
      //---------------------------------------------------  empty  full   determine
    
      //empty
      always@(*)
      begin
        if( rd_rst_n == 0 )
        begin
          wempty <= 0 ;
        end
        else if(rd_addr_gray == wr_addr_gray2)
        begin
          wempty <= 1 ;
        end
        else
        begin
          wempty <= 0 ;
        end
      end
    
    
    
      // full
      always@(*)
      begin
        if(wr_rst_n == 0)
        begin
          wfull <= 0 ;
        end
        else if( wr_addr_gray == {~rd_addr_gray2[ADDR_WIDTH:ADDR_WIDTH-1],rd_addr_gray2[ADDR_WIDTH-2 : 0] } )
        begin
          wfull <= 1 ;
        end
        else
        begin
          wfull <= 0 ;
        end
      end
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218

    asychro_tb.v

    `timescale 1ns/1ps
    module asych_tb #(
        parameter   WIDTH       =   8               ,
        parameter   DEEPTH      =   8               ,
        parameter   ADDR_WIDTH  =   3
      );
      reg                               wr_clk          ;
      reg                               rd_clk          ;
      reg                               wr_en           ;
      reg                               rd_en           ;
      reg                               wr_rst_n        ;
      reg                               rd_rst_n        ;
      reg  [WIDTH-1 : 0 ]               din             ;
      wire                              wfull           ;
      wire                              wempty          ;
      wire [WIDTH-1 : 0 ]               dout            ;
    
    
      asyn#(
            .WIDTH     ( WIDTH ),
            .DEEPTH    ( DEEPTH ),
            .ADDR_WIDTH ( ADDR_WIDTH )
          )u_asyn(
            .wr_clk    ( wr_clk    ),
            .rd_clk    ( rd_clk    ),
            .wr_en     ( wr_en     ),
            .rd_en     ( rd_en     ),
            .wr_rst_n  ( wr_rst_n  ),
            .rd_rst_n  ( rd_rst_n  ),
            .din       ( din       ),
            .wfull     ( wfull     ),
            .wempty    ( wempty    ),
            .dout      ( dout      )
          );
    
    
    
    
      always     #10     wr_clk  =   ~wr_clk       ;
      always     #5      rd_clk  =   ~rd_clk       ;
    
    
    
      initial
      begin
        wr_clk      =     0 ;
        wr_rst_n    =     1 ;
        wr_en       =     0 ;
    
    
        rd_clk      =     0 ;
        rd_rst_n    =     1 ;
        rd_en       =     0 ;
    
        #10
         wr_rst_n    =      0;
        rd_rst_n    =      0;
    
        #10
         wr_rst_n    =      1;
        rd_rst_n    =      1;
    
    
        // next is write
        wr_en       =       1;
        rd_en       =       0;
    
        //only write
        wr_en       =       1;
        rd_en       =       0;
    din = 1 ;
        repeat(10)
        begin
          @(negedge wr_clk)
           begin
             din  =  {$random}%30  ;
           end
         end
    
         //only read
         wr_en       =       0;
        rd_en       =       1;
    
        repeat(10)
        begin
          @(negedge rd_clk) ;
    
        end
        rd_en      =       0   ;
    
    
    //read and write
        wr_en = 0;
        rd_en = 0;    
        #80;
        wr_en = 1;
        rd_en = 1;
    
        repeat(20) begin
            @(negedge wr_clk) begin
                din = {$random}%30;
            end
        end
    
    end
    
    
    endmodule  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
  • 相关阅读:
    Kalibr 对单目相机进行标定
    vue中禁止ios浏览器页面滚动的橡皮筋效果
    vue--9.路由
    sqlserver2012查看表大小情况
    UML软件哪个好?10款好用的UML工具和画图软件推荐!
    浅析设计模式3 —— 装饰者模式
    初始网络原理
    OpenGL_Learn07(变换)
    R 语言 |普通矩阵怎么保存为稀疏矩阵的3列(i, j, x)格式?
    LeetCode笔记:Weekly Contest 318
  • 原文地址:https://blog.csdn.net/weixin_50965981/article/details/134095898