Files
retroSoC/scripts
maksyuki 6fbc6ec521 fix(flow): retain terminal evidence across interrupted runs
Record parent and child process IDs for diagnostics, persist interruption
before cleanup, and ignore repeated termination signals during cleanup.
Close unexpected failures with a terminal result and retain the child's
exit status without treating namespace-local PID absence as completion.

Require a successful terminal run_flow result when checking simulation
logs with an associated result file. Cover repeated cancellation and
reject running, failed or inconsistent terminal records despite PASS text.

This supports the TINY-R2-P7 campaign. Interrupted and timed-out runs remain
non-acceptance evidence; UART output alone cannot qualify a Tiny simulation.
2026-10-14 16:55:12 +08:00
..
2026-09-27 09:09:53 +08:00

Build and Quality Scripts

This directory contains the Python implementation of setup, dependency locking, build manifests, flow execution, simulation checks, regression orchestration, quality checks, metrics, packaging, and cleanup.

apu_mcasm.py, apu_isa.py, apu_interpreter.py, and apu_primitives.py are the frozen APU microcode V1 assembler/ABI model, P3/P4/P5 target interpreters, and bit-accurate P4 primitive model. They accept only the APU instruction language and deliberately have no C, ELF, RV32, dynamic linking, or runtime code-generation path.

setup_apu_reference.py installs the checksum-pinned libFLAC and official FLAC corpus as host-only P5 verification inputs and builds libFLAC with Ogg disabled below the selected build variant. These inputs never enter firmware, RTL, or shipped APU microcode. qualify_apu_p5_corpus.py enumerates that exact corpus, records source and decoded-PCM hashes, and classifies each file against the frozen P5 profile. run_apu_p5_corpus_rtl.py then runs every classified file through one shared, verification-only apb4_apu fixture compiled for Icarus and Verilator. It records exact production result/accounting and PCM hashes in the same manifest; per-case results are resumable and neither the fixture nor corpus enters a product filelist.

Scripts are part of the build contract. Prefer existing helpers over ad-hoc shell behavior, preserve structured JSON results, and keep setup/download behavior controlled by dependencies/dependencies.lock.json.

generate_apu_kws_rtl_constants.py also emits the frozen APU-P9 APUC image and 15-bank layout manifest. apu_kws_coeff.py owns the independent APUC 1.0 schema and release validator; generated assets remain below the selected variant's apu/coefficients/ directory. apu_p9_evidence.py initializes or assembles the six frozen P9 evidence files; missing qualifying runs stay explicitly unrun rather than becoming passes. apu_p9_memory_ab.py performs the like-for-like inferred-memory, macro-count, synthesis-time and process-tree peak-RSS comparison from two explicit variant roots; it never creates or switches Git worktrees itself.

The frozen P9 qualification entry points are explicit and do not turn smoke runs into release evidence:

make CONFIG=configs/ci/ihp130.mk setup-apu-kws-reference apu-p9-coefficients apu-p9-evidence
python3 scripts/run_apu_p7_kws_rtl.py \
  --build-dir build/<candidate>/apu/p9/accuracy --profile ihp130-p9
python3 scripts/run_apu_p7_concurrent_rtl.py \
  --build-dir build/<candidate>/apu/p9/concurrent --seconds 60
make CONFIG=configs/ci/ihp130.mk apu-p9-memory-ab \
  APU_P9_BASELINE_ROOT=build/<baseline> APU_P9_CANDIDATE_ROOT=build/<candidate>

Both A/B roots must come from clean committed revisions; the baseline is the frozen pre-P9 revision and both configurations must enable P7 with the same IHP130 tool, PDK, recipe, and dependency inputs. Assemble the six final reports with scripts/apu_p9_evidence.py assemble; a passed input is accepted only when its report-specific checks and named source artifacts are complete.

setup_npu_reference.py prepares the locked KWS/VWW inputs and the existing TensorFlow/gemmlowp reference sources. npu_framework_reference.py builds the host-only adapter in tests/cpp/npu_framework_reference.cc; its integer kernels consume original tensor constants and quantization, never NPU packed artifacts. Only raw model parsing is shared with the NPU compiler. Run make CONFIG=configs/ci/ihp130.mk npu-p0-qualify after make CONFIG=configs/ci/ihp130.mk setup-npu-reference to compare both complete 1000-input corpora against the Python graph reference and compiled executor. The VWW archive is fetched from the ordered HTTPS URLs in the dependency lock; every mirror must produce the same locked SHA-256 before extraction. The selected variant's npu/p0/ directory retains oracle build provenance, per-input golden tensors, three-way hashes, logs and qualification-p0.json. The runner uses at most 16 workers (JOBS); missing sources/tools, numerical differences and incomplete runs cannot pass. A direct --limit invocation is debug-only and returns a nonzero status even when its selected cases match.

