The other chapters document each tool on its own; this one shows how they combine. Every walkthrough below is a real investigation shape -- the same ones Copperline’s own regressions were hunted with -- written against the standard tool set: the debugger window, the The Console, the frame analyzer, reverse execution, headless knobs, and the GDB stub.
All of these start the same way: get the machine near the problem
cheaply, then investigate precisely. Save states are the lever --
snapshot once just before the scene (--save-state-after SECS out.state
headlessly, or from the menu), then every later experiment starts from
--load-state in seconds instead of re-emulating minutes.
A sprite vanishes¶
The logo disappears mid-demo, or an in-game object flickers out. Sprites fail for a handful of reasons: sprite DMA got turned off, the sprite pointers were repointed somewhere wrong, the control words disarmed it, or the display window moved off it.
Pause just before the vanish (reverse-step back if you overshot:
RFRAMEin the console rewinds a whole frame).Debugger Video tab: the sprite viewer decodes all eight channels -- SPRxPOS/CTL positions, DMA line counts, and a thumbnail of what each channel fetched this frame. A sprite that is armed but empty fetched nothing: suspect DMA. A sprite with data but a wrong position: suspect the copper list that positions it.
If DMA is the suspect: console
RWATCH DMACON(or the Break tab’s register watch) and run. When it fires, the console names the writer -- CPU instruction, Copper, or blitter -- with its address. A game clearingSPRENdeliberately looks exactly like this.If the pointers are the suspect:
RWATCH SPR0PTHcatches every repoint, and the Copper tab shows the list that does it each frame.Layer isolation confirms any theory instantly: the Video tab’s plane/sprite masks re-render the paused frame with channels removed, so “is that object sprite 4 or a playfield trick?” is one click.
The picture is torn or the copper list is trashed¶
A horizontal band of garbage, colours changing at the wrong line, or a display that falls apart after some event.
Open the Frame Analyzer and enable the picture underlay (
U): the captured DMA heatmap draws over the actual frame, so a band of garbage lines up visually with whatever DMA was (or was not) happening there.Hover the analyzer at the first bad line: it decodes the custom register writes near the beam position. A
COLORxxwrite that arrives a line late, or a missingBPLxPTHrefresh, is visible directly.Set a beam trap at the first bad line (
BTRAP 145in the console, or the analyzer’s To-slot). The machine halts with the beam exactly there; the Copper tab now shows what the Copper is executing at that moment, live.CSTEPsingle-steps Copper instructions from there. A WAIT with a wrong comparator, or a list that ran past its terminating WAIT into garbage, shows up within a few steps.CBREAK ADDRbreaks when the Copper reaches a specific instruction on any frame.If the list itself is corrupt in memory:
WRITER ADDRreverse-scans execution to find the last instruction that wrote the corrupted word. That answers “who trashed my copper list” in one command -- typically a blitter destination running long, which the attribution names as such.
Something writes where it should not¶
Memory corruption generally: a variable, a bitmap, or OS structure gets stomped.
WATCH ADDRsets an attributed watchpoint. Any CPU, blitter, or disk-DMA write there halts the machine and names the writer. Filter to one source withWATCH ADDR BLITTERwhen the CPU legitimately touches the address constantly.If the corruption already happened:
WRITER ADDRuses the reverse engine to find the most recent writer without re-running anything by hand.For “when did this go bad” rather than “who”: binary-search with save states -- load,
MEM ADDR, and the deterministic core guarantees the same answer on every replay.
Crash triage: guru meditation¶
The machine gurus, or worse, freezes silently.
Arm
CATCHALERT. When exec’sAlert()runs, the machine halts with D7 holding the alert code -- before the flashing box is drawn, with the faulting context still warm.GURUdecodes it: deadend flag, subsystem, cause -- and for CPU traps the vector name (address error,illegal instruction).STACKandHISTORYshow how it got there: the call-stack scan and the disassembled ring of recently retired PCs.RSTEPwalks backwards from the alert into the faulting code with full state.A double fault (bus/address error during exception processing) cannot guru -- the CPU halts. Copperline surfaces it on screen, in the console, and on the Break tab automatically;
HISTORYis the main tool from there.For OS-level context:
TASKSshows what was scheduled,CATCHTASK NAMEstops when a suspect process next gets the CPU, andSEGMENTSmaps a process’s loaded hunks so addresses inHISTORYcan be attributed to a program rather than “somewhere in RAM”.
Find the lives counter (memory hunting)¶
The trainer-making workflow, also the fastest way to locate any game variable you can influence.
HUNT STARTsnapshots all writable RAM (chip, slow, and Zorro boards). Word width is the default;HUNT START Bhunts bytes.You have three lives:
HUNT EQ 3. Thousands of candidates.Lose a life, pause,
HUNT EQ 2. The intersection is usually a handful of addresses; two or three rounds isolate one.HUNT SAME/HUNT DIFFfilter against the previous snapshot when you cannot name the value (“it changed”, “it did not change”).HUNT LISTshows the survivors with live values.From there:
WATCH ADDRanswers “what code decrements this” (the death routine), andPOKE ADDR 9tests the theory.
Source-level debugging of your own program¶
For programs you build yourself with an amiga-gcc toolchain, the GDB
stub supports full source-level debugging -- breakpoints on lines,
next, print on variables -- via automatic segment relocation. The
walkthrough lives in the GDB chapter, “Source-Level Debugging of
Amiga Programs”. The short version: build with -g, run inside the
emulator from a CLI, and m68k-amigaos-gdb prog + target remote
relocates itself using the emulator’s qOffsets answer.
Making it reproducible¶
Any of the above is dramatically easier when the failure replays identically every run:
Record the session:
--record-input session.clscript(Cmd+Shift+Rlive) captures input on emulated time;--script session.clscriptreplays it byte-identically.Headless repro: once scripted,
--screenshot-after/--dump-framesplus theCOPPERLINE_DBG_*knobs (headless chapter) turn the bug into a shell command -- the form a regression test wants.Trace the suspect window: console
TRACE START PATHwrites every retired PC with beam positions to a file; diff two traces (one good run, one bad) to find the first divergence.