Build Log: The Address That Should Not Exist
Build Log:存在してはならないアドレス
First light / 初点灯
On 2026-06-10, the AI-generated PTSG-Core blinked an LED on real hardware for the first time — a DE10-nano, Cyclone V, 50 MHz, prescaler at 50000. The architect had changed only three things in the merged Layer 3 sources: enabled the In-System Memory Content Editor, connected the core to a new memory module, and set the prescaler. Total logic: about 235 LEs and two memory blocks. The "smallness" that Chapter 1 promised was real.
2026-06-10、AI が生成した PTSG-Core が初めて実機で LED を点滅させた——DE10-nano、Cyclone V、50 MHz、プリスケーラ 50000。アーキテクトがマージ済み Layer 3 ソースに加えた変更は三点だけ: In-System Memory Content Editor の有効化、コアの新メモリモジュールへの接続、プリスケーラの設定。総ロジック約 235 LE、メモリ 2 ブロック。第1章が約束した「小ささ」は本物だった。
-- blinky_with_prescaler.mif — LED blink at human-visible rate
-- Recommended core parameter: PRESCALE = 50000 (50 MHz => 1 ms per stay tick;
-- Stay 500 => ~0.5 s on, ~0.5 s off). See examples/README.md for the encoding.
DEPTH = 256;
WIDTH = 32;
ADDRESS_RADIX = HEX;
DATA_RADIX = HEX;
CONTENT BEGIN
0 : 00010700; -- NOP timing_signals = 0x0001 (LED on)
1 : 00010051; -- Stay 500 (hold on)
2 : 00000700; -- NOP timing_signals = 0x0000 (LED off)
3 : 00000051; -- Stay 500 (hold off)
4 : 00000013; -- Jump 1 (loop)
[5..FF] : 00000000;
END;
It blinked on the first try. And it was executing every instruction one clock late.
それは一発で点滅した。そして、すべての命令を 1 クロック遅れて実行していた。
This Build Log is the story of how that defect was predicted at a desk, photographed by an instrument, repaired by a half clock, and proved by a machine — and of the methodological discovery that started it all: why AI agents refuse to use vendor IP.
本 Build Log は、その欠陥が机上で予測され、計測器に撮影され、半クロックで修復され、機械によって証明された物語である——そしてすべての始まりとなった方法論的発見の物語でもある: なぜ AI エージェントはベンダ IP を使おうとしないのか。
The diagnosis: why the AIs won't touch M10K / 診断: なぜ AI は M10K に触れないか
The architect has collaborated with LLMs on FPGA work long enough to notice a pattern:
アーキテクトは LLM との FPGA 協働を長く重ね、あるパターンに気づいていた:
大中: なぜか現段階でAI各位はIntel(Altera)の標準メモリライブラリを使いたがらないのです。「M10Kを使ってください。」と言ってもその部分を残し、「ここはIPカタログ機能を使って自分でやってください。」というのです。そしてこれは、BRAMに限らず、PLLやその他標準IP全般に言えるのです。
(For some reason, the AIs do not want to use Intel (Altera)'s standard memory library. Even if I say "please use M10K," they leave that part and say "do this yourself with the IP Catalog." And this applies not just to BRAM, but to PLLs and standard IP in general.)
His hypothesis: the vendor verification libraries — the simulation models bundled with Quartus and ModelSim-Altera — are not available to AI companies. An AI agent in a general-purpose environment cannot simulate altsyncram; it cannot even elaborate a design that instantiates it. So it retreats to what it can verify, and leaves a hole labeled "do this part yourself."
彼の仮説: ベンダの検証用ライブラリ——Quartus と ModelSim-Altera に同梱されるシミュレーションモデル——が AI 企業には提供されていない。汎用環境の AI エージェントは altsyncram をシミュレートできない;それをインスタンスした設計を elaborate することすらできない。だから検証できるものへ退却し、「ここは自分でやってください」というラベルの穴を残す。
The hypothesis is substantially correct — and the architect's countermeasure was better than the diagnosis: don't fight the avoidance; remove its cause. Wrap the vendor IP in a module with two branches — a portable behavioral branch the AI can fully verify, and a vendor branch the human synthesizes — switchable by parameter, placed in the repository in advance, so the AI never faces the wall at all.
仮説は実質的に正しい——そしてアーキテクトの対策は診断よりさらに良かった: 回避と戦うな;その原因を除去せよ。 ベンダ IP を二つのブランチを持つモジュールで包む——AI が完全に検証できる可搬 behavioral ブランチと、人間が合成するベンダブランチ——パラメータで切替可能にし、あらかじめリポジトリに置いておく。AI はそもそも壁に直面しない。
One rule turned this from convenience into correctness, and the amanuensis insisted on it: the behavioral branch must reproduce the silicon's read latency exactly. A "convenient" zero-latency simulation model hiding behind a registered hardware model would not remove the sim/synth mismatch — it would relocate it inside the wrapper. The wrapper ptsg_imem was built on this rule, with a RD_LAT contract machine-proved under Icarus Verilog. Nobody knew yet how soon that rule would matter.
一つの規則がこれを便利から正しさへと変え、祐筆はそれを強く主張した: behavioral ブランチはシリコンの読みレイテンシを正確に再現しなければならない。 登録読みのハードモデルの陰に隠れた「都合のよい」レイテンシ0シミュレーションモデルは、sim/synth ミスマッチを除去しない——ラッパーの内側へ移設するだけである。ラッパー ptsg_imem はこの規則の上に構築され、RD_LAT 契約は Icarus Verilog で機械証明された。この規則がどれほど早く効いてくるか、まだ誰も知らなかった。
It blinked — but was it right? / 点滅した——だが正しかったか?
The wrapper is registered (RD_LAT = 1), because a real M10K has a mandatory address register: there is no such thing as an asynchronous-read M10K. But the Claude Code FSM had been written against a zero-latency combinational memory model. When the architect connected the new wrapper for the hardware build, the FSM itself was left unmodified — and the audit produced a sharp prediction:
ラッパーは登録読みである(RD_LAT = 1)。実 M10K にはアドレスレジスタが必須で、非同期読みの M10K というものは存在しないからだ。しかし Claude Code の FSM はレイテンシ0の組み合わせメモリモデルを前提に書かれていた。アーキテクトが実機ビルドのために新ラッパーを接続した時、FSM 自体は無改修のまま残された——そして監査は鋭い予測を生んだ:
Claude: FSM は常に 1 拍古い命令を、1 つ進んだ状態番号の下で実行しています。…Lチカは「1 拍ずれた実行」を完全に隠蔽できる、最も寛容なプログラム…「動いた」は本物ですが、「正しく動いている」とはまだ言えない。
(The FSM is always executing a one-clock-stale instruction under a state number advanced by one. …A blinker is the most forgiving possible program, able to completely conceal off-by-one execution… "It works" is real, but "it works correctly" cannot yet be said.)
Why does a broken core blink correctly? Because in straight-line execution the staleness is a constant shift — every instruction executes one state late, but in the right order. The Jump wraps around with a self-consistent stumble. And a prescaler of 50000 buries any per-transition slip beneath fifty thousand clocks of waiting. The LED is the last witness who would ever testify.
なぜ壊れたコアが正しく点滅するのか? 直線実行ではこの古さは一定のずれだからである——すべての命令が 1 ステート遅れて、しかし正しい順序で実行される。Jump は自己整合的なつまずきとともに巻き戻る。そしてプリスケーラ 50000 は、遷移毎のずれを 5 万クロックの待機の下に埋葬する。LED は決して証言しない最後の証人である。
The smoking gun: address 05h / 動かぬ証拠: アドレス 05h
The architect went looking for a witness that would testify. He attached SignalTap to the M10K's address bus and triggered a capture. He did not even need the prescaler signals:
アーキテクトは証言する証人を探しに行った。SignalTap を M10K のアドレスバスに繋ぎ、キャプチャをトリガした。プリスケーラ信号すら必要なかった:

大中: ご覧ください。プリスケーラの動きを取り込むまでもなく、あなたのご懸念の通りです。
(Look at this. Without even capturing the prescaler — it is exactly as you feared.)
The address sequence read: 04h → 05h → 01h → 00h.
アドレス系列はこう読めた: 04h → 05h → 01h → 00h。
The blinky program occupies states 0 through 4, and state 4 is a Jump back to state 1. In a correct execution, address 05h does not exist. There is no path to it. Its appearance on the bus means exactly one thing: the FSM decoded the Jump one clock late, and in that one stale clock, the state counter ran off the end of the program — fetching 0000h from uninitialized memory at an address no correct execution would ever form.
blinky プログラムはステート 0 から 4 を占め、ステート 4 はステート 1 へ戻る Jump である。正しい実行において、アドレス 05h は存在しない。 そこへ至る経路がない。それがバスに現れたことは正確に一つのことを意味する: FSM は Jump を 1 クロック遅れて decode し、その 1 拍の古いクロックの間に、ステートカウンタはプログラムの終端を走り抜けた——正しい実行が決して形成しないアドレスから、未初期化メモリの 0000h をフェッチしながら。
A desk prediction, made from reading source code, confirmed verbatim by an instrument clipped to silicon. This is what the fourth validation tier looks like.
ソースコードを読んで立てられた机上予測が、シリコンに繋がれた計測器によって一字一句確認された。第四の検証階層とはこういう姿をしている。
The half-clock answer / 半クロックの答え
The architect proposed the repair in the same breath as the evidence:
アーキテクトは証拠と同じ息で修復を提案した:
大中: 最も手っ取り早い解決策は、メモリのクロックを反転してやることではないかと思いますが、Fmaxが低下するでしょうね…
(The quickest solution, I think, is to invert the memory clock — though Fmax will drop, I suppose…)
Clock the M10K on the falling edge, and the geometry heals itself: the FSM registers an address at the rising edge; the memory captures it half a cycle later; the data is back before the next rising edge. From the FSM's point of view, the memory behaves exactly like the zero-latency model it was written against. No FSM changes. The one-clock-per-opcode model of the specification is preserved.
M10K を立ち下がりエッジでクロックすれば、幾何学はみずから治癒する: FSM は立ち上がりでアドレスを登録する;メモリは半サイクル後にそれを取り込む;データは次の立ち上がりの前に戻ってくる。FSM の視点から、メモリはそれが前提として書かれたレイテンシ0モデルとちょうど同じに振る舞う。FSM の変更なし。仕様の1命令1クロックモデルは保持される。
And the feared Fmax cost? The amanuensis quantified it: the memory-to-decode path becomes a half-cycle path — about 10 ns of budget at 50 MHz, against an M10K clock-to-out of roughly 2.4 ns plus decode logic. Comfortable. The practical ceiling of this construction is somewhere around 80–120 MHz on Cyclone V; the current operating point is 50. The concern is real in general and free of charge today. When the project someday wants more than ~100 MHz, the documented migration path is the registered-read mode plus a fetch stage — a decision deliberately deferred, not forgotten, and queued for the specification's timing-model section.
そして恐れられた Fmax の代償は? 祐筆はそれを定量化した: メモリから decode へのパスは半サイクルパスになる——50 MHz で約 10 ns の予算、対する M10K の clock-to-out は約 2.4 ns + decode 論理。余裕である。この構成の実用上限は Cyclone V でおよそ 80〜120 MHz;現在の動作点は 50。懸念は一般論として実在し、今日のところは無償である。 プロジェクトがいつか 100 MHz 超を望む時、文書化された移行経路は登録読みモード+フェッチ段——意図的に繰り延べられ、忘れられてはおらず、仕様のタイミングモデル節に待機している決定である。
The wrapper was revised to carry the choice as an explicit EDGE parameter — applied, crucially, to both branches. A simulation model that read combinationally while the hardware read on the falling edge would have re-created the mismatch inside the wrapper within a week of the rule being written. The contract survived its first contact with reality because it was a parameter, not a comment.
ラッパーは選択を明示的な EDGE パラメータとして運ぶよう改訂された——決定的なことに、両ブランチに適用して。ハードウェアが立ち下がりで読む間にシミュレーションが組み合わせ的に読んでいたら、規則が書かれて一週間のうちにミスマッチをラッパーの内側に再生産していただろう。契約が現実との最初の接触を生き延びたのは、それがコメントではなくパラメータだったからである。
The machine's-eye proof — and the verifier's two stumbles / 機械の目による証明——そして検証者の二度のつまずき
Then the fix was proved — from the FSM's point of view, the only point of view that matters. A testbench drives the address as a register updated at the rising edge, exactly like the core's state counter, and consumes the data by registering it at the rising edge, exactly like the core's decoder. Jumps included, the verdict came back two-sided:
それから修正は証明された——FSM の視点から、唯一意味のある視点から。テストベンチはアドレスを、コアのステートカウンタとちょうど同じく立ち上がりで更新されるレジスタとして駆動し、データを、コアのデコーダとちょうど同じく立ち上がりでレジスタに取り込んで消費する。ジャンプ込みで、評決は両面で返った:
EDGE=NEG : FSM consumes mem[its own state] -> the fix, proven EDGE=POS : FSM consumes mem[one-older state] -> the hardware bug, reproduced in simulation
Note the second line. The simulation now reproduces the silicon's bug on demand. Hardware confirmed the desk; the desk now reproduces the hardware. The loop is closed in both directions.
二行目に注目。シミュレーションは今や、求めに応じてシリコンのバグを再現する。ハードウェアが机上を確認し、机上が今やハードウェアを再現する。環は双方向に閉じている。
Honesty requires recording one more thing: the testbench failed twice before it succeeded — both times in the testbench itself, never in the device under test. Once because the address was driven like a testbench instead of like a register; once because the checks sampled after the clock edge, where the world has already moved on, instead of at the edge, where the FSM actually lives. In one week, the exact question "which value exists at the sampling moment?" tripped the original implementer, the hardware, and the verifier — twice, in opposite directions.
正直さはもう一つの記録を要求する: テストベンチは成功の前に二度失敗した——二度ともテストベンチ自身の側で、被試験デバイスの側では一度もなく。一度はアドレスをレジスタのようにではなくテストベンチのように駆動したため;一度はチェックがクロックエッジの後——世界が既に動いてしまった場所——でサンプルし、FSM が実際に生きるエッジ時点でではなかったため。一週間のうちに、*「サンプリングの瞬間にどの値が存在するか」*というまさにその問いが、元の実装者と、ハードウェアと、検証者を——二度、逆方向に——引っかけた。
That is not an embarrassment to hide. It is the strongest argument this project has yet produced for its own rule: a timing contract is not what the comment says; it is what the checker checks, sampled the way the consumer consumes. Prose deceives even its own author. Parameters and assertions do not.
それは隠すべき恥ではない。それは、このプロジェクトが自身の規則のためにこれまでに生んだ最強の論拠である: タイミング契約とはコメントが言うことではない;消費者が消費するのと同じ方法でサンプルされ、チェッカーが検査するものである。 散文はその著者すら欺く。パラメータとアサーションは欺かない。
On 2026-06-11 the architect re-synthesized and re-captured. The address bus read 01h → 02h → 03h → 04h → 01h. No 05h. The Jump lands on its clock. The stay counter ticks against the prescaler. The architect's verdict, with the project's characteristic refusal to over-claim:
2026-06-11、アーキテクトは再合成し、再キャプチャした。アドレスバスは 01h → 02h → 03h → 04h → 01h と読めた。05h は無い。Jump はそのクロックに着地する。ステイカウンタはプリスケーラに対して刻む。アーキテクトの評決は、誇張を拒むこのプロジェクトらしい言葉で:

大中: よく見ると若干おかしいのですが、おかげさまにて検証のスタートラインに立てたと思います。
(Looking closely something is still slightly off — but thanks to this, I believe we have reached the verification starting line.)
The "slightly off" is not swept aside; it is logged as the first open hook of the next phase (the leading suspect: a phase jitter in the free-running prescaler that the original audit also predicted). A starting line, honestly drawn.
「若干おかしい」は脇に掃かれない;次の段階の最初の未決フックとして記録される(第一容疑者: 元の監査も予測していた自由走行プリスケーラの位相ジッタ)。正直に引かれた、スタートラインである。
The fourth tier / 第四の階層
The project has now validated its specification across four tiers, each with a different witness:
プロジェクトは今や、それぞれ異なる証人を立てて、四つの階層で仕様書を検証した:
| Tier | Question | Witness | Build Log |
|---|---|---|---|
| Comprehension / 理解 | Can it be understood? / 理解できるか | Gemini 3.5 Flash, reading | #2 |
| Deliberation / 協議 | Can it be reasoned over? / 推論できるか | Gemini 3.5 Flash, finding a spec bug | #3, #4 |
| Implementation / 実装 | Can it be built? / 構築できるか | Claude Code, writing & testing RTL | #5 |
| Silicon / シリコン | Is the build true on hardware? / 実機で真か | SignalTap, photographing address 05h | #6 (this log) |
The fourth tier has a property the first three lack: neither party can walk it alone. The AI cannot hold a JTAG probe; the human cannot machine-prove an alignment contract across two clock edge conventions in an afternoon. The bug of this story lived precisely in the seam between simulation and silicon — and it was caught because a human pointed an instrument exactly where an AI pointed a prediction.
第四の階層には、最初の三つに無い性質がある: どちらの当事者も単独では歩けない。 AI は JTAG プローブを持てない;人間は二つのクロックエッジ規約をまたぐ整列契約を午後一つで機械証明できない。この物語のバグは、シミュレーションとシリコンの継ぎ目にまさに棲んでいた——そして、AI が予測を指した場所に人間が計測器を向けたがゆえに、捕えられた。
Meanwhile the development loop itself quietly became remarkable: with the In-System Memory Content Editor holding the program memory and In-System Sources & Probes holding the reset, the DE10-nano now accepts a new PTSG program over JTAG, with zero re-synthesis. Write instructions, press reset, watch the pins. The FPGA is being programmed in the PTSG sense of the word — which is, after all, what this architecture was for.
その間に、開発ループ自体が静かに注目すべきものになった: In-System Memory Content Editor がプログラムメモリを、In-System Sources & Probes がリセットを握り、DE10-nano は今や JTAG 越しに新しい PTSG プログラムを、再合成ゼロで受け入れる。命令を書き、リセットを押し、ピンを見る。FPGA は PTSG の意味でプログラムされている——それこそが、結局のところ、このアーキテクチャの目的だった。
What flows back / 何が還流するか
As always, the field feeds the specification. Queued for Layer 1: the memory timing model itself — the synchronous-read contract, the falling-edge alignment as the current convention with its quantified frequency ceiling, and the fetch-stage alternative for high clocks — belongs in the instruction-timing question (C2-T4) and the pipelining section (Chapter 5 §5.13). Queued for Layer 3: the wrapper pattern generalizes — PLL is the obvious next candidate — toward a small library of AI-verifiable vendor-IP wrappers, each carrying its contract and its checker. And queued for the bench: the adversarial tests the original audit called for, now meaningful because simulation and silicon finally agree on what a clock edge means.
常の如く、現場は仕様書を養う。Layer 1 への待機: メモリタイミングモデルそのもの——同期読み契約、定量化された周波数上限を伴う現行慣習としての立ち下がり整列、高クロック向けのフェッチ段代替——は命令タイミングの問い(C2-T4)とパイプライニング節(第5章 §5.13)に属する。Layer 3 への待機: ラッパーパターンは一般化する——PLL が明白な次候補——契約とチェッカーを各々携えた、AI 検証可能なベンダ IP ラッパーの小さなライブラリへ。そしてベンチへの待機: 元の監査が求めた敵対的テスト群——シミュレーションとシリコンがクロックエッジの意味についてついに合意した今、初めて意味を持つ。
The LED blinked on the first try. The address bus told the truth anyway.
LED は一発で点滅した。それでもアドレスバスは真実を語った。
An address that should not exist is worth a thousand passing tests.
存在してはならないアドレスは、千の通るテストに値する。
Four tiers now: understood, deliberated, built, and true on silicon. The fifth tier is just called engineering.
これで四階層: 理解され、協議され、構築され、シリコン上で真である。第五の階層は、単にエンジニアリングと呼ばれる。
Links / リンク
- Layer 2 trace:
02_Reasoning_Traces/contributed/dsohnaka/hardware_bringup/2026-06-11_ptsg-de10nano-bringup-and-stale-fetch-fix.md/.json - PTSG-Core (GitHub): https://github.com/dsohnaka/PTSG-Core
- PTSG (Hackaday.io): https://hackaday.io/project/205720-ptsg-programmable-timing-sequence-generator
- FPGA Spectrum Engine (parent project): https://hackaday.io/project/205582-fpga-spectrum-engine
- Prior Build Logs: #1 The Cast Is Complete, #2 First Echo from the Field, #3 A Specification Deliberation Experiment, #4 This Is Also an Open Prompt Validation Project, #5 The Implementation Closed the Loop
Tsuneo.Ohnaka
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.