K2 FPGA Manager turns the RP2040 on the Wildbits/K2 into an FPGA boot supervisor. It chooses a core for the physical context selected by the DIP switches, programs the Artix FPGA, and then stays available to the running K2 through a small supervisor mailbox.
The companion K2 Core Manager application provides the user interface. From the K2 itself it can browse cores on either SD card, copy them between cards, install gzip images into replaceable flash, choose the next boot core, inspect the boot log, and start a core without changing the saved default.
K2 hardware was produced by Wildbits and by Foenix Retro Systems (FRS). The firmware target is determined by the revision printed on the PCB:
| Hardware | Revision |
|---|---|
| Wildbits K2 or FRS purple board | RevB0C |
| Earlier FRS black prototype board | RevB3B |
The Wildbits PCB is also black, so color alone does not distinguish it from an FRS black board. Use the printed revision when choosing firmware.
The K2 has four hardware contexts selected by the physical DIP switches. A context selects both an FPGA core and one 512 KiB slice of the K2's 2 MiB NOR flash. The core defines the hardware presented by the FPGA; the associated NOR slice supplies that context's firmware or operating environment. Changing the context can therefore change the identity of the machine, rather than merely selecting a different application.
Current examples include the 65816-based K2 2x core and a 6809 core intended for NitrOS-9. Other platform-specific cores can use the remaining contexts and their independent NOR slices. Because the DIP switches also select the NOR slice, the manager can prepare another context but cannot switch the running machine into it in software. Select the context physically and restart the K2.
The manager works with four physical FPGA contexts and four kinds of storage:
| Storage | Role |
|---|---|
| RP2040 SD card | Core library, organized as CNTX1/ through CNTX4/. |
| K2/MicroKernel SD card | The user's normal filesystem and a convenient source or destination for core files. |
| K2 NOR flash | Four 512 KiB slices selected by the physical context switches. This is separate from the RP2040's flash. |
| RP2040 flash | One replaceable 2 MiB gzip slot per context, plus firmware and one immutable recovery core shared by contexts 1 and 4. |
Each context has an independent saved boot choice. The available choices are:
AUTO: discover a core on the RP2040 SD card, then try the context's replaceable flash slot;- an exact SD path: try that file, then the replaceable flash slot;
FLASH: try the replaceable slot, then automatic SD discovery; orGOLDEN: boot the immutable recovery image. This choice exists in contexts 1 and 4; both use the same embedded payload.
Contexts 1 and 4 add the immutable recovery image after the mutable fallbacks above. Contexts 2 and 3 have no embedded core. If every mutable source for one of those contexts fails, move the physical switches to context 1 or 4 and use the recovery environment to repair the affected SD directory, flash slot, or saved selection. Context 4 retains this fallback for compatibility with the original K2 context layout; it does not consume a second copy of the image.
The embedded image is the board-specific K2 2x core shared by contexts 1 and 4:
fpga/B0C/context1.gzfor RevB0C hardwarefpga/B3B/context1.gzfor RevB3B hardware
The two FPGA bitstreams are not interchangeable and are clearly marked in the releases as two separate versions.
Context 1 is the normal 2x environment and the recommended recovery path for the whole machine. Context 4 provides the same recovery image for historical compatibility.
- Set the physical context switches to context 1.
- Restart the computer. If the saved context-1 sources are suspect, keep RESET held through the restart to force the embedded recovery core.
- Run
k2coremgr.pgz, or use the equivalent two-blockcoremgr.kupbuild. - Use Left/Right to inspect another context. Copy a core from the local K2 SD
with
F5, program its flash slot withF3, or save a new default withF7. - Set the physical switches to the repaired context and restart the machine.
The manager may maintain another context while a recovery core is running, but it cannot run that context in place: the DIP switches also select the corresponding FLASH area for the core to use and must be changed before boot.
The RP2040 SD card must contain a single FAT16 or FAT32 volume. Missing context directories are created automatically when the card is writable:
CNTX1/
CNTX2/
CNTX3/
CNTX4/
The card is optional. Without it, the supervisor can still boot and update the replaceable flash slots, and contexts 1 and 4 can still use embedded recovery.
Raw .bin and gzip-compressed .bin.gz/.gz cores are accepted from SD. The
uncompressed FPGA payload must be exactly 9,730,652 bytes. Replaceable flash
accepts gzip only, and the compressed file must fit in its 2 MiB slot.
Automatic SD discovery checks, in order:
CNTXn/contextn.bin;- visible
Wildbits*.gzandWildbits*.binfiles, newest name first by case-insensitive lexical order; - the traditional context basename (
CFP95600C,CFP95616E,f256k2t9, orfoenix138), compressed before raw.
Directories, dotfiles, and FAT hidden/system entries are omitted from the catalog. Named uploads use hidden temporary and backup files so an interrupted copy does not replace the previous destination.
k2coremgr.pgz and coremgr.kup open the RP2040 catalog. Tab switches to
the K2's local SD browser. The most important controls are:
| Key | Action |
|---|---|
| Up/Down | Move the selection |
| Left/Right | Change context in the catalog, or jump ten entries in the local SD browser |
| Enter | Run the selected core once without changing the default |
F3 |
Copy the selected gzip core into the displayed context's flash slot |
F5 |
Copy a local-SD core to RP2040 SD, or copy an SD, flash, or golden catalog image to K2 SD |
F7 |
Save the selected catalog entry as the default |
S |
Save the selected entry as default and run it |
F2 |
Display the RP2040 boot and fallback log |
F8 |
Restart the RP2040 and repeat FPGA loading |
U |
From the local SD view, install a board-specific .k2fw FPGA Manager update |
| Q | Restart the K2 through the FPGA host-reset registers |
| RUN/STOP | Close Help or Diagnostics; cancel image validation |
Catalog markers are an amber triangle for the cursor, a green check for the saved default, and an orange dot for the core that actually booted. See k2/README.md for more details.
The manager validates gzip structure, CRC-32, uncompressed size, FPGA INIT_B
behavior, flash page readback, and persistent metadata. Flash uploads erase and
verify in bounded steps, write the gzip header page last, and commit metadata
only after the image is complete. An interrupted upload is therefore invalid
rather than deceptively bootable.
Boot selections and flash labels live in alternating CRC-protected metadata
sectors. A corrupt or erased journal defaults context 1 to GOLDEN and the
other contexts to AUTO. Context 4's AUTO path still ends with the shared
embedded recovery image if its SD and replaceable-flash candidates fail.
The K2 does not route the FPGA DONE pin to the RP2040. The manager can prove
that a bitstream has the right shape and that INIT_B remained healthy, but it
cannot prove that the loaded core reached a useful application state. A core
that lacks the supervisor mailbox also cannot be managed after it starts.
The embedded recovery core in context 1 or 4 is the independent way back from
either case.
Release packages contain separate UF2 and ELF files for the two board revisions. Check the revision of your K2 PCB and use only the matching file:
| PCB revision | BOOTSEL | SWD |
|---|---|---|
| RevB0C | fpga_mgr_B0C.uf2 |
fpga_mgr_B0C.elf |
| RevB3B | fpga_mgr_B3B.uf2 |
fpga_mgr_B3B.elf |
The release package's K2-FPGA-MANAGER.pdf contains the installation guide,
operating reference, and recovery procedures.
The UF2 and ELF include the same supervisor firmware and matching immutable
recovery core, shared by contexts 1 and 4. They do not overwrite the four
replaceable slots.
These factory images introduce the protected first-stage loader and must be
installed once through BOOTSEL or SWD when migrating from older firmware.
They initialize the separate firmware-update journal but preserve core boot
metadata and all replaceable FPGA slots.
After that migration, normal releases can be installed in-system: copy the
matching .k2fw package to the K2 SD card, select it in the Core Manager's
Local SD view, and press U. The update does not require the optional RP2040
SD card. See the firmware-update design for
the flash layout and rollback guarantees.
Prerequisites are the Raspberry Pi Pico SDK, CMake and a build tool. Python 3,
Node.js/npm, picotool, 64tass, uv, and
just support the combined UF2, K2
application, PDF documentation, and release workflows. The first PDF build
downloads pinned Mermaid CLI and headless-browser versions through npx.
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
make -C k2 core-managerEquivalent shortcuts are:
just build
just build-k2-core-manager
just package-releaseThe main build produces board-qualified factory/recovery .uf2, .elf, and
.bin files in build/. It also produces board-qualified .k2fw application
packages and internally linked fpga_mgr_app_* artifacts. Use the factory UF2
or ELF for the one-time loader migration and for recovery; after that,
the K2 Core Manager can install matching .k2fw packages in-system. The optional
_with_fpga.uf2 target also initializes context 1's replaceable flash slot
with the recovery core; the normal firmware already contains its own immutable
copy.
Run the package-format and cross-language image-validation tests with:
just test-firmware-packagesThe project version in CMakeLists.txt is the source of truth for UF2 metadata,
the mailbox firmware version, and the release ZIP name. Release builds keep USB
diagnostics enabled and disable the optional FTDI UART mirror. Configure with
-DFPGA_MGR_UART_DEBUG=ON when that UART trace is needed.
To substitute a different shared recovery image in a private build:
cmake -S . -B build \
-DGOLDEN_B0C_CONTEXT1=/path/to/core.bin.gz \
-DGOLDEN_B0C_CONTEXT1_LABEL=descriptive-name.bin.gzUse the corresponding GOLDEN_B3B_CONTEXT1 variables for RevB3B.
After programming the FPGA, the RP2040 remains available as a PIO-based SPI
mode-0 slave. The FPGA exposes this service to the 65816 at $DDE0-$DDEF.
The protocol supports catalog snapshots, persistent selections, boot status
and logs, transactional SD transfers, verified flash programming, deletion,
one-shot reconfiguration, and supervisor restart.
The CPU register map and wire format are maintained in
docs/rp2040-mailbox.md in the FPGA cores repository. That specification is
authoritative for command layouts, response pipelining, retry behavior, and
error values; the top-level README deliberately does not duplicate a
version-by-version protocol changelog.
fpga_mgr.cpp,supervisor_service.cpp: boot and runtime supervisor logicboot_config.cpp: persistent selections and replaceable-slot metadatafpga/B0C/,fpga/B3B/: board-specific recovery payloads shared by contexts 1 and 4k2/: interactive manager and standalone uploader for the 65816release/README.md: end-user installation and quick-reference guidedocs/core-bundles-and-loader.md: future bundle/loader architecture notesdocs/rp2040-firmware-updates.md: failure-safe in-system firmware update design and implementation
The firmware is distributed under the BSD 3-Clause License. The portions of
the K2 interface adapted from PEXEC retain their MIT notice in
k2/PEXEC-NOTICE.md.