設計・検証の手引きと早見表
コードを書き始めるとき、警告で止まったとき、レビュー前に使える手引きだよ。note教材の特典に分かれていた内容を、教科書と実習へつながる形でまとめたよ。
1. assign / alwaysを選ぶ
まず「状態を持つか」「いつ更新するか」を決めるよ。クロックで状態を更新するなら always @(posedge clk)、現在の入力だけで決まる組合せなら assign または always @* を選ぶ。短い式にはassign、複数の条件や出力を整理したいときにはalwaysが読みやすいことが多いんだ。
条件が2個以上ならassign禁止、という言語規則はないよ。三項演算の入れ子も合法。読者が優先順位を追えるか、全経路で出力が決まるかを基準に、チームの規約に合わせよう。
| 目的 | 書き方の例 | 確認すること |
|---|---|---|
| 配線や短い論理式 | assign y = a & b; |
幅、符号、駆動元 |
| 条件で選ぶ組合せ | always @* と = |
すべての出力に全経路で代入 |
| エッジで保持・更新 | always @(posedge clk) と <= |
リセット、enable、優先順位 |
| 意図したラッチ | 対象設計の規約に従う | 透明期間、対象資源、タイミング |
エディタのスニペットは入力補助だよ。リセット値や信号名の空欄を埋めたら、必ずコンパイルと試験を行おう。動作するテンプレート を小さく変更して始める方法もあるよ。
2. Warningを理由付きで処理する
最初のエラーのファイル・行・信号名を読み、その行の少し前も調べる。文法エラーはセミコロン、begin/end、括弧、モジュール境界の欠落が原因のこともあるよ。後続のエラーは最初の不備から連鎖しているかもしれないんだ。
次の文言は診断の種類を示す例。特定ツールで実測したログではなく、番号や重要度は製品・版・設定によって異なるよ。
| 診断の種類 | まず見るもの | 対処と再確認 |
|---|---|---|
| Latch inferred | 組合せ出力に代入しない経路 | 全経路への代入。意図した保持ならタイミング仕様を確認 |
| Multiple drivers | 同じ信号を書くassign/always/接続 | RTL変数の更新元を一つへ集約。外部バスの三態制御とは区別 |
| Combinational loop / feedback | 記憶素子なしで出力が入力計算へ戻る経路 | 接続・式・階層を追って循環を除く |
| Pin assignment / I/O standard | 基板の回路図、対象デバイス、電圧規格 | ピン番号と規格を合わせる。一般例の制約を流用しない |
| Implicit net | 未宣言名、タイポ、include漏れ | 宣言と名前を修正しdefault_nettype noneで確認 |
| Unused / truncated / width mismatch | 未接続、使わないビット、ポート幅 | 意図的なら根拠を明示。必要な上位ビットは保存 |
| CDC | 送信・受信クロックと信号の性質 | 同期化、パルス転送、バス整合性を方式ごとに検証 |
| Timing violation / negative slack | 制約、最長/最短経路、setup/hold | 誤制約を修正、構造を改善し配置配線後も再確認 |
| Memory inferred | 配列の用途、容量、読み出し遅延 | 推論そのものは異常とは限らない。期待するRAM資源か確認 |
警告を一律に消すための抑制設定を先に入れないでね。原因、仕様への影響、修正または許容する理由を残すよ。判断に迷ったら、ツール名・版・正確な診断番号と文言で公式ドキュメントを探そう。ログ、Timing Report、SDC/XDC、ピン定義を一緒に読むと切り分けやすいんだ。
3. 20のコード確認ポイント
| 項目 | 確認と修正の入口 |
|---|---|
| 1. ifの代入漏れ | 組合せはelseまたは先頭の既定値で全経路を覆う。FFのenable保持は別 |
| 2. caseの代入漏れ | 空のdefaultだけでは解決しない。各出力の代入を確認 |
| 3. FFでのブロッキング代入 | 更新順・他プロセスとの競合を確認し、状態更新を<=へ |
| 4. 組合せでのNBA | 不要なデルタサイクルや依存関係を避けるため=へ |
| 5. 感度リスト漏れ | always @*。入力単独の変化も試す |
| 6. 暗黙ネット | default_nettype none。宣言済みの別信号へのタイポは試験でも確認 |
| 7. 初期化 | 仕様で必要な状態・validをリセット。無効なデータ部まで一律リセットするかは資源と仕様で判断 |
| 8. RTLの#遅延 | TB用の時間記述を混ぜない。待ちサイクルはカウンタや状態で表す |
| 9. CDC直結 | 単ビット、パルス、複数ビットで転送方式を分ける |
| 10. 幅の不一致 | 拡張と切り捨てを明示し、境界値を試す |
| 11. 論理式のクロック生成 | 一般ロジックのANDよりenable、必要なら専用クロック資源 |
| 12. ==と=== | RTLの機能比較とTBのX/Zを含む厳密判定を区別 |
| 13. 除算・剰余 | 幅・符号・定数か可変かを確認し、面積と遅延を測る。符号なしの2のべき乗除算はシフトで表せるが、負値の丸めは単純置換できない |
| 14. wire/reg | ネットと手続き変数を区別。型だけで回路は決まらない |
| 15. タイムアウト | クロック停止でも有限時間で失敗終了できるTBへ |
| 16. TBの競合 | 刺激・取り込み・判定の時刻を分ける |
| 17. リセット解除忘れ | 極性と解除後に実際に動作する試験を確認 |
| 18. 合成対象にTB | トップ名とファイルリストを分離 |
| 19. 周波数と周期 | MHzとnsを換算し実際のクロックへ適用 |
| 20. casez/casex | 入力側のZ/Xまで無視しないか、無効入力を試す |
切り分けの練習: FSMが動かないなら、リセット→クロック→入力イベント→state→next_stateを追おう。出力が更新されないなら、enable・代入経路・接続・幅を順に見る。RTLだけ通って実機で不安定なら、タイミング制約、CDC、リセット解除、ピンとボード条件を確認する。ただし症状だけで原因を断定せず、各段の観測結果を残してね。
CIにコンパイル、自己判定TB、必要なLintを組み込むと、同じ不具合の再発に気づきやすくなるよ。Warningを失敗にする規約と、理由付きで許容する診断を分けよう。単なる文字列検索は点検の入口にはなるけれど、RTLの構造解析やCDC検証の代わりにはならないんだ。
4. SystemVerilog対応表
| 記法 | 意味とVerilogとの関係 |
|---|---|
| logic | 4値のデータ型。ネット/変数の区分とは別。多重駆動を解決する配線にはwireなどのネット型が必要 |
| always_ff | FFとして使う手続きブロックの意図と制約を表す。状態更新は<=を基本にする |
| always_comb | 組合せの意図、時刻0の評価、代入先の制約などを持つ。always @*の単なる別名ではない |
| always_latch | 意図したラッチを表す。対象ツールと設計規約に従う |
| '0 | 代入などの文脈に合わせた全ビット0。Verilogの複製記法より短く書ける |
| interface / modport | 関連信号をまとめ、役割ごとのアクセス方向を表す |
| class / rand / randomize() | 検証用のオブジェクトと制約付き刺激生成。ツールの対応範囲を確認 |
logic [7:0] data_q;
always_ff @(posedge clk or negedge rst_n)
if (!rst_n) data_q <= '0;
else data_q <= data_d;
これは負論理非同期リセット付きの8ビットFFだよ。logic と書いても自動で回路が安全になるわけではなく、駆動元と更新条件の設計は必要。always_comb でも全経路に代入しよう。診断の厳しさはツールで異なるんだ。
always_comb begin
case (sel)
2'd0: out = a;
2'd1: out = b;
2'd2: out = c;
default: out = '0;
endcase
end
bus_if.data は宣言を調べて、interfaceの信号、構造体のメンバー、階層参照のどれかを確認しよう。ドットがあるだけでinterfaceと決めつけないでね。モジュール接続の .clk(clk) はポート名を指定する構文だよ。
input logic / output logic の宣言では方向と幅に加え、ネットか変数かの規則、どこから駆動するかも読む。クラス・ランダム制約はRTL設計の代わりではなく検証を組み立てる機能だよ。ランダム試験にも期待値、カバレッジ、再現用シードが必要なんだ。
5. 次の学習を選ぶ
最初は AND → カウンタとTB → 電子錠 の順に、ひとつずつ自分で実行しよう。その後、使うデバイスの公式資料を読み、ボードのクロックとI/O条件を確認して実機へ進むよ。
| 目標 | 次に確かめること |
|---|---|
| FPGAでセンサーや制御 | UARTの送受信、SPIのクロック位相/極性、I2Cのオープンドレインと応答 |
| データ処理・高性能FPGA | パイプライン、valid/ready、同期FIFO、非同期FIFOとCDC |
| SoC接続 | AXI4-Liteのレジスタアクセス、AXI4のバースト、AXI4-Streamの転送規則 |
| ASIC/LSI設計 | 合成と制約、リセット、CDC、SystemVerilog設計、実装フロー |
| 検証 | 自己判定TB、SystemVerilogの制約付きランダムとカバレッジ、必要に応じてUVMや形式検証 |
非同期FIFOのグレイコードは、ポインタ転送時の変化を扱いやすくする仕組みだよ。グレイコードだけでCDCが完成するわけではなく、同期化、full/empty判定、リセット、配線の制約まで学ぼう。通信やAXIも、信号名を覚えるだけでなく「いつ受理されたか」を仕様に沿って検証してね。
資料を調べる入口
対象の製品・バージョンの資料へ切り替えて確認してね。このサイトの実行確認は各実習に記した環境と範囲を示していて、すべてのツールや実機での動作を保証するものではないよ。
配布教材と検証範囲
各ZIPに回路、テストベンチ、実行手順をまとめたよ。Windows / Icarus Verilog 13.0でコンパイルとRTLシミュレーションを確認。合成・配置配線・FPGA実機の結果は含まないよ。PASSの範囲は各ページとREADMEで確認してね。
- AND回路・全4入力(ZIP) — 解説と結果
- ブール代数・144比較(ZIP) — 解説と結果
- ラッチと感度リスト(ZIP) — 解説と結果
- 4ビットカウンタ・10/40チェック(ZIP) — 解説と結果
- カウンタ・LED・パイプライン・電子錠(ZIP) — 解説と結果
- X伝搬と比較の見逃し(ZIP) — 解説と結果
- バス読み書きtask・16チェック(ZIP) — 解説と結果
- セレクタ4記法・272チェック(ZIP) — 解説と結果
- 7セグの条件漏れ・34チェック(ZIP) — 解説と結果
- 加算器3記法・1024比較(ZIP) — 解説と結果
- wire/regと記憶・19チェック(ZIP) — 解説と結果
- functionの幅とゲート接続・68チェック(ZIP) — 解説と結果
- 未使用状態からの復帰・19チェック(ZIP) — 解説と結果
- case/casez/casex・60チェック(ZIP) — 解説と結果
- 優先順位エンコーダ3記法・48チェック(ZIP) — 解説と結果
- ビット幅と符号・544チェック(ZIP) — 解説と結果
- 位置接続と名前付き接続・1024チェック(ZIP) — 解説と結果
書き換えたコードでは、元の実行ファイルを使わずにコンパイルからやり直そう。テストの期待値まで回路の誤りに合わせないよう、仕様を基準に確認するんだ。
テーマから移管先を探す
noteの41本の無料原稿で扱っていたテーマを、教科書の各章へまとめた索引だよ。同じ話は重ねず、必要な補足と実験へつないでいるよ。
| テーマ | 読む場所 |
|---|---|
| 学習の入口 | STの解説・実習 |
| 意図しないラッチ | O5の解説・実習 |
| 複数出力の代入漏れ | O5の解説・実習 |
| Sim/Synthミスマッチ | O2の解説・実習 |
| ラッチとD-FF | L3の解説・実習 |
| ブロッキングとノンブロッキング | E2の解説・実習 |
| HDL設計の全体像 | E3の解説・実習 |
| RTLとテストベンチ | T1の解説・実習 |
| Warningと論理合成 | E3の解説・実習 |
| RTL・GLS・実機の違い | T6の解説・実習 |
| 論理ゲート | L1の解説・実習 |
| ブール代数 | L1の解説・実習 |
| 真理値表 | L1の解説・実習 |
| 回路記号 | L1の解説・実習 |
| タイミングチャート | L1の解説・実習 |
| 代入順序とシフト動作 | O2の解説・実習 |
| 組合せ回路と順序回路 | L2の解説・実習 |
| 全加算器 | C3の解説・実習 |
| 論理式の簡単化 | L2の解説・実習 |
| リップルキャリー | C3の解説・実習 |
| キャリー・ルックアヘッド | C3の解説・実習 |
| セレクタ | C1の解説・実習 |
| 7セグと条件漏れ | C2の解説・実習 |
| ラッチの透過とFF | L3の解説・実習 |
| カウンタとクロック | C6の解説・実習 |
| シフトレジスタの遅延 | C6の解説・実習 |
| タイミング制約 | S2の解説・実習 |
| FSMの未使用状態 | O3の解説・実習 |
| ゲートプリミティブの接続順 | E5の解説・実習 |
| functionの戻り値幅 | E5の解説・実習 |
| 可変ビット選択と範囲 | E6の解説・実習 |
| casexと未知値 | O6の解説・実習 |
| ifの優先順位 | C2の解説・実習 |
| wireとreg | E4の解説・実習 |
| エンコーダとvalid | C2の解説・実習 |
| 感度リスト | O2の解説・実習 |
| ビット幅の不一致 | E4の解説・実習 |
| X伝搬と検査 | T4の解説・実習 |
| 位置接続と名前付き接続 | C7の解説・実習 |
| signedとunsigned | E4の解説・実習 |
| Xを含む比較 | O8の解説・実習 |