PanBadge/OPTIMIZATION.md

3.5 KiB
Raw Blame History

Size optimization backlog

Flash budget is 16 KB. Read the real usage with:

riscv-none-elf-size tama.elf     # flash = text+data, RAM = data+bss

(Ignore .elf/.hex file sizes — they include debug info / ASCII framing and are not the flashed image. tama.bin is the true image.)

Current state (after the printf removal below): ~11.9 KB / 16 KB (~73%).


DONE

Drop printf/snprintf — saved ~1.4 KB

Replaced every snprintf with tiny s_cat/u_cat string builders (in tama.c), disabled both printf backends in funconfig.h (FUNCONF_USE_DEBUGPRINTF/FUNCONF_USE_UARTPRINTF = 0), and stubbed the SSD1306 I2C driver's lone printf with #define printf(...) ((void)0) before its include. Result: mini_vpprintf + mini_itoa + mini_pad + _write fully garbage-collected. Readability: neutral/positive. No behaviour change (the stubbed printf only logged an I2C timeout we can't recover from anyway).


TODO — ranked by value vs. effort

1. Crop sprite frames — ~0.50.7 KB · low risk

Every creature frame is stored as 32×32 = 128 bytes, but the art only fills roughly the middle ~28 rows; the top/bottom rows are empty padding. ssd1306_drawImage already takes explicit width/height, so we can store shorter frames.

  • How: in sprites_gen.py, crop each frame to e.g. 32×28 (width must stay a multiple of 8; height is free). Emit the real height and adjust the draw y.
  • Savings: ~4 rows × 4 bytes × ~18 frames ≈ 0.30.7 KB.
  • Readability: art stays editable as ASCII; only the generator changes.

2. Alias more Panko frames — ~0.130.26 KB · trivial

Shell/Tmux already reuse 4 frames across the 7 expression slots. Panko (the panda) still has 7 distinct frames. EXP_BLINK and EXP_EAT could alias idle/happy with little visible loss.

  • How: in the species_frames[SP_PANKO] row of sprites_gen.py, point the blink/eat slots at pana_idle/pana_happy and delete the now-unused frames.
  • Savings: 128 B per dropped frame (12 frames).
  • Readability: neutral. (Trade-off: loses the dedicated blink/eat animation.)

3. Table-drive the beep jingles — ~0.10.2 KB · low risk

Many multi-call beep(...) beep(...) beep(...) sequences inline a lot of immediates.

  • How: store jingles as small {freq,ms} arrays and add a play(jingle, n) helper; replace the inline sequences with one call each.
  • Savings: modest, scales with number of jingles (~8 today).
  • Readability: arguably improves it (named jingles).

fontdata in ssd1306.h is a full 256-char × 8-byte table = 2048 B; we only use ASCII ~0x200x7A.

  • Why not: requires editing the vendored ch32v003fun/extralibs/ssd1306.h, which is fragile across library updates and hurts ease-of-use. Only worth it if we're truly out of space. If done, keep a local patched copy and document it.

Sprites are mostly runs of 0x00/0xFF and would compress well, but this needs a decoder in the draw path and makes the art opaque (no more ASCII editing). Net readability loss; only revisit under severe pressure.


Already optimal — don't bother

  • Compiler flags: already -Os -flto -ffunction-sections -fdata-sections -Wl,--gc-sections. GCC has no -Oz.
  • RAM: ~55% used, not the constraint. The 1 KB ssd1306_buffer is mandatory (full framebuffer); don't touch.