2017-01-30 6 views
0

私はVerilogの初心者で、32ビットレジスタを含むレジスタファイルを作成しようとしています。私はすべて正しく書いて読み込むことができますが、アドレス5b00000にある最初のレジスタ(R0と名づけましょう)は常に0に等しくなければならず、いつでも変更してはいけません。テストベンチでそれを読むとき、R0が0または00000000の代わりに突然 "xxxxxxxx"になったときに問題が発生します。残りのレジスタは正しく読み取られました。コードで何が間違っているのでしょうか?このコードの回避策は何ですか?以下はコードです最初のレジスタを0に割り当てて書き込みしない

module regfile (
    clk, 
    nrst, 
    rd_addrA, 
    rd_addrB, 
    wr_addr, 
    wr_en, 
    wr_data, 
    rd_dataA, 
    rd_dataB 
); 

//Input and output ports 
input wire clk; 
input wire nrst; 
input wire [4:0] rd_addrA; 
input wire [4:0] rd_addrB; 
input wire [4:0] wr_addr; 
input wire wr_en; 
input wire [31:0] wr_data; 
output reg [31:0] rd_dataA; 
output reg [31:0] rd_dataB; 

reg [31:0] regfile[0:31]; 
integer i; 

always @ (nrst) 
    begin: RESET 
     if(nrst == 0) begin 
      for(i = 0; i < 32; i++) begin 
       regfile[i] = 0; 
      end 
     end 
    end 

always @(rd_addrA or rd_addrB) 
    begin: READ 
     if(rd_addrA) begin 
      case (rd_addrA) 
       5'b00000: rd_dataA = regfile[0]; 
       5'b00001: rd_dataA = regfile[1]; 
       5'b00010: rd_dataA = regfile[2]; 
       5'b00011: rd_dataA = regfile[3]; 
       5'b00100: rd_dataA = regfile[4]; 
       5'b00101: rd_dataA = regfile[5]; 
       5'b00110: rd_dataA = regfile[6]; 
       5'b00111: rd_dataA = regfile[7]; 
       5'b01000: rd_dataA = regfile[8]; 
       5'b01001: rd_dataA = regfile[9]; 
       5'b01010: rd_dataA = regfile[10]; 
       5'b01011: rd_dataA = regfile[11]; 
       5'b01100: rd_dataA = regfile[12]; 
       5'b01101: rd_dataA = regfile[13]; 
       5'b01110: rd_dataA = regfile[14]; 
       5'b01111: rd_dataA = regfile[15]; 
       5'b10000: rd_dataA = regfile[16]; 
       5'b10001: rd_dataA = regfile[17]; 
       5'b10010: rd_dataA = regfile[18]; 
       5'b10011: rd_dataA = regfile[19]; 
       5'b10100: rd_dataA = regfile[20]; 
       5'b10101: rd_dataA = regfile[21]; 
       5'b10110: rd_dataA = regfile[22]; 
       5'b10111: rd_dataA = regfile[23]; 
       5'b11000: rd_dataA = regfile[24]; 
       5'b11001: rd_dataA = regfile[25]; 
       5'b11010: rd_dataA = regfile[26]; 
       5'b11011: rd_dataA = regfile[27]; 
       5'b11100: rd_dataA = regfile[28]; 
       5'b11101: rd_dataA = regfile[29]; 
       5'b11110: rd_dataA = regfile[30]; 
       5'b11111: rd_dataA = regfile[31]; 
       default: rd_dataA = 16'hXXXX; 
      endcase 
     end 

     if(rd_addrB) begin 
      case (rd_addrB) 
       5'b00000: rd_dataB = regfile[0]; 
       5'b00001: rd_dataB = regfile[1]; 
       5'b00010: rd_dataB = regfile[2]; 
       5'b00011: rd_dataB = regfile[3]; 
       5'b00100: rd_dataB = regfile[4]; 
       5'b00101: rd_dataB = regfile[5]; 
       5'b00110: rd_dataB = regfile[6]; 
       5'b00111: rd_dataB = regfile[7]; 
       5'b01000: rd_dataB = regfile[8]; 
       5'b01001: rd_dataB = regfile[9]; 
       5'b01010: rd_dataB = regfile[10]; 
       5'b01011: rd_dataB = regfile[11]; 
       5'b01100: rd_dataB = regfile[12]; 
       5'b01101: rd_dataB = regfile[13]; 
       5'b01110: rd_dataB = regfile[14]; 
       5'b01111: rd_dataB = regfile[15]; 
       5'b10000: rd_dataB = regfile[16]; 
       5'b10001: rd_dataB = regfile[17]; 
       5'b10010: rd_dataB = regfile[18]; 
       5'b10011: rd_dataB = regfile[19]; 
       5'b10100: rd_dataB = regfile[20]; 
       5'b10101: rd_dataB = regfile[21]; 
       5'b10110: rd_dataB = regfile[22]; 
       5'b10111: rd_dataB = regfile[23]; 
       5'b11000: rd_dataB = regfile[24]; 
       5'b11001: rd_dataB = regfile[25]; 
       5'b11010: rd_dataB = regfile[26]; 
       5'b11011: rd_dataB = regfile[27]; 
       5'b11100: rd_dataB = regfile[28]; 
       5'b11101: rd_dataB = regfile[29]; 
       5'b11110: rd_dataB = regfile[30]; 
       5'b11111: rd_dataB = regfile[31]; 
       default: rd_dataB = 16'hXXXX; 
      endcase 
     end 
    end 

