Mirage — A Transformer Accelerator Designed by an AI Agent
Mirage is an open-source transformer accelerator designed by an AI agent, specifically Kimi K3. It runs Transformer encoder inference for English to Arabic and Arabic to English machine translation. It targets the Digilent Cora Z7-07S (Zynq-7007S), a board that carries 14,400 LUTs, 66 DSP48E1 slices, 50 RAMB36 blocks and one 667 MHz ARM Cortex-A9. This page documents the agentic workflow that built it against a 19-task plan, a week-by-week schedule of module-specific features in which each core was verified before the next, from the matrix multiply array through multi-head attention to the fully integrated encoder.
Mirage/images/mirage-top-level-bd.png. The four cores it names are where the plan's audits and drafts land. Select any image on this page for its full-resolution file.01 The problem
In the silicon budget, a 6-layer encoder with 256-dimensional activations has to run on a part that offers 66 DSP48E1 multipliers and about 225 KB of BRAM. Since the full stack cannot fit, one physical encoder layer stands in for all six and is walked six times per sentence. Pre-synthesis, the multiplier budget can then be expressed like this:
◂ swipe to pan the diagram ▸
reports/w11-resource-map.md).The other constraint is trust, since a chip is a long chain of decisions where a week-3 arithmetic error can quietly poison week 9. Every task closes on evidence for that reason, and every claim on this page carries the tier of evidence behind it.
02 Architecture
The four roles
The structure of this project is a chain of four parts, and each part has
exactly one job. The agent is the harness loop in workflow/
and harness/, which picks one task at a time from the plan
and refuses to close it until the files it promised exist on disk. The
model is Kimi K3, which takes each brief and does the engineering work of
writing the reference models, drafting and repairing the VHDL, and leaving
a report behind. The Mirage transformer is the accelerator itself, the
design that all of that work lands in. Together the agent, the model and
the transformer constitute the workflow, while I steer the design process
by writing the spec, building the gates, and reviewing what comes out of
each phase:
◂ swipe to pan the diagram ▸
Substantial work on Mirage predated my involvement, since the starting point was a provided minimal codebase that was roughly 40% complete. That base contributed the matrix multiplication, attention and softmax cores, the block diagram in Fig. 1 and the model scripts, and it is credited directly as the upstream Mirage repository. The workflow treated all of that code as read-only for the entire run.
The harness
The harness is the half of the workflow that never trusts a transcript, and each block below can be selected for the note recorded against it:
◂ swipe to pan the diagram ▸
data · artifacts gate checks purple = the model
workflow/, harness/hooks.py). Briefs come from the state file and evidence comes from ghdl and spec-first goldens, while completion is decided by a gate that reads the disk.Write-up for this section is still in progress.
The datapath
In the datapath, int8 weights stream in from DDR while int16 activations stay inside the fabric, and four of the blocks below carry real defects that the loop found:
◂ swipe to pan the diagram ▸
data flow control · prefetch heavy edge = layer reuse ×6 dashed outline = model-drafted
spec/mirage.state.json and the W6 to W11 reports. Reusing one layer six times is what makes it fit.03 The loop & the ledger
A task the loop can act on has to be falsifiable, so "verify the softmax"
cannot be a task while "smx_core matches the Python golden for
8 heads and 4 tokens" can be one. The loop below runs five verbs against 19
such tasks, and the timeline under it records when each closure landed:
◂ swipe to pan the diagram ▸
harness/loop.py, workflow/query.py.◂ swipe to pan the timeline ▸
spec/mirage.state.json in order. Select a task, or step through the run, for what it found and when it closed.The gate itself is one command, and a refusal is recorded verbatim as follows:
# close a task whose declared report does not exist yet $ python -m workflow.cli complete p1/w3 --artifacts reports/w3-exp-error-histogram.md REFUSED p1/w3: acceptance not verified artifact missing: reports/w3-exp-error-histogram.md fix, or re-run with --force to override $ echo $? 2
Format as implemented in workflow/cli.py, where --force was used zero times.
What the run spent
Both sittings were logged end to end, so the model's spend is measured from the session logs rather than estimated, and the numbers below are rounded from those logs:
live session time
≈9.2 h5.6 h on Jul 24 and 3.6 h on Jul 25, around the overnight pause
model calls
308Kimi K3 requests across the 19 tasks
fresh tokens
≈583k≈416k read in as prompts and ≈167k written out
cached reads
≈30Mprompt tokens re-read from cache to keep context warm
Provider-measured counts from the Kimi wire logs, summed over the two sittings that closed all 19 tasks. A 6.2 h session after the freeze is not counted.
Where the phases landed
The plan's phases land inside the four cores of the block diagram, which are shown here as direct crops from Fig. 1:
score_sum overflow, and W6 integrated all 8 heads at worst 3.98 LSB.
smx_cache and smx_core.
04 Results
Golden model first and RTL second kept finding real upstream defects, which the table records module by module:
| Module | As found | Root cause | After the loop |
|---|---|---|---|
taylor_exp | 64/64 sampled points ≥100% error | implicit clamp swallowed the input (Q-format) | 0.9683% max error (Q9, |x| ≤ 0.5352) |
smx_core e2e | attention 87–107 int8 LSB from golden | exp input scaling off by ≈2¹⁸ | worst 2.99 LSB, RMS 0.52 |
ffn_core | 10/10 trials fail and it won't compile | no declaration for "mac_array", 278 KB vs 225 KB BRAM | redesign spec: 16-bit activations, streamed weights |
| 6-layer stack | drift >1 LN unit by layer 1 | softmax chaotic under int8 inter-stage quantization | int16 inter-stage: 0.0062 LN worst over 3 layers |
Composition
reports/w11-resource-map.md).Comparison
reports/optimization-report-v1.md).reports/w11-resource-map.md).Across layers and across the run
reports/w9-multilayer.md).purple band = Kimi K3 live session unshaded gap = my pause · review
spec/mirage.state.json. The shaded bands are Kimi K3's two live sessions, and the unshaded gap is where I paused the run overnight and reviewed.Comparison against golden reference, FPGA model and hardware
reports/evaluation-report-draft.md).reports/robustness-matrix.md).The release check is one command, and the recorded v1.0 re-run reads as follows:
$ bash outputs/run_regression.sh == model-level golden checks == PASS taylor_exp_model.py PASS smx_e2e_model.py (2.99 < 4.0) PASS ffn_model.py PASS encoder_e2e_model.py (0.0296 < 0.05) PASS multilayer_e2e_model.py (0.0047 < 0.01) PASS greedy_decode_model.py PASS bidirectional_demo.py PASS beam_search_model.py (13 >= 13) PASS robustness_model.py == RTL (ghdl) checks == PASS ghdl:gemm_latency_tb == REGRESSION: ALL GREEN exit=0
Evidence tiers & the exit bar
ghdl-simulated
The gemm tile at 36 of 36 dot products with start to done measured at 1 clock, and every model-drafted VHDL file analyzing and elaborating clean.
Model-level golden
All accuracy claims, from LSB drift to token-identical decode, come from bit-accurate Python models against float references, not from full-pipeline RTL sim.
Estimate / projection
Latency, throughput, the 1,700× comparison and the resource map are cycle-model or pre-synthesis figures, and nothing was measured on silicon.
| Exit criterion | Standing | Status |
|---|---|---|
| EN→AR & AR→EN encoder translation | 10/10 token-identical vs golden on toy random weights, and no trained checkpoint exists in the repo | model-level |
| ≥3× latency vs CPU baseline | the cycle model clears it with margin, and no int8-CPU comparison exists in the repo | modeled |
| <90% LUT & <95% BRAM, timing met | LUT 25% and BRAM 84% pre-synth, timing unmeasured, DSP 98% against the task's 90% bar | pre-synth |
| Open-source repo + build/sim docs | the regression script and per-week reports exist, and no LICENSE file exists | blocked |
| Demo script + pitch deck | both exist | done |
Four numbers do not exist in the repository and are not charted on this page: a BLEU score, since no trained checkpoint exists, a board power figure and a measured silicon latency, since no board run exists, and post-synthesis utilization and timing, since no Vivado run exists.