第 3 回の終わりで、チップ v5 は配線とフィニッシュを終え、15,056 件の配線違反は既知の残課題として書き留めてありました。次のステップはサインオフタイミングです。業界と同じやり方で行い、その選択がバグを見つけることになりました。
サインオフは出荷するものを読む
配置配線ツールは自分のデータベースからタイミングを報告でき、OpenROAD にもそれができます。しかしファウンドリーへ、あるいは階層の 1 つ上へ渡るのはファイルです。配置配線ツールが書き出したネットリストと寄生成分(SPEF)です。サインオフは、そのファイルを別のツールで読むべきです。そこでプロジェクトのルールは サインオフは別ツールで行う でした。OpenRCX が寄生成分を抽出し、OpenROAD がネットリストと SPEF を書き出し、スタンドアロンの OpenSTA がそれを読みます。

抽出にはメタル層ごとのルールが必要で、sky130 には 5 層しかありません。10 層の代用スタックでは、OpenRCX は標準のルールでエラーを報告せずにクラッシュしました。そこで、上の層が下の層をコピーするルール(メタル 6〜8 はメタル 4、メタル 9〜10 はメタル 5 として)を生成し、そこから cworst と cbest を ±10% とした 4 つのコーナーを作りました。このルールは仮のものであり、数値が出てくる場所ではどこでもそう明記しています。
G2 では、抽出はそれ自体が 1 つのステージです。完成した設計を読み、コーナーごとに 1 つの SPEF を書き出し、ネットリストの隣にある設計データマネージャーにファイルをチェックインします。OpenSTA のシナリオはどちらもそこから取得します。
2:38YouTube で見る(英語) ↗Bilibili で見る(中国語) ↗
バグ 1:寄生成分のない 98,251 個のドライバー
最初のスタンドアロン OpenSTA の実行では、98,251 個のドライバーに寄生成分がないという警告が出て、さらに "instance not found" が 48,926 件、"net not found" が 431,493 件ありました。そのドライバーのうち約 77,000 個は配線がまったくないもので、これは想定どおりです。残りの 21,000 個は本物の配線で、そのほとんどはクロックツリー全体でした。
ところが、同じ SPEF で OpenROAD が自分のデータベースを読むと、一致しなかった名前は 490 個だけでした。ファイルは書き出したツールにとっては問題なく、他のどのツールにとっても壊れていたのです。
最初の誤った仮説
Claude Code の最初の答えは、クロックツリーツールがバッファに誤った名前を付けている、というものでした。もっともらしい説明で、裏づけとしてバッファを 1 つたどってもいました。エンジニアは別の問いを投げました。同じファイルは、そのモジュールの論理合成済みのネットを階層パス付きで正しく書いている。そこで正しくできていて、ここでできていないのは何か。
その問いが指したのは CTS ではなく書き出し処理でした。ツールがサブモジュール内に作るオブジェクトは、名前と所属するモジュールの組として保存されます。ネットリストの書き出し処理はモジュールを読みます。write_spef は読んでいなかったため、CTS が階層内に作ったバッファはすべてパスなしで書き出されていました。

OpenROAD の write_spef を修正し、回帰テストを追加し、既存の階層テストを実行しました。60 件すべて結果は変わりませんでした。チップでは "instance not found" が 48,926 件から 0 件に、"net not found" が 431,493 件から 164 件になりました。調査の全体は、最初の誤った仮説も含め、前後の数値とともに文書にしてあります。
なぜこれまで表に出なかったのでしょうか。OpenROAD の中ではデータベースがフラットで完全なので、名前は常に解決できます。書き出したファイルを読んで初めてバグが現れます。これがサインオフを別にしておく一番の理由です。もう 1 つのルールも生まれました。データを回避してタイミングを取るのではなく、データを直すことです。
バグ 2:間違ったモジュールにあるダミー負荷
クロックツリーの末端のネットに、ずれが 1 つ残っていました。ダミー負荷とは、クロックツリーツールが枝のバランスを取るために加える小さなセルです。私たちのチップでは、クロックバッファはすべて top_earlgrey モジュールの中にありましたが、CTS は 14,348 個のダミー負荷を、チップの最上位モジュールに作っていました。2 つのあいだにポートはありません。
OpenROAD の中ではデータベースがフラットなので、それぞれはまだ 1 本のネットです。しかしネットリストの書き出し処理は、同じ名前のネットを 2 本書きます。ドライバーがあって配線がないものと、配線があってドライバーがないものです。この形で 13,566 本のクロックネットが分断され、クロック配線容量 619 pF のうち 206.7 pF(33%)が間違った側に載っていました。
1:57YouTube で見る(英語) ↗Bilibili で見る(中国語) ↗

