weixin_56994677 2026-01-06 13:59 采纳率: 0%
浏览 4

关于异步fifo实现的一些问题

出现了问题,写32个数,读31个数,第一个数显示4个X,从第二个数开始读发生了错位,找不到原因

//async_fifo
module async_fifo #(
      parameter DATA_WIDTH = 16,
      parameter FIFO_DEPTH = 32,
      parameter ADDR_WIDTH = 5
)(
//write
      input  wire                                 wck,
      input  wire                                 wrst_b,
      input  wire                                 winc,
      input  wire [DATA_WIDTH-1:0] wdata,
      output wire                                 wfull
//read
      input  wire                                    rck,
      input  wire                                    rrst_b,
      input  wire                                    rinc,
      output  reg [DATA_WIDTH-1:0] rdata,
      output wire                                   rempty
);
//
reg  [DATA_WIDTH-1:0] mem [0:31];
reg  [ADDR_WIDTH:0] wptr, rptr;
wire [ADDR_WIDTH:0] wptr_gray, rptr_gray;
reg [ADDR_WIDTH:0] wptr_sync0,wptr_sync1,rptr_sync0,rptr_sync1;
//write ptr control
always @(posedge wck or negedge wrst_b) begin
       if (!wrst_b) begin
           wptr <= 0;
       end else if (winc &&!wfull) begin
            mem[wptr[ADDR_WIDTH-1:0]] <= wdata;
           wptr <=wptr +1;
       end
end
//read ptr control
always @(posedge rck or negedge rrst_b) begin
       if (!rrst_b) begin
           rptr <= 0;
           rdata <= 0;
       end else if (rinc &&!rempty) begin
            rdata <= mem [rptr[ADDR_WIDTH-1:0]]
            rptr <= rptr +1;
       end
end
//write ptr to read clk
always @(posedge wck or negedge wrst_b) begin
     if (!wrst_b) begin
      {rptr_sync1,rptr_sync0} <= 0;
     end
     else begin
            rptr_sync0 <= rptr_gray;
            rptr_sync1 <= rptr_sync0;
      end
end
//read ptr to write clk
always @(posedge rck or negedge rrst_b) begin
     if (!rrst_b)   {wptr_sync1,wptr_sync0} <= 0;
     else begin
            wptr_sync0 <= wptr_gray;
            wptr_sync1 <= wptr_sync0;
      end
end
//gray
assign wptr_gray = wptr ^ (wptr >> 1);
assign rptr_gray = rptr ^ (rptr >> 1);
//
assign wfull =(wptr_gray == {~rptr_sync1[ADDR_WIDTH:ADDR_WIDTH-1],rptr_sync1[ADDR_WIDTH-2:0]});
//
 assign rempty = (rptr_gary == wptr_sync1);
//
endmodule


'timescale 1ns/1ps
//async_fifo_testbench
module async_fifo_testbench;
//
  reg wck;
  reg rck;
  reg wrst_b;
  reg rrst_b;
  reg winc;
  reg rinc;
  wire wfull;
  wire rempty;
  reg [15:0] wdata;
  wire [15:0] rdata;
  reg wdata_txt;
  reg  rdata_txt;
//
  initial begin
       wck = 0;
       forever #5 wck = ~wck;
 end
//
  initial begin
       rck = 0;
       forever #19 rck = ~rck;
 end
//
  initial begin
        wdata_txt = $fopen("wdata_txt");
        rdata_txt = $fopen("rdata_txt");
  end
//
   initial begin
   wck = 1'b0;
   rck = 1'b0;
   wrst_b = 1'b0;
   rrst_b = 1'b0;
   winc = 1'b0;
   rinc = 1'b0;
   #100
   wrst_b = 1'b1;
   rrst_b = 1'b1;
   winc = 1'b1;
   #1500
   winc = 1'b0;
   rinc = 1'b0;
   #2500
    rinc = 1'b0;
// $fclose(wdata_txt);
// $fclose(rdata_txt);
   $display ("Simulation finished");
   $finish;
   end
always @(posedge wck) begin
    if (winc && !wfull) begin
         wdata <= $random;
    end
end
//
always @(posedge wck) begin
    if (winc && !wfull) begin
    #1
     $fwrite(wdata_txt, "%h\n", wdata);
     $display("Write data: %h", wdata);
    end
end
//
always @(posedge rck) begin
    if (rinc && !rempty) begin
    #1
     $fwrite(rdata_txt, "%h\n", rdata);
     $display("Rrite data: %h", rdata);
    end
end
//
   initial begin
     $fsdbDumpfile("wave.fsdb");
    $fsdbDumpvars(0,"async_fifo_testbench");
   end
//
async_fifo u_async_fifo(
      .wck(wck),
      .rck(rck),
      .wrst_b(wrst_b),
      .rrst_b(rrst_b),
      .winc(winc),
      .rinc(rinc),
      .wdata(wdata),
      .rdata(rdata),
      .wfull(wfull),
      .rempty(rempty)
      );
endmodule
  • 写回答

