Files
adsp219x-re/docs/ROM_ANALYSIS_WALKTHROUGH.md
2026-04-12 13:55:24 +00:00

3.7 KiB

ADSP-219x ROM Analyse Walkthrough

Dieses Dokument beschreibt den systematischen Prozess der Analyse eines ADSP-219x Binär-Dumps. Da wir mit einer 24-Bit Architektur auf einer 8-Bit-basierten Dateisystem-Welt arbeiten, ist der erste Schritt immer die Validierung des Formats.

1. Phase: Format-Validierung (Padded vs. Packed)

Ein ADSP-2191 Befehl ist 24 Bit (3 Bytes) groß. In einem ROM-Dump liegen diese meist in einem von zwei Formaten vor:

  • Packed (3-Byte): [B0][B1][B2] [B3][B4][B5] ... (Keine Lücken)
  • Padded (4-Byte): [00][B0][B1][B2] [00][B3][B4][B5] ... (Oft bei 32-Bit EPROM-Builds)

Woran erkenne ich das Format?

Suche nach dem NOP Opcode.

  • Ein klassischer NOP (Type 30) ist 0x000000.
  • Ein Multifunktions-NOP (Type 1) ist 0xC00000.

Wenn du alle 3 oder 4 Bytes lange Ketten von 00 findest, hast du wahrscheinlich das Alignment gefunden.

2. Phase: Den Einstiegspunkt finden (Vector Table)

Der ADSP-2191 startet nach einem Reset bei Adresse 0x0000 im Programm-Memory (PM). Die ersten Adressen sind die Interrupt-Vektoren (jeweils 8 oder 16 Words Platz).

Typisches Muster am Anfang:

0x0000:  JUMP 0x0100   <-- Reset Vector
0x0008:  RTI           <-- Power Down Vector
0x0010:  RTI           <-- Kernel Interrupt
...

Wenn dein Disassembler am Anfang nur UNKNOWN auswirkt, ist meistens das Alignment (3 vs 4 Byte) oder die Endianness falsch. ADSP-219x ist standardmäßig Big-Endian.

3. Phase: Den Code "lesen" (Pattern Recognition)

A. Register Initialisierung (Type 6/7)

DSP-Code beginnt fast immer damit, die DAGs (Data Address Generators) zu füttern.

  • I0 = 0x2000 (Index-Register auf Start eines Buffers)
  • M0 = 1 (Modifier auf Schrittweite 1)
  • L0 = 0 (Circular Buffering aus)

In deinem Disassembler: AX0 = 0x1234 entspricht Opcode 0x4x..... Das ist ein Type 6 Befehl.

B. Die "Magic" des DSP: Multifunktions-Opcodes (Type 1)

Das ist der Kern des DSPs. In einem einzigen Takt passiert:

  1. Eine Berechnung (ALU/MAC)
  2. Ein Read aus dem DM (Data Memory)
  3. Ein Read aus dem PM (Program Memory)

Beispiel: MR + X * Y (SS), AX0 = DM(I0 += M0), AY0 = PM(I4 += M4)

  • Identifikation: Opcodes die mit 0xC bis 0xF beginnen.
  • Schlussfolgerung: Das ist oft eine innere Schleife (z.B. ein FIR-Filter). Wenn du viele dieser Befehle hintereinander siehst, hast du den Signalverarbeitungs-Kernel gefunden.

4. Phase: Daten vs. Code im PM

Der ADSP-2191 hat eine Harvard-Architektur. Das Programm-Memory (PM) kann aber auch Daten enthalten (24-Bit breit). Dank des Visible Instruction State (VIS) kann der 2191 hocheffizient 24-Bit Koeffizienten aus dem PM laden, während er rechnet.

Woran erkenne ich Daten im PM? Wenn der Disassembler sinnlose Befehle ausgibt (z.B. hunderte UNKNOWN oder seltsame Sprünge in ungültige Bereiche), handelt es sich wahrscheinlich um eine Koeffizienten-Tabelle (z.B. Sinus-Werte oder Filter-Taps).

5. Phase: Analyse-Workflow mit radare2

Wenn du den Dump in iaito oder r2 lädst:

  1. Bit-Breite: Setze e asm.bits = 24.
  2. Suchen: Suche nach 000000 (NOPs), um Funktionsgrenzen zu finden.
  3. Cross-References: Suche nach CALL Befehlen (0x11....), um die Programmstruktur zu verstehen.
  4. I/O Analyse: Der ADSP-2191 steuert Peripherie über I/O-Register. Suche nach IO(addr) = Dreg. Adressen wie 0x00 bis 0x3F sind oft System-Controller oder Sport (Serial Port) Konfiguration.

Tipp: Nutze das beiliegende Skript analysis/analyze_rom.py, um eine erste Statistik über die verwendeten Instruktionstypen zu erhalten. Das zeigt dir sofort, ob der Dump primär aus Logik (JUMP, IF) oder aus Mathe (Compute, Multifunction) besteht.