What this is

A Vitis-free bare-metal stack for Zynq UltraScale+ MPSoC. An A53 boots from on-chip RAM only, talks over JTAG (not the PS UART), and owns the path into the programmable logic: bitstream load, clocks, isolation, and named pin control.

Reference hardware is the Kria K26 SOM (KR260-class). The day-to-day loop is OpenOCD, a small freestanding image, and a Python console. No FSBL, no DDR, no Xilinx BSP. PL work includes multi-part builds so the same fabric designs can target every MPSoC FPGA part in the family, not only the lab board.

Why it exists

Vendor flows for ZynqMP usually mean FSBL, DDR init, a BSP, and Vitis or Petalinux. That is fine for shipping products; it is heavy for lab bring-up, custom pin routing, and learning the silicon.

This project asks a narrower question: can we own the A53, the console, the PL fabric, and eventually every useful package pin - with only OCM, OpenOCD, and a small freestanding firmware? If yes, you get a transparent debug platform: poke MMIO, load bitstreams, route EMIO to real connectors, and never leave the JTAG cable.

Architecture

Three ideas carry the design:

OCM only. The app lives at 0xFFFC0000 (256 KiB). Day-to-day load never depends on DDR or FSBL.

JTAG is the UART. OpenOCD reaches the debug MEM-AP while the CPU runs. Firmware uses a fixed OCM mailbox; the host is a short Python console. Throughput is command-and-log scale, not a bulk pipe - and that is enough.

EMIO for levels, AXI for steering. Pin levels come from PS GPIO over EMIO. Which pin and which direction come from a small PL mux map on LPD AXI. The CLI names pins (uf2, …), sets mode, and drives them after a one-shot PL load.

Try the console

A small browser sim of the JTAG CLI. Load OCM firmware, stream a PL bitfile, clear isolation, enable FCLK, and drive pins - no board required. Type help or mission to start the bring-up game.

jtag_console.py - openocd :6666 sim
mpsoc> 
OCM:empty · PL:none

↑/↓ history · load · load_pl --emio-mux · pl status · mission · reset

What works today

Interactive CLI over the mailbox: GPIO and pad pulls, board LEDs, bit-bang I2C, SOM EEPROM, guarded memory peek/poke, APU clocks, and PL status. Exception vectors dump panics over the same console instead of silent hangs.

PL bitstream load uses the same OpenOCD session: PCAP, isolation clear, FCLK, and AFIFM release. Golden designs cover CFGMCLK and FCLK blinky, fixed EMIO passthrough, AXI LEDs, and the EMIO pin mux used by the mux / pin commands. Vivado is only needed when rebuilding a .bit; programming does not require Hardware Manager.

The EMIO crossbar path can build bitfiles for every MPSoC FPGA fabric variant from one script (K26 and common ZU* parts), with pin counts sized per device. Day-to-day lab work stays on Kria K26; the multi-part flow keeps the design portable across the family.

Probes are flexible: on-board FTDI, a Pico CMSIS-DAP, or a Pi Zero running OpenOCD over the network.

Soft-core in the PL

A RISC-V soft-core path was built and brought up on hardware: PicoRV32 in the fabric, bootloader resident in the bitstream, and small apps streamed from the A53 over an AXI mailbox (load without a full rebuild). LEDs blink under loaded PL firmware; the host stack reuses the same OpenOCD / PCAP / isolation path as the rest of the project.

Honest takeaway: it works, and it is a good exercise in PS/PL handoff - but for this lab platform the practical benefit over just using the hard PS (A53 CLI, GPIO, clocks, pin mux) is not really there. The soft-core does not replace the PS bring-up stack; it sits beside it. Active focus stays on pin control and the bare-metal PS tools, not on growing a second CPU in the PL.

Where it is going

Pin control is the active track. Fixed EMIO to user LEDs is done; a slim AXI-routed mux with named CLI is hardware-proven. Next is a bidirectional PMOD bank, then broader connector maps.

Deliberately out of scope for now: DDR and cold-boot packaging, Vitis/BSP, and full production images. The lab stack stays small and honest.

Bottom line

A lab-first ZynqMP platform: small image, honest console, proven PL load across the MPSoC fabric family, and a clear path from "blink an LED from the A53" to "name a pad and route it at runtime." The hard silicon lessons - isolation, FCLK, LPD vs FPD AXI, PCAP - are already paid down. A PL soft-core was proven too; for day-to-day work the PS remains the better tool. The remaining work is growing the pin map without reinventing the stack.


references