PanBadge/OPTIMIZATION.md

75 lines
3.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Size optimization backlog
Flash budget is **16 KB**. Read the real usage with:
```bash
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).
### 4. Trim the font table — up to ~1.5 KB · NOT recommended
`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.
### 5. RLE-compress sprites — ~1 KB · NOT recommended
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.