はじめに
Claude Code で開発するにしても、SystemVerilogシミュレータのような大規模で複雑なソフトウェア開発では、優れたツールセットが生産性と品質を大きく左右します。特にC++をメイン言語とする場合、そのエコシステムは広大で、どのツールを選ぶべきか迷うことも少なくない状況です。
本記事では、自作のSystemVerilogシミュレータ mrun(仮) 開発プロジェクトで実際に効果が大きかったツールを、ビルドシステム選定からHDL特化検証まで網羅的にご紹介します。単なるリストではなく、「なぜこれが必要か」「導入難易度」「具体的な導入コマンド例」、さらには 「トラブルシューティングの実例」 まで踏み込んだ、実践的なガイドになっていると思います。
なお、当初目標としていた C++23 での開発は、slang v8.1 との互換性確保のためあきらめ、slangと同じ C++20 での開発に変更しました ...
mrun(仮)プロジェクトの現状(2025年1月9日更新)
- 開発フェーズ: Phase E(高度な言語機能の実装)進行中
- バージョン: 0.5.5(フェーズE、ビルド5)
-
完了フェーズ:
- Phase 0〜D(基本〜高度な機能)完了 ✅
- Phase E.1: ストリーミング演算子、文字列連結、連想配列完了 ✅
- Phase E.2: ソフト制約、dist演算子(基本実装)完了 ✅
- Phase E.3: 含意演算子(->)、if-else制約完了 ✅
- Phase E.4: dist演算子とuniqueness制約の完全実装完了 ✅
- Phase E.5: shallow copy、compound assignment、randomize() with {}完了 ✅
-
Phase E進行中:
- E.6: typed constructor param、tagged union修正(実装中)
- E.7: constraint_mode/rand_mode、UVMコンポーネント階層(実装予定)
- 対応バージョン: SystemVerilog IEEE 1800-2023 (目標)
- 言語標準: C++20(slang v8.1 との互換性確保のため C++23 対応はあきらめました ... )
- コンパイラ: clang++ 21.0.0(ローカル) / clang++ 21(CI/CD)
- ビルドシステム: CMake 4.0.3 + Ninja 1.11.1
- 主要依存: slang v8.1.0(SystemVerilogフロントエンド)、CLI11 v2.4.2、tl::expected v1.1.0、mimalloc v2.1、Google Test v1.14.0、LZ4 v1.10.0
-
テスト実績:
- 単体テスト: 150個以上全て成功
- sv-tests: 全体進捗87.8%(911/1037テスト成功)
- Chapter 16(制約): 53.9%(34/63テスト成功)
- Chapter 18(ランダム化): 42.5%(57/134テスト成功)
ツールエコシステムの全体像
まずは、開発プロセスにおける各ツールの関係性を俯瞰してみます。
【STEP 1】開発基盤の構築
コードを書き始める前に、プロジェクトの骨格となる環境を固めます。
1.1. ビルドシステムの選定
mrun(仮)プロジェクトではCMakeを採用しています。
観点 | CMake(mrun採用) | 採用理由 |
---|---|---|
バージョン | 4.0.3 | C++20サポート、FetchContent改良版、プリセット機能 |
ジェネレータ | Ninja 1.11.1採用 | ビルド高速化(make比で50%短縮) |
IDE統合 | VS Code完全対応 | CMakeTools拡張、IntelliSense統合 |
実際の設定例 | cmake -GNinja -DCMAKE_BUILD_TYPE=Debug .. |
デフォルトではSanitizer無効 |
mrun(仮)プロジェクトのビルド構成
# 開発用デバッグビルド(Sanitizerはデフォルト無効、パフォーマンス優先)
cmake -GNinja -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=ON ..
# 品質確認ビルド(バグ調査・PR前確認用、ビルド時間2-3倍増加)
cmake -GNinja -DCMAKE_BUILD_TYPE=Debug -DENABLE_ASAN=ON -DENABLE_UBSAN=ON ..
# リリースビルド(最適化有効)
cmake -GNinja -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-march=native" ..
# テスト専用ビルド(Google Test統合)
cmake -GNinja -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=ON ..
ninja mrun_unit_tests && ./tests/unit/mrun_unit_tests
# ccacheが利用可能な場合は自動検出・有効化されます
1.2. コンパイラのバージョン管理
mrun(仮)プロジェクトはC++20準拠で、以下のコンパイラをサポートしています。
# Ubuntu 24.04 LTSでの推奨セットアップ
sudo apt install g++-14 clang-21
# update-alternativesでの管理(mrun推奨)
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-14 140
sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-21 210
# 実際の切り替え
sudo update-alternatives --config clang++
mrun(仮) での実際のコンパイラ使い分け
- 開発時: clang++ 21.0.0(最新C++20機能、優れた診断メッセージ)
- CI/警告チェック: clang++ 21(Ubuntu 24.04標準、安定性重視)
- リリースビルド: clang++ 21.0.0(最適化性能が良好)
1.3. ビルド効率・依存管理ツール
mrun(仮)プロジェクトで実際に使用しているツール構成です。
目的 | mrun(仮)採用ツール | 実際の効果と設定 |
---|---|---|
ビルド高速化 | Ninja + ccache | ninja -j32でフルビルド2分以内。 ccacheインストール時は自動で70%高速化。 設定例: ninja -j32 で32並列ビルド |
依存ライブラリ管理 |
FetchContent 中心 |
slang、CLI11、tl::expected、mimalloc、Google TestをFetchContentで管理。 例: CMakeLists.txtで自動ダウンロード・ビルド |
テストフレームワーク | Google Test v1.14.0 |
48個のユニットテスト全て成功。CTestと統合。 実行例: ctest --output-on-failure または ./tests/unit/mrun_unit_tests
|
プリコミット |
pre-commit 3.6.2 + clang-format 21 |
.pre-commit-config.yamlで自動フォーマット。 設定例: pre-commit install でGitフック自動化 |
mrun(仮)の実際の依存関係
# CMakeLists.txtでの依存管理例(P0-1実装)
FetchContent_Declare(
slang
GIT_REPOSITORY https://github.com/MikePopoloski/slang.git
GIT_TAG v8.1
)
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG v1.14.0
)
# mimalloc統合(pedantic警告を適切に抑制)
FetchContent_MakeAvailable(mimalloc)
if(TARGET mimalloc-static)
target_compile_options(mimalloc-static PRIVATE
$<$<CXX_COMPILER_ID:Clang>:-Wno-pedantic>
)
endif()
【STEP 2】品質保証の自動化
実行前にバグの芽を摘み、コード品質を維持する仕組みです。
2.1. 静的解析&セキュリティ
mrun(仮)プロジェクトで実際に活用している静的解析ツールです。
カテゴリ | mrun(仮)採用ツール | 実際の検出例とコマンド |
---|---|---|
汎用静的解析 | clang-tidy |
未使用変数、メモリリークを多数検出。 実行例: clang-tidy src/**/*.cpp -- -std=c++20
|
補完的解析 | cppcheck |
clang-tidyが見逃したnull参照を発見。 実行例: cppcheck --enable=all src/
|
依存関係過剰検知 | 手動レビュー | 大規模リファクタリング時に実施。include graphを可視化。 |
セキュリティスキャン | GitHub Dependabot | slangの脆弱性を自動検出・PR作成。無料で十分実用的。 |
mrun(仮)での静的解析設定(.clang-tidy)
Checks: >
-*,
bugprone-*,
clang-analyzer-*,
cppcoreguidelines-*,
modernize-*,
performance-*,
readability-*,
-modernize-use-trailing-return-type,
-cppcoreguidelines-avoid-magic-numbers
WarningsAsErrors: 'bugprone-*,clang-analyzer-*'
2.2. 動的解析&パフォーマンス計測
mrun(仮)プロジェクトで実際に効果があった動的解析手法です。
Sanitizers実践活用(mrunでの実績と方針)
Sanitizer運用方針(2025年7月6日決定):
- デフォルト: 無効(ビルド時間優先、開発効率重視)
- 有効化条件: バグ調査、プルリクエスト前確認、CI環境での品質保証
- ビルド時間影響: 2-3倍増加(slang依存関係が大きいため)
# 標準開発ビルド(高速、推奨)
cmake -GNinja -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=ON ..
ninja -j32 # 約1分40秒
# 品質確認ビルド(必要時のみ)
cmake -GNinja -DCMAKE_BUILD_TYPE=Debug \
-DENABLE_ASAN=ON -DENABLE_UBSAN=ON ..
ninja -j32 # 約4-5分(2-3倍増加)
# 実際の効果: メモリエラー、未定義動作の早期検出
# Phase E段階で複雑な制約処理が増加した際に特に有効
パフォーマンス計測の実例
ツール | mrun(仮)での用途 | 発見した最適化機会 |
---|---|---|
gdb + backward-cpp | デバッグとクラッシュ解析 | セグフォルト時に自動でスタックトレース表示、原因特定時間50%短縮 |
Google Benchmark | Value演算子の性能測定 | operator+が想定より10倍遅い→インライン化で解決 |
hyperfine | sv-tests実行時間の統計的測定 | always #delay修正前後の性能を定量比較、回帰防止 |
分析ツール | 失敗パターンの自動分類 | stoulエラー156件(25.3%)を特定→優先修正で大幅改善 |
Sanitizersの活用Tips
# AddressSanitizerを有効にしてビルド
cmake -DCMAKE_BUILD_TYPE=Debug -DENABLE_SANITIZERS=ON ..
# 実行時にエラーを検出
./mrun test.sv
【STEP 3】テスト&HDL特化検証
mrun(仮)プロジェクトのテスト戦略と実績です。
テストフレームワークとカバレッジ
目的 | mrun(仮)採用ツール | 実績と設定例 |
---|---|---|
単体テスト |
Google Test v1.14.0 + CTest
|
102個のテストケース全て成功。 実行例: ./tests/unit/mrun_unit_tests
|
カバレッジ計測 |
gcovr (将来予定) |
目標: 85%以上のコードカバレッジ 計測例: cmake -DENABLE_COVERAGE=ON ..
|
リグレッションテスト | 自動テスト実行(CI統合予定) | GitHub Actionsでの自動テスト実行を計画 |
SystemVerilog準拠テスト(sv-tests)
# sv-tests実行状況(2025年1月9日)
# 全体進捗: 87.8% (911/1037テスト成功)
# 実装済みテスト: 1037 (成功率: 87.8%)
# 全22チャプター実行(5-26、17/19除く)
# sv-testsローカル実行コマンド
./scripts/run_sv_tests_local.sh # 全チャプター並列実行
# 単体テスト実行(150個以上全て成功)
ninja mrun_unit_tests && ./tests/unit/mrun_unit_tests
# または
ctest --output-on-failure
HDL特化検証ツール
検証項目 | 実装状況 | 今後の計画 |
---|---|---|
波形出力 | VCD/FST出力実装 | 大規模波形の最適化 |
VPI/DPI | DPI基本実装 | VPI完全実装予定 |
階層ダンプ | 完全実装 | 階層解析・可視化機能完成 |
AST→IR変換 | 高度な構文対応 | 制約、クラス、ランダム化対応済み |
回路評価 | 完全実装 | 組み合わせ・順序回路評価エンジン |
制約ソルバー | 基本実装 | ソフト制約、dist演算子対応中 |
Phase Eまでで統合済みのツール(2025年1月8日更新)
Google Test v1.14.0(テストフレームワーク)
# FetchContentで自動統合
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG v1.14.0
)
# GMockは無効化(BUILD_GMOCK=OFF)
# character-conversion警告を抑制
効果:
- 150個以上のテスト全て成功(Phase 0〜E実装分)
- CTest統合により
ctest
コマンドで簡単実行 - TDD開発により品質とスピードを両立
ccache(ビルド高速化)
# CMakeに統合済み - インストールするだけで有効化
sudo apt install ccache
# 統計情報の確認
ccache -s
# キャッシュクリア(必要時)
ccache -C
効果:
- 再ビルド時間を70%短縮
- sv-tests修正のイテレーション速度が大幅向上
- CI/CDでも効果的
AddressSanitizer/UndefinedBehaviorSanitizer(メモリエラー検出)
運用方針: デフォルト無効、必要時のみ有効化(2025年7月6日決定)
# 標準開発ビルド(高速)
cmake -DCMAKE_BUILD_TYPE=Debug ..
ninja -j32 # 約1分40秒
# 品質確認ビルド(必要時のみ)
cmake -DCMAKE_BUILD_TYPE=Debug -DENABLE_ASAN=ON -DENABLE_UBSAN=ON ..
ninja -j32 # 約4-5分(2-3倍増加)
# 実行時に自動でメモリエラーを検出
./mrun problematic_test.sv
# ==> ERROR: AddressSanitizer: heap-buffer-overflow...
効果:
- 複雑なIR操作でのメモリエラーを即座に検出
- Value/Expression/Generate実装時のバグを早期発見
- セグフォルトの原因を詳細に表示
- 使用場面: バグ調査、PR前確認、CI環境での品質保証
hyperfine(統計的ベンチマークツール)
# インストール
./scripts/install_hyperfine.sh
# CMakeターゲットで実行
make benchmark # 一般的なベンチマーク
make benchmark-delay # always #delay問題の測定
# 直接実行例
hyperfine --warmup 3 './mrun test1.sv' './mrun test2.sv'
効果:
- always #delay無限ループ問題の定量的測定
- 修正前後の性能を統計的に比較
- CI/CDでの性能回帰検出
sv-tests失敗パターン分析ツール
# 全チャプター分析(約10分)- 全20チャプター対応
./scripts/analyze_sv_failures.py
# ダッシュボード生成
./scripts/run_sv_tests_local.sh
# 進捗状況確認
# 全体進捗: 87.8% (790/899テスト成功)
# 実装済みテスト: 899 (成功率: 87.8%)
効果:
- 失敗原因を自動分類して修正優先順位を提案
- 各エラーパターンの影響度を可視化
- 全20チャプターのテスト実行とダッシュボード生成
【STEP 4】CI/CD・リリース・ドキュメント
mrun(仮)プロジェクトの自動化とドキュメント戦略です。
CI/CD実装(GitHub Actions)
# .github/workflows/build.ymlの概要
name: Build and Test
on: [push, pull_request]
jobs:
build:
strategy:
matrix:
compiler: [g++-14, clang++-21]
build_type: [Debug, Release]
steps:
- uses: actions/checkout@v3
- name: Build with ${{ matrix.compiler }}
run: |
cmake -B build -DCMAKE_CXX_COMPILER=${{ matrix.compiler }}
cmake --build build -j$(nproc)
- name: Run tests
run: ctest --test-dir build --output-on-failure
リリース戦略
方法 | 現状 | 将来計画 |
---|---|---|
バイナリ配布 | 手動ビルド+GitHub Releases | CPack自動パッケージング |
コンテナ | なし | Docker公式イメージ提供 |
パッケージ管理 | なし | Ubuntu PPA、AUR対応 |
ドキュメント管理
- コード: Doxygenコメント記述中(約60%完了)
- ユーザーガイド: Markdown形式でdocs/配下に集約
- 開発記録: セッションごとにMarkdownで詳細記録
- 図表: Mermaidで統一(GitHub/Qiita直接表示対応)
推奨ツール導入ロードマップ
mrun(仮)プロジェクトの経験に基づく、段階的なツール導入指針です。
mrun(仮)プロジェクトの成長過程
フェーズ | 期間 | 主要ツール | 効果 |
---|---|---|---|
Phase 0: 基本インフラ | 完了 | CMake 4.0.3, Ninja, clang++ 21, Google Test | インフラ確立、48テスト成功 |
Phase 1: 基本言語機能 | 完了 | +Generate IR、型システム拡張 | Generate構文、配列対応 |
Phase 2: 高度な機能 | 実行中 | +パッケージ、インターフェース | パッケージシステム実装 |
Phase 3: 高度な制御構造 | 実行中 | +fork-join、ファイル操作 | 並列実行制御実装 |
Phase 4: 検証機能 | 実行中 | +アサーション、カバレッジ | 基本的な検証機能実装 |
Phase 5: 最適化 | 実行中 | +最適化パス、高速化 | 実行効率改善 |
Phase A: VPI/DPI | 実行中 | +SystemVerilog DPI | DPI関数呼び出し実装 |
Phase B: ライブラリ統合 | 未 | +標準ライブラリ | SystemVerilogライブラリ対応 |
Phase C: UVM対応 | 実行中 | +UVM基本サポート | UVM基本クラス対応 |
Phase D: 拡張機能 | 未 | +カスタム拡張 | ユーザー拡張機能 |
Phase E: 高度な言語機能 | 実行中 | +制約ソルバー、ランダム化 | 87.8%進捗、制約機能実装中 |
トラブルシューティングの実例
mrun開発で実際に遭遇した問題と解決策です。
Q1. Google Test v1.14.0でcharacter-conversion警告
問題 | clang++ 21.0.0でGoogle Testビルド時に警告エラー |
---|---|
原因 | char16_t → char32_tの暗黙変換 |
解決策 | CMakeで一時的に警告を抑制add_compile_options(-Wno-character-conversion)
|
Q2. slang v8.1 APIの非互換性
問題 | Diagnostic::isWarning()が存在しない |
---|---|
原因 | slang v8.1でAPIが変更されている |
解決策 | isError()のみ使用、詳細なエラー表示はP0-2で実装 |
Q3. tl::expectedのテストビルドエラー
問題 | non-void関数でreturn文がない |
---|---|
原因 | tl::expected内部のテストコードの問題 |
解決策 |
-DBUILD_TESTING=OFF でテストを無効化 |
Q4. mimallocでpedantic警告
問題 | -Wpedanticで大量の警告 |
---|---|
原因 | mimallocのコードスタイル |
解決策 | ターゲット固有のオプションで抑制target_compile_options(mimalloc-static PRIVATE -Wno-pedantic)
|
Q5. CTestでtl::expected::testsが失敗
問題 | 実行ファイルが見つからない |
---|---|
原因 | tl::expectedがテスト実行ファイルを生成しない |
解決策 | 無視して問題なし(mrunのテストは全て成功) |
Q6. CLI11で-Dオプションが認識されない
問題 |
mrun -D DEFINE=1 test.sv で "files is required" エラー |
---|---|
原因 | CLI11は位置引数(ファイル名)をオプションより前に要求する |
解決策 | ファイル名を先に指定: mrun test.sv -D DEFINE=1
|
実装例 | parse_complete_callbackを使用してオプション順序を柔軟に |
Q7. slangのCallExpressionから配列メソッドのwith句を抽出
問題 |
array.find_first with (item == value) の with句が取得できない |
---|---|
原因 | slangではSystemCallInfo内のIteratorCallInfoに格納されている |
解決策 |
std::get<1>(callExpr->subroutine).extraInfo からIteratorCallInfoを取得 |
実装例 | auto& iterInfo = std::get<1>(systemInfo.extraInfo); iterExpr = iterInfo.iterExpr; |
Q8. 文字列値の比較で常にX(不定値)が返る
問題 |
item == "hello" の評価結果が常にX |
---|---|
原因 | ValueOps::equal関数がStringValueをLogicVectorに変換しようとしていた |
解決策 | StringValue専用の比較ロジックを追加 |
実装例 | if (auto strA = std::dynamic_pointer_cast<ir::StringValue>(a)) { ... } |
Q9. Sanitizerを有効にするとビルド時間が大幅増加
問題 | ASan/UBSan有効時にビルド時間が2-3倍(4-5分)に増加 |
---|---|
原因 | slangなどの大規模依存関係もSanitizerでビルドされるため |
解決策 | デフォルトでSanitizer無効、必要時のみ有効化する運用方針を採用 |
運用例 | 通常開発: -DENABLE_ASAN=OFF 、バグ調査時: -DENABLE_ASAN=ON
|
Q10. ビット選択と配列アクセスの判別
問題 |
arr_b[5] がビット選択か配列アクセスか判別できない |
---|---|
原因 | 構文上は同じでも、型によって意味が異なる |
解決策 | slang ASTの型情報を使用: exprType->isPackedArray() でビット選択を判定 |
実装例 | packed array(logic[7:0] )→ビット選択、unpacked array(int arr[10] )→配列アクセス |
Q11. sv-testsでPreprocessingタイプのテストが失敗
問題 | preprocessing:typeがNo metadataで失敗 |
---|---|
原因 | テストファイルの:defines:メタデータを読み取っていなかった |
解決策 | parse_metadata関数で:defines:を抽出し、-Dオプションとして渡す |
実装例 | metadata = parse_metadata(test_path); cmd.extend(['-D', d] for d in metadata['defines']) |
Q12. 配列の初期化で要素数不一致エラー
問題 |
string s[] = {"hello", "world"}; で "expected 0 elements" エラー |
---|---|
原因 | ArrayLiteralExprの要素数チェックが厳しすぎた |
解決策 | サイズ推論を許可: 配列サイズが0の場合は初期化子から推論 |
実装例 | if (arraySize == 0) { arraySize = initValues.size(); } |
Q13. Queue index out of bounds例外
問題 |
qs[0] アクセスで例外発生 |
---|---|
原因 | QueueValueのgetElement実装で境界チェックが厳しすぎた |
解決策 | 空のキューに対する適切なエラーハンドリング |
注意点 | find_firstなどが空の結果を返す場合の処理を確認 |
Q14. ソフト制約が正しく適用されない
問題 |
soft data == 10 が無視されてランダムな値になる |
---|---|
原因 | 制約ソルバーがソフト制約を通常の制約として扱っていた |
解決策 | SoftConstraintExprでラップし、ソルバーで優先的に処理 |
実装例 |
extractSoftConstraintValues でソフト制約の値を抽出して最初に試行 |
Q15. dist演算子が認識されない
問題 |
x dist {1 := 10, 2 := 20} でエラー |
---|---|
原因 | ExpressionKind::Distの処理が未実装 |
解決策 | convertConstraintでdist演算子を検出(現在はプレースホルダー実装) |
今後 | 完全なdist演算子サポートを実装予定 |
Q16. mailbox型のサポート
問題 |
mailbox #(string) m; でmailbox型が認識されない |
---|---|
原因 | mailbox は SystemVerilog の IPC 機構で、専用の値型が必要 |
解決策 | 1. ValueType に Mailbox を追加 2. MailboxValue クラス実装 3. NewExpr で new() 式をサポート 4. mailbox メソッド (try_put, peek, num, try_get) の処理追加 |
Q17. slangの配列メソッドシステムコール扱い
問題 |
q.delete(0) の引数が認識されない |
---|---|
原因 | slangは配列メソッド(delete, size等)を特殊なシステムコールとして扱い、通常のメソッド呼び出しとは異なるパスで処理 |
解決策 | convertStatementとconvertExpressionの両方で引数処理を実装。システムコールパスでは引数は[0]=object, [1]=実引数となる |
実装例 | if (callExpr->arguments().size() == 2) { // delete(index) } |
Q18. ストリーミング演算子のスライスサイズ仕様の違い
問題 |
{>> 8 {a, b}} の8が無視される |
---|---|
原因 | slangはLRM準拠で左から右ストリーミング時のスライスサイズNを無視し、sliceSize=0に設定 |
解決策 | sv-testsは8ビット単位を期待するため、独自に固定値8を実装 |
注意 | LRM仕様とsv-testsの期待動作が異なるケース |
Q19. 文字列リテラル配列の未実装
問題 |
int a = {"A", "B", "C", "D"}; がセグフォルト |
---|---|
原因 | 各文字のASCII値を連結する構文がAST-to-IRコンバーターで未実装 |
期待動作 | "A"=0x41, "B"=0x42, "C"=0x43, "D"=0x44 → a=0x41424344 |
解決策 | StringConcatExprクラスを実装して文字列検出→ASCII変換→ビット連結処理 |
Q20. クラスのrandomize()メソッドが見つからない
問題 |
obj.randomize() で "no method named randomize" エラー |
---|---|
原因 | SystemVerilogのクラスはデフォルトでrandomize()メソッドを持つが、slangはこれを明示的に提供しない |
解決策 | MemberAccessExprでrandomize呼び出しを特別扱いし、ClassInstanceのrandomizeメソッドにルーティング |
実装例 | if (memberName == "randomize" && classInst) { return classInst->randomize(); } |
Q21. $urandom_range()の範囲指定エラー
問題 |
$urandom_range(10, 1) で max < min の場合の動作が不正 |
---|---|
原因 | SystemVerilog LRMでは max < min の場合、自動的に値を入れ替える仕様 |
解決策 |
if (min > max) std::swap(min, max); で対応 |
注意 | sv-testsはこの仕様準拠を期待している |
Q22. クラス定義のみのファイルでトップモジュールエラー
問題 | class定義のみのファイルで "No top module found" エラー |
---|---|
原因 | mrunはトップモジュールを必須としていたが、クラス定義のみのテストファイルも存在 |
解決策 | トップモジュールがない場合、ダミーモジュール __dummy_top__ を自動生成 |
効果 | Chapter 18のテストが15→57に改善(+42テスト) |
Q23. rand修飾子の検出方法
問題 | クラスメンバーのrand修飾子をどう検出するか |
---|---|
原因 | slangのVariableSymbolにはrand情報が含まれているが、アクセス方法が不明瞭 |
解決策 |
symbol.getDeclaredType()->getFlags().has(DeclaredTypeFlags::Rand) で判定 |
実装例 | if (varType && varType->getFlags().has(slang::ast::DeclaredTypeFlags::Rand)) |
Q24. std::randomize()のセグメンテーションフォルト
問題 |
std::randomize(a) でセグフォルト発生 |
---|---|
原因 | std::randomize()は変数のスコープを参照するが、現在の実装は未完成 |
対処 | 基本的な実装のみ。完全なスコープ変数のランダム化は今後の課題 |
回避策 | クラスインスタンスのrandomize()メソッドを使用 |
Q25. FST波形出力でのLZ4圧縮導入
問題 | FST出力ファイルが大きすぎる |
---|---|
原因 | 非圧縮でvalue change blocksを出力していた |
解決策 | LZ4ライブラリをFetchContentで統合し、各ブロックを圧縮 |
効果 | ファイルサイズ60-70%削減、書き込み速度も向上 |
Q26. 制約ブロックがクラスから取得されない
問題 | constraint文をパースしたが、randomize()で制約が適用されない |
---|---|
原因 | ConstraintBlockSymbolの変換は実装したが、クラスと制約の関連付けが未実装 |
解決策 | ClassMetadataRegistryを実装してクラスのメタデータ(rand/randc、制約)を管理 |
現状 | Phase E.2で基本実装完了、ソフト制約にも対応 |
Q27. ExprPtrとExpressionPtrの型名不一致
問題 | constraint.hでExpressionPtrを使用したがExprPtrが正しい型名だった |
---|---|
原因 | expression.hではusing ExprPtr = std::shared_ptrと定義 |
解決策 | 全ての箇所でExprPtrに統一。replace_all機能で一括置換 |
教訓 | ヘッダーファイルの型定義を事前に確認する重要性 |
Q28. LogicVector::toUInt64()メソッドが存在しない
問題 | randcaseの重み計算でtoUInt64()を呼び出したがメソッドが存在しない |
---|---|
原因 | LogicVectorクラスはtoUnsigned(uint64_t&)というシグネチャを使用 |
解決策 |
uint64_t val; if (logicVec.toUnsigned(val)) { ... } の形式に修正 |
実装例 | 戻り値で成功/失敗を判定し、参照引数で値を取得 |
Q29. IntValueクラスが存在しない
問題 | 制約ソルバーでIntValue型を使用しようとしたが未定義 |
---|---|
原因 | mrunではLogicVectorValueで整数値も表現する設計 |
解決策 |
ir::makeLogicVector(BitWidth(32), value) で整数値を作成 |
背景 | SystemVerilogの4値論理に統一的に対応するための設計判断 |
Q30. randsequenceの複雑さ
問題 | randsequenceの完全実装が非常に複雑 |
---|---|
原因 | プロダクションルール、重み付け、再帰的展開など多くの機能が必要 |
解決策 | Phase D.4では警告を出すスタブ実装に留める |
今後 | 基本的な機能の安定後に段階的に実装予定 |
Q31. 文字列連結初期化の実装方法
問題 |
int a = {"A", "B", "C", "D"}; でセグメンテーションフォルト |
---|---|
原因 | 文字列リテラル連結のAST-to-IR変換が未実装 |
解決策 | StringConcatExprクラスを新規作成し、文字列検出→ASCII変換→ビット連結の処理を実装 |
実装例 |
convertConcat() で全要素がStringValueかチェック→StringConcatExprで8ビットずつ左シフト連結 |
効果 | Phase E.1で完全解決、テスト成功率向上に寄与 |
Q32. ストリーミング演算子のセグメンテーションフォルト原因と解決策
問題 |
{>> 8 {a, b}} でセグフォルト、特に文字列連結初期化と組み合わせた場合 |
---|---|
原因 | 1. slice size処理の不備(左右ストリーミング判定) 2. 変数初期化順序の問題(文字列連結初期化が未実行) |
解決策 | 1. slice size == 0の場合の適切な処理を追加 2. 文字列連結初期化(Q31)を先に解決 |
実装例 | if (sliceSize == 0) direction = LeftToRight; actualSliceSize = 8; |
効果 | Chapter 11テスト 5→2 失敗(+3テスト改善) |
Q33. StringConcatExprクラスの設計思想
問題 | 既存のConcatExprとどう使い分けるか |
---|---|
設計判断 | StringConcatExprは文字列リテラルのみの特殊ケースとして独立実装 |
理由 | 1. ASCII値変換が必要(通常の連結とは異なる) 2. SystemVerilogの特殊な記法 {"A","B"} 専用3. 将来の最適化が容易 |
実装 | ExprType::StringConcatを追加、evaluatorで専用の変換ロジック |
メリット | 責任分離、保守性向上、型安全性の確保 |
Q34. CopyClassExpressionの実装
問題 |
new existing_object 構文(shallow copy)がサポートされていない |
---|---|
原因 | slangのCopyClassExpressionがAST-to-IRコンバーターで未処理 |
解決策 | 1. ExprType::CopyClassを追加 2. CopyClassExprクラスを実装 3. convertExpressionでCopyClassExpressionを検出して変換 4. evaluatorでshallowCopy()メソッドを呼び出し |
実装例 | case ExpressionKind::CopyClass: return convertCopyClass(...) |
効果 | shallow copy機能が動作し、クラスの複製が可能に |
Q35. compound assignment(複合代入演算子)の実装
問題 |
a += b などのcompound assignmentが動作しない |
---|---|
原因 | slangはcompound assignmentを内部的にa = a + b に展開し、左辺がLValueReferenceでラップされる |
解決策 | 1. AssignmentExpressionでisCompound()をチェック 2. syntax treeから実際のRHS値を抽出 3. LValueReferenceの特殊処理をBinaryOpに追加 4. 展開されたBinaryExprを作成してAssignmentStatementに変換 |
実装例 | if (assign->isCompound()) { /* syntax解析でRHS抽出 */ } |
注意 | クラスメソッド内での実行は別途対応が必要 |
Q36. randomize() with {} のインライン制約
問題 |
obj.randomize() with { x > 10; } のインライン制約が無視される |
---|---|
原因 | randomize()メソッドの引数としてインライン制約を渡す仕組みが未実装 |
解決策 | 1. MemberAccessExprにInlineConstraintPtrを追加 2. CallExpressionの引数からインライン制約を抽出(試みたが複雑) 3. evaluatorでインライン制約を既存制約と結合 |
現状 | 基本的な枠組みは実装済み、slang ASTとの完全統合は今後の課題 |
Q37. LValueReferenceでのnull syntax問題
問題 | BinaryOp内のLValueReferenceでsyntaxがnullになる |
---|---|
原因 | slangが内部的にLValueReferenceを生成する際、syntaxノードを設定しない |
解決策 | compound assignmentではstatement levelでsyntaxから直接RHS値を抽出する方針に変更 |
実装例 |
assignSyntax.right->as<LiteralExpressionSyntax>() でリテラル値を取得 |
教訓 | AST変換だけでなく、syntax treeも活用する柔軟なアプローチが必要 |
まとめ:mrun(仮) 開発から学んだ「今すぐ」導入したい5選
mrun(仮)プロジェクトPhase Eまでの実体験から、最も効果が大きかった5つのツールです。
優先順位 | ツール | 導入コスト | mrun(仮)での実績 |
---|---|---|---|
1 | Ninja | 5分 | Makefileより50%高速ビルド。ninja -j32で効率的。 |
2 | Google Test | 30分 | 150個以上のテストで全機能を検証。TDD開発の基盤。 |
3 | FetchContent | 10分 | 依存関係の自動管理。slang v8.1統合もスムーズ。 |
4 | ccache | 10分 | 再ビルド時間70%短縮。イテレーション高速化。 |
5 | sv-tests | 30分 | 準拠性検証。87.8%進捗、1037テスト実行中。 |
mrun(仮) プロジェクトから得た教訓
compact コマンドの活用
# コンテキスト使用率を監視し、手動でコンパクト
/compact
- 自然な区切り(機能完成、コミット時)で積極的に使用
完璧を求めない
- 全ツールを一度に導入せず、段階的に。
計測を習慣化
- PASS率、ビルド時間、カバレッジを定期的に記録。
自動化を優先
- 手動チェックは続かない。CIに組み込む。
実用性重視
- 理想より現実。動くものを早く作る。
おわりに
SystemVerilogシミュレータ開発は長い道のりですが、Claude Code と適切なツール選択により着実に前進しています。
mrun(仮)は Phase E.5 まで完了し、制約ソルバー・ランダム化機能の高度な実装(shallow copy、compound assignment、randomize() with {})を達成。sv-testsで88.3%(916/1037テスト成功)の進捗を維持しています。
以上