Integration and Verification
mace/integrator.py sends each config or workload task’s instruction to the LLM as written, and writes the prompt for an rtl task with rtl_prompt().
It decides the order in which tasks run and whether an iteration continues.
Dependency Order
topological_levels() groups the tasks into levels, keeping their relative order within a level, and raises ValueError on a duplicate id, an unknown dependency, or a cycle.
integrate_parallel() runs the levels in order and stops after the first level that holds a failed task, so no later task builds on a tree that failed verification.
A task changes the design through its build configuration, which carries its CACHES: and CONFIG_RTL: overrides, and through any tools the caller gives the agent.
For an rtl task and the tasks that depend on it, the integrator also applies RTL edits before the build and reverts them after the runs (see Parallel Task Execution).
A task that carries no edits first reverts any that a killed task left applied.
A unit_test task also scaffolds its environment and edits its testbench (see Parallel Task Execution).
The drivers in the repository, examples/mace_end_to_end.py and the mace shell, pass no tools to run_mace_loop().
Build
OpenPitonWorkspaceNode.build() runs sims <flags> -build_id=<build ID> -vlt_build, passing --no-timing to Verilator 5 and later.
A build succeeds when sims exits 0 within 7200 s and the model binary exists.
When an earlier successful build with the same build ID left its binary and a .mace_build_ok marker that matches the checkout’s source fingerprint, build() skips sims and returns that build with reused=True.
_config_for_task() constructs its PitonConfig directly rather than through configure(), so the source-revision, Verilator-version, and diff fields stay empty.
A loop task’s build ID therefore covers its configuration only.
An edit made outside an rtl task leaves the build ID unchanged but changes the fingerprint, so the next build of that configuration rebuilds the model (see OpenPitonWorkspaceNode).
An rtl task’s edits set PitonConfig.source_edits, so its build gets its own build ID.
Run
For a config, workload, or rtl task, run() simulates each entry of MaceSpec.workloads in order, each in a new directory under the model’s runs/, and stops at the first that does not pass.
It passes the spec’s simulation limits and an -asm_diag_root pointing at mace/workloads/, which sims searches in addition to the checkout’s own diags.
The finish mask holds one 1 per tile, so a multi-tile run passes only when every tile reaches the good trap.
A program listed in MaceSpec.workload_args uses its own finish mask and extra sims options instead, as OpenSPARC T1’s multi-thread diags need.
The planner prompt lists every gate workload.
Verdict
chia_openpiton.parse.sim_verdict() checks the whole sim.log against these patterns, in order:
Transcript |
Verdict |
|---|---|
|
|
any other |
|
|
|
|
|
|
|
none of the above |
|
A failure marker therefore wins over a PASS line.
A transcript with no verdict from a run that hit its wall-clock limit counts as timeout. The limit is 3600 s, or the time left in the run’s budget when that is less.
See Parsers.
Pass Criteria
PitonRunResult.decide() holds the rule: returncode != -1 and verdict == "pass".
A return code of -1 marks a timeout or a failed launch; any other exit code is ignored, because a simulation exits 0 whether or not the program passed.
A config or workload task passes when its run succeeds, and fails with run=None when its build fails.
A unit_test task passes when its build succeeds.
An iteration passes when it produced results and all of them passed.
record_iteration() stores each task row with its build’s PitonConfig.caches: all four caches, with a task’s CACHES: overrides in place of the defaults.