@henols/c64-re-tools 2.0.0-rc.12 → 2.0.0-rc.15

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.
Files changed (66) hide show
  1. package/package.json +1 -1
  2. package/skills/c64-assembler/SKILL.md +9 -2
  3. package/skills/c64-assembler/scripts/assemble.ts +13 -5
  4. package/skills/c64-disk/SKILL.md +1 -1
  5. package/skills/c64-disk/scripts/disk.ts +1 -1
  6. package/skills/c64-emulator/SKILL.md +8 -4
  7. package/skills/c64-knowledge/SKILL.md +43 -5
  8. package/skills/c64-knowledge/scripts/knowledge.ts +227 -16
  9. package/skills/c64-memory-map/SKILL.md +2 -2
  10. package/skills/c64-provenance/SKILL.md +1 -1
  11. package/skills/c64-provenance/scripts/provenance.ts +4 -4
  12. package/skills/c64-reverse-engineering/SKILL.md +3 -1
  13. package/skills/c64-source/SKILL.md +30 -6
  14. package/skills/c64-source/scripts/generate.ts +205 -25
  15. package/skills/c64-source/scripts/{loader.ts → lib/loader.ts} +3 -1
  16. package/skills/c64-source/scripts/{opcodes.ts → lib/opcodes.ts} +1 -1
  17. package/skills/c64-source/scripts/{source.ts → lib/source.ts} +303 -25
  18. package/skills/c64-static-analysis/SKILL.md +6 -3
  19. package/skills/c64-static-analysis/scripts/analyze.ts +103 -10
  20. package/skills/c64-static-analysis/scripts/{coverage.ts → lib/coverage.ts} +20 -0
  21. package/skills/c64-static-analysis/scripts/{idioms.ts → lib/idioms.ts} +14 -3
  22. package/skills/c64-static-analysis/scripts/lib/macros.ts +233 -0
  23. package/skills/c64-testing/SKILL.md +3 -2
  24. package/skills/c64-testing/references/scenario-format.md +1 -1
  25. package/skills/c64-testing/scripts/checklist.ts +1 -1
  26. package/skills/c64-testing/scripts/{scenario.ts → lib/scenario.ts} +11 -9
  27. package/skills/c64-testing/scripts/run.ts +4 -4
  28. package/skills/c64-testing/scripts/test.ts +1 -1
  29. package/skills/c64-unpacker/SKILL.md +4 -1
  30. package/skills/c64-unpacker/scripts/unpack.ts +4 -4
  31. package/src/c64.ts +10 -0
  32. package/src/cli/cleanup.ts +1 -1
  33. package/src/cli/main.ts +2 -1
  34. package/src/cli/status.ts +69 -2
  35. package/src/host/main.ts +14 -1
  36. package/src/host/vice/session.ts +71 -15
  37. package/src/host-client/steps.ts +7 -2
  38. package/src/host-client/vice-session.ts +5 -3
  39. package/src/knowledge/conflicts.ts +12 -0
  40. package/src/knowledge/history.ts +30 -1
  41. package/src/knowledge/read.ts +128 -1
  42. package/src/knowledge/schema.ts +48 -2
  43. package/src/knowledge/text.ts +38 -11
  44. package/src/knowledge/write.ts +368 -6
  45. package/src/mcp/server.ts +1 -0
  46. package/src/mcp/tools/debug.ts +22 -7
  47. package/src/mcp/tools/execution.ts +17 -3
  48. package/src/mcp/tools/machine.ts +11 -2
  49. package/src/mcp/tools/media.ts +1 -0
  50. package/src/mcp/tools/memory.ts +7 -2
  51. package/src/mcp/tools/video.ts +3 -4
  52. package/src/native/ghidra/language/c64rt_6510.slaspec +4 -1
  53. package/src/protocol/vice.ts +32 -6
  54. /package/skills/c64-assembler/scripts/{compare.ts → lib/compare.ts} +0 -0
  55. /package/skills/c64-disk/scripts/{containers.ts → lib/containers.ts} +0 -0
  56. /package/skills/c64-provenance/scripts/{compare.ts → lib/compare.ts} +0 -0
  57. /package/skills/c64-provenance/scripts/{library.ts → lib/library.ts} +0 -0
  58. /package/skills/c64-provenance/scripts/{runtime.ts → lib/runtime.ts} +0 -0
  59. /package/skills/c64-provenance/scripts/{separate.ts → lib/separate.ts} +0 -0
  60. /package/skills/c64-static-analysis/scripts/{findings.ts → lib/findings.ts} +0 -0
  61. /package/skills/c64-static-analysis/scripts/{instructions.ts → lib/instructions.ts} +0 -0
  62. /package/skills/c64-static-analysis/scripts/{pointers.ts → lib/pointers.ts} +0 -0
  63. /package/skills/c64-unpacker/scripts/{evidence.ts → lib/evidence.ts} +0 -0
  64. /package/skills/c64-unpacker/scripts/{loads.ts → lib/loads.ts} +0 -0
  65. /package/skills/c64-unpacker/scripts/{machine.ts → lib/machine.ts} +0 -0
  66. /package/skills/c64-unpacker/scripts/{stages.ts → lib/stages.ts} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@henols/c64-re-tools",
