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 + 5はxを生成します。未知との算術はすべて未知を生成します。出力はxが4個並ぶaaaaです。
設計でxが現れる一般的な原因:
- 宣言されたがresetされたことがない
reg(ほとんどの合成可能Verilogは明示的なresetでクリアする)。 - defaultがない
case文に、どのcaseにも一致しない入力値が当たった。 - リファクタ後に唯一のドライバを失った
wire。 - 一方の分岐がsignalを代入し、他方が代入しない
if/else(カバーしないとxをラッチ)。 - vectorや配列の末尾を超えて読む。
X伝播:ほんの少しのxがすべてを台無しに
xの残酷なところは伝播することです。オペランドに1つのxビットがあると結果全体がxになります:
0 & xは0(0とのANDは常に0)、1 | xは1(1とのORは常に1)です。シミュレータはビット単位で悲観的ですが、恒等性は尊重します。算術や比較はそれほど寛大ではありません。
これが、1つの未初期化registerが出力バス全体をxxxxにできる理由です。任意のxから逆方向にたどれば、ソースが見つかります。
zはどう現れるか
zは誰も駆動していないwireの値です:
このスニペットの2つのパターン:
floatingは宣言されただけで決して駆動されません。デフォルトでzです。data_outは意図的なtri-stateです。enableが低のとき、出力は明示的にzに解放されます。これがバスドライバが「手放す」方法で、別のドライバが引き継げます。
内部ロジックでは、zはほぼ常に間違いです。双方向ピンや共有バスでは、zは正にそれが正しい状態です。
==と===の比較
通常の等価演算子==は、どちらかのオペランドがxまたはzビットを持つとxを返します:
===(とそのパートナー!==)はxとzを含む厳密なビット単位の比較を行います。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だらけで見つめています。レシピ:
- 最も早い
xを見つける。 波形を時間方向に戻ります。最初にxになったsignalがソースに最も近いです。 - そのドライバを見つける。 ソースを開く。何がこのsignalを代入する?
assign?alwaysブロック? - ドライバの入力を確認する。 ドライバの右辺に
xがあれば、伝播がちゃんと動いている - バグは上流。 - ドライバがきれいな入力で
xを生成するなら、ドライバが不完全。 defaultが欠けたcase、elseが欠けた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をチェックするには?
===演算子を使います。xとzを含めてビット精密に比較します。a === 1'bxはaが実際にxのとき真です。通常の==はどちらかのオペランドがxビットを含むとxを返すので、a == 1'bxは決して欲しい答えではありません。$isunknown(a)もあり、きれいなブール値です。
Verilogでデフォルトとしてxを代入できますか?
はい。case文での意図的なテクニックです:default: out = 'x;は合成ツールに「このケースは決して起きないと約束する、自由に最適化してくれ」と伝えます。コストはシミュレーションで起きてしまった場合にxが伝播してバグが見えることです。defaultが到達不能であることをすでに証明済みのときに使い、caseを書かない手段として使うのではありません。