131 lines
6.8 KiB
Markdown
131 lines
6.8 KiB
Markdown
# 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.
|