3
- "version": "2.0.0-rc.12",
3
+ "version": "2.0.0-rc.15",
4
4
  "description": "Agent-friendly Commodore 64 engineering toolkit for reverse engineering, debugging, development and testing.",
5
5
  "license": "MIT",
6
6
  "author": "Henrik Olsson",
@@ -32,10 +32,12 @@ node <skill>/scripts/assemble.ts --source-root src --entry main.a --out build/ga
32
32
  | `--define DEBUG=1` | An assembler symbol: an integer, also as `$` hex, or `true` or `false`. Use it again for more symbols. |
33
33
  | `--set-pc '$0801'` | The start address when the source does not set one. |
34
34
  | `--compare unpacked/image.json` | Check the program byte by byte against a reference. The reference is the `image.json` of the c64-unpacker skill, a PRG, or 64 KiB of memory. |
35
+ | `--plain` | Write only the bytes of the program, without the 2-byte load address of a PRG. `loadRange` still tells where the bytes go. |
36
+ | `--all-symbols` | List all symbols. Without it, the list does not include the constants that the source does not use. `unusedConstants` gives their count. |
35
37
 
36
38
  The script copies the full source root. Put all files that the program includes under it. Version control directories stay out.
37
39
 
38
- The script prints one JSON object. The target CPU is the 6510 and the output is always a C64 PRG.
40
+ The script prints one JSON object. The target CPU is the 6510. The output is a C64 PRG, or the bytes only with `--plain`.
39
41
 
40
42
  ### Project folder
41
43
 
@@ -48,10 +50,15 @@ The script prints one JSON object. The target CPU is the 6510 and the output is
48
50
 
49
51
  1. Find the source root and the entry source. The entry source sets its own start address with `* = $0801` or similar.
50
52
  2. Run the script.
51
- 3. If `assembled` is `true`, the PRG is at `output`. `loadRange` tells where it loads. `symbols` gives each symbol as an `address` or a `value`.
53
+ 3. If `assembled` is `true`, the PRG is at `output`. `loadRange` tells where it loads. `symbols` gives each symbol:
54
+ - Kind `address` has a value in `loadRange`. It gives the `address`.
55
+ - Kind `constant` has a value outside `loadRange`. It gives the `value` as `$` and four or more hex digits. A label in a `!pseudopc` block can be a constant, because its value is the run address, not the load address.
56
+ - `used` is `false` when the source does not use the symbol.
52
57
  4. If `assembled` is `false`, read `diagnostics`. Each one has a severity, a file, a line and a message. Correct the source and run the script again.
53
58
  5. To run the program, give the PRG path to the c64-emulator skill.
54
59
 