npu_compiler.py is the P5 production entry point. It accepts one static batch-one INT8 TFLite v3 subgraph, rejects unsupported placement with an operator-specific diagnostic, and emits ABI-1 descriptors, packed constants, npu.json, and a model-prefixed freestanding C plan. The generated plan uses caller-owned aligned descriptor/arena storage, checked physical relocation, bounded HAL waits, 64-byte Zicbom maintenance when compiled for HP, and the model-derived terminal integer Softmax. Generated files remain below the selected build variant. make CONFIG=configs/ci/ihp130.mk npu-p5-deployments builds the locked KWS and VWW packages reproducibly.

qualify_npu_p5.py builds one production NPU fixture per simulator and runs the frozen ten-input sets from both manifests. Every accepted output byte is checked in actual tile-write order, so later arena reuse cannot hide an intermediate mismatch. Invoke it through make CONFIG=configs/ci/ihp130.mk npu-p5-rtl; missing tools, inputs, terminal markers, or any layer write fail the required run.

npu_p5_report.py fails closed while assembling P5 evidence. It verifies P0, compiler/parity and embedded-C/HAL results; exact dual-simulator case counts; source, trace, log and deployment hashes; LP/HP build manifests and firmware; cross-profile KWS package identity; and zero skipped/rejected cases. Invoke it through npu-p5-report with the retained LP/HP variant roots and config digests. The generated report records its fully expanded command.

NPU-P6 qualification is split into auditable drivers. npu_p6_corpus.py builds deterministic CRC-protected 100-case KWS/VWW shards from retained P0 goldens. run_npu_p6_verilator.py builds the existing hp_boot composition, runs all shards on one PRODUCT Verilator model, and aggregates architectural cycles and NPU counters. run_npu_p6_netlist.py runs macro-aware isolated synthesis/STA and four directed synthesized-block transactions covering dense, depthwise, rejection and accumulation-overflow behavior; run_npu_p6_physical.py invokes the unchanged full PRODUCT Yosys/OpenSTA and warning/metric gates. run_npu_p6_regression.py retains PR/nightly verdicts, and npu_p6_report.py requires current-revision PASS evidence for all of NPU-V015 through NPU-V018. None of these scripts treats FPGA execution or host elapsed time as mandatory performance evidence.

development_environment.py is the shared Docker, Nix, and manual bootstrap entry point. It installs only the checksum-verified open-source tool bundles and hash-pinned Python dependencies; project-local PDK and source setup remains under the existing Make targets.

publish_fatfs_artifact.sh is the manual release helper for the lock-pinned FatFs R0.16 archive. It verifies the archive, GitHub authentication, release absence, and the published asset checksum before reporting the checksum-pinned URL.

parse_performance_log.py converts the APP=benchmark UART PERF records into meta/performance.json. The parser requires the terminal PERF_BENCHMARK_PASS marker. parse_coremark_log.py converts the fixed SRAM CoreMark quick report into meta/coremark.json; it requires one valid COREMARK_RESULT record and COREMARK_PASS. Both reports complement, rather than replace, the common SIM_TEST_PASS simulation verdict.

generate_vexiiriscv.py verifies the locked VexiiRiscv revision, rejects local source changes before and after generation, and generates the fixed HP core below build/; generated RTL is never tracked. setup_hp_linux.py installs the locked OpenSBI, Linux, and Buildroot revisions and can resume a checkout left without HEAD by an interrupted fetch. build_hp_linux.py builds the RV64 lp64d userspace/OpenSBI image set with the repo-owned external OpenSBI platform. package_hp_boot.py creates the V2 typed LP/HP flash bundle and its SHA-256/CRC manifest. check_lp_hp_performance.py applies the measured 2.5x CoreMark/MHz gate.

setup_hp_rtthread.py installs the locked kernel, RV64 bare-metal compiler and isolated SCons environment. build_hp_rtthread.py stages only the repository BSP under the variant and records the source/compiler/configuration inputs. hp_tools.py checks source revisions and RV64 ELF class. run_hp_sim.py keeps Linux, smoke and RT-Thread logs/verdicts separate and checks every required workload marker together with a successful process exit.

run_debug_session.py is the local Hazard3 debug acceptance driver. It starts the Verilator remote-bitbang endpoint, the lock-pinned OpenOCD binary, and RISC-V GDB, then records their logs and a structured result. Invoke it through make CONFIG=configs/ci/ihp130-debug.mk SIMU=VERILATOR debug-sim; see ../docs/hazard3-debug.md for its scope and limitations.

