0

非同期 fifo バッファーを作成しましたが、実行すると出力ポートに XXX が表示されます。リセット信号をアサートすると機能するはずですが、それを行ったにもかかわらず、私はまだ同じ問題に直面しています。

どんな助けでも大歓迎です。ありがとう

module fifo 
    #(parameter width =8,
                           addr_width = 4,
                            depth = (1 << addr_width)
     )
     ( // Read port
      output  [width - 1:0] dout,
      output reg                 empty_out,
      input wire                 rd_en,
      input wire              rclk,
      //write port
        input wire [width-1:0]  din,
        output reg                  full,
        input wire                  wr_en,
        input wire                  wclk,

        input wire                  rst
);

(* ram_style = "bram" *)
reg [width-1:0] memory_s[depth-1:0];
reg [31:0] push_ptr;
reg [31:0] pop_ptr;

assign dout = memory_s[pop_ptr];  // assign cannot assign values to registers
always @(posedge wclk)
    begin
        if (rst == 1)
            push_ptr <= 0;
        else if(wr_en == 1)
            begin
                memory_s\[push_ptr\] <= din;
                //$display("w: %d", push_ptr);
            if (push_ptr == (depth -1))
                    push_ptr <= 0;
            else 
                push_ptr <= push_ptr + 1;
        end
    end

always @ (posedge rclk)
    if (rst == 1)
        pop_ptr <= 0;
    else if (rd_en ==1)
        begin
                //dout <= memory_s\[pop_ptr\]; 
                //$display("r: %d", pop_ptr);
            if (pop_ptr == depth-1)
                pop_ptr <=0;
            else
                pop_ptr <= pop_ptr+1;
        end

reg full_s;
reg overflow;

always @*
begin
        if (rst == 1)
            full_s <= 0;
        else if (push_ptr <= pop_ptr)
            if (push_ptr + 1 == pop_ptr)
               begin
                full_s <= 1;
                $display("push,pop,full: %d %d %d", push_ptr,pop_ptr,full_s); 
                end
            else 
                full_s <=0;
        else 
            if(push_ptr + 1 == pop_ptr + depth) 
               begin
                full_s <= 1;
                $display("push,pop,full: %d %d %d", push_ptr,pop_ptr,full_s);
                end
            else
                full_s <= 0;

        end
endmodule]

ここに波形があります:

波形
外部リンク

テストベンチ モジュール fifoTb を追加。

// Inputs
reg rd_en;
reg rclk;
reg [7:0] din;
reg wr_en;
reg wclk;
reg rst;

// Outputs
wire[7:0] dout;
wire empty_out;
wire full;

// Instantiate the Unit Under Test (UUT)
fifo uut (
    .dout(dout), 
    .empty_out(empty_out), 
    .rd_en(rd_en), 
    .rclk(rclk), 
    .din(din), 
    .full(full), 
    .wr_en(wr_en), 
    .wclk(wclk), 
    .rst(rst)
);
initial begin
    // Initialize Inputs
    rd_en = 0;
    rclk = 0;

    wr_en = 0;
    wclk = 0;
    rst = 1;
    din = 8'h0;
    // Wait 100 ns for global reset to finish
    #100;
  rst = 0; 
    wr_en = 1;
    din = 8'h1;
    #101 din = 8'h2;
    rd_en = 1;
    // Add stimulus here

end

always begin #10 wclk = ~wclk; end

always begin #10 rclk = ~rclk; end
endmodule
4

1 に答える 1

1

の初期値があるため、値doutを持たないように出力信号に追加のロジックを追加することをお勧めします。'bxxxmemory_s'bxxx

assign dout = (rd_en) ? memory_s[pop_ptr] : 0;

テストベンチを作成する際のその他のヒント:

まず、デバイスがどのように機能するかを理解しようとすることが非常に重要です。

あなたの RTL コードを読んだところ、あなたの fifo は次のように機能すると結論付けました。

書き込み操作

always @(posedge wclk)
  begin
     if (rst == 1)
       push_ptr <= 0;
     else if(wr_en == 1)
       begin
          memory_s[push_ptr] <= din;
          if (push_ptr == (depth -1))
            push_ptr <= 0;
          else
            push_ptr <= push_ptr + 1;
       end
  end

wr_enが高い場合、2 つの操作が実行されます。

  1. からの値は、 の次の正のエッジでによってポイントされ dinて書き込まれます。memory_spush_ptrwclk
  2. push_ptrが と等しい場合(depth -1)0がレジスタに書き込まれます。push_ptrそうでない場合、代わりにレジスタpush_ptrが 1 増加します。

    wr_enが Low の場合、書き込み動作は実行されません。

読み取り操作

assign dout = memory_s[pop_ptr];

always @ (posedge rclk)
  if (rst == 1)
    pop_ptr <= 0;
  else if (rd_en ==1)
    begin
       if (pop_ptr == depth-1)
         pop_ptr <=0;
       else
         pop_ptr <= pop_ptr+1;
    end

がハイのとき、レジスタをrd_enインクリメントしますif is not equal to else代わりに書き込みます。 レジスタ が指す値を常に保持します。pop_ptr1pop_ptrdepth-10doutmemory_spop_ptr

通常、実行する操作ごとにタスクを作成すると便利です。

  wr_en = 1;
  din = 8'h1;
  #101 din = 8'h2;
  rd_en = 1;

例として書き込みタスクと読み取りタスクを作成しましたが、上記のコードを置き換えたいと思うかもしれません。

task write(input [7:0] pdin);
   $display("[ testbench ] writing data: %0x", pdin);
   din <= pdin;
   wr_en <= 1;
   @(posedge wclk);
   din <= 0;
   wr_en <= 0;
endtask

task read(output [7:0] prdata);
   rd_en <= 1;
   @(posedge rclk);
   prdata = dout;
   rd_en <= 0;
   $display("[ testbench ] reading data: %0x", prdata);
endtask

タスクの使用方法は次のとおりです。

  write(8'hAA);
  read(read_data);

  write(8'hCC);
  read(read_data);

  write(8'hBC);
  read(read_data);

組み合わせ回路を作成する際に、リセットロジックを追加することはお勧めしません。

 always @*
 begin
         if (rst == 1)
             full_s <= 0; . . .

また、ほとんどの EDA ツール ベンダーは、組み合わせ回路ではブロッキング ( ) 代入を使用し、順序回路では=ノンブロッキング代入 ( ) を使用することを推奨しています。<=

を呼び出して終了したら、シミュレーションを終了します$finish

initial begin
   #1000; $finish;
end
于 2015-01-23T11:05:32.267 に答える