Hacks & BuildsRP2350ARMJITbitmap fontsRaph Levien
RP2350 microcontroller JIT-compiles each text string into ARM code to draw proportional bitmap fonts in real time
The renderer belongs to vic-2350, his re-envisioned 1980s home computer. It sends DVI through the HSTX block, keeps the font in SRAM and settles kerning before the beam starts.

Raph Levien likes the look of early Macintosh text, and he wants it on a microcontroller without the fixed grid. “I prefer the aesthetic of a crisp, intentionally designed bitmap font,” he writes on the Linebender blog. Then comes the catch: “I also wanted proportional spacing and kerning.” Most RP2350 projects dodge that by locking text into fixed character cells, because proportional text is slow.
Here is how slow he can afford to be. The chip pushes DVI through its HSTX peripheral and fills each scanline just before it goes out the door, which is called racing the beam. “There’s a budget of approximately 6 cycles per pixel,” he says. Rust couldn’t hit it: “Rust is not capable of meeting the performance requirement,” so the renderer is ARM assembly in his own symbolasm language. (Brave, or stubborn.)
The trick is to stop looping over font widths and shifts while the beam waits. For each string, a JIT compiler writes a fresh little program that assembles the 1-bit-per-pixel scanline, then a second pass expands it to 16-bit RGB565. The basic loop costs “23 cycles per iteration,” one per glyph, plus 3 cycles times the glyph height for the bitmap. He says “the JIT compiler runs under 100µs before scanout of the video line.” In his text demo that comes to “about 21k cycles for the JIT and 42k cycles to run the JIT code,” about 2.6 percent of one core. It is just-in-time typesetting, and the chip is setting its own type.
The font gets the same squeeze. The packer lines glyphs up so each row of ink can be read with one 32-bit load, and it hunts for overlaps. “Any glyph contained within another glyph doesn’t need to be packed separately,” he writes, and his examples are good: l is the left side of U, and “0 is identical to () with the space between them removed.” That trims the bitmap from 1140 to 960 bytes.
Kerning turns out to be a dot product. Each glyph carries a left and a right bitvector, and the gap between two neighbors is the popcount of one glyph’s right vector ANDed with the next one’s left. “That’s actually just the dot product of the two vectors, bits interpreted as 0 and 1,” he writes. It runs when the display list is built, not while the beam is racing. The kern table in his demo was built by hand, and he admits “I haven’t done a real implementation yet.”
There is a price for all this cleverness: the generated code is about ten times the size of the string, and he doesn’t cache it because “saving RAM is more important.” The comparison he gives is the dvhstx library, at roughly 2 to 2.5 cycles per pixel but “limited to a 14x24 grid” and RGB222 color. Faster, yes. Also a lot more boxed in.
Where does this go? Anyone building a retro-flavored computer on a Pico-class board now has a reason to stop settling for 8x8 cells, and a font packer that finds 0 inside () is the kind of trick that gets copied. Kerning as a popcount will probably be reused well beyond this one chip.
Levien even addresses the history. A 1996 US patent compiled glyphs to machine code, and he says his own method “absolutely counts as prior art.”