2つの名前、1つの役割
Verilogのすべてのsignalには型があります。最初に出会う2つはwireとregです。両方とも値を保持できます。両方ともシングルビットでもマルチビットでも可能です。違いはsignalが 何であるか ではなく、 誰が駆動するか です。
wiresignalは手続きブロックの 外側 から駆動されます。assign文、サブmoduleの出力、またはmoduleの入力ポートからです。regsignalは手続きブロックの 内側 から駆動されます。initialまたはalwaysです。
それがルールの全部です。キーワード名はモダンなVerilogの書き方より前のものなので不格好です。regは 常に ハードウェアのregisterになるわけではありません。理由は読み進めてください。
Wire:連続的な接続
wireは電気的なwireです。ドライバが生成しているものを連続的に運びます。wireが駆動される2つの方法:
3つの注目点:
yとzはmodule内でwire、testbenchでも再びwireと宣言されています。- それらは
assignで駆動されます。連続代入形式です。=の右辺はそこにあるsignalが変わるたびに再計算されます。 alwaysブロック内でyをwireのままにしてy = a & bと書くことは できません 。コンパイラが拒否します。
wireキーワードを忘れると、Verilogはsignalを暗黙的に1ビットwireとして宣言します。便利なこともあれば、静かなバグの原因にもなります。多くのチームは暗黙的なwireでエラーにするツールオプションを有効にしています。明示的にして、罠を避けましょう。
Reg:手続きブロック内のストレージ
regはinitialまたはalways内で代入するsignalです。名前は言語の初期に「register」のように聞こえた名残です。モダンな使い方では、regは単に 手続き的コードが書き込むsignalの型 です。
countはmodule内ではreg(alwaysブロックが書き込むから)で、testbench内ではwire(DUTの出力ポートが駆動するから)です。同じsignal、異なる役割、各スコープで異なる型です。
なぜ「Reg」が常に「Register」を意味しないか
これは最もよくある初心者の罠です。このmoduleはyをregとして宣言していますが、合成されたハードウェアにはflip-flopが含まれません:
always @(*)ブロックは どの 入力変化にも感応します。組み合わせです。合成ツールはこのパターンを見てAND gateを生成します。flip-flopもクロックもなく、ロジックだけです。regキーワードは、yがalways内で代入されるから純粋に構文上の要件として必要なだけです。
実際のflip-flopを得るには、alwaysブロックがクロックエッジに感応する必要があります:
always @(posedge clk) begin
q <= d;
end
これが「合成ツールよ、flip-flopを作って」パターンです。クロック同期の感応リスト、非blocking代入。同じregキーワード、まったく異なるハードウェア。区別はAlways BlockとBlocking vs Non-blockingで扱います。
実用上の判断
signalを宣言するたびに自問してください:「どう駆動するか?」
assignで駆動? →wire。- サブmoduleの出力ポートに接続? →
wire。 - moduleの入力ポート? →
wire。(inputは常にwire。) initialまたはalwaysから駆動? →reg。- 手続き的コードで駆動するmoduleの出力ポート? →
output reg。 assignで駆動するmoduleの出力ポート? →output wire。(または単にoutput。方向だけでwireをデフォルトとする。)
この判断木はプレーンVerilogで出会うすべての状況をカバーします。
ドライバの競合
wiresignalは理論上 複数 のドライバを持てます。それがtri-stateバスの動作で、複数のmoduleが同じwireを駆動でき、非アクティブのものはハイインピーダンス(z)になります。通常のロジックでは、同じwireに2つのassignを書くと未定義動作になります:
assign y = a;
assign y = b; // 悪い - yに2つのドライバ
シミュレータは片方を選ぶかもしれないし、signalをxにするかもしれず、ツール次第です。どちらにせよバグです。バスを明示的に作る場合以外、1つのwireに1つのドライバ。
regsignalは1つの手続きブロックからしか駆動できません。2つのalwaysブロックが同じregに代入することは合成エラーで、シミュレーションでも奇妙です。同じルール:1つのドライバ。
SystemVerilogのアップデート:logic
SystemVerilog(Verilogが進化したスーパーセット)は、両方を置き換える単一のキーワードlogicを追加しました。logicsignalはassignまたは手続きブロックで駆動できます(ただし両方ではない)。コンパイラは多ドライバのバグを誤って作るのを止めてくれます。
module modern(input logic a, input logic b, output logic y);
assign y = a ^ b;
endmodule
新しいプロジェクトを始めて、ツールがSystemVerilogをサポートしている(このページのエディタは-g2012でサポート)なら、どこでもlogicを使えばルールが簡単になります。プレーンの.vファイルは依然としてwire/regの分割が必要で、両スタイルとも今後ずっと現場で見られるでしょう。
次に読むもの
次のドキュメントVectors and Arraysでは、同じ2つの型をマルチビット化する方法を示します。バス幅、range、packedディメンション、ビットのvectorとvectorの配列の違い。1ビット加算器より大きなものを作る前に必要なすべてです。
よくある質問
Verilogのwireとregの違いは?
wireとregはどちらもシミュレーションのどの瞬間もsignal値を保持しますが、選び方は誰がsignalを駆動するかに基づきます。wireは手続きブロックの外側から駆動されます。assignまたはサブmoduleの出力です。regはinitialまたはalwaysブロックの内側から駆動されます。名前は歴史的なもので誤解を招きます。regは常に「register」を意味するわけではありません。
Verilogのregはflip-flopを意味しますか?
必ずしもそうではありません。regは、そのalwaysブロックがクロックエッジに感応し、非blocking代入を使うときにのみflip-flopに合成されます。組み合わせalways @(*)ブロック内で代入されるregは、純粋な組み合わせ論理に合成されます。このキーワードはハードウェアではなくVerilogのデータ型を選択します。
wireとregはいつ使い分けるべき?
経験則:signalをassignで駆動するか、サブmoduleの出力ポートに接続するならwire。alwaysまたはinitialブロックの内側でsignalに代入するならreg。moduleへのinputは常にwire。outputは、assignで駆動ならwire、手続きブロックで駆動ならreg。
alwaysブロック内でwireに代入できますか?
いいえ - 構文エラーです。wireは連続代入(assign)またはサブmoduleインスタンスの出力としての接続でのみ駆動できます。initialまたはalwaysの内側のものはreg(SystemVerilogならlogic)をターゲットにしなければなりません。コンパイラはこれを検出し「左辺の型不一致」を訴えます。
SystemVerilogのlogicとは?
logicはSystemVerilogによるwireとregの統一です。連続代入または手続きブロックで駆動できます(ただし両方同時には不可)。モダンなコードではlogicをどこでも使い、wire/regの区別を忘れる傾向が増えています。プレーンVerilogのファイルは依然として選択する必要があります。