Menu

Verilog XとZの値:未知とハイインピーダンスsignalを解説

Verilogのsignalは2つではなく4つの値を持ちます。シミュレーションにおけるx(未知)とz(ハイインピーダンス)の意味と、デバッグ方法。

このページのコードはエディタで実行できます - 編集してすぐに結果を確認できます。

2-state vs 4-state論理

ソフトウェアではビットは0か1です。Verilogでは、ビットは 4つの 値のいずれかになります:

  • 0 - wireが低に駆動されている。
  • 1 - wireが高に駆動されている。
  • x - wireの値は 未知 。シミュレータが判別できない。
  • z - wireが ハイインピーダンス 。何も駆動していない。

その4-state モデルは、ハードウェアが同じ問題を持つから存在します。実際のwireは低に結ばれているか、高に結ばれているか、未定義(2つのソースが争う)か、フローティング(ドライバなし)になります。シミュレータは有用であるために4つすべてをモデル化しなければなりません。

xはどう現れるか

これを実行して出力を見てください:

aは宣言されていますが書き込まれないので、xのままです。x + 5xを生成します。未知との算術はすべて未知を生成します。出力はxが4個並ぶaaaaです。

設計でxが現れる一般的な原因:

  • 宣言されたがresetされたことがないreg(ほとんどの合成可能Verilogは明示的なresetでクリアする)。
  • defaultがないcase文に、どのcaseにも一致しない入力値が当たった。
  • リファクタ後に唯一のドライバを失ったwire
  • 一方の分岐がsignalを代入し、他方が代入しないif/else(カバーしないとxをラッチ)。
  • vectorや配列の末尾を超えて読む。

X伝播:ほんの少しのxがすべてを台無しに

xの残酷なところは伝播することです。オペランドに1つのxビットがあると結果全体がxになります:

0 & x0(0とのANDは常に0)、1 | x1(1とのORは常に1)です。シミュレータはビット単位で悲観的ですが、恒等性は尊重します。算術や比較はそれほど寛大ではありません。

これが、1つの未初期化registerが出力バス全体をxxxxにできる理由です。任意のxから逆方向にたどれば、ソースが見つかります。

zはどう現れるか

zは誰も駆動していないwireの値です:

このスニペットの2つのパターン:

  • floatingは宣言されただけで決して駆動されません。デフォルトでzです。
  • data_outは意図的なtri-stateです。enableが低のとき、出力は明示的にzに解放されます。これがバスドライバが「手放す」方法で、別のドライバが引き継げます。

内部ロジックでは、zはほぼ常に間違いです。双方向ピンや共有バスでは、zは正にそれが正しい状態です。

=====の比較

通常の等価演算子==は、どちらかのオペランドがxまたはzビットを持つとxを返します:

===(とそのパートナー!==)はxzを含む厳密なビット単位の比較を行います。testbenchでx/zをテストするときはこれを使ってください。===は合成不可ですが、testbenchのinitialブロック内ではそれは問題ありません。

$isunknown(expr)システム関数は「この式はxまたはzビットを持つか?」と尋ねるきれいな方法です。あれば1、なければ0を返します。

意図的なdon't-careとしてのx

論争のあるが正当なパターン:状態機械のdefaultケースでの'xは、合成ツールに「この状態は到達不能、自由に最適化してくれ」と伝えます:

case (state)
    IDLE:    next_state = go ? RUNNING : IDLE;
    RUNNING: next_state = done ? IDLE : RUNNING;
    default: next_state = 'x;   // 到達不能
endcase

合成ツールはxを使ってstateを統合し、gate数を減らせます。シミュレーションでは、推論が間違っていてdefaultが 実際に 到達されると、next_stateからxが伝播し、バグが即座に見えるようになります。

これはdefaultが本当に到達不能かを考え抜いた場合にだけ使ってください。そうでなければ、defaultを安全なstateに設定してください。

一般的なデバッグレシピ

波形がxだらけで見つめています。レシピ:

  1. 最も早いxを見つける。 波形を時間方向に戻ります。最初にxになったsignalがソースに最も近いです。
  2. そのドライバを見つける。 ソースを開く。何がこのsignalを代入する?assignalwaysブロック?
  3. ドライバの入力を確認する。 ドライバの右辺にxがあれば、伝播がちゃんと動いている - バグは上流。
  4. ドライバがきれいな入力でxを生成するなら、ドライバが不完全。 defaultが欠けたcaseelseが欠けたif、resetが欠けたregister。

ほとんどのx嵐バグは、resetの欠落、defaultの欠落、または接続されていないサブmoduleのいずれかに収束します。

次に読むもの

これでデータ型の全体像が揃いました。wire/reg、vector、parameter、数値リテラル、4-state論理モデル。次の章はそのすべてを使って式を組み立て始めます。あらゆる種類のoperator、ソフトウェアでは意味をなさないビットレベルのoperatorも含めて。

よくある質問

Verilogのxの意味は?

x未知の値です。xであるsignalは0かもしれないし1かもしれず、シミュレータには判別できません。signalが駆動されていないとき、2つのドライバが競合するとき、resetされる前にregisterが読まれるとき、未定義動作が静かに伝播するあらゆる場面で現れます。xはバグsignalとして扱ってください。ほぼ意図したものではありません。

Verilogのzの意味は?

zハイインピーダンスの値で、wireがまったく駆動されていません。tri-state出力(データバス、双方向ピン)の正当な状態ですが、内部signalでzは通常「ここに何も接続されていない」を意味する間違いです。合成ツールは明示的なtri-state出力イネーブル以外のzパターンを大半拒否します。

Verilogの出力がxxxxになるのはなぜ?

ほぼ常に、signalが何にも駆動されていないか、別のsignalからxが伝播されたかのどちらかです。逆方向にたどります。どのsignalがxか、何が供給しているか、ドライバはアクティブか。よくある犯人はcase文の欠落default、resetされていないregister、リファクタ後にドライバを失ったwireです。

Verilogでxまたはzをチェックするには?

===演算子を使います。xzを含めてビット精密に比較します。a === 1'bxaが実際にxのとき真です。通常の==はどちらかのオペランドがxビットを含むとxを返すので、a == 1'bxは決して欲しい答えではありません。$isunknown(a)もあり、きれいなブール値です。

Verilogでデフォルトとしてxを代入できますか?

はい。case文での意図的なテクニックです:default: out = 'x;は合成ツールに「このケースは決して起きないと約束する、自由に最適化してくれ」と伝えます。コストはシミュレーションで起きてしまった場合にxが伝播してバグが見えることです。defaultが到達不能であることをすでに証明済みのときに使い、caseを書かない手段として使うのではありません。

Coddy programming languages illustration

Coddyでコードを学ぼう

始める