# Lofi-12 XT firmware — cross-version diff (v1.1.156 → v1.2.179 → v1.5.205) Per-version structural notes: `docs/firmware/notes-v{1.1.156,1.2.179,1.5.205}.md` (Sep-26 snapshots; update-entry + checksum notes there are superseded — see `docs/firmware-update.md` and `tools/README.md`). This file only documents what *changed* between builds. Method: `cmtd/mmtd/sect` headers parsed per build (all verified to tile EOF exactly); string sets compared as `sort -u` of `strings` output with length ≥ 6. (Raw set lists were scratch files, not shipped.) Code sects are rebased between builds (different DDR load addresses), so no byte-level code diff was attempted — deltas below are sizes + string/symbol evidence. ## TL;DR - v1.1.156 → v1.2.179: small delta (+10,592 B file, +10,080 B code). Only two user-visible string additions: `TRACK MUTE`, `AppPad::handleKeyPadOnSliceMode`. - v1.2.179 → v1.5.205: big delta (+100,852 B file, +90,912 B code). New subsystems with fresh class families: **audio export**, **MIDI Note Map**, new master FX (`MIsolator`, `MRackComp`, `SlipRoll`, `HoldDelay`), sample tag search, precount/sequencer-transport rework, `REVERSE` sample mode, step-LED updates. - Callback ABI shift in v1.5: many `std::function` symbols change `Fv` (void) → `Fvi`/`Fvii`/`Fviii` signatures; `FileUtil` gains `removeResourceFork` + `Rb` params; old `RenderBufferIhLi128ELi128E` display path symbols disappear. ## Image headers | Field | v1.1.156 | v1.2.179 | v1.5.205 | |---|---|---|---| | filesize | 1,595,605 (`0x1858D5`) | 1,606,197 (`0x188235`) | 1,707,049 (`0x1A0C29`) | | sha256 | `617c3efe…1908ac5` | `30ea9eeb…b616a212` | `a8bffa65…4198026` | | cmtd cksum | `0xF58AF539` | `0xDFF0D8C2` | `0xB17C0857` | | mmtd flags | `6e 25 13 20` | `4e b6 e4 04` | `e8 bc f8 4f` | | version triple | (1, 1, 156) | (1, 2, 179) | (1, 5, 205) | | entry point | `0xC26C4820` | `0xC26CA4C0` | `0xC2CD1AA0` | | nsect | 7 | **6** (8 B zero slot absent) | 7 (slot back) | All three entries disassemble (C64x LE) to the same reset prelude (`ZERO b0; mvc b0,ier; mvc b0,csr; mvk/mvklh b15/b14; and -8,…`) — only the stack immediates differ. Container version field stays `(1, 3)` in all builds. Checksum is solved: CRC32-IEEE init 0 over the image with bytes `[8:12]` replaced by `0xC27C6282` (proven 3/3; `tools/` computes it). `mmtd` flags semantics unknown, covered as-is, no handling needed. ## Section map evolution | Role | v1.1.156 (addr / len) | v1.2.179 (addr / len) | v1.5.205 (addr / len) | |---|---|---|---| | asset/blob | C27753B8 / 85,912 | C277B320 / 83,496 | C2DA7600 / 86,168 | | float table | C2774C6C / 656 | C277AB18 / 660 | C2DA6DD4 / 688 | | record table | C2775000 / 512 | C277B000 / 512 | C2DA7400 / 512 | | **code (.text)** | C2589800 / 1,389,120 | C258D800 / 1,399,200 | C2B80C00 / 1,490,112 | | 8 B zero slot | C2589508 / 8 | — absent — | C2B809E8 / 8 | | **strings (.rodata)** | C2755488 / 115,561 | C275A7A0 / 117,825 | C2D84DE0 / 125,081 | | float ramp tail | C27737F8 / 3,668 | C27793E8 / 4,348 | C2DA5680 / 4,312 | Notes: - Whole image rebased upward each release (code base `C2589800 → C258D800 → C2B80C00`); relative layout (code → data → assets) is unchanged. - Code delta v1.1→v1.2 is +10,080 B; v1.2→v1.5 is +90,912 B. - Strings-sect cross-refs grow monotonically: code-ptrs 5,854 → 5,909 → 6,362; self-ptrs 2,932 → 2,967 → 3,141. - Big-sect entropy constant (6.890 / 6.887 / ~6.89, ~12.6% zeros) — same code+data mix, no new packing/encryption introduced. - The 8 B zero sect comes and goes (present, absent, present) — looks like alignment/patch-slot churn in Sonicware's image generator, not a payload. ## v1.1.156 → v1.2.179: +369 / −318 unique strings (≥6) Essentially a feature-point release; only two user-visible additions: - `TRACK MUTE` (+ `PTN MUTE` behavior per changelog) - `AppPad::handleKeyPadOnSliceMode` (+ lambda variant) — slice-mode pad handling (matches v1.2 changelog: EVEN slice mode, PAD hold/ROLL, per-track swing, new LSF/HSF filters — the rest is parameter/data churn, no new class families) ## v1.2.179 → v1.5.205: +551 / −427 unique strings (≥6) ### Added — new subsystems (each a whole class family, not one-offs) - Audio export: `18AppAudioExportMenu`, `21AppAudioExportMixdown`, `25AppAudioExportMenuPattern`, `31AppAudioExportIndividualPattern`, `22AppSongAudioExportMenu`, `25AppSongAudioExportMixdown`, `28AppSongAudioExportIndividual` (+ `…::execute` lambdas), `20DialogAudioExporting`, UI strings `AUDIO EXPORT`, `PATTERN/SONG MIXDOWN`, `MIXDOWN FILE NAME:`, `INDIVIDUAL TRACKS`, `CANNOT EXPORT`, `TO EXPORT.` - MIDI Note Map: `14AppMIDINoteMap`, `MIDI NOTE MAP`, `NOTE MAP` - New master FX (match v1.5 changelog): `SoundEffect::MIsolator`, `MRackComp`, `SlipRoll`, `HoldDelay` - Sequencer transport rework: `…AppSequencerTransport…::startPrecount` (new `EibiEUliE`/`EibiEUlvE` overloads; old `EbiEUliE`/`EbiEUlvE` removed) - `REVERSE` (sample reverse mode), `18AppAudioFileSelect::playPreview`, `18AppSampleTagSearch::action`, `22StepEditPageController::updateAppLED`, `MixDown~` ### Added — API/ABI evolution - `FileUtil::removeResourceFork` (4 refs, previously 0) + `Rb` (bool) params on `convFsRecursive`/`searchFileRecursive` etc. — matches the v1.5 "1,024 files per folder / FILE DATABASE" rework. Old `(…S1_jjPjS2_…)` / `(…_PA256_c…Fv…)` overloads removed (6 `convFsRecursive` old-sig symbols gone). - Broad `Fv` (void-callback) → `Fvi`/`Fvii`/`Fviii` signature migration across `TrackAndModuleController::checkStepLock*`, `MainDelegate::loadProjectData…`, graphics `RenderBuffer` functors, etc. ### Removed (meaningful, 35 strings ≥12 chars; rest is relocated code-sect noise) - Old `FileUtil` overloads (see above), old `startPrecount` overloads, `TrackAndModuleController::checkStepLock{ForUpdateParams,ForSendingMidiCc}` old shapes, `MainDelegate::loadProjectDataWithProgressBar` old shape. - Display pipeline: all `RenderBufferIhLi128ELi128ELi1327E` symbols gone — matches the "enhanced GUI / visual feedback" rework. - `CONVERTABLE FILES:` and `?REPITCH TO TEMPO` strings gone. ### Continuity (present in all three) Crash dumper (`Legacy NMI Exception`, `A0–A31/B0–B31`, `NTSR/ITSR/…`), `N3HAL*Driver` family, `14AppSongBrowser`, `Lofi-12XT` branding, `TRACK MUTE` (added in v1.2, retained in v1.5). `AppPad::handleKeyPadOnSliceMode` (added in v1.2) is *superseded* in v1.5 (symbol absent — slice engine reworked for 16 slices / multi-slice edit). ## Open questions (updated 2026-09-30) - ~~Checksum unknown~~ — solved (see above + `tools/lofi_image.compute_checksum`). - C64x byte-level code diff: now feasible — Ghidra 12.1.3 + ghidra-c6000 lab is set up (`ghidra/headless/`, PyGhidra path) and `analysis/gen_funcmap.py` maps vtable-anchored functions; rebase-aware function-hash diffing still to be run.