60
+ The source of the c64-source skill has switches. Each switch is 0 when the build does not define it. `--define CRACK=1` puts in the patches of the switch `CRACK`. With `--compare`, only the bytes of those patches are different.
61
+
55
62
  ## Knowledge
56
63
 
57
64
  Automatic write:
@@ -12,7 +12,7 @@ import { localToolContext } from "#src/native/local.ts";
12
12
  import type { AcmeParams } from "#src/native/types.ts";
13
13
  import { resolveProjectPath } from "#src/project.ts";
14
14
  import { runScript, UsageError } from "#src/script.ts";
15
- import { compareBuild } from "./compare.ts";
15
+ import { compareBuild } from "./lib/compare.ts";
16
16
 
17
17
  const USAGE = `assemble.ts --source-root <dir> --entry <file> --out <file.prg> [options]
18
18
 
@@ -24,8 +24,10 @@ const USAGE = `assemble.ts --source-root <dir> --entry <file> --out <file.prg> [
24
24
  --set-pc <address> start address when the source sets none, for example '$0801'
25
25
  --compare <file> check the program byte by byte against an image.json of the
26
26
  c64-unpacker skill (each segment), a PRG, or 64 KiB of memory
27
+ --plain write the bytes only, without the 2-byte load address of a PRG
28
+ --all-symbols list also the constants that the source does not use
27
29
 
28
- The result is one JSON object. Addresses are $ and four hex digits.`;
30
+ The result is one JSON object. Addresses and symbol values are $ and at least four hex digits.`;
29
31
 
30
32
  function parseDefine(text: string): [string, number | boolean] {
31
33
  const match = /^([A-Za-z_][A-Za-z0-9_]*)=(.+)$/.exec(text);
@@ -49,6 +51,8 @@ async function run(argv: string[]): Promise<{ output: unknown; failed: boolean }
49
51
  define: { type: "string", multiple: true },
50
52
  "set-pc": { type: "string" },
51
53
  compare: { type: "string" },
54
+ plain: { type: "boolean" },
55
+ "all-symbols": { type: "boolean" },
52
56
  help: { type: "boolean" },
53
57
  },
54
58
  });
@@ -79,19 +83,23 @@ async function run(argv: string[]): Promise<{ output: unknown; failed: boolean }
79
83
  const { result, attachments } = await assemble(params, tree.contents, localToolContext());
80
84
  if (!result.assembled) return { output: { assembled: false, diagnostics: result.diagnostics }, failed: true };
81
85
  mkdirSync(dirname(outPath), { recursive: true });
82
- writeFileSync(outPath, attachments![0]!);
86
+ writeFileSync(outPath, values.plain ? attachments![0]!.subarray(2) : attachments![0]!);
83
87
  const range = result.loadRange!;
84
88
  const compared = values.compare === undefined ? undefined : compareBuild(attachments![0]!, values.compare);