always @ (posedge clk) 
    begin: WRITE 
     if(wr_en == 1'b1) begin 
      if(wr_addr != 5'd0) begin 
       regfile[wr_addr] = #1 wr_data; 
       //$display("%X", regfile[wr_addr]); 
      end 
      else begin 
       $display("R0: %X", regfile[wr_addr]); 
      end 
     end 
    end 

endmodule 

ありがとうございました。

+0

入力信号のタイミングがわかるように、テストベンチコードを記入してください。 – toolic

+0

レジスタに何があっても値を含める場合は、初期条件も必要です。これにより、あなたの 'R0'が値ゼロを含む何らかの理由でGSRまたはあなたのリセットがヒットしなかった場合に確実になります。 –

答えて

1

if(rd_addrA)は、if(rd_addrA>0)と解釈されます。したがって、regfile[0]に到達できません。すべてのエントリが有効なので、if文は必要ありません。あなたの主な質問に関連していない

その他の問題:

regfileは、2つの異なる常にブロックに割り当てられているので、あなたのコードでは、論理合成されていません。 regfileのリセットと書き込みを1つのalwaysブロックにマージする必要があります。同期リセット用のalways @(posedge clk)(FPGA用に推奨)。非同期リセットの場合はalways @(posedge clk or negedge nrst)(ASICの場合は再開)。

組み合わせブロックの感度を指定するのは、1995年版の場合のみ旧式です。 2001年以来、自動選択性(always @*または同義語always @(*))は、組み合わせブロックを開始するための完全な方法です。モジュールヘッダースタイルの推奨事項もVerilog-1995以降に変更されています。 Verilog-1995スタイルはまだ有効でサポートされています。ちょうど完成していません。

ノンブロッキング割り当て(<=)で同期ロジック(クロックイネーブルまたはラッチイネーブルによって割り当てられたレジスタ)を割り当てる必要があります。ブロッキングとノンブロッキングの割り当てを適切に使用しないと、RTLとゲートの間の動作ミスマッチのリスクが高くなります。

ケースステートメントは、rd_dataA = regfile[rd_addrA];という1行に簡略化することができます。しかし、いくつかのシンセサイザーはcase文に比べてこのスタイルを最適化しないので、合成結果を確認してください。

+0

なぜFPGAで同期リセットを推奨しますか?私は非同期リセットがFPGAとASICの両方に推奨される技術だと考えました – Prashant

+0

ほとんどのFPGAは、非同期リセット/プリセット(ある場合)を備えた限られた数のフロップを持っています。少なくともデザイナーがアクセス可能なもの。 FPGAは、通常、パワーオンリセット値を定義するために「初期」ブロックを使用します。 ASICシンセサイザは、通常、初期ブロックを無視するため、非同期リセットが使用されます。 – Greg

+0

私は、非同期リセットが主にパワーオンリセットに使用されるべきであることを明確にすべきです。通常の操作では、ほとんどのシナリオでは同期リセットが推奨されます。例:カウンタは決して非同期にリセットされるべきではありません(メタ安定性の問題)。 – Greg

関連する問題