Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Lean_4をRTL開発の中核にする。SparkleにおけるJIT、検証、Reverse_Sy...

Avatar for junji hashimoto junji hashimoto
August 26, 2026
23

 Lean_4をRTL開発の中核にする。SparkleにおけるJIT、検証、Reverse_Synthesis、逆合成

Avatar for junji hashimoto

junji hashimoto

August 26, 2026

Transcript

  1. 目次 • Sparkle / Lean / RTL • アーキテクチャ: Elab

    → IR → SystemVerilog / JIT • ベンチマーク: Verilator との勝負 • 証明の活⽤: 等価検証‧スキップ‧逆合成 • エコシステムと JupyterLite • FPGA デモ: Ethereum 署名機(Macで動かない) • 「結局 AI で作ってるんじゃない?」 FPGA: Tang Nano 20K 2
  2. プロフィール • グリー: シニアリードテック (インフラ 13 年⽬) • 前職はハードウェアエンジニア (10

    年) • KVS / Web3 (Sui, Avalanche, Polygon, Oasys) • Haskell: Hasktorch 開発 • ML: アナザーエデンの AI (2017〜) • WebGPU: gpu.cpp 開発、rustを使ったプロダクトに導⼊中 3
  3. Sparkle はなに? • Lean 4 の DSL で回路を書くシステム • RTL

    → SystemVerilog を⽣成 • シミュレーションが⾼速 (C ⽣成 + JIT) • 証明が使える: 等価検証‧スキップ‧逆合成 • ブラウザで試せる: verilean.github.io/sparkle 4
  4. Lean —「ないものリスト」が半年で埋まった • 証明アシスタント + ⾼速コンパイルの関数型⾔語 • Web フレームワーク →

    lean-tea (Elm + Yesod + Persistent + MCP) • Jupyter カーネル → xeus-lean (Native + WASM) • GPGPU → hesper (WebGPU + Bitnet + Gemma4) • Flare → k8s operator (時相論理 + 安定性) : 開発中 証明するものを決めるのが⼤変。 • Game → TRPG?? • 「ないもの」は AI 時代には空き地 5
  5. RTL (Register Transfer Level) • ゲートレベル • RTL ← SystemVerilog

    / Sparkle はここ • ビヘイビアレベル ← 逆合成でここに登る • クロック + DFF + 組み合わせ回路の抽象 6
  6. Sparkle DSL — 10 行で回路 def grayCtr {dom : DomainConfig

    } : Signal dom (BitVec 4) := circuit do let bin ← Signal.reg 0#4 let binSig := bin. 1 let shifted := (fun x => x >>> 1) <$> binSig bin <~ binSig + 1#4 return (binSig ^^^ shifted) #synthesizeVerilog grayCtr -- これだけで SV が出る • Signal dom α = ドメイン上の時系列 / circuit do = レジスタ DSL 7
  7. 依存型と RTL • 回路は常にビット幅を指定する世界 • ソフトの型に「4bit」はない → Int に詰めて祈る •

    Lean: BitVec (n : Nat) — 型に数が⼊る • 幅ミスマッチ = コンパイルエラー • Lean を使う理由の⼀丁⽬⼀番地 8
  8. circuit do は「後付けの文法」 — syntax 宣言 -- Lean に新しい文法を足している (本体の改造ゼロ

    ) syntax "let " ident " ← " "Signal.reg " term : cdoStmt syntax ident " <~ " term : cdoStmt syntax "circuit" "do" ... : term • やりたいこと: 回路を命令型っぽく書きたい • でも Lean に <~ なんて⽂法はない • syntax = ユーザーが⽂法⾃体を追加できる Lean の標準機能 • <~ も Signal.reg も私たちが定義した「新しい構⽂」 9
  9. 展開先: 状態はただのタプル -- macro が circuit do を純関数に翻訳する -- レジスタ

    2 本なら状態 = タプル (Prod): step : (BitVec 4 × BitVec 8) → (BitVec 4 × BitVec 8) -~~~~~~~~ 今の状態 ~~~~~~~~ ~~~ 次の状態 ~~~ • 命令型に⾒えるが、実体は「状態を受けて次状態を返す純関 数」 • モナドと⾔っても魔法なし — タプルの詰め替えだけ • 純関数 + タプルなら elaborator が構造を追える • → そのまま回路 (レジスタ + 配線) に落ちる 10
  10. 苦労した話 (1): 出力は何でもよくない class HasDomain (ρ : Type) (dom :

    outParam DomainConfig ) instance : HasDomain (Signal dom τ) dom instance [HasDomain α dom] [HasDomain β dom] : HasDomain (α × β) dom • AI は任意の値を出⼒にしようとして失敗し続けた • ⼈間の解決: HList + typeclass で「可能な形」を閉じる • dom 不⼀致 = インスタンス探索失敗 = コンパイルエラー • AI が⾃発的に出さない設計判断だった 11
  11. 苦労した話 (2): 合成が N² に遅くなる • FSM の各レジスタが同じ部分式 (次状態ロジック) を参照

    • elaborator は同じ⽊を毎回「新品の Expr」として再⽣成 • 重複に気づけないと同じ回路を N 回合成 → 時間も回路も N² 12
  12. 解決: content-addressed な AST キャッシュ -- キャッシュのキーを変えた : -旧: Std.HashMap

    Lean.Expr _ -BEq Expr ≈ ポインタ等価 → ヒット率 < 10% -新: Lean.ExprStructMap _ -Expr.equal (構造等価 ) + Expr.hash exprCache : IO.Ref (Lean.ExprStructMap String) • ポインタが違っても構造が同じなら同じワイヤに collapse • 合成時間が線形に戻り、重複回路も消えた • 教訓:「同じ式」には 3 つの同⼀性がある ‒ ポインタ / 構造 / 意味 — どれで持つかが性能を決める 13
  13. #synthesizeVerilog の実装 (実物) elab "#synthesizeVerilog" id:ident : command => do

    let declName ← liftCoreM (resolveGlobalConstNoOverload id) liftTermElabM do let (module, _) ← synthesizeCombinational declName for w in DRC.checkRegisteredOutputs module do logWarning m! "{w}" let optimized := IR.Optimize.optimizeModule module IO.println (toVerilog optimized) • ユーザー定義コマンドが 10 ⾏ — 解決→合成→DRC→最適化→ 出⼒ 15
  14. Expr → IR 変換 let constInfo ← getConstInfo declName --

    定義の Expr let resultWire ← translateExprToWire body "result" • (· + ·) <$> a <*> b → add ノード • Signal.mux c t e → mux ノード • Signal.register init next → DFF • 補助 def は unfoldDefinition? で 1 段ずつ inline ‒ whnf で⼀括正規化すると深いタプルで指数爆発した 16
  15. IR 最適化 • 定数畳み込み: mux(true,a,b) → a など • 単⼀使⽤ワイヤのインライン化

    • 到達可能性 DCE (Dead Code Elimination): 出⼒から BFS • 効果: JIT 2.0x (6.3M → 12.6M cyc/s) • 信号名ハードコードなし — 全部汎⽤ 17
  16. SystemVerilog 出力 module grayCtr ( input logic clk, input logic

    rst, output logic [3:0] out); always_ff @(posedge clk) begin if (rst) _tmp_a_6 <= 4'd0; else _tmp_a_6 <= _tmp_reg_input_5; end assign out = (_gen_binSig ^ (_gen_binSig >> endmodule 4'd1)); • let の名前が _gen_<name> として SV に⽣存 • yosys / Vivado / Gowin にそのまま⼊る 18
  17. JIT: IR → C → dlopen @[extern "sparkle_jit_load" ] opaque

    JIT.load (path : @& String) : IO JITHandle @[extern "sparkle_jit_eval_tick" ] opaque JIT.evalTick (h : @& JITHandle) : IO Unit • clang -shared -O2 → ハッシュキャッシュ → dlopen • 回路変更 → 数秒で再実⾏ • このループの速さが後の AI 話に効く 19
  18. Q: Verilator に勝てるの ? • Verilator のプロファイルを取った • 良: 変数削除‧キャッシュ最適化

    • 悪: シングルクロックでも Mutex 多⽤ • 作戦: Mutex なし + スタックローカル化 + DCE 20
  19. ベンチ (1): RV32I SoC (10M cycles) バックエンド cyc/s vs Sparkle

    JIT (ピーク 時) 14.2M 1.63x Verilator 5.040 8.73M 1.00x • Sparkle 製フル SoC (RV32IMA, Linux ブート) • ※現 main は開発中で退⾏ (2.6M) — 回復予定 21
  20. ベンチ (2): LiteX + PicoRV32 (1730 行の実SV) バックエンド cyc/s vs

    Sparkle JIT (ピーク 時) 11.7M 1.13x Verilator 5.040 (-O2) 10.5M 1.00x • 他⼈の Verilog を SVParser で取り込んで JIT • ※現 main は退⾏中 22
  21. ベンチ (3): マルチコア (8 コア共有バス ) 構成 Verilator Sparkle 比

    1 コア 10.5M 11.7M 1.13x 8 コア並列 5.07M 1.06M 4.78x • Sparkle は命令共有で劣化が緩い 23
  22. なぜ勝てるのか • 1. ワイヤ全ローカル化 (L1 に載る)<- Verilatorもやっている • 2. 汎⽤ガード検出

    (_valid/_enable)<- Verilatorもやっている • 3. DCE + 定数伝播 + fused evalTick<- Verilatorもやっている • 4. 異なるクロック間のやり取りはロックフリー&投機実⾏ • 5. 証明つき逆合成: FSM → 直接計算 24
  23. 証明の活用 — 独自の 3 本柱 • 1. 回路の等価検証 • 2.

    不変条件でシミュレーションをスキップ • 3. 逆合成 — RTL をビヘイビアに登る • 証明が安全のためだけでなく速度のためにある 25
  24. 等価検証 example : ∀ op a b, aluPlain op a

    b = aluSpec op a b := by decide • ⼩空間: decide / native_decide で全数 • BitVec: bv_decide (SAT に委譲) • SATでできない場合は帰納法で証明(⾃動の証明は難しい) • リファクタ前後の同⼀性を CI で証明 • 各種コマンド(完全に等価、サイクル精度を跨いで等価、) #verify_eq, #verify_eq_at, #verify_eq_git 26
  25. Verilog を読み込んで証明する verilog! " module sum_reg(...); always @( posedge clk)

    if (rst) result <= 1'b0; else result <= a ^ b; endmodule" theorem spec (s : State) (i : Input) : (nextState s i)._reg_result = (if i.rst = 0 then i.a ^^^ i.b else 0) := by simp [nextState]; bv_decide • 既存 SV 資産にあとから証明を貼れる 27
  26. 逆合成 — OracleReduction class OracleReduction (tag State Input Output) where

    step : State → State -- FSM の 1 サイクル compute : Input → Output -- 直接計算 numCycles : Nat /-- MANDATORY PROOF -/ equiv : ∀ input, extractResult (iterateN step numCycles (initState input)) = compute input • 「N サイクル = 直接計算」の証明が必須フィールド • 証明が書けなければインスタンスが作れない 29
  27. 逆合成の実例 : 乗算器 • pcpi_mul: 38 assign のマルチサイクル FSM •

    a * b = fold (+ a) 0 [1..b] <- 掛け算は⾜し算の畳み込み • 回路では畳み込みで掛け算を表現 • 計算機では掛け算は掛け算 • 回路の表現は畳み込みだが計算は掛け算にする。 • 合成の逆向きだから「逆合成」 30
  28. Timer Oracle: 48.9 GHz 相当 モード 実効速度 倍率 通常シミュレーション 5.04M

    cyc/s 1x Timer oracle 48.9 GHz 相当 9,707x • CPU アイドル検出 → タイマー分を⼀括スキップ • 実クロックをシミュレーションが追い越す 31
  29. IP カタログ — 全部 Lean 製 • RV32: RISC-V SoC

    (Linux ブート) • Crypto: secp256k1 / Ed25519 / BLS12-381 / AES-GCM • BitNet: 1-bit LLM / YOLOv8 / H.264 • Bus: AXI4 / PCI-E • 完成度はまちまち — が同じ証明インフラに乗る 32
  30. ドキュメント & チュートリアル • チュートリアル 12 章 (Ch0〜Ch11) https://verilean.github.io/sparkle •

    組み合わせ → 順序 → 証明 → FPGA → Web3 実機 • API リファレンス⾃動⽣成 (doc-gen4) • IP ごとの仕様書 (docs/ip-catalog/) 33
  31. JupyterLite — ブラウザだけで試せる • xlean カーネルを WASM ビルド • verilean.github.io/sparkle/lab/

    を開くだけ • インストールゼロ • #synthesizeVerilog も #eval も動く 34
  32. Jupyter + MCP: AI と同じ画面で開発 • xeus-lean (native kernel) +

    jupyter-collaboration (RTC) • AI がノートブックをライブ編集 → 実⾏ • 波形 SVG がブラウザに即出る • notebook_run_cell 1 コールで完結 35
  33. 開発の TAT 実測 操作 実測 ファイル / md⇄ipynb 変換 1–8

    ms カーネル実行 150–240 ms 回路変更 → JIT 再シム 数秒 • LLM 推論 (~3s) が⽀配的、ツール側はゼロ • この数字が最終章の伏線 36
  34. FPGA デモ: 鍵がチップから出ない Ethereum 署名機 • Tang Nano 20K (約5,000円)

    実機 • 全部 Sparkle (Lean) 製 • 危殆化ホストでも d も k も漏れない 37
  35. Lean → 実機 → 実チェーン lake env lean GenSignZDemoSynth .lean

    yosys + nextpnr-gowin openFPGALoader → Tang Nano 20K nix-shell -p foundry –-run anvil python3 sign_tx.py --send → anvil # Lean → SV # 合成+P&R # 書き込み # anvil を起動 # 実チェーン • 実機で 2 回の実転送に成功 • ecrecover がチップのアドレスに⼀致 • だが、Linuxでは動いたがMacだと動かない。(デバッグ中) 38
  36. 「結局 AI で作ってるんじゃない ?」 • そうです。半年で「ないもの」が全部埋まった • ただし: 何を作るか‧証明を速度に使う着想は⼈間 •

    AI が埋めたのは実装の膨⼤な⼿数 • 実話: AI は「Python で作れば?」と⾔ってきた • AI は踏まれた道を勧める。道を決めるのは⼈間 • 本題: 律速はモデルの賢さでなく TAT 40
  37. E2Bのカーネルチューニング: webgpu + js • 30分程度で 254.8 tok/s — llama.cpp

    (220, 240?) 超え https://x.com/xenovacom/status/2065656427117437213 だが、leanのフレームワークだと数⽇かけても50%も難しい 41
  38. 実証: E4B エンジンをスクラッチで一朝 フェーズ 時間 リポ作成 + 資料読み 24 分

    ベースライン計測 30 分 ハーネス + golden 値 35 分 初回実行で token 一致 50 分 合計 1 時間 46 分 • 同⽇中に 124.2 tok/s — llama.cpp (102.4) 超え 42
  39. Sparkle は「ハードウェア版の同じ賭け」 観点 e4b-webgpu Sparkle 実行まで 秒 (no build) 秒

    (elab + JIT) 正しさ golden 一致 Lean 証明 観測 tok/s 波形が即出る • HW は本来 TAT 最悪 → 秒の世界に持ち込む • 証明は AI の柵: sorry はバレる、等価性とか型でコンパイルで落 ちるのだが、それが⽣産性を下げる場合があるかも。 43
  40. まとめ • Lean の elab がコンパイラフロントエンド • JIT: Verilator ⽐

    1.6‒1.7x / オラクルで 9,707x • 証明を「速度」に変える 3 本柱 • Tang Nano 20K で実チェーンに送⾦ • verilean.github.io/sparkle で今すぐ • Q&A 44