# Lofi-12 XT — Findings Library Living knowledge base for this device. Process/tips live in `RE-PROCESS.md`. Per-version structural notes: `docs/firmware/notes-v{1.1.156,1.2.179,1.5.205}.md`; version diff: `rev-diff.md`; mod feasibility: `tweakability-report.md`; tool docs: `tools/README.md`. Deep dives: `docs/hardware.md`, `docs/bootloader.md`, `docs/firmware-update.md`, `docs/firmware/v1.5.205.md`. ## 1. Hardware - Device: Sonicware Lofi-12 XT (shares platform with SmplTrek/Cydrums). - Main SoC (core module): **TI TMS320C6748** — ARM9 + C674x DSP. Marking on unit: `TMS320 C6748EZW T / 13CP99W / GI 375 / 527 ZWT`. - DRAM (core module): **EtronTech EM68C16CWQG-25H** — 1 Gbit DDR2, base `0xC0000000`. - SPI flash (core module, 2×): **Macronix MX25L12833F** (`MXIC MX 25L12833F M2I-10G`), 16 MByte each, SOIC-8, silkscreen `IC300` / `IC301`. Shipping units hide the marking under small stickers (`C047`/`C949`-style labels) — peel + photo to confirm. - USB/aux MCU (main board): **ARTERY AT32F421K8T** (own firmware, out of scope). - Storage: full-size SD slot (firmware update + samples/projects). - PCBs seen: `405-VTOR-3852` (I/O), `405-VTOR-3849B` (main), `405-VTOR-3853` (jack), core module with `CN201A/CN200A/CN203A/CN203B` board-to-board connectors. - Silkscreen pin tables on main board expose `UART1_RX1/TX1`, `SPI1_SCK/MOSI`, `SD_*`, `USB_DP/DN`, key/LED matrix — worth mapping before any invasive work. ## 2. Memory map (DDR2) | Region | Content | |---|---| | `0xC0000000…` | DDR2 base (128 MB) | | `0xC2xxxxxx` | SD `.bin` application image (DSP). v1.5 code `C2B80C00`, strings `C2D84DE0`, assets `C2DA7600` | | `0xC7074630–C70B0598` | SPI AIS bootloader image (DSP), entry `C70A28A0` | | `0xC706F280` | Runtime constant seen in updater (also == checksum seed, §5) | | `0xC27C6282` | Scratch DDR used by updater (§5; value doubles as checksum seed) | ## 3. SPI flash layout (`ic300.bin` / `ic301.bin`, 16 MiB each) Dumps: `ic300.bin` (`c2b86808…`), `ic301.bin` (`81f7b1f5…`). Always keep these as recovery backups; re-verify with a second read (`sha256sum` + `cmp`). **IC300 (boot + app):** TI AIS image, magic `0x41504954` (`TIPA`) at file `0x0`. PLL/DDR config (`0x5853590D` ×2), then 10× Section Load (`0x58535901`): | File off | DDR | Size | |---|---|---| | `0x000050` | `C7074630` | `0x1D0` | | `0x00022C` | `C7074800` | `0x33B00` (main code) | | `0x033D38` | `C70A8300` | `0x28CC` (rodata) | | … | `C70AABD0`/`C70AABE0`/`C70AABF0` | `0xC`/`0xC`/`0xD44` | | … | `C70AF000`/`C70AF4E8`/`C70AF5EC`/`C70AF660` | `0x200`/`0x104`/`0x70`/`0xF38` | `JumpClose (0x58535906)` at file `0x38660` → entry `C70A28A0` (DSP reset prelude `ZERO b0; mvc b0,ier; mvc b0,csr`). After it: `FF` gap to `~0x100000`, data to `~0x1EFFFF`, `FF` gap `0x1F–0x4Fxxxx`, data `0x500000–0xFC7C17`. No AIS CRC opcodes. **IC301 (data):** `AILS` header + drum-pattern names (`KICK/HIHAT/BALLAD/BLUES/…`), 24× `RIFF/WAVE` starting `0x8007E0`, nearly full to `0xFFFD7B`. Factory-sample flash. **Update path (from updater strings + code):** `SystemUpdater::{start, updateBootSection, updateMainSection, updatePresetSection, updateMCUSection, updateMCUBootSection}(CatMetaData::ROMSection)` + `SystemVerify::verifyPresetSection`. Public ZIPs ship only the SYSTEM section (the SD `.bin`); BOOT/PRESET/MCU use separate (unreleased) files. Updater lives in AIS flash, so a bad SYSTEM image cannot kill recovery — hold PAD while powering on → `SYSTEM UPDATE` still works. ## 4. SD `.bin` container (`cmtd/mmtd/sect → EOF`) | Off | Field | |---|---| | `0x00` | `cmtd` magic | | `0x04` | u32 LE filesize (must match actual) | | `0x08` | u32 checksum — **solved, §5** | | `0x0C` | reserved 0 | | `0x10–0x2F` | `12, 1, 3, fw_maj, fw_min, fw_patch, 48, remaining` | | `0x30` | `mmtd` magic; `+0x04` remaining; `+0x08` flags (per-build, part of hash) | | `0x40` | fw triple; `0x4C` entry point; `0x50` sect count | | `0x54…` | `sect` ×N: `73 65 63 74` + u32 load_addr + u32 len + payload; must tile EOF | Known builds: v1.1.156 (1,595,605 B, entry `C26C4820`, 7 sects), v1.2.179 (1,606,197 B, entry `C26CA4C0`, 6 sects), v1.5.205 (1,707,049 B, entry `C2CD1AA0`, 7 sects). Code is C674x LE, entropy ~6.89, unencrypted. Parser/packer: `tools/lofi_image.py` (`parse_image` asserts filesize + chain fit). ## 5. Checksum (SOLVED) **Rule:** `cmtd+0x08` = CRC32-IEEE (init 0) over the entire file with bytes `[8:12]` replaced by `0xC27C6282`. - `tools/lofi_image.py`: `CKSEED = 0xC27C6282`, `compute_checksum()`; `build_image()` auto-computes by default (`--checksum keep` in `lofi_pack.py` preserves). - Proof: GF(2) linear solve per image for the 32 unknown bits at `[8:12]` gives `K = 0xC27C6282` on **all three** images independently (2⁻⁶⁴ fluke); forward recompute reproduces `F58AF539 / DFF0D8C2 / B17C0857`; `unpack→pack` rebuilds stock v1.5.205 byte-identical; a `Threshold→ThresholX` mod forges to a self-consistent `462F735B`. - Code anchors (bootloader DSP): CRC routine `C70A0A60` (`NOT A6→state`, poly `EDB88320` via `MVK/MVKH`, byte loop, final `NOT` in delay slot ≡ zlib chaining `F(buf,len,init)`); 4K-chunk caller `C708E4E4` (`MVK 0x1000`, `CMPGT`, `CALLP C70A0A60`); check fn `C709E7C0` (16-byte header CRC init 0 → chained 0x40000 chunks → `CMPEQ A13,A12` compare); orchestrator `C708678C CALLP C709E7C0`, reject path builds `ERROR : This file is invalid.` (`C70A8E82`). - Forging: build image normally, then set `[8:12] = compute_checksum(image)`. ## 6. OLED / updater UI strings (orientation) `Checking... 0%`, `Check the firmware file.`, `ERROR : This file is invalid.`, `Erasing.../Writing.../Verifying... 0%`, `100%, done./OK./NG.`, `Update completed./Update failed.`, `Please restart.`, `Are you sure?`, `[CLR] : No / [OK] : Yes`, `>> BOOT/MCU/MCU Boot/PRESET/SYSTEM`, `BOOT:/MCU:/MCU Boot:/PRESET:/SYSTEM:`, `$ systemupdate`, `[Lofi-12 XT] ~`, `SYSTEM INFO/VERSION/BOOT/SYSTEM/MCU`, crash dumper (`Legacy NMI Exception`, `A0–A31/B0–B31`, `NTSR/ITSR/…`). v1.5-only markers: `AppAudioExport*`, `MIsolator/MRackComp/SlipRoll/HoldDelay`, `MIDINoteMap`, `REVERSE`, `removeResourceFork` (all present in IC300 → board runs v1.5). ## 7. Open questions - `mmtd+0x08` flags semantics (timestamp? covered by checksum as-is, no need to crack). - Exact flash section table for BOOT/PRESET/MCU offsets (only SYSTEM reverse-engineered). - AT32F421 firmware extraction/update protocol. - UART/JTAG test-point mapping (silkscreen names exist, continuity not traced).