@henols/c64-re-tools 0.2.4 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/skills/acme-build/SKILL.md +22 -22
- package/skills/c64-disk-access/SKILL.md +49 -46
- package/skills/c64-memory-mapping/SKILL.md +71 -70
- package/skills/c64-petcat/SKILL.md +11 -11
- package/skills/c64-program-recon/SKILL.md +109 -105
- package/skills/c64-program-recon/references/control-flow.md +13 -13
- package/skills/c64-program-recon/references/graphics.md +6 -6
- package/skills/c64-program-recon/references/observation-hazards.md +7 -7
- package/skills/c64-program-recon/references/reconstruction.md +6 -6
- package/skills/c64-program-recon/references/sound-and-input.md +8 -8
- package/skills/c64-program-recon/references/tool-selection.md +11 -11
- package/skills/c64-program-recon/templates/memory-map.template.md +16 -12
- package/skills/c64-provenance-diff/SKILL.md +43 -43
- package/skills/c64-ram-capture/SKILL.md +96 -45
- package/skills/c64-ram-capture/scripts/compare-cross-binary.mjs +525 -0
- package/skills/c64-ram-capture/templates/capture-record.template.md +11 -11
- package/skills/c64-ram-capture/transients/README.md +11 -10
- package/skills/routine-queue-walker/SKILL.md +205 -176
- package/skills/vice-wedge-triage/SKILL.md +48 -48
|
@@ -77,10 +77,11 @@ loop: ldx $dc01 ; $DC01 = Port B, keyboard matrix ro
|
|
|
77
77
|
rts
|
|
78
78
|
```
|
|
79
79
|
|
|
80
|
-
|
|
81
|
-
and region
|
|
82
|
-
the eleven-line listing above grows a 23-line header and the
|
|
83
|
-
below grows a 25-line one — a little over 2x the input
|
|
80
|
+
`annotate` prepends a header block that lists every referenced address with its
|
|
81
|
+
full description, symbol and region (elided above). Measured on the two examples
|
|
82
|
+
on this page, the eleven-line listing above grows a 23-line header and the
|
|
83
|
+
nine-line IRQ excerpt below grows a 25-line one — a little over 2x the input
|
|
84
|
+
either way. Pass
|
|
84
85
|
`--no-header` to drop it and get the annotated body alone.
|
|
85
86
|
|
|
86
87
|
Options:
|
|
@@ -91,8 +92,8 @@ Options:
|
|
|
91
92
|
(`$0400-$07E7`, 1000 bytes) or the `$C000-$CFFF` block still earns an inline
|
|
92
93
|
comment, while the 8 KB BASIC and KERNAL ROM blocks do not — a branch
|
|
93
94
|
annotated "KERNAL ROM (8192 bytes)" teaches nobody anything. The cap applies
|
|
94
|
-
only to non-flow instructions
|
|
95
|
-
`RTS`, `RTI`)
|
|
95
|
+
only to non-flow instructions. `annotate` holds flow instructions (`JMP`,
|
|
96
|
+
`JSR`, branches, `RTS`, `RTI`) to 2 bytes regardless of `--max-span`, so a jump or
|
|
96
97
|
branch only earns a comment when it targets a specific vector such as
|
|
97
98
|
`$0314`. `--max-span 2` gives register- and variable-level comments only.
|
|
98
99
|
- `--no-header` suppresses the prepended header block, for piping annotated
|
|
@@ -128,11 +129,11 @@ Weigh a comment by the region it describes:
|
|
|
128
129
|
equally solid wherever ROM is banked in — `$01` bits #0-#2 select it, and the
|
|
129
130
|
vector at `$0314` shows whether the KERNAL IRQ path is in use.
|
|
130
131
|
- **Zero page, `$0200-$07FF` and the BASIC area describe BASIC and KERNAL usage.**
|
|
131
|
-
Read them as a strong hint and
|
|
132
|
+
Read them as a strong hint and check against the program's own behaviour
|
|
132
133
|
before adopting the name. A game that banks ROM out keeps its own variables
|
|
133
134
|
there. A real case: at `$08E6` a game's `LDA $49` gets labelled `FORPNT`
|
|
134
135
|
("value of current variable during LET"), when `$49` is really one of that
|
|
135
|
-
game's own variables. Take the address,
|
|
136
|
+
game's own variables. Take the address, check the meaning.
|
|
136
137
|
- **A region-only answer is not an error.** An address that no source names
|
|
137
138
|
specifically prints only the wider regions enclosing it — no error, no
|
|
138
139
|
not-found line. `node $D lookup '$1234'` prints:
|
|
@@ -154,7 +155,7 @@ Weigh a comment by the region it describes:
|
|
|
154
155
|
table that loses coverage, not for anything the current one omits.
|
|
155
156
|
|
|
156
157
|
For a game, the fastest route to a real name is to annotate with `--max-span 2`,
|
|
157
|
-
trust the I/O lines immediately, and
|
|
158
|
+
trust the I/O lines immediately, and check the rest by watching what the code
|
|
158
159
|
does with them.
|
|
159
160
|
|
|
160
161
|
## Where the data comes from
|
|
@@ -170,16 +171,16 @@ what the others leave out:
|
|
|
170
171
|
| [C64io.txt](https://www.zimmers.net/anonftp/pub/cbm/maps/C64io.txt) | VIC/SID/CIA registers broken down per bit |
|
|
171
172
|
|
|
172
173
|
The built table is committed alongside the script, so `lookup` and `annotate` need
|
|
173
|
-
only Node. Rebuild when a source publishes a correction
|
|
174
|
+
only Node. Rebuild when a source publishes a correction. `lookup`'s `<src>` tags
|
|
174
175
|
show which table any given claim came from.
|
|
175
176
|
|
|
176
177
|
`memmap` overwrites the committed, git-tracked `memmap.json` (driver.mjs:270 —
|
|
177
|
-
235,925 bytes as of 2026-08-04,
|
|
178
|
-
and no diff.**
|
|
179
|
-
|
|
178
|
+
235,925 bytes as of 2026-08-04, check with `wc -c`) **in place, with no backup
|
|
179
|
+
and no diff.** `memmap` gets one of the four sources (`http://unusedino.de/…`,
|
|
180
|
+
driver.mjs:33) over plain HTTP with no TLS. The only guard against a bad rebuild
|
|
180
181
|
is a per-source emptiness check plus a 600-entry floor across all sources
|
|
181
|
-
combined (driver.mjs:262, 268)
|
|
182
|
-
|
|
182
|
+
combined (driver.mjs:262, 268). A partially-reachable or partially-changed source
|
|
183
|
+
set can therefore silently replace good tracked data with less of it. Rebuild, then
|
|
183
184
|
run `git diff --stat` on `memmap.json` before accepting the result, and
|
|
184
185
|
`git checkout` the file if the diff is not explainable as the correction you
|
|
185
186
|
were expecting. **`memmap` mutates tracked files** — unlike `lookup` and
|
|
@@ -191,8 +192,8 @@ tree, and review the diff before you commit it.
|
|
|
191
192
|
`memmap.json`'s structured `bits` entries are the source of the curated register bit-name table used
|
|
192
193
|
to generate program-specific enums for this project's annotation store: register
|
|
193
194
|
writes disassemble as `lda #D011_YSCROLL3_ROW25_SCREENON_TEXT` instead of a bare `#$1b`. The
|
|
194
|
-
generator is `src/mcp/vice/anno-regbits-gen.ts
|
|
195
|
-
`src/mcp/vice/anno-regbits.json
|
|
195
|
+
generator is `src/mcp/vice/anno-regbits-gen.ts`. Its committed output is
|
|
196
|
+
`src/mcp/vice/anno-regbits.json`. That output is **digest-pinned** to `memmap.json`. A
|
|
196
197
|
`node anno-regbits-gen.ts` run compares its own fresh build against the committed file, and CI fails
|
|
197
198
|
if `memmap.json` changed without a re-run.
|
|
198
199
|
|
|
@@ -200,7 +201,7 @@ if `memmap.json` changed without a re-run.
|
|
|
200
201
|
`$D017`, `$D01A` and `$D01B`–`$D01D` — the sprite-plane bitmask registers a real game writes
|
|
201
202
|
constantly — are **not** among those 29, so the enum generator supplies them from its own curated
|
|
202
203
|
override table (`OVERRIDES` in `anno-regbits-gen.ts`), not from this file. Widening `memmap.json`'s
|
|
203
|
-
`io` parser (or
|
|
204
|
+
`io` parser (or correcting the OCR damage already present in some `bits` prose, e.g. a letter `O` for
|
|
204
205
|
the digit `0`) so those registers get a real structured entry here is separate work belonging to this
|
|
205
206
|
skill, not the generator.
|
|
206
207
|
|
|
@@ -208,10 +209,10 @@ skill, not the generator.
|
|
|
208
209
|
table above only builds `anno-regbits.json`. Turning a specific program's register *writes* into
|
|
209
210
|
named enum variants was the `gen-enums` CLI verb, and **that verb is WITHDRAWN from this surface, and
|
|
210
211
|
no phase currently owns its return.** This notice previously forecast that it would come
|
|
211
|
-
back as a rebuild over the annotation store alongside the ACME export route
|
|
212
|
+
back as a rebuild over the annotation store alongside the ACME export route. The ACME export route
|
|
212
213
|
did come back on 2026-08-31, but the phase that rebuilt it covered that route only — no requirement
|
|
213
|
-
and no success criterion of it mentioned `gen-enums`.
|
|
214
|
-
|
|
214
|
+
and no success criterion of it mentioned `gen-enums`. This notice corrects that forecast rather than
|
|
215
|
+
removing it. Do not invoke the verb — it does not exist, and the invocation fails with an unknown-verb
|
|
215
216
|
error and nothing to explain it.
|
|
216
217
|
|
|
217
218
|
What it did, so the rebuild has a specification and so a reader knows what is missing: it read the
|
|
@@ -229,7 +230,7 @@ manual where `gen-enums` was bulk, but it writes exactly the same rows into the
|
|
|
229
230
|
Two deeper jobs feed the annotate/lookup job above, rather than standing apart from it: knowing
|
|
230
231
|
what a whole region actually is (code, or one of eight kinds of data) before it can be annotated
|
|
231
232
|
at all, and knowing what one of a program's own addresses represents when no published table can
|
|
232
|
-
say. Both exist to serve a documented listing
|
|
233
|
+
say. Both exist to serve a documented listing. You do not invoke either one as a job on its own.
|
|
233
234
|
|
|
234
235
|
### Classifying every region of an annotation project
|
|
235
236
|
|
|
@@ -242,7 +243,7 @@ data?**
|
|
|
242
243
|
answers the *live* code-versus-data question — its step 5 is "what the PC
|
|
243
244
|
actually visits across full coverage", and an execution trace beats every
|
|
244
245
|
static heuristic on this page. Run the live pass when you have a running
|
|
245
|
-
machine
|
|
246
|
+
machine. Run this one when all you have is a file, and treat a later trace as
|
|
246
247
|
the thing that overrules it.
|
|
247
248
|
|
|
248
249
|
When a binary is first loaded, the auto-analyzer traces reachable code from the
|
|
@@ -279,11 +280,11 @@ four hundred lines of fiction.
|
|
|
279
280
|
#### The order of the passes
|
|
280
281
|
|
|
281
282
|
Work the Undefined blocks in four passes, in this order. Do not interleave
|
|
282
|
-
them
|
|
283
|
+
them. Each pass makes the next one cheaper.
|
|
283
284
|
|
|
284
285
|
1. **Provably-reachable code** — read from the entry point of each region that
|
|
285
286
|
meets the proof bar above with `anno_disassemble`, then type the range you
|
|
286
|
-
actually
|
|
287
|
+
actually checked as `code` with `anno_set_data_type`. **Reading and typing
|
|
287
288
|
are two calls on this surface, and that is deliberate:** `anno_disassemble`
|
|
288
289
|
decodes fresh from the image bytes and writes nothing at all, so nothing is
|
|
289
290
|
ever classified as code by a decoder's guess — the boundary you record is
|
|
@@ -291,7 +292,7 @@ them; each pass makes the next one cheaper.
|
|
|
291
292
|
2. **Text** — PETSCII and screencode strings.
|
|
292
293
|
3. **Tables** — byte, word, address and split (lo/hi, hi/lo) tables.
|
|
293
294
|
4. **Whatever is left** — decide data, or leave it Undefined for a human.
|
|
294
|
-
**Never** speculatively disassemble in this pass
|
|
295
|
+
**Never** speculatively disassemble in this pass. By definition nothing here
|
|
295
296
|
met the proof bar.
|
|
296
297
|
|
|
297
298
|
#### Scope, and reading a region
|
|
@@ -309,24 +310,24 @@ them; each pass makes the next one cheaper.
|
|
|
309
310
|
data** — they are valid instructions. The flag is a human's hint, not a
|
|
310
311
|
guarantee: some programs use them with the flag false.
|
|
311
312
|
2. `anno_get_blocks` to see what is already classified, and focus on the
|
|
312
|
-
Undefined entries. `max_results` is REQUIRED with no default
|
|
313
|
+
Undefined entries. `max_results` is REQUIRED with no default. Pass a ceiling
|
|
313
314
|
above the range count you expect and compare the returned count against it.
|
|
314
315
|
3. Read each candidate region twice, through `anno_read_region` (which names
|
|
315
316
|
both the `store` and the `image`): `view:
|
|
316
317
|
"hexdump"` shows the byte patterns, and **omitting `view`** gives the
|
|
317
318
|
disassembly view — that is the parameter's documented default — which shows
|
|
318
|
-
how the region would decode.
|
|
319
|
-
(`ANNO_READ_REGION_MAX_BYTES`)
|
|
320
|
-
name rather than
|
|
319
|
+
how the region would decode. `anno_read_region` caps the combined byte count
|
|
320
|
+
at **4096 bytes** per call (`ANNO_READ_REGION_MAX_BYTES`). It refuses a
|
|
321
|
+
request above the cap by name rather than truncating it — so walk a large binary in consecutive ranges.
|
|
321
322
|
Chunks of **256–512 bytes** are the practical working size for
|
|
322
|
-
classification
|
|
323
|
+
classification. A 4096-byte hexdump is more than can be read carefully in
|
|
323
324
|
one pass.
|
|
324
325
|
|
|
325
326
|
#### Applying the classification
|
|
326
327
|
|
|
327
328
|
- **Code**: `anno_disassemble` from the entry-point address to READ, then
|
|
328
|
-
`anno_set_data_type` with `"code"` to RECORD the range you
|
|
329
|
-
`anno_disassemble` performs no write, so
|
|
329
|
+
`anno_set_data_type` with `"code"` to RECORD the range you checked.
|
|
330
|
+
`anno_disassemble` performs no write, so it classifies nothing until you say
|
|
330
331
|
so. Type only as far as you actually followed the flow — the end of a routine
|
|
331
332
|
at its `RTS`/`RTI`/`JMP`, not "to the end of the region" — because the typed
|
|
332
333
|
`code` ranges are what `anno_get_cross_references` and `anno_search` decode
|
|
@@ -337,9 +338,9 @@ them; each pass makes the next one cheaper.
|
|
|
337
338
|
- **A wrong classification is not a disaster and does not need undoing.**
|
|
338
339
|
`anno_set_data_type` is idempotent over a range: set the correct type again
|
|
339
340
|
over the same range and the previous one is gone, and an identical repeat
|
|
340
|
-
succeeds reporting `changed: false`. (Upstream reaches for an undo call here
|
|
341
|
-
|
|
342
|
-
- **Read the disclosures on a successful retype
|
|
341
|
+
succeeds reporting `changed: false`. (Upstream reaches for an undo call here.
|
|
342
|
+
This project does not expose one, and does not need to.)
|
|
343
|
+
- **Read the disclosures on a successful retype. They are not errors and they
|
|
343
344
|
are never dropped.** `contradictedComments` names comments whose recorded
|
|
344
345
|
confidence now contradicts the type you just applied, and
|
|
345
346
|
`reinterpretedSplitTables` names every split table the write FRAGMENTED, with
|
|
@@ -349,9 +350,9 @@ them; each pass makes the next one cheaper.
|
|
|
349
350
|
ones a human recorded.
|
|
350
351
|
- A split layout REFUSES an odd byte count — the low half and the high half must
|
|
351
352
|
be the same length.
|
|
352
|
-
- Re-read `anno_get_blocks` after each batch to
|
|
353
|
-
`max_results` is REQUIRED on that read and has no default
|
|
354
|
-
|
|
353
|
+
- Re-read `anno_get_blocks` after each batch to check what actually landed.
|
|
354
|
+
`max_results` is REQUIRED on that read and has no default. That read returns
|
|
355
|
+
the true match count beside the list.
|
|
355
356
|
|
|
356
357
|
Example of a valid data-only batch, then the code regions separately:
|
|
357
358
|
|
|
@@ -368,7 +369,7 @@ then: anno_get_blocks max_results=500 # refresh
|
|
|
368
369
|
|
|
369
370
|
| Block type | `data_type` | When |
|
|
370
371
|
|---|---|---|
|
|
371
|
-
| **Code** | `code` | Provably-executed instructions. Read the extent with `anno_disassemble` first — it writes nothing — then record exactly what you
|
|
372
|
+
| **Code** | `code` | Provably-executed instructions. Read the extent with `anno_disassemble` first — it writes nothing — then record exactly what you checked. |
|
|
372
373
|
| Byte | `byte` | Raw 8-bit data: sprites, bitmaps, charsets, lookup tables, variables, unknowns |
|
|
373
374
|
| Word | `word` | 16-bit little-endian values: 16-bit variables, math constants, SID frequencies |
|
|
374
375
|
| Address | `address` | 16-bit LE pointers — jump tables, vector lists. Creates cross-references |
|
|
@@ -383,17 +384,17 @@ then: anno_get_blocks max_results=500 # refresh
|
|
|
383
384
|
|
|
384
385
|
#### Recognising each kind
|
|
385
386
|
|
|
386
|
-
**Byte data** — regular patterns that form no valid instruction sequence
|
|
387
|
-
|
|
388
|
-
(padded to 64) units, usually grouped
|
|
389
|
-
|
|
387
|
+
**Byte data** — regular patterns that form no valid instruction sequence.
|
|
388
|
+
Addressed by `LDA addr,X` / `LDA addr,Y` table lookups. Sprite data in 63-byte
|
|
389
|
+
(padded to 64) units, usually grouped. Bitmap data in 8-byte character cells.
|
|
390
|
+
Colour data confined to `$00`–`$0F`. Or random-looking bytes between two code
|
|
390
391
|
blocks whose disassembly is nonsense.
|
|
391
392
|
|
|
392
393
|
**Word data** — byte pairs forming meaningful 16-bit values (screen addresses,
|
|
393
|
-
timer values)
|
|
394
|
+
timer values). Loaded low-then-high by adjacent `LDA addr` / `LDA addr+1`.
|
|
394
395
|
|
|
395
396
|
**Address tables** — byte pairs that read as little-endian addresses landing
|
|
396
|
-
*inside* the binary
|
|
397
|
+
*inside* the binary. Reached by `JMP ($addr)` or indexed indirect reads. Jump
|
|
397
398
|
tables, dispatch tables and vector lists all live here.
|
|
398
399
|
|
|
399
400
|
**Split lo/hi (or hi/lo) tables** — two equal halves, one of plausible low
|
|
@@ -404,25 +405,25 @@ on the 6502. **The total byte count must be even and the halves equal** — an
|
|
|
404
405
|
odd count means the boundary is in the wrong place.
|
|
405
406
|
|
|
406
407
|
**PETSCII text** — bytes in `$20`–`$7E` (unshifted) or `$C0`–`$DF` (shifted),
|
|
407
|
-
often recognisably English since PETSCII shares `$20`–`$5F` with ASCII
|
|
408
|
-
|
|
408
|
+
often recognisably English since PETSCII shares `$20`–`$5F` with ASCII.
|
|
409
|
+
Terminated by `$00`, `$0D`, or a high-bit sentinel. Reached by `$FFD2` (CHROUT)
|
|
409
410
|
or `$AB1E` (BASIC STROUT). `GAME OVER`, `PRESS FIRE`, menus, credits.
|
|
410
411
|
|
|
411
|
-
**Screencode text** — bytes in `$00`–`$3F` where `$00` is `@` and `$01` is `A
|
|
412
|
-
|
|
412
|
+
**Screencode text** — bytes in `$00`–`$3F` where `$00` is `@` and `$01` is `A`.
|
|
413
|
+
Copied directly to `$0400`–`$07E7`. `LDA data,X / STA $0400,X` is the
|
|
413
414
|
give-away. A full screen dump is exactly 1000 bytes.
|
|
414
415
|
|
|
415
416
|
**External file** — a large contiguous non-code block matching a known format:
|
|
416
417
|
a `PSID`/`RSID` header, a 2048-byte charset (256 chars × 8 bytes), sprite data
|
|
417
418
|
in multiples of 64, or a bitmap. Export it rather than annotate it.
|
|
418
419
|
|
|
419
|
-
**PETSCII is not screencode.** If
|
|
420
|
-
|
|
420
|
+
**PETSCII is not screencode.** If the program copies it to `$0400`, it is
|
|
421
|
+
screencode. If the program passes it to CHROUT, it is PETSCII. Getting this backwards produces text
|
|
421
422
|
that renders as garbage in exactly one of the two places.
|
|
422
423
|
|
|
423
424
|
#### The adjacent-table limitation, and how it was closed
|
|
424
425
|
|
|
425
|
-
**Dated limitation, recorded 2026-08-24
|
|
426
|
+
**Dated limitation, recorded 2026-08-24. CLOSED 2026-08-29 when the store
|
|
426
427
|
changed underneath it.** The old store auto-merged two adjacent regions of the
|
|
427
428
|
*same* type into one block, so two byte tables side by side — or the two halves
|
|
428
429
|
of a split table sitting next to each other — lost their boundary on read, and
|
|
@@ -443,7 +444,7 @@ So the working rules are now the ordinary ones:
|
|
|
443
444
|
- **Do** still record the boundary in the annotations as well — an
|
|
444
445
|
`anno_set_label_name` at the start of the second table and a line comment on
|
|
445
446
|
both naming the extent you determined. A name and an evidence line survive a
|
|
446
|
-
later retype
|
|
447
|
+
later retype. A row boundary does not.
|
|
447
448
|
- **Do not** carry the old over-merge caveat into a report taken from this
|
|
448
449
|
store. It was true of the retired one and is not true here.
|
|
449
450
|
|
|
@@ -464,14 +465,14 @@ Then report, and mean it:
|
|
|
464
465
|
regions on a real game is almost always a report that stopped looking.
|
|
465
466
|
- The store revision, read with `anno_save_project`. That verb performs **no
|
|
466
467
|
write** — every classification call above already committed and fsynced its
|
|
467
|
-
own — so quoting the revision
|
|
468
|
+
own — so quoting the revision pins the report to an exact store
|
|
468
469
|
state rather than to "after the pass".
|
|
469
470
|
|
|
470
471
|
#### What goes wrong
|
|
471
472
|
|
|
472
473
|
| Symptom | What it actually is |
|
|
473
474
|
|---|---|
|
|
474
|
-
| A region disassembles beautifully but has no incoming reference | Data. Decodability is not evidence
|
|
475
|
+
| A region disassembles beautifully but has no incoming reference | Data. Decodability is not evidence. Leave it Undefined. |
|
|
475
476
|
| Disassembly full of impossible branches or `BRK` (`$00`) floods | Data misread as code. |
|
|
476
477
|
| Odd-looking instructions, but real `JSR`/`JMP` cross-references land here | Probably code using undocumented opcodes. Check the `may_contain_undocumented_opcodes` hint. |
|
|
477
478
|
| A split table's addresses recombine to nonsense | The half boundary is misplaced, or the table is hi/lo rather than lo/hi. |
|
|
@@ -485,7 +486,7 @@ a hardware register, a KERNAL entry point, an OS variable. That answer comes
|
|
|
485
486
|
from four tables and holds for every program.
|
|
486
487
|
|
|
487
488
|
This section is the other half: **what a program's *own* address represents.**
|
|
488
|
-
No table can tell you, because the
|
|
489
|
+
No table can tell you, because the program's code decided the meaning.
|
|
489
490
|
When `lookup` returns a region-only answer — the dominant case for a game's own
|
|
490
491
|
code and variables, as noted above — this is the procedure that gets you a
|
|
491
492
|
name.
|
|
@@ -507,7 +508,7 @@ name.
|
|
|
507
508
|
#### 2. Gather the usage
|
|
508
509
|
|
|
509
510
|
`anno_get_cross_references` on the address — naming the `store`, the `image` and
|
|
510
|
-
a REQUIRED `max_results` — returns
|
|
511
|
+
a REQUIRED `max_results` — returns every site that touches it. Read the
|
|
511
512
|
instruction at each site, because the instruction is the evidence:
|
|
512
513
|
|
|
513
514
|
- **Writes**: `STA`, `STX`, `STY`
|
|
@@ -540,14 +541,14 @@ field of auto-generated offsets.
|
|
|
540
541
|
|
|
541
542
|
**An external ROM or system routine?** An `e_` prefix, or an address in KERNAL
|
|
542
543
|
space (`$E000`–`$FFFF`), or a standard shadow vector. `lookup` gives the
|
|
543
|
-
routine's published name
|
|
544
|
+
routine's published name. Rename to the conventional form — `$FFD2` becomes
|
|
544
545
|
`KERNAL_CHROUT`, `$EA31` becomes `SYSTEM_IRQ_HANDLER`.
|
|
545
546
|
|
|
546
547
|
**A 16-bit pointer?** Below `$0100`, and used with indirect-indexed `($xx),Y`
|
|
547
548
|
or indexed-indirect `($xx,X)`. Rename to `ptr_`/`vec_` form and comment what it
|
|
548
549
|
points *to*, which is the thing the name cannot carry.
|
|
549
550
|
|
|
550
|
-
**A flag or bitmask?** Only ever `$00`/`$01` or `$00`/`$FF
|
|
551
|
+
**A flag or bitmask?** Only ever `$00`/`$01` or `$00`/`$FF`. Tested with `BIT`
|
|
551
552
|
or `LDA`/`BEQ`. Name it as a predicate — `is_active`, `has_collided`. When the
|
|
552
553
|
individual bits carry separate meanings, that is an enum: define it with
|
|
553
554
|
`anno_create_project_enum` (`$01 = ACTIVE`, `$02 = COLLIDED`, `$04 =
|
|
@@ -559,8 +560,8 @@ with `CPX`/`CPY`/`CMP`. `loop_idx`, `sprite_count`, `delay_timer`.
|
|
|
559
560
|
|
|
560
561
|
**A state variable?** Several distinct values, often feeding a dispatch
|
|
561
562
|
(`ASL` / `TAX` / `JMP (table,X)`). Name it `game_state` or `current_mode` — and
|
|
562
|
-
these are the best enum candidates of all. Look for an existing enum first
|
|
563
|
-
|
|
563
|
+
these are the best enum candidates of all. Look for an existing enum first.
|
|
564
|
+
Define one (`0 = INIT`, `1 = TITLE`, `2 = GAMEPLAY`, `3 = GAME_OVER`) with a
|
|
564
565
|
real `description` if none matches, then apply it to every instruction reading
|
|
565
566
|
or writing the variable.
|
|
566
567
|
|
|
@@ -612,19 +613,19 @@ still readable even though the store cannot format it.
|
|
|
612
613
|
variable, dead.
|
|
613
614
|
- **Evidence**: the specific cross-references or usage patterns that decided
|
|
614
615
|
it. A classification with no evidence line is a guess wearing a name.
|
|
615
|
-
- **Actions taken**: what
|
|
616
|
+
- **Actions taken**: what you renamed, what you commented, which enums were
|
|
616
617
|
defined or applied.
|
|
617
618
|
- **Uncertainty**: if `anno_get_cross_references` returned nothing, say which
|
|
618
619
|
of the three explanations in step 2 you could and could not rule out.
|
|
619
620
|
|
|
620
621
|
## Troubleshooting
|
|
621
622
|
|
|
622
|
-
| Symptom |
|
|
623
|
+
| Symptom | Correction |
|
|
623
624
|
|---|---|
|
|
624
|
-
| Comments land on regions too wide to be useful | `--max-span 2
|
|
625
|
-
| A `JSR` or branch target got no comment at all |
|
|
625
|
+
| Comments land on regions too wide to be useful | `--max-span 2`. The default is 4096 bytes. |
|
|
626
|
+
| A `JSR` or branch target got no comment at all | `annotate` caps flow instructions at 2 bytes regardless of `--max-span`. `lookup` the target directly for the ROM routine name. |
|
|
626
627
|
| The output is mostly header | `--no-header`. |
|
|
627
|
-
| `lookup` printed only wide region lines and no specific name | Nothing in the four tables names that address
|
|
628
|
-
| `lookup` printed `(not in memory map)` | Nothing covers it
|
|
629
|
-
| `no memmap.json; run: node driver.mjs memmap` | Restore the committed table with `git checkout` rather than rebuilding
|
|
630
|
-
| `memmap` rewrote `memmap.json` and the diff is large or negative | A source was unreachable or changed
|
|
628
|
+
| `lookup` printed only wide region lines and no specific name | Nothing in the four tables names that address. This answer is normal for the game's own code. Take the region and name the address from what the code does with it. |
|
|
629
|
+
| `lookup` printed `(not in memory map)` | Nothing covers it. Check the address parsed as intended, since a bare `1234` reads as decimal. |
|
|
630
|
+
| `no memmap.json; run: node driver.mjs memmap` | Restore the committed table with `git checkout` rather than rebuilding. The rebuild needs network and overwrites tracked data. |
|
|
631
|
+
| `memmap` rewrote `memmap.json` and the diff is large or negative | A source was unreachable or changed. `git checkout` the file. |
|
|
@@ -14,11 +14,11 @@ S=src/skills/c64-petcat/scripts/petcat.mjs # from the repo root
|
|
|
14
14
|
node $S decode --image path/to/program.prg # detokenize + resolve the SYS handover
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
The script wraps `petcat` and nothing else.
|
|
18
|
-
is optional, defaulting to the image's own directory, exactly like
|
|
19
|
-
`acme-build`'s own `--out-dir` default.
|
|
20
|
-
**workspace-relative** to the smallest ancestor directory containing both
|
|
21
|
-
before the request ever reaches the seam — the same resolution
|
|
17
|
+
The script wraps `petcat` and nothing else. The script requires `--image`.
|
|
18
|
+
`--out-dir` is optional, defaulting to the image's own directory, exactly like
|
|
19
|
+
`acme-build`'s own `--out-dir` default. The script resolves both
|
|
20
|
+
**workspace-relative** to the smallest ancestor directory containing both.
|
|
21
|
+
This happens before the request ever reaches the seam — the same resolution
|
|
22
22
|
`acme-build`/`c64-disk-access` already go through.
|
|
23
23
|
|
|
24
24
|
Options: `--image PATH` `--out-dir DIR` `--json`.
|
|
@@ -67,15 +67,15 @@ posture `acme-build` already takes for its own assembler target.
|
|
|
67
67
|
|
|
68
68
|
## Failure shape
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
missing file —
|
|
72
|
-
non-zero exit code
|
|
73
|
-
verdict. `petcat` itself exits `0` even on garbage input
|
|
74
|
-
classifier, not the exit code, is what decides success here.
|
|
70
|
+
The seam reports a file `petcat` does not recognise as a BASIC program at
|
|
71
|
+
all — including a missing file — as `{"ok":false,"message":"..."}` with a
|
|
72
|
+
non-zero exit code. It never reports a success envelope carrying an empty
|
|
73
|
+
or guessed verdict. `petcat` itself exits `0` even on garbage input. The
|
|
74
|
+
seam's own classifier, not the exit code, is what decides success here.
|
|
75
75
|
|
|
76
76
|
## What this skill does NOT do
|
|
77
77
|
|
|
78
|
-
- **No direct binary spawn.** `petcat` runs host-side
|
|
78
|
+
- **No direct binary spawn.** `petcat` runs host-side. This script only ever
|
|
79
79
|
constructs a typed request and reads the produced listing file back off
|
|
80
80
|
the shared workspace tree — the host-tool execution seam is the only
|
|
81
81
|
route.
|