CTS の修正は、各ダミー負荷を、それが負荷となるバッファのモジュールに作ることです。新しいテストはもう 1 つのことを明らかにしました。OpenROAD の既存の参照出力の 1 つ(gated_clock4)に、すでに同じ分断が含まれていて、18 個のダミー負荷が最上位モジュールにありました。ゴールデンファイルがバグを抱えていることもあるのです。他の 53 件の CTS テストは変わりませんでした。
チップを CTS から再実行すると 1 日以上かかります。代わりに 5 分のスクリプトで、完成した v5 のデータベース内の 13,553 個のダミー負荷を正しいモジュールに移し、抽出とタイミングをやり直しました。
アップストリームへ
どちらのバグも、OpenROAD で階層フローを使う人すべてに影響するので、アップストリームに送りました。
- 各バグを OpenROAD 自身のテストの形式で、数個のセルで再現し、まず最新のアップストリームで確認しました。
- テストスイート全体を参照出力と比較しました。rcx、cts、dbSta は 142 件中 142 件が通り、rsz は 295 件中 294 件で、変更前と同じでした。
- 修正ごとにブランチを 1 つ。
- エンジニアが了承するまで、何も投稿しませんでした。
結果は issue 2 件と pull request 2 件です。issue #11839 と #11840、pull request #11841 と #11842。2026-10-22 時点で、いずれもオープンでレビュー待ちです。
そして自分たちの作業を検証した
G2 のツールバンドルで OpenROAD をアップグレードしたあと、小さなサンドボックスのチップで 2 つの問題が見つかりました。パッドリングでのグラウンドの切れ目と、寄生成分のないクロックネットです。Earlgrey にもあるのでしょうか。チェックはテストバージョン v5a に入れました。2 つのステージだけで新たな配置配線はなく、他の実行と同じようにバージョン表に記録されています。
1:51YouTube で見る(英語) ↗Bilibili で見る(中国語) ↗
電源グリッド。 フロアプランのチェックで VDD のオープンが見つかりました。416 個の電源グリッド図形と 1,000 本を超えるパッドの電源ピンがつながっていませんでした。私たちの電源グリッドのスクリプトは、パッドの層を指定せずにパッドへ接続していたのです。これは私たち自身のミスで、チップ v2 から隠れていました。修正方法は次のバージョンに向けてわかっています。
チェックそのものにも問題がありました。オープンのチェックは約 1 分で終わりましたが、そのあと OpenROAD のショートのチェックが 1 コアで 9 時間 20 分、何も出力せずに動き続けました。止めて、すでに書き出されていた結果を残し、バグとして報告しました。VSS はチェックしておらず、それもリストに載っています。
寄生成分。 同じネットリストと SPEF でプローブを実行しました。寄生成分のないドライバーが 73,824 個というと悪く聞こえますが、原因別に分けると、ほとんどは配線がない(71,633 個)か負荷がない(1,939 個)、あるいはポートです。実際に何かを駆動しているのは 120 個だけ。本当のずれはそれで、しかも小さいものでした。

悪い知らせが 1 つ、良い知らせが 1 つ。どちらも次の人が見る場所に書いてあります。バージョン表のメモの行、README、バグリスト、そして再開用のページです。
注意書き付きのサインオフ数値
両方の修正を入れたあと、低速コーナー(ss、cworst)でのトップレベルの reg2reg セットアップスラックは、10 MHz で −7.87 ns です。クロックの届いていないレジスタのクロックピンはありません。入出力パスにはまだタイミング例外がないので、その数値にはまだ意味がなく、ホールドのレポートもありません。それらと VDD の修正は、チップ v6 の計画に入っています。
次回:エンジニアと Claude Code がどう作業を分担したか。エンジニアが眠っていた夜のことも含めて。