89
+ // An include file of platform names gives many constants that the program does not use.
90
+ const listed = result.symbols!.filter((symbol) => values["all-symbols"] || symbol.kind === "address" || symbol.used);
85
91
  return {
86
92
  output: {
87
93
  assembled: true,
88
94
  output: out,
95
+ ...(values.plain ? { plain: true } : {}),
89
96
  loadRange: { start: formatC64Address(range.start), end: formatC64Address(range.end), bytes: range.bytes },
90
- symbols: result.symbols!.map((symbol) =>
97
+ symbols: listed.map((symbol) =>
91
98
  symbol.kind === "address"
92
99
  ? { name: symbol.name, kind: "address", address: formatC64Address(symbol.address), used: symbol.used }
93
- : { name: symbol.name, kind: "constant", value: symbol.value, used: symbol.used },
100
+ : { name: symbol.name, kind: "constant", value: `$${symbol.value.toString(16).padStart(4, "0")}`, used: symbol.used },
94
101
  ),
102
+ ...(values["all-symbols"] ? {} : { unusedConstants: result.symbols!.length - listed.length }),
95
103
  diagnostics: result.diagnostics,
96
104
  ...(compared === undefined ? {} : { compare: compared }),
97
105
  },
@@ -40,7 +40,7 @@ node <skill>/scripts/disk.ts <action> <image> [name] [--out <file>]
40
40
 
41
41
  The script prints one JSON object.
42
42
 
43
- File names show the characters that the C64 shows in a directory list. A byte that has no character shows as `{$xx}`, for example `{$c1}`. Write the name in the same form. The letter case of a name is not important. Put the name in single quotes in a shell, for example `'GAME {$c1}'`.
43
+ File names show the characters that the C64 shows in a directory list. A byte that has no character shows as `{$xx}`, for example `{$c1}`. Write the name in the same form. The letter case of a name is not important. Put the name in single quotes in a shell, for example `'GAME {$c1}'`. A name that starts with `-` needs `--` before it, after all options, for example `read d.d64 --out x.prg -- '-----'`.
44
44
 
45
45
  ### Project folder
46
46
 
@@ -11,7 +11,7 @@ import { inspectDisk } from "#src/host-client/tools.ts";
11
11
  import { readProjectFile, writeProjectFile } from "#src/host-client/transfer.ts";
12
12
  import { resolveProjectPath } from "#src/project.ts";
13
13
  import { runScript, UsageError } from "#src/script.ts";
14
- import { ContainerError, parseCrt, parseT64, tapeFile } from "./containers.ts";
14
+ import { ContainerError, parseCrt, parseT64, tapeFile } from "./lib/containers.ts";
15
15
 
16
16
  const USAGE = `disk.ts <action> <image> [name] [--out <file>]
17
17
 
@@ -25,7 +25,7 @@ Use only the MCP tools. Each MCP session has its own C64. Nothing else can chang
25
25
 
26
26
  | Need | Tool |
27
27
  |---|---|
28
- | Run state, video standard, warp mode, window | `c64_status` |
28
+ | Run state, video standard, warp mode, window, version of the MCP server | `c64_status` |
29
29
  | Reset, power cycle | `c64_reset` |
30
30
  | Fast emulation | `c64_warp` |
31
31
  | Show the C64 to the user in a window, hide it again | `c64_window` |
@@ -48,10 +48,15 @@ Use only the MCP tools. Each MCP session has its own C64. Nothing else can chang
48
48
 
49
49
  Each memory and register tool has a `space`. Use `c64` for the computer. Use `drive8` for the CPU of the 1541 disk drive. The memory `view` is `cpu` or `ram`. With `cpu`, you see what the CPU sees now, with ROM and I/O where the memory configuration puts them. With `ram`, you see the RAM under them.
50
50
 
51
- For a large result, give `out` with a path in the project. `c64_memory_read`, `c64_disassemble`, `c64_cpu_history` and `c64_screen` then write the result to that file. The answer gives only the file, the number of bytes and a SHA-256. Use it for a memory dump of more than a few hundred bytes, a long listing, or a screen that the user wants to keep.
51
+ For a large result, give `out` with a path in the project. `c64_memory_read`, `c64_disassemble`, `c64_cpu_history` and `c64_screen` then write the result to that file. The answer gives only the file, the number of bytes and a SHA-256. Use it for a memory dump of more than a few hundred bytes, a long listing, or a screen that the user wants to keep. `c64_memmap` action `read` and `c64_snapshot` action `save` also take `out`.
52
52
 
53
53
  `c64_memmap` keeps RAM, ROM and I/O apart. Use action `summary` to see which code ran. Use action `read` with `out` to keep a coverage run as a file, for example `coverage/attract.bin`. Clear the map before each run that you want to keep apart.
54
54
 
55
+ - Only the first byte of an instruction gets execute. Thus `read` without `out` gives a new range at each instruction of code. For code, use `summary`, or `read` with `out`.
56
+ - A read on a byte right after executed code, or at a return address, can be a dummy read of the 6502. The CPU reads such a byte but does not use it.
57
+
58
+ `c64_profile` gives the routines that used the most cycles since the session started, the last `clear` or the last `c64_window`. Use action `clear` before the part of the program that you want to measure. The profiler gives the cycles to the routine that a JSR called last. Code that the CPU enters with JMP or a branch counts for that routine. After `c64_window` or a snapshot restore, the profiler of VICE keeps the routines that ran before the restore. Then `c64_profile` can give the cycles of the program to such a routine, for example `$fd50`. Do not trust the routine addresses of `c64_profile` after a restore.
59
+
55
60
  ### Project folder
56
61
 
57
62
  Paths (`path`, `file` and `out`) are relative to the project folder. A project folder holds `.c64-re-tools/`. The tools use the nearest project folder at or above the folder where the agent started. If that folder is not in a project and has projects below it, a tool with a path refuses and lists them. Then give `project` with the project folder, for example `"project": "game"`. Give the same folder as the `--project` of the skill scripts. A tool without a path does not need `project`.
@@ -62,7 +67,7 @@ Paths (`path`, `file` and `out`) are relative to the project folder. A project f
62
67
  2. Get the machine state with `c64_status`.
63
68
  3. Load the subject if it is not loaded. Use `c64_autostart` to start it as a user does. Use `c64_program_load` to put a PRG in memory with no start.
64
69
  4. Set the stop condition. Use a breakpoint, a watchpoint or a `c64_run_until` target. Add a typed condition when the stop must occur only in one state. The `list` result shows the condition of each breakpoint and each watchpoint.
65
- 5. Run, step or give input. Prefer `c64_run_until` and `advance-frames` to waits. They stop at the same emulated time on every run.
70
+ 5. Run, step or give input. Prefer `c64_run_until` and `advance-frames` to waits. They stop at the same emulated time on every run. To wait for a breakpoint or a watchpoint, use `advance-frames` with a large count. `stopReason` and `pointId` in the result tell what stopped the CPU. `c64_status` also gives them.
66
71
  6. Read only the state that answers the question. To read several things from one moment, use `c64_observe`.
67
72
  7. Interpret the evidence. Keep the observed facts apart from your conclusions.
68
73
 
@@ -76,7 +81,6 @@ Step, next and until-return work only in space `c64`. The emulator cannot stop t
76
81
 
77
82
  `c64_keyboard` puts keys in the keyboard queue of the KERNAL. A program that reads the keyboard hardware directly does not see them. Many games do this. The emulator has no command that presses one key of the keyboard matrix. For such a program:
78
83
 
79
- - After `c64_window` or a snapshot restore, the profiler of VICE keeps the routines that ran before the restore. Then `c64_profile` can give the cycles of the program to such a routine, for example `$fd50`. Do not trust the routine addresses of `c64_profile` after a restore.
80
84
  - VICE 3.10 and older have a known flaw: bits 5-7 of `$DC00` and `$DC01` are always 0. Then `emulatorFlaw` in the result of `c64_keyboard` and `c64_joystick` gives the flaw. With this flaw, a wait for any key that reads all keyboard columns at one time ends without a key. A wait for one specific key, or a compare of the full byte of a joystick port, never ends. Tell the user about the flaw. The next VICE release and the VICE nightly builds do not have it. Joystick port 1 uses the same lines as the keyboard.
81
85
  - For one specific key, for example F1 or RUN/STOP, open the window and ask the user to press the key.
82
86
  - Do not change the program to make it accept a key.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: c64-knowledge
3
- description: Use this skill to read, write, correct and review the durable knowledge of a C64 project in .c64-re-tools/knowledge/. It gives the knowledge at an address, and it names symbols, classifies memory regions, sets comments and records references. It also shows the history of each change, and it can revert to an earlier revision. Do not use it for live emulator state or for static analysis.
3
+ description: Use this skill to read, write, correct and review the durable knowledge of a C64 project in .c64-re-tools/knowledge/. It gives the knowledge at an address, and it names symbols, classifies memory regions, sets comments and records references. It records patches and macros for the generated source. It also shows the history of each change, and it can revert to an earlier revision. Do not use it for live emulator state or for static analysis.
4
4
  ---
5
5
 
6
6
  # c64-knowledge
@@ -9,7 +9,7 @@ description: Use this skill to read, write, correct and review the durable knowl
9
9
 
10
10
  Read, write, correct and review the durable understanding of a C64 project. The knowledge is text in `.c64-re-tools/knowledge/` in the project folder: one JSON line for each row. Commit that folder with git. The script keeps an index of the text in `.c64-re-tools/local/knowledge.db` and makes the index again when the text changes. Do not commit the index.
11
11
 
12
- This skill is the only write path for conclusions of the user and the LLM. It does not run an emulator or an analyzer.
12
+ This skill is the only write path for conclusions of the user and the LLM. It does not run an emulator or an analyzer. Write the knowledge only with the script. The script checks each write. Do not write or edit the files in `.c64-re-tools/knowledge/` or the index yourself.
13
13
 
14
14
  ## Inputs
15
15
 
@@ -47,9 +47,14 @@ The script prints one JSON object. An error prints `{"error": {"code": ..., "mes
47
47
  | Start a file of generated source | `module '$2000' player.asm --title 'Player movement'` / `unmodule '$2000'` |
48
48
  | Write the operand of an instruction as an expression | `operand '$8079' --lo irq_handler --image unpacked/image.json` / `unoperand '$8079'` |
49
49
  | Operand expressions | `operands` with `--start` and `--end` |
50
+ | Replace a range with code when a switch is on | `patch '$100e' '$1010' CRACK --code-file crack.asm --image unpacked/image.json` / `unpatch '$100e'` |
51
+ | Patches and switches | `patches` with `--switch`, and `switches` |
52
+ | Write a macro | `macro inc16 --params dst --body-file inc16.asm` / `unmacro inc16` |
53
+ | Write instructions as one use of a macro | `use '$1005' '$100a' inc16 --args ptr --image unpacked/image.json` / `unuse '$1005'` |
54
+ | Macros and their uses | `macros`, and `uses` with `--start`, `--end` and `--macro` |
50
55
  | Files of generated source | `modules` |
51
56
  | The address spaces that hold knowledge | `spaces` |
52
- | History | `history '$2100'`, `history --name update_player`, `revisions`, `revision 20261015T2145` |
57
+ | History | `history '$2100'`, `history --name update_player`, `history --macro inc16`, `revisions`, `revision 20261015T2145` |
53
58
  | Go back to an earlier state | `revert 20261015T2145` |
54
59
  | Decide the conflicts after a git merge | `merge --reason 'merge of two computers'` |
55
60
 
@@ -122,14 +127,19 @@ The ops and their fields:
122
127
  | `unmodule` | `start` |
123
128
  | `operand` | `address`, `select` (`lo`, `hi`, `value` or `expr`), `symbol` and `offset` (optional), or `expression` for `expr` |
124
129
  | `unoperand` | `address` |
130
+ | `patch` | `start`, `end`, `switch`, `code` (empty for NOP only), `comment` (optional) |
131
+ | `unpatch`, `unuse` | `start` |
132
+ | `macro` | `name`, `params` (a list or a comma list), `body`, `comment` (optional) |
133
+ | `unmacro` | `name` |
134
+ | `use` | `start`, `end`, `macro`, `args` (a list or a comma list) |
125
135
 
126
- A `line` comment is a line of its own above the address. A `side` comment is at the end of the line of the address. All writes become one revision. If the knowledge refuses one write, the script writes nothing, and the error names the write.
136
+ A `line` comment is a line of its own above the address. A `side` comment is at the end of the line of the address. `apply` with an `operand`, `patch` or `use` write needs `--image`. All writes become one revision. If the knowledge refuses one write, the script writes nothing, and the error names the write.
127
137
 
128
138
  The c64-provenance skill writes a batch with `match --out`. The batch holds the names of library routines at their addresses in this program. Read the `batch.leftOut` of its result first. Then apply the batch with the command in its `apply`.
129
139
 
130
140
  ## Modules
131
141
 
132
- A module tells the c64-source skill where a file of the generated source starts. The file runs to the next module or to the end of its segment. Each address has one module, and each file name has one module. A file name has letters, digits, underscores or hyphens, and ends in `.asm`. The c64-source skill writes `main.asm`, `loader.asm` and `constants.asm` itself. Thus a module cannot have one of these names, in upper or lower case. The title becomes the first line of the file. A `module` write without a title keeps the title that the module has. Modules have a history, and `revert` restores them.
142
+ A module tells the c64-source skill where a file of the generated source starts. The file runs to the next module or to the end of its segment. Each address has one module, and each file name has one module. A file name has letters, digits, underscores or hyphens, and ends in `.asm`. The c64-source skill writes `main.asm`, `loader.asm`, `constants.asm` and `macros.asm` itself. Thus a module cannot have one of these names, in upper or lower case. The title becomes the first line of the file. A `module` write without a title keeps the title that the module has. Modules have a history, and `revert` restores them.
133
143
 
134
144
  ## Operand expressions
135
145
 
@@ -153,6 +163,34 @@ Give one selector:
153
163
 
154
164
  Write an operand expression for each immediate that is a byte of an address. Also write one for each table read through the byte before the table. The pointer candidates of the c64-static-analysis skill show many of these places.
155
165
 
166
+ ## Code switches
167
+
168
+ A patch is ACME code that replaces a range of the image when the build defines its switch as 1. Use patches to change the program, for example for a crack, a trainer or a debug hook. The default build does not define the switch. Thus the c64-source skill still makes a source that is identical to the image.
169
+
170
+ - A switch name is upper case, for example `CRACK` or `TRAINER`. It cannot be the name of a symbol or a platform name.
171
+ - Many patches can have the same switch. The c64-source skill builds each switch on its own. It does not build two switches together.
172
+ - The code must fit in the range. NOP ($EA) fills the bytes after the code. `--nop` gives a range of NOP only.
173
+ - `--code` gives the code as text. `--code-file` reads the code from a project file. The code can use the labels and the macros of the source, and local labels with a dot, for example `.skip`.
174
+ - The braces in the code must be pairs, because the source puts the code inside `{ }`.
175
+ - A patch cannot overlap another patch or a macro use.
176
+ - Give the image with `--image`. Each byte of the range must be in the image.
177
+ - A `patch` write without `--comment` keeps the comment that the patch has.
178
+
179
+ Build the program with a switch on with the c64-assembler skill: `--define CRACK=1`.
180
+
181
+ ## Macros
182
+
183
+ A macro writes a run of instructions as one line of the source, for example `+inc16 ptr`. Use macros to make the source shorter and easier to read.
184
+
185
+ - `macro` writes the ACME macro: its name, its params and its body. `--params` gives the params as a comma list, without a dot. The body uses each param with a dot, for example `.dst`.
186
+ - `use` writes the instructions from the start to the end as one use of a macro. `--args` gives one expression for each param, as a comma list. Each name in an arg is a symbol of the knowledge or a platform name.
187
+ - The range of a use is complete instructions. Give the image with `--image`.
188
+ - A `rename` of a symbol changes the name in each arg. The knowledge refuses `remove-symbol` while an arg uses the symbol.
189
+ - The knowledge refuses `unmacro` while the macro has uses. It also refuses a change of the number of params while the macro has uses.
190
+ - A use cannot overlap a patch or another use.
191
+
192
+ The c64-source skill writes a use only when the use gives the bytes of the image. If not, it writes the instructions and gives the reason. The c64-static-analysis skill finds uses of known 6502 idioms and writes them to a batch with `--macro-batch`.
193
+
156
194
  ## Removals
157
195
 
158
196
  `remove-symbol`, `unclassify` and `unreference` block the place for DXA and Ghidra. An analysis does not add a symbol at that address, a region in that range or that reference again. This applies to every removed fact, also to a fact from the LLM.