program_xpi_flash.py drives the SRAM-resident XPI loader through an existing OpenOCD GDB endpoint. It validates and splits a BIN at 4 KiB sector boundaries, generates a reviewable GDB script, and performs erase/program only when --execute is explicit. See ../docs/ip/xpi.md.

check_rtl_style.py applies the ownership-aware RTL style rules from ../rtl/rtl_style_manifest.json. The CI target checks changed self-owned RTL for positional module connections, legacy constructs, and the staged naming contract. rtl-style-check-all retains the historical full-tree structural baseline while naming debt is migrated in module-sized batches. Existing findings must not be expanded by a new change.

migrate_rtl_connections.py is the conservative migration helper for legacy positional instances. It discovers ANSI-style module declarations in the production RTL and locked technology/IP trees, rewrites only exact positional parameter and port lists to named connections, and reports ambiguous instances without modifying them. Run make rtl-migrate-connections, then make rtl-format rtl-style-check; review the generated diff before committing.

migrate_rtl_names.py shortens only local identifiers beginning with s_ or r_ (plus local automatic variables such as read_request). Public module ports and interface fields are intentionally unchanged. Run make rtl-migrate-names, then format and lint the resulting diff.

crypto_constants.py packs the frozen CRYC1 image from data/crypto_constants.json and emits an 848-byte compact firmware header; crypto_p0.py independently checks it against the mathematical oracle in tests/crypto_reference.py. The P0 runner also executes existing V1 tests, full-width RSA-2048 public/private/recheck vectors, SHA padding boundaries and a real DMA-to-AES-to-memory test. Missing tools or missing success markers are errors. It invokes the shared simulation verdict checker; an Icarus $fatal that exits with code zero is still a failed test.

The crypto-p0-constants, crypto-p0-rtl, crypto-p0-baseline and crypto-p0-report Make targets write below build/<variant>/crypto/p0/. Select CONFIG=configs/ci/ihp130.mk SYNTH=YOSYS and one BUILD_TIMESTAMP for all four on the frozen V1 checkout. The runner rejects V2 before writing any P0 artifact. P0 records V1 lifecycle limitations. Block synthesis calls the unchanged synth.tcl and abc_balanced.script, adding JSON checkpoints and standalone interface elaboration only. Each new synthesis attempt uses a fresh synth-* artifact directory recorded in the report, preventing an old netlist from masking a new failed attempt. Its 20833 ps target is derived from the PCLK inventory; it is not a full-chip timing result. A timeout/interruption retains partial checkpoints and cannot pass the aggregate report. See ../docs/ip/crypto.md.

crypto_p1.py owns the separate crypto-p1-constants, crypto-p1-rtl, crypto-p1-formal, crypto-p1-synth and crypto-p1-report targets. P1 artifacts are below build/<variant>/crypto/p1/; P0 artifacts are never reused as candidate outputs. The RTL target exercises public APB initialization, AES/SHA and full RSA-2048 on the IHP FUNCTIONAL model, actual DMA channels 4/5, storage masks and Montgomery carries, then the explicit synchronous fallback. Formal checks use running-clock/synchronous-response assumptions and verify control invariants, private-result release, bounded scrub, APB access ownership and AES output retention across abort/fatal faults. DMA fixtures also inject AXI read and write errors. The exact proof/test mapping is in ../docs/ip/crypto-verification.md. They do not prove the cryptographic arithmetic or physical resistance. The RTL target also runs crypto_response_fault_tb.sv, which models delayed, duplicate, stale-epoch and missing SRAM responses; the product store defaults to fixed one-cycle responses. Candidate synthesis preserves the P0 SAT/ABC recipe and 10800-second limit. The report requires CRYPTO_P0_BASELINE_ROOT, CRYPTO_P1_LP_ROOT and a successful CRYPTO_P1_CI_ROOT for its focused gates. Capture full-SoC evidence with crypto_p1.py firmware --variant-root <variant> --firmware-kind lp|ci after creating the corresponding committed-profile manifest. This runs the build/simulation and binds the actual configuration, input snapshot, ELF and log/result hashes. crypto_p1.py quality --variant-root <variant> records focused formatter and policy results. Report assembly rejects stale inputs or artifacts; it cannot qualify an earlier binary using current source hashes. crypto_p2.py is the fail-closed P2 aggregator. It requires a clean candidate revision and records whole-SoC netlist, STA, physical, metrics, warning and P0/P1 evidence; missing P2 artifacts remain NOT_RUN.

Update or add tests in ../tests for script behavior. Run ruff check . and python3 -m pytest -q; build-flow changes also require the relevant dry-run or regression profile from AGENTS.md.