回路検証を実際にやってみる
仕様から期待値を作り、失敗を見つけて、修正後にもう一度確認しよう。この章では、実行できるカウンタと電子錠の教材を使うよ。ゲートレベル検証は必要な入力資料と判断方法を学び、実行済みのRTL検証と区別して扱うね。
(1)ここで学ぶ内容
到達点は、PASSという文字だけを見るのではなく「何を、いつ、何と比較したか」を説明できることだよ。
| 修了判定 | 取り組む内容 |
|---|---|
| 1 | 合成後検証に必要な資料を選ぶ |
| 2 | RTLのXの楽観視を実習で調べる |
| 3 | カウンタに入れた不具合を検出する |
| 4 | 修正後に境界値と全ロード値を再検証する |
| 5 | 回路・テストベンチ・期待値を切り分ける |
(2)回路検証の手順
- ポート、リセット、優先順位、出力が有効になる時点を仕様にする。
- 仕様から入力列と期待値を作る。RTLの式をそのままコピーすると、同じ間違いを共有することがあるよ。
- RTLをコンパイルし、自己判定テストを実行する。最初の不一致をログと波形で調べる。
- 対象デバイスと制約を指定して合成・配置配線を行い、警告とタイミングレポートを確認する。
- プロジェクトで必要な合成後検証、CDC・リセット検証、等価性検証などを行う。
RTLシミュレーションは機能、静的タイミング解析は制約下の経路のタイミングを調べる。ゲートレベルシミュレーション(GLS)はネットリストを実行し、モデルが表す機能や初期化、タイミングチェックを調べる。遅延なしのGLSもあり、「GLSなら必ず実機の速度が分かる」とは言えないよ。
(3)ゲートレベル検証の必要性1
遅延付きGLSには、対応するネットリスト、セルのシミュレーションモデル、SDFなどの遅延情報、テストベンチが必要になる。セルモデルと遅延情報の版・条件をそろえ、アノテーションが成功したか確認しよう。タイミング違反の検出には、モデル側のタイミングチェックも関わるよ。
特定の入力列で違反が出なかったことは、すべての経路が安全だという証明にはならない。セットアップ/ホールド、入出力遅延、クロックの関係は S2の制約 とタイミングレポートで確認するんだ。
(4)ゲートレベル検証の必要性2
RTLの if は条件がXでも真側を選ばず、else側へ進むことがある。一方、ゲートの4値演算では出力にXが出る場合がある。この違いをXの楽観視として意識しよう。ただし、ゲートレベルなら出力全体が必ずXになるわけではないよ。論理式、入力値、モデルによって結果は変わる。
同じ変数を複数のalwaysから更新する記述は、競合や合成エラーの原因になる。合成警告を整理し、更新元と優先順位をRTLで明確にすることが先決だよ。配置配線でも最適化が行われるため、合成直後の図と物理レイアウトは単純に一対一とは限らない。
(5)適切な検証入力
正常動作だけでなく、リセット直後、最大値から0への折り返し、ロードとenableの同時指定、途中のリセット、保持、連続した異なるデータを試そう。入力回数を増やすだけでは同じ条件を繰り返すこともある。仕様の各項目と試験を対応させるのが大事だよ。
小さな論理回路なら全入力を列挙できる。L1の144比較はその例だね。状態を持つ回路では履歴も効くので、状態遷移、境界、優先順位を分けて考えよう。
(6)検証仕様からテストベンチを作成
ここでは T1のcounter4 を共通の検証対象にする。旧教材のCOUNT4LDとはポートが異なるので、次の仕様で統一するよ。
| 条件(上が優先) | 更新後のq |
|---|---|
| rst_n=0 | クロックを待たず0 |
| rst_n=1、load=1、立ち上がり | dataをロード。enableには依存しない |
| rst_n=1、load=0、enable=1、立ち上がり | 4ビットで+1。15の次は0 |
| rst_n=1、load=0、enable=0 | 保持 |
入力は立ち下がりで変え、立ち上がりの1ns後に比較する。10ns周期の教材でNBA更新後の値を見るための約束であり、1nsが実回路の遅延という意味ではないよ。
(7)修了判定1
問い:RTLの.vファイルだけで「配置配線後の遅延付きGLSを行った」と言えるだろうか。
答えと確認項目
言えないよ。対象の配置配線後ネットリスト、対応するセルモデルと遅延情報、シミュレータの設定、テストベンチが必要だね。アノテーションの成功率、モデルの読み込み、タイミングチェックの有効性、リセットや初期化を確認する。ここで配布するZIPはRTLの機能検証用で、合成後の測定結果は含まないよ。
(8)修了判定2
T4のX検出実習のZIPを使い、通常の比較と4値比較の違いを確かめよう。リンク先の実習では、Xの出た値を見落とす簡易テストと、異常を検出するテストを比較しているよ。
問い:実際値も期待値もXなら、actual !== expected は必ず失敗するだろうか。
答え
同じX同士はケース等価で一致するので、必ず失敗するわけではないよ。期待値が既知であることも確認しよう。既知値だけを許すバスなら、例えば if ((^expected) === 1'bx) $fatal(1, "unknown expectation"); と検査できる。XやZを仕様として許す場面は、許容するビットと時点を別に定義する必要があるよ。
(9)修了判定3
カウンタZIPを展開し、まず元の回路で40チェックを実行しよう。
iverilog -g2012 -Wall -s tb_counter4_extended -o extended.vvp counter4.v tb_counter4_extended.v
vvp extended.vvp
次にコピーした counter4.v の加算値 4'd1 を 4'd2 に変更し、同じコマンドでコンパイルし直してみよう。変更前の実行ファイルをそのまま実行しないよう注意してね。テストがFAILで停止したら、時刻・実際値・期待値を記録する。
なぜ検出できる?
リセット後の最初の加算で、仕様は1、壊した回路は2を出すためだよ。この欠陥はWindows / Icarus Verilog 13.0で検出済み。ロード値だけを試すテストでは加算部分の不具合を見逃す可能性があるね。
(10)修了判定4
加算値を戻し、コンパイルから再実行しよう。成功時は PASS: counter4 extended (40 checks) と表示される。全16値のロード、18回の連続カウント、保持、途中リセット、リセット優先と再開を含むよ。
一般のN進カウンタでは0〜N−1を使い、N−1の次に0へ戻す。6進なら終端は5であって6ではない。実習集のmodulo_counterでパラメータを変えるときは、テストの仕様も合わせて変えよう。リセットの同期/非同期を変えても、終端値の間違いは直らないよ。
(11)修了判定5(概要)
不一致の原因は回路とは限らない。①入力の与え方、②比較する時点、③期待値、④回路の順に情報をそろえよう。回路の内部信号だけを正解として参照すると独立した検査にならないので、仕様の表へ戻るんだ。
| 観測 | まず調べること |
|---|---|
| 最初からX | リセットの極性、クロック、未接続ポート、未初期化 |
| 毎回1サイクルずれる | 入力・比較のエッジ、NBA更新前に読んでいないか |
| 境界だけ違う | ビット幅、符号、終端比較、桁あふれ |
| 途中で停止する | waitの条件、クロック停止、タイムアウト |
(12)修了判定5(検証内容)
q=1の状態で、立ち下がりにload=1、data=11を設定したとする。次の立ち上がり直前はまだq=1、NBA更新後はq=11だよ。期待値ファイルの一行が「更新前」なのか「更新後」なのかを決めずに比較すると、正しい回路でも不一致になる。
| 観測点 | load | data | 期待するq |
|---|---|---|---|
| ロードする立ち上がりの直前 | 1 | 11 | 1 |
| 同じ立ち上がりの更新後 | 1 | 11 | 11 |
| 次の立ち上がりの更新後(load=0、enable=1) | 0 | 11 | 12 |
この表は仕様から作った期待値で、実測波形ではないよ。T1にはVCDから読み取った値の表があるので、両方の時刻の約束を比べよう。さらに 電子錠の4,096入力列や バスtaskの実習へ進むと、状態や出力を組み合わせた確認ができるよ。