@henols/c64-re-tools 2.0.0-rc.2 → 2.0.0-rc.21
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/README.md +28 -62
- package/distribution/package.ts +1 -16
- package/distribution/plugin.ts +5 -3
- package/package.json +1 -1
- package/skills/c64-assembler/SKILL.md +25 -6
- package/skills/c64-assembler/scripts/assemble.ts +45 -10
- package/skills/c64-assembler/scripts/lib/compare.ts +48 -0
- package/skills/c64-basic/SKILL.md +15 -7
- package/skills/c64-basic/scripts/basic.ts +4 -4
- package/skills/c64-disk/SKILL.md +34 -11
- package/skills/c64-disk/scripts/disk.ts +65 -10
- package/skills/c64-disk/scripts/lib/containers.ts +124 -0
- package/skills/c64-docs/SKILL.md +138 -0
- package/skills/c64-docs/references/page-types.md +141 -0
- package/skills/c64-docs/references/style.md +43 -0
- package/skills/c64-docs/scripts/generate.ts +102 -0
- package/skills/c64-docs/scripts/lib/links.ts +155 -0
- package/skills/c64-docs/scripts/lib/markdown.ts +79 -0
- package/skills/c64-docs/scripts/lib/reference.ts +406 -0
- package/skills/c64-docs/scripts/lib/source-map.ts +81 -0
- package/skills/c64-docs/scripts/link.ts +207 -0
- package/skills/c64-emulator/SKILL.md +29 -8
- package/skills/c64-knowledge/SKILL.md +201 -15
- package/skills/c64-knowledge/scripts/knowledge.ts +927 -78
- package/skills/c64-knowledge/scripts/lib/listing.ts +162 -0
- package/skills/c64-memory-map/SKILL.md +14 -2
- package/skills/c64-memory-map/scripts/memmap.ts +15 -4
- package/skills/c64-provenance/SKILL.md +100 -11
- package/skills/c64-provenance/scripts/lib/compare.ts +152 -0
- package/skills/c64-provenance/scripts/lib/library.ts +584 -0
- package/skills/c64-provenance/scripts/lib/runtime.ts +191 -0
- package/skills/c64-provenance/scripts/lib/separate.ts +140 -0
- package/skills/c64-provenance/scripts/provenance.ts +477 -24
- package/skills/c64-reverse-engineering/SKILL.md +90 -11
- package/skills/c64-source/SKILL.md +174 -0
- package/skills/c64-source/scripts/generate.ts +788 -0
- package/skills/c64-source/scripts/lib/loader.ts +630 -0
- package/skills/c64-source/scripts/lib/source.ts +1121 -0
- package/skills/c64-static-analysis/SKILL.md +53 -13
- package/skills/c64-static-analysis/scripts/analyze.ts +260 -31
- package/skills/c64-static-analysis/scripts/lib/coverage.ts +72 -0
- package/skills/c64-static-analysis/scripts/{findings.ts → lib/findings.ts} +11 -5
- package/skills/c64-static-analysis/scripts/lib/idioms.ts +158 -0
- package/skills/c64-static-analysis/scripts/lib/instructions.ts +105 -0
- package/skills/c64-static-analysis/scripts/lib/macros.ts +233 -0
- package/skills/c64-static-analysis/scripts/lib/pitfalls.ts +68 -0
- package/skills/c64-static-analysis/scripts/lib/pointers.ts +108 -0
- package/skills/c64-testing/SKILL.md +57 -4
- package/skills/c64-testing/references/scenario-format.md +50 -6
- package/skills/c64-testing/scripts/checklist.ts +3 -3
- package/skills/c64-testing/scripts/diff.ts +167 -0
- package/skills/c64-testing/scripts/lib/diff.ts +70 -0
- package/skills/c64-testing/scripts/{scenario.ts → lib/scenario.ts} +183 -152
- package/skills/c64-testing/scripts/run.ts +241 -0
- package/skills/c64-testing/scripts/test.ts +20 -10
- package/skills/c64-unpacker/SKILL.md +88 -21
- package/skills/c64-unpacker/scripts/lib/evidence.ts +207 -0
- package/skills/c64-unpacker/scripts/lib/loads.ts +209 -0
- package/skills/c64-unpacker/scripts/lib/machine.ts +80 -0
- package/skills/c64-unpacker/scripts/lib/stages.ts +142 -0
- package/skills/c64-unpacker/scripts/unpack.ts +545 -61
- package/src/c64.ts +240 -12
- package/src/cli/cleanup.ts +1 -1
- package/src/cli/main.ts +14 -8
- package/src/cli/status.ts +105 -11
- package/src/graphics.ts +158 -0
- package/src/host/main.ts +57 -31
- package/src/host/server.ts +30 -47
- package/src/host/tools/c1541.ts +34 -5
- package/src/host/tools/index.ts +6 -2
- package/src/host/tools/petcat.ts +10 -3
- package/src/host/tools/status.ts +23 -6
- package/src/host/vice/adapter.ts +64 -20
- package/src/host/vice/chips.ts +11 -1
- package/src/host/vice/process.ts +19 -8
- package/src/host/vice/screen.ts +4 -44
- package/src/host/vice/session.ts +343 -60
- package/src/host-client/autostart.ts +55 -0
- package/src/host-client/connect.ts +14 -14
- package/src/host-client/coverage.ts +36 -0
- package/src/host-client/image.ts +63 -0
- package/src/host-client/steps.ts +175 -0
- package/src/host-client/tools.ts +7 -6
- package/src/host-client/transfer.ts +60 -10
- package/src/host-client/vice-session.ts +107 -28
- package/src/knowledge/conflicts.ts +161 -0
- package/src/knowledge/database.ts +150 -38
- package/src/knowledge/expression.ts +209 -0
- package/src/knowledge/graph.ts +104 -0
- package/src/knowledge/history.ts +105 -27
- package/src/knowledge/import.ts +141 -85
- package/src/knowledge/join.ts +211 -0
- package/src/knowledge/program.ts +258 -0
- package/src/knowledge/read.ts +445 -63
- package/src/knowledge/schema.ts +277 -65
- package/src/knowledge/text.ts +415 -0
- package/src/knowledge/write.ts +1145 -150
- package/src/mcp/main.ts +44 -19
- package/src/mcp/output.ts +39 -0
- package/src/mcp/server.ts +15 -4
- package/src/mcp/tools/debug.ts +202 -31
- package/src/mcp/tools/execution.ts +39 -5
- package/src/mcp/tools/input.ts +7 -4
- package/src/mcp/tools/machine.ts +14 -2
- package/src/mcp/tools/media.ts +44 -16
- package/src/mcp/tools/memory.ts +68 -12
- package/src/mcp/tools/video.ts +20 -9
- package/src/native/discover.ts +44 -6
- package/src/native/ghidra/analyze.ts +2 -2
- package/src/native/ghidra/index.ts +19 -3
- package/src/native/ghidra/language/c64rt_6510.slaspec +4 -1
- package/src/native/ghidra/scripts/C64Export.java +33 -1
- package/src/native/ghidra/scripts/C64Prepare.java +7 -1
- package/src/native/status.ts +15 -3
- package/src/native/types.ts +43 -8
- package/src/opcodes.ts +133 -0
- package/src/package.ts +21 -0
- package/{skills/c64-memory-map/scripts → src}/platform.ts +87 -7
- package/src/project.ts +166 -3
- package/src/protocol/messages.ts +17 -10
- package/src/protocol/tools.ts +27 -22
- package/src/protocol/vice.ts +255 -33
- package/src/script.ts +49 -9
- package/src/trace.ts +55 -23
- package/skills/c64-provenance/scripts/compare.ts +0 -92
- package/skills/c64-unpacker/scripts/evidence.ts +0 -135
|
@@ -26,8 +26,30 @@ This skill does not do the specialist work itself.
|
|
|
26
26
|
|
|
27
27
|
This skill uses the other skills. It does not use the host runtime or the emulator directly.
|
|
28
28
|
|
|
29
|
+
### Project folder
|
|
30
|
+
|
|
31
|
+
One repository can hold several programs, with one project folder for each program. A project folder holds `.c64-re-tools/`. Work on one project at a time:
|
|
32
|
+
|
|
33
|
+
- From the root of the repository, give `--project <folder>` to each skill script, and `project` to each emulator tool with a path.
|
|
34
|
+
- Write all files in the project folder. Do not write files at the root of the repository.
|
|
35
|
+
- Write each file that you make for your work in `.c64-re-tools/local/` of the project. Git ignores that folder. Examples are results, batches, step files, runs, snapshots and memory dumps.
|
|
36
|
+
- Move a file out of `.c64-re-tools/local/` only when it is the evidence for a finding. Move it before you give it to `--evidence` of c64-knowledge. `--evidence` refuses a file in `.c64-re-tools/local/`.
|
|
37
|
+
- Put a run that is evidence in `runs/<name>/`, with its run file, its results and the snapshot files that it uses. Change the paths in the run file to the new paths. Then git keeps them, and another person can do the run again.
|
|
38
|
+
- A subagent can have no emulator tools. Give it its experiments as run files of the c64-testing skill. Each run starts its own emulator, so many runs can go at the same time. The emulator of the emulator tools is one machine, for the main session.
|
|
39
|
+
- To name a large program with more agents at the same time, give each agent one range of addresses. Each agent writes a batch with its owner range. Then join the batches with `join` of the c64-knowledge skill, and apply the result one time.
|
|
40
|
+
- Do not write a build script or a merge script. c64-source writes and assembles the loader with `--loader`, and `join` of c64-knowledge joins the batches.
|
|
41
|
+
- Do not write a script that makes a deliverable again, for example a capture, copy or replay script. Commit the deliverable.
|
|
42
|
+
- Write the knowledge only with the c64-knowledge script. Do not write or edit the files in `.c64-re-tools/knowledge/` yourself.
|
|
43
|
+
|
|
29
44
|
## Workflow
|
|
30
45
|
|
|
46
|
+
Select the path for the scope:
|
|
47
|
+
|
|
48
|
+
- A narrow scope, for example one routine, the IRQ handler or the input system: use the loop.
|
|
49
|
+
- A full rebuild of the program: use the stages.
|
|
50
|
+
|
|
51
|
+
### The loop
|
|
52
|
+
|
|
31
53
|
1. Write down the scope. Stop when the scope is complete.
|
|
32
54
|
2. Read the current knowledge for the subject with the c64-knowledge skill. Do not examine again what the knowledge already explains.
|
|
33
55
|
3. Find the next unknown or blocker, and use the specialist for it:
|
|
@@ -41,24 +63,79 @@ This skill uses the other skills. It does not use the host runtime or the emulat
|
|
|
41
63
|
| The routines, code, data and references of the program | c64-static-analysis |
|
|
42
64
|
| The platform meaning of an address or a register | c64-memory-map |
|
|
43
65
|
| Differences between releases of the program | c64-provenance |
|
|
66
|
+
| A routine that another program of the workspace has, for example a music driver | c64-provenance, with the library |
|
|
67
|
+
| Source code from the knowledge | c64-source |
|
|
44
68
|
| Source code to build | c64-assembler |
|
|
45
69
|
| Proof that a rebuild behaves as the original | c64-testing |
|
|
46
70
|
|
|
47
71
|
4. Interpret the result. Keep observed facts apart from your conclusions.
|
|
48
72
|
5. Record each conclusion that the evidence supports with the c64-knowledge skill: names of routines and variables, data classifications, comments.
|
|
49
73
|
6. Go back to step 3 until the scope is complete.
|
|
50
|
-
7. For a rebuild scope: write the source, build it with the c64-assembler skill, and test it against the original with the c64-testing skill.
|
|
51
74
|
|
|
52
|
-
|
|
75
|
+
### The stages of a full rebuild
|
|
76
|
+
|
|
77
|
+
Do the stages in this sequence. Go to the next stage only when its exit check is true, or when the user accepts an exception. Remember each exception for the answer of stage 11.
|
|
78
|
+
|
|
79
|
+
| Stage | Work | Exit check |
|
|
80
|
+
|---|---|---|
|
|
81
|
+
| 1. Acceptance | Ask the user for the criteria of the rebuild. Offer these: identical source, a verified loader, passed c64-testing scenarios, and a list of the code that no run executed. Also offer documentation of the flows, tables, formats and graphics. | The user gave the criteria. |
|
|
82
|
+
| 2. Get | c64-disk: list the disk. Extract the start file into `original/`. | The start file is in the project. |
|
|
83
|
+
| 3. Start | c64-basic: find the SYS address of the BASIC start. | You have the entry address. |
|
|
84
|
+
| 4. Unpack | c64-unpacker: examine the program. Capture a packed program into `.c64-re-tools/local/`. Then c64-knowledge: put the capture, or the PRG of a program without a packer, into the knowledge with `image`. | `program` of c64-knowledge shows the segments and the entry. |
|
|
85
|
+
| 5. Run | c64-emulator and the run of c64-testing: run each part that the scope names. Write a coverage map for each part into `.c64-re-tools/local/`. Then c64-knowledge: add the maps with `coverage`. | `program` of c64-knowledge lists a coverage map for each part that the scope names. |
|
|
86
|
+
| 6. Analyze | c64-static-analysis. It reads the program and the coverage from the knowledge. | No coverage conflict is open. |
|
|
87
|
+
| 7. Name | c64-provenance: if the workspace has a library, find its routines with `match` and apply the batch. Then c64-knowledge and c64-memory-map: name each routine in the scope and give it a comment. Record the modules. When the scope has hundreds of routines, ask the user which routines to name. The source gives the other routines an `l_xxxx` label. | Each routine that the user selected has a name and a comment. |
|
|
88
|
+
| 8. Generate | c64-source into `src/`. For an unpacked program, add `--loader`. | `check.identical` is true. For an unpacked program, `loader.verified` is true. |
|
|
89
|
+
| 9. Build and test | c64-assembler with `--compare` into `build/`. c64-testing scenarios in `tests/`. | The criteria of stage 1 are true. |
|
|
90
|
+
| 10. Document | When the criteria ask for documentation: c64-docs into `README.md` and `docs/`. | `link.ts --check` of c64-docs gives no problem. |
|
|
91
|
+
| 11. Hand over | Find each file that you made outside `.c64-re-tools/local/` and that is not a deliverable. Move it into `.c64-re-tools/local/`. Then give the answer (below). | Each file that you made outside `.c64-re-tools/local/` is a deliverable. |
|
|
92
|
+
|
|
93
|
+
In stage 5, if you cannot get to a part of the program, ask the user how to get to it. Do stages 7 and 8 again until the source is clear. Each run of c64-source writes the source again.
|
|
94
|
+
|
|
95
|
+
After stage 7, save each routine that other programs can have to the library with c64-provenance `routine`. Examples are a music driver, a decruncher and a loader. Ask the user before you make a library.
|
|
96
|
+
|
|
97
|
+
### Deliverables of a full rebuild
|
|
98
|
+
|
|
99
|
+
- `.c64-re-tools/knowledge/` with the program, its entry state, the coverage, the names, the regions, the comments and the modules
|
|
100
|
+
- the generated source
|
|
101
|
+
- the built program and the loader
|
|
102
|
+
- the c64-testing scenarios
|
|
103
|
+
- the documentation in `README.md` and `docs/`, when the criteria ask for it
|
|
104
|
+
- the runs in `runs/` that the knowledge gives as evidence
|
|
105
|
+
- the scripts in `tools/` for the formats of this program, when you wrote them.
|
|
106
|
+
|
|
107
|
+
All other files that you made are not deliverables. Keep them in `.c64-re-tools/local/`. Do not delete a file that the user made.
|
|
108
|
+
|
|
109
|
+
### The answer
|
|
110
|
+
|
|
111
|
+
Give the user a short answer at the end. Do not write a report file. Write a report file only when the user asks for it. The knowledge, `docs/` and the scenarios keep the durable results. The answer has:
|
|
112
|
+
|
|
113
|
+
1. Each criterion of stage 1 and its result, and each exception that the user accepted.
|
|
114
|
+
2. The count of the code ranges that no run executed. The ranges are in the `not_executed.json` file of c64-source.
|
|
115
|
+
3. Open questions: what the evidence does not explain.
|
|
116
|
+
|
|
117
|
+
Keep observed facts apart from your conclusions.
|
|
118
|
+
|
|
119
|
+
### Project layout
|
|
120
|
+
|
|
121
|
+
If the project has no layout, use this one. No script checks it. Each script takes the paths that you give.
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
original/ the disk image or the program as you got it
|
|
125
|
+
src/ the generated source from c64-source
|
|
126
|
+
build/ programs from c64-assembler
|
|
127
|
+
tests/ c64-testing scenarios
|
|
128
|
+
runs/ the runs that the knowledge gives as evidence
|
|
129
|
+
docs/ the documentation from c64-docs, with the reference in docs/reference/
|
|
130
|
+
tools/ scripts for the formats of this program only
|
|
131
|
+
README.md the entry page of the documentation from c64-docs
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Commit each folder of the layout and `.c64-re-tools/knowledge/`. The knowledge holds the program, the entry state and the coverage, so the project needs no other folder for them. Put all other files that you make in `.c64-re-tools/local/`, also the captures and the coverage maps after you put them into the knowledge. Do not let git ignore a folder of the layout. Do not change the `.gitignore` files of the project.
|
|
135
|
+
|
|
136
|
+
If the project has a layout, use that layout.
|
|
53
137
|
|
|
54
|
-
|
|
55
|
-
2. c64-basic: find the SYS address of the BASIC start.
|
|
56
|
-
3. c64-unpacker: find out if a packer compressed the program. Unpack it if necessary.
|
|
57
|
-
4. c64-emulator: run the program and observe it.
|
|
58
|
-
5. c64-static-analysis: find the routines, regions and references.
|
|
59
|
-
6. c64-knowledge and c64-memory-map: name the important routines and variables.
|
|
60
|
-
7. c64-static-analysis again: Ghidra now uses the names.
|
|
61
|
-
8. c64-assembler and c64-testing: rebuild and test when the scope asks for it.
|
|
138
|
+
A workspace with several projects keeps its library of routines in `library/` beside the projects. The library is not a project folder.
|
|
62
139
|
|
|
63
140
|
## Knowledge
|
|
64
141
|
|
|
@@ -76,10 +153,12 @@ Record durable conclusions with the c64-knowledge skill. Do not store:
|
|
|
76
153
|
|
|
77
154
|
## Result
|
|
78
155
|
|
|
79
|
-
A clear answer for the scope, with the durable conclusions in the project knowledge. For a rebuild
|
|
156
|
+
A clear answer for the scope, with the durable conclusions in the project knowledge. For a full rebuild, the deliverables and the answer of stage 11, with the criteria of the user met or each exception in the answer.
|
|
80
157
|
|
|
81
158
|
## Failure and conflicts
|
|
82
159
|
|
|
160
|
+
- A skill reports `installation-incomplete`, or `machine-unavailable` with a message that the host runtime does not run: stop the whole task. Give the message to the user and wait for the user. Do not continue with other skills. Do not make a replacement for the tool or the host runtime, for example your own disk parser, disassembler or emulator script.
|
|
161
|
+
- A tool gives a wrong result, and the exit check of a stage cannot be true. Tell the user the defect and the evidence, and wait for the user. Do not make a workaround, for example a change to a generated file. When the user accepts an exception, give the defect and the exception in the answer of stage 11.
|
|
83
162
|
- If the evidence does not support a conclusion, keep the unknown and get more evidence. Do not make up a meaning.
|
|
84
163
|
- Before you replace current knowledge from the user or the LLM, read its history and the evidence for it.
|
|
85
164
|
- A conflict from the static analysis: find the correct answer at run time with the c64-emulator skill.
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: c64-source
|
|
3
|
+
description: Use this skill to generate ACME source code for a C64 program from the project knowledge. The knowledge holds the program, its entry state, the coverage and the names. The script runs Ghidra for the instructions and writes the source files. It checks with ACME that the source assembles to the same bytes as the program. It can also write a loader that sets the entry state of an unpacked program. Use it to make a rebuild. Do not edit the generated files. Change the knowledge and generate again.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# c64-source
|
|
7
|
+
|
|
8
|
+
## Purpose
|
|
9
|
+
|
|
10
|
+
Generate ACME source from the knowledge: the program, its entry state, the coverage, and the names and the other facts. The same knowledge gives the same source. Make the source better through the knowledge: names, comments, regions, modules and macros. Change the program through patches. Then generate again.
|
|
11
|
+
|
|
12
|
+
This skill does not change the knowledge.
|
|
13
|
+
|
|
14
|
+
## Inputs
|
|
15
|
+
|
|
16
|
+
- The program in the knowledge. Put it in with `image` of the c64-knowledge skill: a capture of the c64-unpacker skill, or a PRG.
|
|
17
|
+
- The output directory for the source files, relative to the project folder.
|
|
18
|
+
- Optional entry points for Ghidra.
|
|
19
|
+
- Optional: the coverage in the knowledge. Add it with `coverage` of the c64-knowledge skill.
|
|
20
|
+
- For the loader: the entry state of a capture in the knowledge.
|
|
21
|
+
|
|
22
|
+
## Tools / execution path
|
|
23
|
+
|
|
24
|
+
The script runs Ghidra and ACME on this machine. With `--loader`, it also runs the loader in the emulator through the host runtime.
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
node <skill>/scripts/generate.ts --out src
|
|
28
|
+
node <skill>/scripts/generate.ts --out src --entry '$080d'
|
|
29
|
+
node <skill>/scripts/generate.ts --out src --loader
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
| Option | Meaning |
|
|
33
|
+
|---|---|
|
|
34
|
+
| `--out src` | The directory for the source files. The script writes over the files that it generated before. |
|
|
35
|
+
| `--entry '$080d'` | An entry point for Ghidra. Use it again for more entry points. The entry of the program, the routines and the code regions in the knowledge are entry points too. |
|
|
36
|
+
| `--analyzer-names` | Name an address that has no symbol and no platform name with its analyzer name, for example `FUN_17e2`. The order is heuristic, Ghidra, then DXA. Without it, the source makes its own names, for example `l17e2`. |
|
|
37
|
+
| `--space drive8` | Generate the source of drive code or a cartridge bank from the knowledge of that space. The coverage, `--loader` and the platform names are only for `c64`. |
|
|
38
|
+
| `--loader` | Also write `loader.asm` and `loader.prg`. This needs a capture in the knowledge, with its entry and its entry state. |
|
|
39
|
+
|
|
40
|
+
When the knowledge has coverage, code that no run executed gets the line `; not executed` with its range. `notExecuted` lists it. The executed code is also a seed for Ghidra. Thus the source has the code after a JSR to a routine that Ghidra thinks does not return.
|
|
41
|
+
|
|
42
|
+
### Project folder
|
|
43
|
+
|
|
44
|
+
- Paths are relative to the project folder. The project folder is the nearest folder at or above the working directory that holds `.c64-re-tools/`.
|
|
45
|
+
- If the working directory is not in a project and has projects below it, the script refuses and lists them. Then give `--project <folder>` to each script.
|
|
46
|
+
- Write each file that you make for your work in `.c64-re-tools/local/` of the project. Git ignores that folder. Examples are results, batches, step files, runs, snapshots and memory dumps.
|
|
47
|
+
- Move a file out of `.c64-re-tools/local/` only when it is the evidence for a finding. Move it before you give it to `--evidence` of c64-knowledge. `--evidence` refuses a file in `.c64-re-tools/local/`.
|
|
48
|
+
- Put a run that is evidence in `runs/<name>/`, with its run file, its results and the snapshot files that it uses. Change the paths in the run file to the new paths. Then git keeps them, and another person can do the run again.
|
|
49
|
+
- A shell redirect (`>`) is relative to the working directory, not to the project folder. From the folder above the project, write `<folder>/.c64-re-tools/local/result.json`.
|
|
50
|
+
|
|
51
|
+
## Workflow
|
|
52
|
+
|
|
53
|
+
1. Put the program into the knowledge with `image` of the c64-knowledge skill. For a packed program, capture it first with the c64-unpacker skill. For a program without a packer, use the PRG.
|
|
54
|
+
2. Run the script.
|
|
55
|
+
3. Read `check`. `identical: true` tells that the source assembles to the program byte by byte.
|
|
56
|
+
4. Read the source. A label `l_xxxx` is an address that has no name in the knowledge.
|
|
57
|
+
5. Record names, comments, regions and modules with the c64-knowledge skill. Use `apply` for many changes.
|
|
58
|
+
6. Run the script again. Do steps 4 to 6 again until the source is clear.
|
|
59
|
+
7. Build the program with the c64-assembler skill: `--source-root src --entry main.asm`.
|
|
60
|
+
8. For an unpacked program, run the script with `--loader` at the end. Test `loader.prg` against the original with the c64-testing skill.
|
|
61
|
+
|
|
62
|
+
## The source
|
|
63
|
+
|
|
64
|
+
- `main.asm` sets the address of each segment and includes the files in address order.
|
|
65
|
+
- Each module in the knowledge is one file. A module starts at its address and stops at the next module or at the end of its segment. Without modules, each segment is one file, `segment_xxxx.asm`.
|
|
66
|
+
- `constants.asm` holds the names of addresses outside the program, for example `EXTCOL = $d020`. The file puts the names in groups by memory area, for example zero page, VIC-II registers or CIA 1 registers. Each group is in address order. Drive code and banks have one group only. The side comment of a name tells what the address is. This text is the knowledge comment of the address. Without a comment, the text is the platform meaning. When the knowledge name is not the platform name, the platform name comes first. For an I/O mirror without a meaning, the text gives the register that the mirror repeats. Then `Used:` counts how the source uses the name. The kinds are `read`, `written`, `modified`, `called`, `jumped to`, `jumped through`, `branched to`, `pointer`, `address`, `table` and `macro argument`. `address` is an immediate operand expression. `table` is an entry in a table of addresses.
|
|
67
|
+
- The top of `constants.asm` sets each switch to 0, for example `!ifndef CRACK { CRACK = 0 }`. A build that defines the switch as 1 uses the patches of that switch.
|
|
68
|
+
- A label or a constant gets the name of the address in the knowledge. Without a knowledge name, it gets the platform name of the c64-memory-map skill, for example `EXTCOL` or `CHROUT`. A platform name wins over a name from an analyzer (`dxa`, `ghidra` or `heuristic`), for example `EXTCOL` over `ld020`. A `user` or `llm` name wins over a platform name. An address in the program without a name gets `l_xxxx`.
|
|
69
|
+
- The source uses the names of a ROM only when the program uses that ROM. When the knowledge has coverage, a ROM is in use when a run executed code of it. A read of ROM bytes as data does not count. Without coverage, `$01` of the entry state tells which ROMs are in. When the program uses neither ROM, the zero page and pages 2 and 3 get no system names. `romNamesLeftOut` gives the ROMs that the source did not name, and the evidence.
|
|
70
|
+
- `sta $d011 ; $d011: yScroll 3, rows 25, displayEnabled` is a store of an immediate to a register that the c64-memory-map skill decodes. The side comment gives the decoded value. A side comment in the knowledge replaces it.
|
|
71
|
+
- Code regions, and the instructions that Ghidra decodes outside of data regions, become instructions.
|
|
72
|
+
- Data regions become data by their type: `!byte`, `!word`, `!pet`, `!scr`, `!fill`, tables of labels, and sprite bytes in binary.
|
|
73
|
+
- `lda+2 $0012` is an absolute operand below $0100. `+1` is a zero-page operand with a label.
|
|
74
|
+
- `sta NMINV+1` is an address inside a platform entry of more than one byte, for example the high byte of a vector.
|
|
75
|
+
- `lda room_colours+5` is an address inside a data region whose start has a name. The address has no name of its own.
|
|
76
|
+
- `name = * + 1` is a label inside an instruction, for example for code that changes its own operand.
|
|
77
|
+
- `lda #<irq_handler` and `lda bar_colours-1,x` are operand expressions of the knowledge. The script writes each name of an expression with the name of its address in the source. An operand expression in a non-immediate mode that starts with a bracket gets `0+` before it, because ACME reads `(...)` as indirect.
|
|
78
|
+
- `; = <irq_handler` at the end of an instruction with a number: the source cannot use this operand expression. `operandsAsNumbers` gives the reason.
|
|
79
|
+
- `!byte` with an instruction as its comment: ACME writes this instruction with a different opcode. The bytes keep the source identical.
|
|
80
|
+
- `not decoded` marks bytes in a code region that Ghidra did not decode.
|
|
81
|
+
- `; not executed $xxxx-$yyyy` starts code that no run of the coverage executed. The range is the same as in `not_executed.json`.
|
|
82
|
+
- `+inc16 ptr` is a use of a macro of the knowledge. `macros.asm` holds the macros. `main.asm` and `loader.asm` include it. The comments inside a use go to its side comment.
|
|
83
|
+
- `!zone patch_CRACK_100e` starts a patch of the knowledge. `!if CRACK` has the code of the patch and NOP to the end of the range. `else` has the original code. The labels inside the range come before the zone as `name = * + n`. Thus both builds have them.
|
|
84
|
+
|
|
85
|
+
Do not edit the generated files. The next run writes over them.
|
|
86
|
+
|
|
87
|
+
## Switches and macros
|
|
88
|
+
|
|
89
|
+
A switch changes the program only when the build defines it. Thus the source without a define stays identical to the program.
|
|
90
|
+
|
|
91
|
+
1. The script checks the default build with `check`.
|
|
92
|
+
2. Then it builds each switch on its own, with the switch as 1. It does not build two switches together.
|
|
93
|
+
3. The build of a switch must have the same length as the default build. It can change bytes only in the ranges of its patches.
|
|
94
|
+
4. Build the program with a switch on with the c64-assembler skill: `--define CRACK=1`.
|
|
95
|
+
|
|
96
|
+
The script writes a patch only when its range is complete items of one file. A patch cannot cut an instruction. Its switch name cannot be a name of the source.
|
|
97
|
+
|
|
98
|
+
The script writes a macro use only when the use gives the bytes of the program. First it assembles each use alone at its address. Then it checks the full build. A use that fails stays instructions, and `macrosAsInstructions` gives the reason. A label inside the range of a use also keeps the instructions, because the macro line has no place for the label.
|
|
99
|
+
|
|
100
|
+
## The loader
|
|
101
|
+
|
|
102
|
+
`--loader` writes `loader.asm` and assembles it to `loader.prg`. The loader does these steps:
|
|
103
|
+
|
|
104
|
+
1. `10 SYS 2061` starts it.
|
|
105
|
+
2. It stops the interrupts and makes all RAM visible. Then it moves its copier to two free pages. Thus a copier at $a000 or higher is not read from the BASIC ROM.
|
|
106
|
+
3. It copies each segment and the pages $0002-$03ff of the entry state into place. The script selects an order in which no copy writes over the packed bytes of a copy that has not run yet.
|
|
107
|
+
4. It sets the display registers of the VIC-II and the VIC bank from `io` in the entry state. Then it waits for the raster line of the entry.
|
|
108
|
+
5. It sets the CIA timers, their latches and the interrupt masks from `io` and `cia` in the entry state. A running timer gets the value that counts down to the timer value of the entry at the entry.
|
|
109
|
+
6. It sets $00/$01, the stack pointer, A, X, Y and the flags, and jumps to the entry.
|
|
110
|
+
|
|
111
|
+
The copy table, the copier and the jump to the entry use labels, not numbers. `loader_from_xxxx` and `loader_end_xxxx` are around each packed segment, and `loader_to_xxxx` is its first address in place. The jump goes to the label of the entry. Thus a segment can change its length, and the loader still copies it and jumps to the entry that moved. The display values, the raster line and the CIA values stay numbers. They are the entry state, not addresses of the program.
|
|
112
|
+
|
|
113
|
+
The flags go through the free stack byte below the stack pointer (`stackByte`). The loader changes this byte. The loader does not set the SID, the time of day of the CIAs, the CIA interrupt flags or the interrupt registers of the VIC-II. `loader.limits` names each CIA value that the loader cannot set as it was at the entry. A program that reads the SID voice 3 for random numbers can still differ in a scenario. A raster sync does not change a timer or the SID. Then observe after the program sets up its own random numbers. To sync the original and the rebuild in a test, see the sync rules of the c64-testing skill.
|
|
114
|
+
|
|
115
|
+
The script simulates the copies first. Then it runs `loader.prg` in the emulator to its jump to the entry. It compares the memory, $00/$01, the registers, the display registers of the VIC-II, the VIC bank and the raster line with the entry state there. It also compares the CIA timers, latches and interrupt masks. `loader.verified: true` tells that all of them are equal. An interrupt can run right at the entry, as in the original program.
|
|
116
|
+
|
|
117
|
+
## Knowledge
|
|
118
|
+
|
|
119
|
+
Read:
|
|
120
|
+
- symbols, regions, comments, references, modules, operand expressions, patches, macros and macro uses of all origins.
|
|
121
|
+
|
|
122
|
+
Automatic write:
|
|
123
|
+
- none.
|
|
124
|
+
|
|
125
|
+
Do not store:
|
|
126
|
+
- the generated source or its labels `l_xxxx`.
|
|
127
|
+
|
|
128
|
+
## Result
|
|
129
|
+
|
|
130
|
+
One JSON object:
|
|
131
|
+
|
|
132
|
+
- `files`: the files in the output directory.
|
|
133
|
+
- `instructions`, `dataBytes` and `undecodedBytes`.
|
|
134
|
+
- `labels`: `named` labels from the knowledge and `generated` labels `l_xxxx`.
|
|
135
|
+
- `entriesInData`: each `--entry` in a data region of the knowledge, with the `region` and its `origin`. Ghidra does not decode an entry in a data region.
|
|
136
|
+
- `asBytes`: the instructions that the source has as bytes.
|
|
137
|
+
- `operandExpressions`: the count of instructions that the source has with an operand expression.
|
|
138
|
+
- `operandsAsNumbers`: the operand expressions that the source has as a number with a side comment, each with its `address`, `expression` and `reason`. An expression becomes a number when no instruction with an operand value is at the address, or when a name has no address. An expression that ACME refuses or does not assemble to the program also becomes a number. Then the script assembles the source again, at most six times.
|
|
139
|
+
- `unusedModules`: modules in the knowledge whose start is in no segment of the program. Often this tells that the program does not hold code that the knowledge describes.
|
|
140
|
+
- `entryOutside`: the entry is in no segment of the program in the knowledge, with a `reason`. The capture does not hold the program.
|
|
141
|
+
- `notExecuted`: when the knowledge has coverage, the count of instructions that no run executed, the count of their ranges, and the first ranges. `all` names the file `not_executed.json` in `--out`. It has all of the ranges. Each range has its source `file` and the `routine` before it. `files` counts the ranges in each file.
|
|
142
|
+
- `macroUses`: the count of macro uses that the source has.
|
|
143
|
+
- `macrosAsInstructions`: the macro uses that the source has as instructions, each with its `start`, `end`, `macro` and `reason`.
|
|
144
|
+
- `patchesNotWritten`: the patches that the source does not have, each with its range, `switch` and `reason`.
|
|
145
|
+
- `check`: `identical`, and the result for each segment. A different segment gives its first different address.
|
|
146
|
+
- `switches`: the build of each switch. Each item has the `define` for the c64-assembler skill, the patches and the `result` of the build with the switch on. `fits` tells that the build is good, and `changedBytes` counts the changed bytes. `overflow` tells that the code of a patch is longer than its range. `changes outside` gives the first byte outside the ranges that changed. `does not assemble` gives the diagnostics of ACME. `insideNames` lists the labels inside a patch. Code that writes to one of these labels changes the patch when the switch is on.
|
|
147
|
+
- `loader`: the program, the copies in their order, the copier page, `stackByte`, `verified` and `differences`. `limits` lists the CIA values that the loader cannot set. An entry state from an old capture has no CIA values. Then `limits` tells you to capture the program again. When the script cannot make the loader, `loader` has `verified: false` and a `reason`. The loader includes the source. Thus a source that does not assemble to the program also stops the loader.
|
|
148
|
+
|
|
149
|
+
The exit status is 0 when the source is identical and the emulator check of the loader passes. The exit status is 1 for a failed check, for an entry in no segment, and for an error. A patch that the source does not have, or a switch that does not fit, also gives 1. The exit status is 2 for a wrong argument.
|
|
150
|
+
|
|
151
|
+
## Failure and conflicts
|
|
152
|
+
|
|
153
|
+
- `check.diagnostics`: ACME did not assemble the source. A name in the knowledge can be wrong for ACME. Read the diagnostics and change the name with c64-knowledge.
|
|
154
|
+
- `check.identical: false`: the script has a defect. Give the result to the user.
|
|
155
|
+
- `operandsAsNumbers`: read each `reason`. Correct the expression with `operand` of the c64-knowledge skill, or remove it with `unoperand`.
|
|
156
|
+
- `invalid-input` that names a symbol or a module: change that symbol or module in the knowledge.
|
|
157
|
+
- `switches` with `overflow`: make the code of the patch shorter, or make the range of the patch larger, with `patch` of the c64-knowledge skill.
|
|
158
|
+
- `switches` with `does not assemble`: read the diagnostics and correct the code of the patch.
|
|
159
|
+
- `patchesNotWritten`: read each `reason`. Move the start or the end of the patch to an instruction, or give the switch another name.
|
|
160
|
+
- `macrosAsInstructions`: read each `reason`. Correct the macro or the args, or remove the use with `unuse`. The source stays identical, so this is not a failure.
|
|
161
|
+
- `entryOutside`: the run fails, but the script still writes and checks the source. With `--loader`, `loader.verified` is `false` with the same `reason`. Capture the program again with c64-unpacker `loads` or `capture`. Make sure that a segment holds the entry. Then put it into the knowledge again with `image`.
|
|
162
|
+
- `entriesInData`: an analyzer region of data hides the code at the entry. If the entry is code, record a code region at the entry with the c64-knowledge skill, for example `classify '$0500' '$05ff' code`. A region of the user or the LLM replaces the analyzer region. Then generate again.
|
|
163
|
+
- `loader.verified: false` with a `reason`: the script did not make the loader. The script still writes and checks the source. When no copy order or no free pages exist, or the loader needs too many copies, the reason gives the ranges. Capture the program again with fewer segments, or write the loader by hand.
|
|
164
|
+
- `loader.verified: false` with `differences`: the loader ran, and `differences` gives the bytes and registers that are not equal.
|
|
165
|
+
- `loader.verified: false` with `stop`: the loader did not get to its copier or to its jump. `stop` gives the address where it stopped and `port`, the value of $01. `history` gives the last 16 instructions. `cause` gives the first byte of the copier that is not equal to its byte in the loader file. If the copier ran, `cause` can also give the first byte that a copy did not write correctly.
|
|
166
|
+
- `installation-incomplete`, or `machine-unavailable` with a message that the host runtime does not run: stop the task. Give the message to the user and wait for the user. The message gives the remedy. Do not make a replacement for the tool or the host runtime, for example your own disassembler or emulator script.
|
|
167
|
+
|
|
168
|
+
## Handoffs
|
|
169
|
+
|
|
170
|
+
- Capture a packed program → c64-unpacker
|
|
171
|
+
- Put the program and the coverage into the knowledge → c64-knowledge
|
|
172
|
+
- Names, regions, comments and modules → c64-knowledge
|
|
173
|
+
- Build the program → c64-assembler
|
|
174
|
+
- Test the rebuild against the original → c64-testing
|