1条回答 默认 最新

  • 紫雾凌寒 新星创作者: 人工智能技术领域 2026-01-06 14:01
    关注

    让 “紫雾凌寒” 来帮你回答,本回答结合 DeepSeek

    如果还有问题,请评论或点击头像私信,如果有帮助到您, 请关注、采纳、点赞

    1. 问题关键点分析
      - 写了32个数,读了31个数后出现错位,这表明读写操作的同步和FIFO的状态控制可能存在问题。
      - 从提供的代码片段来看,缺少了很多关键部分,比如读写指针的生成、空满信号的判断与处理、读写控制逻辑等,难以直接从现有代码定位问题,但可以推测这些部分的逻辑错误可能导致了数据错位。
    2. 解决方案
      - 读写指针

      • 写指针:
        verilog reg [LOG2(DEPTH)-1:0] wr_ptr; always @(posedge wr_clk or posedge rst_n) begin if (!rst_n) wr_ptr <= {LOG2(DEPTH){1'b0}}; else if (wr_en &&!full) wr_ptr <= wr_ptr + 1; end
      • 读指针:
        verilog reg [LOG2(DEPTH)-1:0] rd_ptr; always @(posedge rd_clk or posedge rst_n) begin if (!rst_n) rd_ptr <= {LOG2(DEPTH){1'b0}}; else if (rd_en &&!empty) rd_ptr <= rd_ptr + 1; end
      • 空满信号判断
      • 空信号:
        verilog assign empty = (wr_ptr == rd_ptr);
      • 满信号:
        verilog assign full = ((wr_ptr + 1) == rd_ptr);
      • 读写控制逻辑
      • 写操作:
        verilog always @(posedge wr_clk or posedge rst_n) begin if (!rst_n) fifo_mem <= {DATA_WIDTH{1'b0}}; else if (wr_en &&!full) fifo_mem[wr_ptr] <= wr_data; end
      • 读操作:
        verilog always @(posedge rd_clk or posedge rst_n) begin if (!rst_n) rd_data <= {DATA_WIDTH{1'b0}}; else if (rd_en &&!empty) rd_data <= fifo_mem[rd_ptr]; end
      • 这里假设LOG2(DEPTH)是计算FIFO深度的对数函数,用于指针的位宽计算;DEPTH是FIFO的深度。完整代码示例:
        ```verilog
        module async_fifo #(
        parameter DATA_WIDTH = 16,
        parameter DEPTH = 32
        )(
        input wire wr_clk,
        input wire rd_clk,
        input wire rst_n,
        input wire wr_en,
        input wire rd_en,
        input wire [DATA_WIDTH-1:0] wr_data,
        output reg [DATA_WIDTH-1:0] rd_data,
        output reg empty,
        output reg full
        );

      reg [LOG2(DEPTH)-1:0] wr_ptr;
      reg [LOG2(DEPTH)-1:0] rd_ptr;
      reg [DATA_WIDTH-1:0] fifo_mem [DEPTH-1:0];

      always @(posedge wr_clk or posedge rst_n) begin
      if (!rst_n)
      wr_ptr <= {LOG2(DEPTH){1’b0}};
      else if (wr_en &&!full)
      wr_ptr <= wr_ptr + 1;
      end

      always @(posedge rd_clk or posedge rst_n) begin
      if (!rst_n)
      rd_ptr <= {LOG2(DEPTH){1’b0}};
      else if (rd_en &&!empty)
      rd_ptr <= rd_ptr + 1;
      end

      assign empty = (wr_ptr == rd_ptr);
      assign full = ((wr_ptr + 1) == rd_ptr);

      always @(posedge wr_clk or posedge rst_n) begin
      if (!rst_n)
      fifo_mem <= {DATA_WIDTH{1’b0}};
      else if (wr_en &&!full)
      fifo_mem[wr_ptr] <= wr_data;
      end

      always @(posedge rd_clk or posedge rst_n) begin
      if (!rst_n)
      rd_data <= {DATA_WIDTH{1’b0}};
      else if (rd_en &&!empty)
      rd_data <= fifo_mem[rd_ptr];
      end

      function integer LOG2;
      input integer number;
      begin
      LOG2 = 0;
      while (2**LOG2 < number) begin
      LOG2 = LOG2 + 1;
      end
      end
      endfunction

      endmodule
      ```
      3. 多种解决方案优缺点
      - 优点
      - 完整逻辑实现:上述代码提供了一个完整的异步FIFO实现,包括读写指针管理、空满信号判断和读写操作控制,逻辑清晰,易于理解和调试。
      - 通用性:通过参数化设计,适用于不同的数据宽度和深度要求,具有较好的通用性。
      - 缺点
      - 资源消耗:对于较大深度的FIFO,可能会消耗较多的寄存器资源来存储读写指针和FIFO内存。
      - 性能:在高频运行时,读写指针的同步和比较操作可能会引入一定的时序问题,需要仔细进行时序优化。
      4. 总结
      - 数据错位问题通常是由于读写操作的不同步以及FIFO状态控制不当导致的。通过正确实现读写指针、空满信号判断以及读写控制逻辑,可以有效解决该问题。上述完整的异步FIFO代码示例展示了如何构建一个功能正确的异步FIFO,在实际应用中,还需要根据具体的需求和硬件平台进行进一步的优化和调整(如时序优化、资源优化等)。

    希望以上解答对您有所帮助。如果您有任何疑问,欢迎在评论区提出。

    评论

报告相同问题?

问题事件

  • 修改了问题 1月6日
  • 修改了问题 1月6日
  • 创建了问题 1月6日