Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

custom_mec — a custom MEC firmware for gfx11 (RDNA3) AMD GPUs

A clean-room reimplementation of the gfx1100 MEC (Micro Engine Compute) firmware — the RV64 microcontroller inside the GPU's command processor that parses PM4 compute packets, launches waves, and retires queue events.

The firmware built here is a drop-in replacement for the stock gc_11_0_0_mec.bin code image: it boots from the same entry points, answers the same hardware protocols, and runs the tinygrad test/test_tiny.py suite on real hardware. It shares zero bytes with the stock blob — even the hardware-content-checked boot-prefix constants are own-assembled from source (fw/start.c:_boot30) and only cross-checked against the stock values.

This repository contains the MEC firmware, its emulator, and its tests. Building produces the deployment artifacts (mec_fw.elf, mec_fw.bin, jobvec.bin, custom_full.bin, paint_runs.json).

How a kernel gets launched (and where this firmware sits)

On gfx11 the driver submits work as PM4 packets in a per-queue ring: SET_SH_REG (shader state), DISPATCH_DIRECT (launch geometry + GO), and RELEASE_MEM (the fence: write a signal value or a GPU clock timestamp, after the pipe drains). When the driver bumps the ring's write pointer and rings the doorbell, the CP's fetch engine starts streaming dwords to the MEC, whose datapump pops one packet at a time and runs a handler per opcode: mirror the state into the SH window, push the launch descriptor through the dispatch port (the commit word is GO), post the flush event — which releases the held wave onto the CUs, the shader engines that actually run the kernel — and finally write the fence so the host can see the queue finished. The hardware it talks to along the way: the packet push port and job-wake lane (doorbell interrupts), the per-queue HQD window, the GRBM register file (bank/queue selects, per-SE wave status), the GCVM L2 control registers, and the RLC's global clock counter. This firmware implements exactly that datapump + handlers, from scratch, as a drop-in replacement for the stock blob — deep detail in docs/MEC.md.

Hardware-proven (2026-08-17, gfx1100): with this firmware running as the MEC code image on a live GPU, every later driver boot stays on it — unmodified stock tinygrad test processes (DEV=AMD DEBUG=2 test/test_tiny.py) run back-to-back on the custom firmware with clean exits and no "Malformed state" full resets: every sampled MEC instruction pointer inside our paint, the non-beam test_tiny battery 18/18 green including mnist, and DEBUG=2 per-kernel timings tracking stock. Current state and the remaining frontiers: docs/STATUS.md.

Layout

fw/            the firmware (rv64ima, freestanding C + inline asm)
  start.c        entry points, job-wake trap frame + job handlers, datapump head
  main.c         cold-boot init (opcode table, job lane, hw init, queue arm)
  pkt.c          PM4 packet handlers + the C opcode dispatcher
  trace.c        host-visible trace mailbox + GP0 markers
  include/       aperture frames, protocol slots, register tables
  link.ld        image layout (only the two hw-contract addresses are fixed)
  derive_runs.py paint-run manifest + the two build-time jump gates
emu/           the emulator (Unicorn RV64 + a device model)
  hw.py          the MEC environment model (apertures, fetch engine, decoder, EOP engine)
  harness.py     Machine: boot, drive packets, job wakes, state snapshots
  flow.py        full user-flow runs (ring -> doorbell -> datapump -> signal)
  decode.py      the hw fetch-engine/decoder model (PRED_EXEC, IB pivot)
  qdev.py        a compute-queue device (ring + wptr/rptr pages + doorbell)
  fwimg.py       image loaders (stock blob / our ELF)
  image.py       the FULLIMG drop-in image builder (zero stock bytes)
test/          the differential + lifecycle test suite (imports emu/)
tools/         gen_regs.py (fw header generator from tinygrad autogen)
docs/          MEC internals documentation (STATUS.md is the start-here doc)

Build

Requires a clang/LLVM with the RISCV64 backend (any recent version) and python3.

make              # produces fw/mec_fw.elf/.bin, jobvec.bin, custom_full.bin, paint_runs.json

The build runs two safety gates (fw/derive_runs.py): every direct jump must land inside the painted image, and every constant-computed jump target must be ours — so the image can never call into bytes it didn't bring. Only two addresses are hardware-fixed (0x1000 job-wake vector, 0x3000 drop-in entry): the decoder's handler-PC table is locked to the stock layout and unprogrammable post-boot, so the datapump never executes at a presented PC (it logs it and dispatches in C) and the image hardcodes no decoder handler addresses.

Test

Requires unicorn, capstone, pytest, and tinygrad (for the PM4/am autogen tables and the pinned stock-blob hash — the stock reference blob itself is fetched on demand by tinygrad's fetch_fw).

pip install tinygrad unicorn capstone pytest pytest-xdist
cd test && python3 -m pytest . -q       # or: python3 test/test_emu.py

The suite boots both the stock image and this firmware in the emulator and compares them: per-opcode handler side effects, the full driver exec stream end-to-end (acquire → set_sh → dispatch → event → release), the job-wake lane, the doorbell/fetch-kick protocol, post-parse device-state parity, and the drop-in boot lineage (entry at flat 0x3000 through the ABI prefix into the datapump). CI runs the same on every push.

Documentation

  • docs/STATUS.mdstart here: what works, the boot/ teardown contract, the open frontiers, and the doc map.
  • docs/MEC.md — the MEC internals: apertures, boot, the datapump, the job-wake lane, the packet contract, the release/fence protocol, and the hardware quirks this firmware is shaped by.
  • docs/EMULATOR.md — how the emulator models the hardware and where its boundaries are.

About

Custom MEC firmware for 7900XTX

Resources

Stars

10 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages