No. 44 / project of 147 on the ladder

Framebuffer demo (chip-rendered plasma on a PC window)

introduces — First demo where the chip actually generates visual output - 96x96 RGB565 plasma frames rendered by FreeRTOS, dumped from sim, played back as a pygame window

harden statelast run2026-05-03
areaunknownμm²
signoff
  • DRCNOT RUN
  • LVSNOT RUN
  • antennaNOT RUN

P44 is the showpiece. A FreeRTOS task on the chip computes 96×96 RGB565 plasma frames into a memory-mapped framebuffer; the testbench dumps each frame to disk on an MMIO_FRAME_READY pulse; a Python + pygame viewer plays them back as a real window.

Status: RTL pass. 4 frames dumped at 7.5M clocks. Verified visually - both end frames are real plasma patterns with evolving structure. The chip is rendering animation.

How the bridge works

The chip doesn’t know there’s a “screen.” It writes pixels to a contiguous memory region (0x00030000 for 96×96 RGB565 = 18432 bytes), then writes the frame number to a new MMIO address (0x10001ffc). One thing in RTL, two things in software, one thing in the testbench:

layerwhat’s new
RTLMMIO_FRAME_READY register at 0x10001ffc - same shape as P43’s MMIO halt port. Pulses frame_strobe for one cycle on write.
TestbenchOn frame_strobe, peek the framebuffer region of memory and write frames/frame_NNNN.bin.
SoftwareRender task computes plasma into *(uint16_t *)0x00030000[], writes MMIO_FRAME_READY after each frame.
PC viewerapp/viewer.py opens a pygame window, decodes the dumped RGB565 frames, plays back.

That’s the entire framework. No SPI peripheral. No display controller. No new core logic.

What you get

Run:

make -C projects/44_framebuffer_demo/test \
  FREERTOS_KERNEL=/tmp/FreeRTOS-Kernel run

make -C projects/44_framebuffer_demo/test viewer

The pygame window shows four frames of plasma evolution rendered entirely by the chip’s CPU. Each frame is a deterministic function of (x, y, t) evaluated 9216 times per frame at ~1.88M cycles per frame on the multi-cycle FSM core.

Why this is the cool demo, not the LCD demo

The earlier roadmap mentioned an SPI display demo. The user’s question was “if we did it on a real LCD wouldn’t it be the same speed as on a PC screen?” Answer: yes. The bottleneck is the chip’s pixel-generation rate (~13 FPS at 96×96 with our compute budget), not the transport. So:

  • Sim → file → PC window works today, no hardware to buy.
  • Chip → SPI → real LCD is the same software with one line changed. Lands when we add a real SPI peripheral.
  • Chip → SPI → USB-SPI bridge → PC window is the chip-on-real- hardware version that also works. Same chip output, different sink.

P44 is the cheapest first version. The SPI variants are future ladder rungs.

Limits

  • 96×96, not 240×240. The real ST7789 we’d eventually drive is 240×240. Our FSM core renders the smaller frame in ~75 ms; scaling to 240×240 would put us around ~2 FPS and slow the simulator down meaningfully. For a first demo we kept it small.
  • 4 frames, not endless. Testbench would happily dump thousands but iverilog gets slow. Four is enough to see the animation evolve.
  • Plasma, not Mandelbrot. Triangle-wave math is cheap and runs at compute-bound full speed. Mandelbrot at depth 64 would take multiple seconds per pixel on this core; we’d want pipelining first.

Files

  • src/top.sv - RTL with MMIO_FRAME_READY added (everything else verbatim from P43).
  • app/main.c - FreeRTOS render task with the plasma formula.
  • app/viewer.py - pygame window, RGB565 decode, scale, loop.
  • test/tb_framebuffer.sv - dumps the framebuffer on every strobe.
  • test/Makefile - new make viewer target.

What does not change

  • CPU core, ISA, trap path, halt port, MMIO router, FreeRTOS port - all verbatim from P43.
  • mimpid bumps to 0x44.

Harden status

NOT RUN. The expected delta is ~35 cells over P43 (frame_seq register + frame_strobe flop + address decode). Hardenable trivially if we want a real fab-shaped artifact, but not the point of P44.

What just happened?

P43 closed the FreeRTOS arc with a printout. P44 gives it a face. We can point at a window on the screen and say “this is the chip running” - the same chip we hardened to a sky130A GDS, the same FreeRTOS we boot, the same MMIO halt port that says “done.”

The chip is now an animation generator that runs an RTOS.