@henols/c64-re-tools 2.0.0-rc.13 → 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.
- package/package.json +1 -1
- package/skills/c64-assembler/SKILL.md +7 -2
- package/skills/c64-assembler/scripts/assemble.ts +13 -5
- package/skills/c64-disk/SKILL.md +1 -1
- package/skills/c64-disk/scripts/disk.ts +1 -1
- package/skills/c64-emulator/SKILL.md +8 -4
- package/skills/c64-memory-map/SKILL.md +2 -2
- package/skills/c64-provenance/SKILL.md +1 -1
- package/skills/c64-provenance/scripts/provenance.ts +4 -4
- package/skills/c64-reverse-engineering/SKILL.md +2 -1
- package/skills/c64-source/SKILL.md +1 -1
- package/skills/c64-source/scripts/generate.ts +3 -3
- package/skills/c64-static-analysis/SKILL.md +4 -3
- package/skills/c64-static-analysis/scripts/analyze.ts +16 -10
- package/skills/c64-static-analysis/scripts/{coverage.ts → lib/coverage.ts} +20 -0
- package/skills/c64-static-analysis/scripts/{idioms.ts → lib/idioms.ts} +14 -3
- package/skills/c64-testing/SKILL.md +3 -2
- package/skills/c64-testing/references/scenario-format.md +1 -1
- package/skills/c64-testing/scripts/checklist.ts +1 -1
- package/skills/c64-testing/scripts/{scenario.ts → lib/scenario.ts} +11 -9
- package/skills/c64-testing/scripts/run.ts +4 -4
- package/skills/c64-testing/scripts/test.ts +1 -1
- package/skills/c64-unpacker/SKILL.md +4 -1
- package/skills/c64-unpacker/scripts/unpack.ts +4 -4
- package/src/c64.ts +10 -0
- package/src/cli/cleanup.ts +1 -1
- package/src/cli/main.ts +2 -1
- package/src/cli/status.ts +69 -2
- package/src/host/main.ts +14 -1
- package/src/host/vice/session.ts +71 -15
- package/src/host-client/steps.ts +7 -2
- package/src/host-client/vice-session.ts +5 -3
- package/src/mcp/server.ts +1 -0
- package/src/mcp/tools/debug.ts +22 -7
- package/src/mcp/tools/execution.ts +17 -3
- package/src/mcp/tools/machine.ts +11 -2
- package/src/mcp/tools/media.ts +1 -0
- package/src/mcp/tools/memory.ts +7 -2
- package/src/mcp/tools/video.ts +3 -4
- package/src/native/ghidra/language/c64rt_6510.slaspec +4 -1
- package/src/protocol/vice.ts +32 -6
- /package/skills/c64-assembler/scripts/{compare.ts → lib/compare.ts} +0 -0
- /package/skills/c64-disk/scripts/{containers.ts → lib/containers.ts} +0 -0
- /package/skills/c64-provenance/scripts/{compare.ts → lib/compare.ts} +0 -0
- /package/skills/c64-provenance/scripts/{library.ts → lib/library.ts} +0 -0
- /package/skills/c64-provenance/scripts/{runtime.ts → lib/runtime.ts} +0 -0
- /package/skills/c64-provenance/scripts/{separate.ts → lib/separate.ts} +0 -0
- /package/skills/c64-source/scripts/{loader.ts → lib/loader.ts} +0 -0
- /package/skills/c64-source/scripts/{opcodes.ts → lib/opcodes.ts} +0 -0
- /package/skills/c64-source/scripts/{source.ts → lib/source.ts} +0 -0
- /package/skills/c64-static-analysis/scripts/{findings.ts → lib/findings.ts} +0 -0
- /package/skills/c64-static-analysis/scripts/{instructions.ts → lib/instructions.ts} +0 -0
- /package/skills/c64-static-analysis/scripts/{macros.ts → lib/macros.ts} +0 -0
- /package/skills/c64-static-analysis/scripts/{pointers.ts → lib/pointers.ts} +0 -0
- /package/skills/c64-unpacker/scripts/{evidence.ts → lib/evidence.ts} +0 -0
- /package/skills/c64-unpacker/scripts/{loads.ts → lib/loads.ts} +0 -0
- /package/skills/c64-unpacker/scripts/{machine.ts → lib/machine.ts} +0 -0
- /package/skills/c64-unpacker/scripts/{stages.ts → lib/stages.ts} +0 -0
package/src/mcp/tools/memory.ts
CHANGED
|
@@ -12,6 +12,8 @@ import { AddressInput, AddressOutput, Byte, defineTool, HexData, HexDataInput, M
|
|
|
12
12
|
/** With out, a read or a disassembly can be larger than one answer of the session: it is read in parts (D39). */
|
|
13
13
|
const MAX_MEMORY_READ_OUT = 0x10000;
|
|
14
14
|
const MAX_DISASSEMBLE_OUT = 32768;
|
|
15
|
+
/** A memory byte in a result: two lowercase hex digits, as memory data is. */
|
|
16
|
+
const HexByte = z.string().regex(/^[0-9a-f]{2}$/);
|
|
15
17
|
|
|
16
18
|
export const c64MemoryRead = defineTool({
|
|
17
19
|
name: "c64_memory_read",
|
|
@@ -182,6 +184,7 @@ export const c64MemoryCompare = defineTool({
|
|
|
182
184
|
description:
|
|
183
185
|
`Compare two memory ranges of size bytes (1 to ${MAX_COMPARE_SIZE}). Each range has its own address, space and view. ` +
|
|
184
186
|
`The result tells if they are equal, how many bytes differ, and the first ${MAX_COMPARE_DIFFERENCES} differences with their offset. ` +
|
|
187
|
+
"The bytes of a difference are lowercase hex. " +
|
|
185
188
|
"This does not change the run state of the machine.",
|
|
186
189
|
inputSchema: z
|
|
187
190
|
.object({ left: Location, right: Location, size: z.number().int().min(1).max(MAX_COMPARE_SIZE) })
|
|
@@ -189,11 +192,13 @@ export const c64MemoryCompare = defineTool({
|
|
|
189
192
|
outputSchema: z.object({
|
|
190
193
|
equal: z.boolean(),
|
|
191
194
|
differentBytes: z.number().int().min(0),
|
|
192
|
-
firstDifferences: z.array(z.object({ offset: z.number().int().min(0), left:
|
|
195
|
+
firstDifferences: z.array(z.object({ offset: z.number().int().min(0), left: HexByte, right: HexByte })),
|
|
193
196
|
}),
|
|
194
197
|
readOnly: true,
|
|
195
198
|
async run(input, session) {
|
|
196
|
-
|
|
199
|
+
const result = await session.memoryCompare(input);
|
|
200
|
+
const hex = (byte: number) => byte.toString(16).padStart(2, "0");
|
|
201
|
+
return { ...result, firstDifferences: result.firstDifferences.map((difference) => ({ ...difference, left: hex(difference.left), right: hex(difference.right) })) };
|
|
197
202
|
},
|
|
198
203
|
});
|
|
199
204
|
|
package/src/mcp/tools/video.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
|
|
6
|
-
import { formatC64Address } from "../../c64.ts";
|
|
6
|
+
import { formatC64Address, formatSprite, formatVicii } from "../../c64.ts";
|
|
7
7
|
import { WireFailure } from "../../protocol/messages.ts";
|
|
8
8
|
import { CIA_SELECTIONS, MAX_MASK_RECTANGLES, MAX_MEMORY_READ, MAX_OBSERVE_BYTES, MAX_OBSERVE_RANGES, SPACES, VICII_MODES, type ObserveParams } from "../../protocol/vice.ts";
|
|
9
9
|
import { OutInput, ProjectInput, writeOut, WrittenOutput } from "../output.ts";
|
|
@@ -31,8 +31,7 @@ export const c64Vicii = defineTool({
|
|
|
31
31
|
}),
|
|
32
32
|
readOnly: true,
|
|
33
33
|
async run(_input, session) {
|
|
34
|
-
|
|
35
|
-
return { ...state, screenAddress: formatC64Address(state.screenAddress), graphicsAddress: formatC64Address(state.graphicsAddress) };
|
|
34
|
+
return formatVicii(await session.vicii());
|
|
36
35
|
},
|
|
37
36
|
});
|
|
38
37
|
|
|
@@ -62,7 +61,7 @@ export const c64Sprite = defineTool({
|
|
|
62
61
|
readOnly: true,
|
|
63
62
|
async run(input, session) {
|
|
64
63
|
const result = await session.sprites(input.sprites ?? []);
|
|
65
|
-
return { sprites: result.sprites.map(
|
|
64
|
+
return { sprites: result.sprites.map(formatSprite) };
|
|
66
65
|
},
|
|
67
66
|
});
|
|
68
67
|
|
|
@@ -263,13 +263,16 @@ REL: target is rel [ target = inst_next + rel; ] { export *:2 target; }
|
|
|
263
263
|
}
|
|
264
264
|
|
|
265
265
|
# BRK skips its padding byte: the return address is two bytes on.
|
|
266
|
+
# The vector at $FFFE is in ROM unless the program banks the KERNAL out, and
|
|
267
|
+
# the analysis cannot know the banking. Thus BRK ends the flow, and Ghidra
|
|
268
|
+
# does not follow the RAM bytes at $FFFE of a flat image (R2-07).
|
|
266
269
|
:BRK is op=0x00 {
|
|
267
270
|
*:2 (SP - 1) = inst_next + 1;
|
|
268
271
|
SP = SP - 2;
|
|
269
272
|
pushP(1);
|
|
270
273
|
I = 1;
|
|
271
274
|
local vector:2 = 0xfffe;
|
|
272
|
-
|
|
275
|
+
return [*:2 vector];
|
|
273
276
|
}
|
|
274
277
|
|
|
275
278
|
:CLC is op=0x18 { C = 0; }
|
package/src/protocol/vice.ts
CHANGED
|
@@ -337,8 +337,16 @@ export interface MachineStatus {
|
|
|
337
337
|
pc?: number;
|
|
338
338
|
/** True while a cartridge from an autostart is attached (D64). */
|
|
339
339
|
cartridge: boolean;
|
|
340
|
+
/** Present only while stopped by a user breakpoint or watchpoint, or by a JAM. */
|
|
341
|
+
stopReason?: PointStopReason;
|
|
342
|
+
/** The id of the breakpoint or watchpoint that stopped the machine. */
|
|
343
|
+
pointId?: number;
|
|
340
344
|
}
|
|
341
345
|
|
|
346
|
+
/** What stopped the machine outside a request that stops it. */
|
|
347
|
+
export const POINT_STOP_REASONS = ["breakpoint", "watchpoint", "jam"] as const;
|
|
348
|
+
export type PointStopReason = (typeof POINT_STOP_REASONS)[number];
|
|
349
|
+
|
|
342
350
|
export interface MemoryReadParams {
|
|
343
351
|
address: number;
|
|
344
352
|
size: number;
|
|
@@ -406,6 +414,10 @@ export interface ExecutionResult {
|
|
|
406
414
|
pc?: number;
|
|
407
415
|
executed?: number;
|
|
408
416
|
advancedFrames?: number;
|
|
417
|
+
/** advance-frames only: frames when all frames ran, else what stopped the run early. */
|
|
418
|
+
stopReason?: "frames" | PointStopReason;
|
|
419
|
+
/** The id of the breakpoint or watchpoint that stopped the run. */
|
|
420
|
+
pointId?: number;
|
|
409
421
|
}
|
|
410
422
|
|
|
411
423
|
/** c64_run_until targets. */
|
|
@@ -425,6 +437,8 @@ export interface RunUntilResult {
|
|
|
425
437
|
/** The PC of the CPU in `space`: the CPU that stopped. */
|
|
426
438
|
pc: number;
|
|
427
439
|
space: Space;
|
|
440
|
+
/** The id of the breakpoint or watchpoint that stopped the run. */
|
|
441
|
+
pointId?: number;
|
|
428
442
|
}
|
|
429
443
|
|
|
430
444
|
export interface ViceOperations {
|
|
@@ -469,7 +483,8 @@ export interface ViceOperations {
|
|
|
469
483
|
backtrace: { params: { depth: number; space: Space }; result: { frames: BacktraceFrame[] } };
|
|
470
484
|
/** `cycles` is a decimal string. */
|
|
471
485
|
timing: { params: { action: (typeof TIMING_ACTIONS)[number] }; result: { started: boolean } | { cycles: string } };
|
|
472
|
-
|
|
486
|
+
/** clear starts the profiler again from zero. */
|
|
487
|
+
profile: { params: { action: "read"; limit: number } | { action: "clear" }; result: { entries: ProfileEntry[] } | { cleared: boolean } };
|
|
473
488
|
memmap: {
|
|
474
489
|
params: { action: "read"; start: number; end: number; maxRanges: number } | { action: "clear" };
|
|
475
490
|
/** `next`: more ranges follow from this address; read again from there. */
|
|
@@ -646,9 +661,11 @@ export function validateViceParams<O extends ViceOperation>(op: O, params: unkno
|
|
|
646
661
|
return result as ViceOperations[O]["params"];
|
|
647
662
|
}
|
|
648
663
|
case "profile": {
|
|
649
|
-
onlyFields(params, ["limit"]);
|
|
664
|
+
onlyFields(params, params.action === "clear" ? ["action"] : ["action", "limit"]);
|
|
665
|
+
if (params.action === "clear") return { action: "clear" } as ViceOperations[O]["params"];
|
|
666
|
+
if (params.action !== "read") invalid("action must be read or clear");
|
|
650
667
|
if (!isInteger(params.limit, 1, MAX_PROFILE)) invalid(`limit must be an integer from 1 to ${MAX_PROFILE}`);
|
|
651
|
-
return { limit: params.limit } as ViceOperations[O]["params"];
|
|
668
|
+
return { action: "read", limit: params.limit } as ViceOperations[O]["params"];
|
|
652
669
|
}
|
|
653
670
|
case "memmap": {
|
|
654
671
|
onlyFields(params, params.action === "clear" ? ["action"] : ["action", "start", "end", "maxRanges"]);
|
|
@@ -1011,7 +1028,9 @@ export function validateViceResult<O extends ViceOperation>(op: O, value: unknow
|
|
|
1011
1028
|
typeof value.warp === "boolean" &&
|
|
1012
1029
|
typeof value.window === "boolean" &&
|
|
1013
1030
|
(value.pc === undefined || isInteger(value.pc, 0, 0xffff)) &&
|
|
1014
|
-
typeof value.cartridge === "boolean"
|
|
1031
|
+
typeof value.cartridge === "boolean" &&
|
|
1032
|
+
(value.stopReason === undefined || isOneOf(POINT_STOP_REASONS, value.stopReason)) &&
|
|
1033
|
+
(value.pointId === undefined || isInteger(value.pointId, 1, Number.MAX_SAFE_INTEGER));
|
|
1015
1034
|
if (!ok) throw new ProtocolError("status result is malformed");
|
|
1016
1035
|
break;
|
|
1017
1036
|
}
|
|
@@ -1080,7 +1099,8 @@ export function validateViceResult<O extends ViceOperation>(op: O, value: unknow
|
|
|
1080
1099
|
isOneOf(STOP_REASONS, value.stopReason) &&
|
|
1081
1100
|
isOneOf(RUN_STATES, value.state) &&
|
|
1082
1101
|
isInteger(value.pc, 0, 0xffff) &&
|
|
1083
|
-
isOneOf(SPACES, value.space)
|
|
1102
|
+
isOneOf(SPACES, value.space) &&
|
|
1103
|
+
(value.pointId === undefined || isInteger(value.pointId, 1, Number.MAX_SAFE_INTEGER));
|
|
1084
1104
|
if (!ok) throw new ProtocolError("runUntil result is malformed");
|
|
1085
1105
|
break;
|
|
1086
1106
|
}
|
|
@@ -1089,7 +1109,9 @@ export function validateViceResult<O extends ViceOperation>(op: O, value: unknow
|
|
|
1089
1109
|
isOneOf(RUN_STATES, value.state) &&
|
|
1090
1110
|
(value.pc === undefined || isInteger(value.pc, 0, 0xffff)) &&
|
|
1091
1111
|
(value.executed === undefined || isInteger(value.executed, 0, MAX_EXECUTION_COUNT)) &&
|
|
1092
|
-
(value.advancedFrames === undefined || isInteger(value.advancedFrames, 0, MAX_EXECUTION_COUNT))
|
|
1112
|
+
(value.advancedFrames === undefined || isInteger(value.advancedFrames, 0, MAX_EXECUTION_COUNT)) &&
|
|
1113
|
+
(value.stopReason === undefined || value.stopReason === "frames" || isOneOf(POINT_STOP_REASONS, value.stopReason)) &&
|
|
1114
|
+
(value.pointId === undefined || isInteger(value.pointId, 1, Number.MAX_SAFE_INTEGER));
|
|
1093
1115
|
if (!ok) throw new ProtocolError("execution result is malformed");
|
|
1094
1116
|
break;
|
|
1095
1117
|
}
|
|
@@ -1198,6 +1220,10 @@ export function validateViceResult<O extends ViceOperation>(op: O, value: unknow
|
|
|
1198
1220
|
break;
|
|
1199
1221
|
}
|
|
1200
1222
|
case "profile": {
|
|
1223
|
+
if ("cleared" in value) {
|
|
1224
|
+
if (value.cleared !== true) throw new ProtocolError("profile result is malformed");
|
|
1225
|
+
break;
|
|
1226
|
+
}
|
|
1201
1227
|
const ok =
|
|
1202
1228
|
Array.isArray(value.entries) &&
|
|
1203
1229
|
value.entries.every(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|