c64bridge 0.9.0 → 0.9.1

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 (49) hide show
  1. package/README.md +158 -164
  2. package/data/vice/vice-binary-monitor-spec.md +21 -4
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/c64Client.js +76 -2
  5. package/dist/device.js +43 -3
  6. package/dist/rag/indexer.js +18 -8
  7. package/dist/sidwaveCompiler.js +1 -1
  8. package/dist/{assemblyConverter.js → tools/assember.js} +10 -1
  9. package/dist/{basicConverter.js → tools/basicTokenizer.js} +1 -1
  10. package/dist/tools/debug.js +158 -5
  11. package/dist/tools/disassembler.js +478 -0
  12. package/dist/tools/input.js +338 -0
  13. package/dist/tools/memory.js +317 -1
  14. package/dist/tools/programRunners.js +45 -6
  15. package/dist/tools/registry/batch.js +167 -0
  16. package/dist/tools/registry/graphics.js +101 -1
  17. package/dist/tools/registry/index.js +4 -0
  18. package/dist/tools/registry/input.js +2 -0
  19. package/dist/tools/registry/memory.js +61 -1
  20. package/dist/tools/schema.js +4 -5
  21. package/dist/tools/symbolRegistry.js +49 -0
  22. package/dist/tools/types.js +19 -4
  23. package/dist/vice/process.js +43 -2
  24. package/dist/vice/viceClient.js +5 -1
  25. package/mcp/schemas/c64_batch.schema.json +53 -0
  26. package/mcp/schemas/c64_config.schema.json +461 -2
  27. package/mcp/schemas/c64_debug.schema.json +641 -3
  28. package/mcp/schemas/c64_disk.schema.json +340 -2
  29. package/mcp/schemas/c64_drive.schema.json +157 -2
  30. package/mcp/schemas/c64_extract.schema.json +359 -2
  31. package/mcp/schemas/c64_graphics.schema.json +415 -3
  32. package/mcp/schemas/c64_input.schema.json +136 -0
  33. package/mcp/schemas/c64_memory.schema.json +562 -3
  34. package/mcp/schemas/c64_printer.schema.json +253 -2
  35. package/mcp/schemas/c64_program.schema.json +499 -2
  36. package/mcp/schemas/c64_rag.schema.json +82 -2
  37. package/mcp/schemas/c64_select_backend.schema.json +35 -2
  38. package/mcp/schemas/c64_sound.schema.json +793 -2
  39. package/mcp/schemas/c64_stream.schema.json +73 -2
  40. package/mcp/schemas/c64_system.schema.json +301 -2
  41. package/mcp/schemas/c64_vice.schema.json +71 -2
  42. package/mcp/server.json +1 -1
  43. package/mcp/tools.json +6718 -1257
  44. package/mcp.json +1 -1
  45. package/package.json +1 -1
  46. package/scripts/run-coverage.mjs +7 -0
  47. package/scripts/run-tests.ts +2 -0
  48. package/scripts/update-readme.ts +79 -2
  49. package/server.json +2 -2
@@ -0,0 +1,478 @@
1
+ /**
2
+ * 6502/6510 disassembler covering the full 256-opcode space, including
3
+ * undocumented (illegal) opcodes. Mnemonic naming follows the canonical
4
+ * convention used by the 1541U monitor (HLT->JAM, ASO->SLO, LSE->SRE,
5
+ * DCM->DCP, INS->ISC).
6
+ */
7
+ function entry(mnemonic, mode, illegal = false) {
8
+ return { mnemonic, mode, illegal };
9
+ }
10
+ // Canonicalization rules from disassembler_6502.cc:
11
+ // HLT -> JAM, ASO -> SLO, LSE -> SRE, DCM -> DCP, INS -> ISC
12
+ function canonical(mnemonic) {
13
+ switch (mnemonic) {
14
+ case "HLT": return "JAM";
15
+ case "ASO": return "SLO";
16
+ case "LSE": return "SRE";
17
+ case "DCM": return "DCP";
18
+ case "INS": return "ISC";
19
+ default: return mnemonic;
20
+ }
21
+ }
22
+ // 256-entry opcode table mirroring `opcode_templates` in disassembler_6502.cc.
23
+ // `illegal` is taken from the bitmap `illegal_map` in the same reference.
24
+ const OPCODES = (() => {
25
+ // Build the illegal-opcode bitmap from the reference file.
26
+ const ILLEGAL_MAP = [
27
+ 0x989C, 0x9C9C, 0x888C, 0x9C9C,
28
+ 0x889C, 0x9C9C, 0x889C, 0x9C9C,
29
+ 0x8A8D, 0xD88C, 0x8888, 0x888C,
30
+ 0x888C, 0x9C9C, 0x888C, 0x9C9C,
31
+ ];
32
+ const isIllegal = (op) => {
33
+ const row = ILLEGAL_MAP[op >> 4];
34
+ return ((row >> (op & 0x0F)) & 1) !== 0;
35
+ };
36
+ const t = new Array(256);
37
+ // Helper: fill one row of 16 entries by mnemonic/mode pairs.
38
+ const set = (op, mnemonic, mode) => {
39
+ t[op] = { mnemonic: canonical(mnemonic), mode, illegal: isIllegal(op) };
40
+ };
41
+ // 0x00-0x0F
42
+ set(0x00, "BRK", 0 /* Mode.Imp */);
43
+ set(0x01, "ORA", 12 /* Mode.IndX */);
44
+ set(0x02, "HLT", 0 /* Mode.Imp */);
45
+ set(0x03, "ASO", 12 /* Mode.IndX */);
46
+ set(0x04, "NOP", 3 /* Mode.Zp */);
47
+ set(0x05, "ORA", 3 /* Mode.Zp */);
48
+ set(0x06, "ASL", 3 /* Mode.Zp */);
49
+ set(0x07, "ASO", 3 /* Mode.Zp */);
50
+ set(0x08, "PHP", 0 /* Mode.Imp */);
51
+ set(0x09, "ORA", 2 /* Mode.Imm */);
52
+ set(0x0A, "ASL", 1 /* Mode.Acc */);
53
+ set(0x0B, "ANC", 2 /* Mode.Imm */);
54
+ set(0x0C, "NOP", 8 /* Mode.Abs */);
55
+ set(0x0D, "ORA", 8 /* Mode.Abs */);
56
+ set(0x0E, "ASL", 8 /* Mode.Abs */);
57
+ set(0x0F, "ASO", 8 /* Mode.Abs */);
58
+ // 0x10-0x1F
59
+ set(0x10, "BPL", 7 /* Mode.Rel */);
60
+ set(0x11, "ORA", 13 /* Mode.IndY */);
61
+ set(0x12, "HLT", 0 /* Mode.Imp */);
62
+ set(0x13, "ASO", 13 /* Mode.IndY */);
63
+ set(0x14, "NOP", 4 /* Mode.ZpX */);
64
+ set(0x15, "ORA", 4 /* Mode.ZpX */);
65
+ set(0x16, "ASL", 4 /* Mode.ZpX */);
66
+ set(0x17, "ASO", 4 /* Mode.ZpX */);
67
+ set(0x18, "CLC", 0 /* Mode.Imp */);
68
+ set(0x19, "ORA", 10 /* Mode.AbsY */);
69
+ set(0x1A, "NOP", 0 /* Mode.Imp */);
70
+ set(0x1B, "ASO", 10 /* Mode.AbsY */);
71
+ set(0x1C, "NOP", 9 /* Mode.AbsX */);
72
+ set(0x1D, "ORA", 9 /* Mode.AbsX */);
73
+ set(0x1E, "ASL", 9 /* Mode.AbsX */);
74
+ set(0x1F, "ASO", 9 /* Mode.AbsX */);
75
+ // 0x20-0x2F
76
+ set(0x20, "JSR", 8 /* Mode.Abs */);
77
+ set(0x21, "AND", 12 /* Mode.IndX */);
78
+ set(0x22, "HLT", 0 /* Mode.Imp */);
79
+ set(0x23, "RLA", 12 /* Mode.IndX */);
80
+ set(0x24, "BIT", 3 /* Mode.Zp */);
81
+ set(0x25, "AND", 3 /* Mode.Zp */);
82
+ set(0x26, "ROL", 3 /* Mode.Zp */);
83
+ set(0x27, "RLA", 3 /* Mode.Zp */);
84
+ set(0x28, "PLP", 0 /* Mode.Imp */);
85
+ set(0x29, "AND", 2 /* Mode.Imm */);
86
+ set(0x2A, "ROL", 1 /* Mode.Acc */);
87
+ set(0x2B, "ANC", 2 /* Mode.Imm */);
88
+ set(0x2C, "BIT", 8 /* Mode.Abs */);
89
+ set(0x2D, "AND", 8 /* Mode.Abs */);
90
+ set(0x2E, "ROL", 8 /* Mode.Abs */);
91
+ set(0x2F, "RLA", 8 /* Mode.Abs */);
92
+ // 0x30-0x3F
93
+ set(0x30, "BMI", 7 /* Mode.Rel */);
94
+ set(0x31, "AND", 13 /* Mode.IndY */);
95
+ set(0x32, "HLT", 0 /* Mode.Imp */);
96
+ set(0x33, "RLA", 13 /* Mode.IndY */);
97
+ set(0x34, "NOP", 4 /* Mode.ZpX */);
98
+ set(0x35, "AND", 4 /* Mode.ZpX */);
99
+ set(0x36, "ROL", 4 /* Mode.ZpX */);
100
+ set(0x37, "RLA", 4 /* Mode.ZpX */);
101
+ set(0x38, "SEC", 0 /* Mode.Imp */);
102
+ set(0x39, "AND", 10 /* Mode.AbsY */);
103
+ set(0x3A, "NOP", 0 /* Mode.Imp */);
104
+ set(0x3B, "RLA", 10 /* Mode.AbsY */);
105
+ set(0x3C, "NOP", 9 /* Mode.AbsX */);
106
+ set(0x3D, "AND", 9 /* Mode.AbsX */);
107
+ set(0x3E, "ROL", 9 /* Mode.AbsX */);
108
+ set(0x3F, "RLA", 9 /* Mode.AbsX */);
109
+ // 0x40-0x4F
110
+ set(0x40, "RTI", 0 /* Mode.Imp */);
111
+ set(0x41, "EOR", 12 /* Mode.IndX */);
112
+ set(0x42, "HLT", 0 /* Mode.Imp */);
113
+ set(0x43, "LSE", 12 /* Mode.IndX */);
114
+ set(0x44, "NOP", 3 /* Mode.Zp */);
115
+ set(0x45, "EOR", 3 /* Mode.Zp */);
116
+ set(0x46, "LSR", 3 /* Mode.Zp */);
117
+ set(0x47, "LSE", 3 /* Mode.Zp */);
118
+ set(0x48, "PHA", 0 /* Mode.Imp */);
119
+ set(0x49, "EOR", 2 /* Mode.Imm */);
120
+ set(0x4A, "LSR", 1 /* Mode.Acc */);
121
+ set(0x4B, "ALR", 2 /* Mode.Imm */);
122
+ set(0x4C, "JMP", 8 /* Mode.Abs */);
123
+ set(0x4D, "EOR", 8 /* Mode.Abs */);
124
+ set(0x4E, "LSR", 8 /* Mode.Abs */);
125
+ set(0x4F, "LSE", 8 /* Mode.Abs */);
126
+ // 0x50-0x5F
127
+ set(0x50, "BVC", 7 /* Mode.Rel */);
128
+ set(0x51, "EOR", 13 /* Mode.IndY */);
129
+ set(0x52, "HLT", 0 /* Mode.Imp */);
130
+ set(0x53, "LSE", 13 /* Mode.IndY */);
131
+ set(0x54, "NOP", 4 /* Mode.ZpX */);
132
+ set(0x55, "EOR", 4 /* Mode.ZpX */);
133
+ set(0x56, "LSR", 4 /* Mode.ZpX */);
134
+ set(0x57, "LSE", 4 /* Mode.ZpX */);
135
+ set(0x58, "CLI", 0 /* Mode.Imp */);
136
+ set(0x59, "EOR", 10 /* Mode.AbsY */);
137
+ set(0x5A, "NOP", 0 /* Mode.Imp */);
138
+ set(0x5B, "LSE", 10 /* Mode.AbsY */);
139
+ set(0x5C, "NOP", 9 /* Mode.AbsX */);
140
+ set(0x5D, "EOR", 9 /* Mode.AbsX */);
141
+ set(0x5E, "LSR", 9 /* Mode.AbsX */);
142
+ set(0x5F, "LSE", 9 /* Mode.AbsX */);
143
+ // 0x60-0x6F
144
+ set(0x60, "RTS", 0 /* Mode.Imp */);
145
+ set(0x61, "ADC", 12 /* Mode.IndX */);
146
+ set(0x62, "HLT", 0 /* Mode.Imp */);
147
+ set(0x63, "RRA", 12 /* Mode.IndX */);
148
+ set(0x64, "NOP", 3 /* Mode.Zp */);
149
+ set(0x65, "ADC", 3 /* Mode.Zp */);
150
+ set(0x66, "ROR", 3 /* Mode.Zp */);
151
+ set(0x67, "RRA", 3 /* Mode.Zp */);
152
+ set(0x68, "PLA", 0 /* Mode.Imp */);
153
+ set(0x69, "ADC", 2 /* Mode.Imm */);
154
+ set(0x6A, "ROR", 1 /* Mode.Acc */);
155
+ set(0x6B, "ARR", 2 /* Mode.Imm */);
156
+ set(0x6C, "JMP", 11 /* Mode.Ind */);
157
+ set(0x6D, "ADC", 8 /* Mode.Abs */);
158
+ set(0x6E, "ROR", 8 /* Mode.Abs */);
159
+ set(0x6F, "RRA", 8 /* Mode.Abs */);
160
+ // 0x70-0x7F
161
+ set(0x70, "BVS", 7 /* Mode.Rel */);
162
+ set(0x71, "ADC", 13 /* Mode.IndY */);
163
+ set(0x72, "HLT", 0 /* Mode.Imp */);
164
+ set(0x73, "RRA", 13 /* Mode.IndY */);
165
+ set(0x74, "NOP", 4 /* Mode.ZpX */);
166
+ set(0x75, "ADC", 4 /* Mode.ZpX */);
167
+ set(0x76, "ROR", 4 /* Mode.ZpX */);
168
+ set(0x77, "RRA", 4 /* Mode.ZpX */);
169
+ set(0x78, "SEI", 0 /* Mode.Imp */);
170
+ set(0x79, "ADC", 10 /* Mode.AbsY */);
171
+ set(0x7A, "NOP", 0 /* Mode.Imp */);
172
+ set(0x7B, "RRA", 10 /* Mode.AbsY */);
173
+ set(0x7C, "NOP", 9 /* Mode.AbsX */);
174
+ set(0x7D, "ADC", 9 /* Mode.AbsX */);
175
+ set(0x7E, "ROR", 9 /* Mode.AbsX */);
176
+ set(0x7F, "RRA", 9 /* Mode.AbsX */);
177
+ // 0x80-0x8F
178
+ set(0x80, "NOP", 2 /* Mode.Imm */);
179
+ set(0x81, "STA", 12 /* Mode.IndX */);
180
+ set(0x82, "NOP", 2 /* Mode.Imm */);
181
+ set(0x83, "SAX", 12 /* Mode.IndX */);
182
+ set(0x84, "STY", 3 /* Mode.Zp */);
183
+ set(0x85, "STA", 3 /* Mode.Zp */);
184
+ set(0x86, "STX", 3 /* Mode.Zp */);
185
+ set(0x87, "SAX", 3 /* Mode.Zp */);
186
+ set(0x88, "DEY", 0 /* Mode.Imp */);
187
+ set(0x89, "NOP", 2 /* Mode.Imm */);
188
+ set(0x8A, "TXA", 0 /* Mode.Imp */);
189
+ set(0x8B, "XAA", 2 /* Mode.Imm */);
190
+ set(0x8C, "STY", 8 /* Mode.Abs */);
191
+ set(0x8D, "STA", 8 /* Mode.Abs */);
192
+ set(0x8E, "STX", 8 /* Mode.Abs */);
193
+ set(0x8F, "SAX", 8 /* Mode.Abs */);
194
+ // 0x90-0x9F
195
+ set(0x90, "BCC", 7 /* Mode.Rel */);
196
+ set(0x91, "STA", 13 /* Mode.IndY */);
197
+ set(0x92, "HLT", 0 /* Mode.Imp */);
198
+ set(0x93, "AHX", 13 /* Mode.IndY */);
199
+ set(0x94, "STY", 4 /* Mode.ZpX */);
200
+ set(0x95, "STA", 4 /* Mode.ZpX */);
201
+ set(0x96, "STX", 5 /* Mode.ZpY */);
202
+ set(0x97, "SAX", 5 /* Mode.ZpY */);
203
+ set(0x98, "TYA", 0 /* Mode.Imp */);
204
+ set(0x99, "STA", 10 /* Mode.AbsY */);
205
+ set(0x9A, "TXS", 0 /* Mode.Imp */);
206
+ set(0x9B, "TAS", 10 /* Mode.AbsY */);
207
+ set(0x9C, "SHY", 9 /* Mode.AbsX */);
208
+ set(0x9D, "STA", 9 /* Mode.AbsX */);
209
+ set(0x9E, "SHX", 10 /* Mode.AbsY */);
210
+ set(0x9F, "AHX", 10 /* Mode.AbsY */);
211
+ // 0xA0-0xAF
212
+ set(0xA0, "LDY", 2 /* Mode.Imm */);
213
+ set(0xA1, "LDA", 12 /* Mode.IndX */);
214
+ set(0xA2, "LDX", 2 /* Mode.Imm */);
215
+ set(0xA3, "LAX", 12 /* Mode.IndX */);
216
+ set(0xA4, "LDY", 3 /* Mode.Zp */);
217
+ set(0xA5, "LDA", 3 /* Mode.Zp */);
218
+ set(0xA6, "LDX", 3 /* Mode.Zp */);
219
+ set(0xA7, "LAX", 3 /* Mode.Zp */);
220
+ set(0xA8, "TAY", 0 /* Mode.Imp */);
221
+ set(0xA9, "LDA", 2 /* Mode.Imm */);
222
+ set(0xAA, "TAX", 0 /* Mode.Imp */);
223
+ set(0xAB, "LAX", 2 /* Mode.Imm */);
224
+ set(0xAC, "LDY", 8 /* Mode.Abs */);
225
+ set(0xAD, "LDA", 8 /* Mode.Abs */);
226
+ set(0xAE, "LDX", 8 /* Mode.Abs */);
227
+ set(0xAF, "LAX", 8 /* Mode.Abs */);
228
+ // 0xB0-0xBF
229
+ set(0xB0, "BCS", 7 /* Mode.Rel */);
230
+ set(0xB1, "LDA", 13 /* Mode.IndY */);
231
+ set(0xB2, "HLT", 0 /* Mode.Imp */);
232
+ set(0xB3, "LAX", 13 /* Mode.IndY */);
233
+ set(0xB4, "LDY", 4 /* Mode.ZpX */);
234
+ set(0xB5, "LDA", 4 /* Mode.ZpX */);
235
+ set(0xB6, "LDX", 5 /* Mode.ZpY */);
236
+ set(0xB7, "LAX", 5 /* Mode.ZpY */);
237
+ set(0xB8, "CLV", 0 /* Mode.Imp */);
238
+ set(0xB9, "LDA", 10 /* Mode.AbsY */);
239
+ set(0xBA, "TSX", 0 /* Mode.Imp */);
240
+ set(0xBB, "LAS", 10 /* Mode.AbsY */);
241
+ set(0xBC, "LDY", 9 /* Mode.AbsX */);
242
+ set(0xBD, "LDA", 9 /* Mode.AbsX */);
243
+ set(0xBE, "LDX", 10 /* Mode.AbsY */);
244
+ set(0xBF, "LAX", 10 /* Mode.AbsY */);
245
+ // 0xC0-0xCF
246
+ set(0xC0, "CPY", 2 /* Mode.Imm */);
247
+ set(0xC1, "CMP", 12 /* Mode.IndX */);
248
+ set(0xC2, "NOP", 2 /* Mode.Imm */);
249
+ set(0xC3, "DCM", 12 /* Mode.IndX */);
250
+ set(0xC4, "CPY", 3 /* Mode.Zp */);
251
+ set(0xC5, "CMP", 3 /* Mode.Zp */);
252
+ set(0xC6, "DEC", 3 /* Mode.Zp */);
253
+ set(0xC7, "DCM", 3 /* Mode.Zp */);
254
+ set(0xC8, "INY", 0 /* Mode.Imp */);
255
+ set(0xC9, "CMP", 2 /* Mode.Imm */);
256
+ set(0xCA, "DEX", 0 /* Mode.Imp */);
257
+ set(0xCB, "AXS", 2 /* Mode.Imm */);
258
+ set(0xCC, "CPY", 8 /* Mode.Abs */);
259
+ set(0xCD, "CMP", 8 /* Mode.Abs */);
260
+ set(0xCE, "DEC", 8 /* Mode.Abs */);
261
+ set(0xCF, "DCM", 8 /* Mode.Abs */);
262
+ // 0xD0-0xDF
263
+ set(0xD0, "BNE", 7 /* Mode.Rel */);
264
+ set(0xD1, "CMP", 13 /* Mode.IndY */);
265
+ set(0xD2, "HLT", 0 /* Mode.Imp */);
266
+ set(0xD3, "DCM", 13 /* Mode.IndY */);
267
+ set(0xD4, "NOP", 4 /* Mode.ZpX */);
268
+ set(0xD5, "CMP", 4 /* Mode.ZpX */);
269
+ set(0xD6, "DEC", 4 /* Mode.ZpX */);
270
+ set(0xD7, "DCM", 4 /* Mode.ZpX */);
271
+ set(0xD8, "CLD", 0 /* Mode.Imp */);
272
+ set(0xD9, "CMP", 10 /* Mode.AbsY */);
273
+ set(0xDA, "NOP", 0 /* Mode.Imp */);
274
+ set(0xDB, "DCM", 10 /* Mode.AbsY */);
275
+ set(0xDC, "NOP", 9 /* Mode.AbsX */);
276
+ set(0xDD, "CMP", 9 /* Mode.AbsX */);
277
+ set(0xDE, "DEC", 9 /* Mode.AbsX */);
278
+ set(0xDF, "DCM", 9 /* Mode.AbsX */);
279
+ // 0xE0-0xEF
280
+ set(0xE0, "CPX", 2 /* Mode.Imm */);
281
+ set(0xE1, "SBC", 12 /* Mode.IndX */);
282
+ set(0xE2, "NOP", 2 /* Mode.Imm */);
283
+ set(0xE3, "INS", 12 /* Mode.IndX */);
284
+ set(0xE4, "CPX", 3 /* Mode.Zp */);
285
+ set(0xE5, "SBC", 3 /* Mode.Zp */);
286
+ set(0xE6, "INC", 3 /* Mode.Zp */);
287
+ set(0xE7, "INS", 3 /* Mode.Zp */);
288
+ set(0xE8, "INX", 0 /* Mode.Imp */);
289
+ set(0xE9, "SBC", 2 /* Mode.Imm */);
290
+ set(0xEA, "NOP", 0 /* Mode.Imp */);
291
+ set(0xEB, "SBC", 2 /* Mode.Imm */);
292
+ set(0xEC, "CPX", 8 /* Mode.Abs */);
293
+ set(0xED, "SBC", 8 /* Mode.Abs */);
294
+ set(0xEE, "INC", 8 /* Mode.Abs */);
295
+ set(0xEF, "INS", 8 /* Mode.Abs */);
296
+ // 0xF0-0xFF
297
+ set(0xF0, "BEQ", 7 /* Mode.Rel */);
298
+ set(0xF1, "SBC", 13 /* Mode.IndY */);
299
+ set(0xF2, "HLT", 0 /* Mode.Imp */);
300
+ set(0xF3, "INS", 13 /* Mode.IndY */);
301
+ set(0xF4, "NOP", 6 /* Mode.ZpS */);
302
+ set(0xF5, "SBC", 4 /* Mode.ZpX */);
303
+ set(0xF6, "INC", 4 /* Mode.ZpX */);
304
+ set(0xF7, "INS", 4 /* Mode.ZpX */);
305
+ set(0xF8, "SED", 0 /* Mode.Imp */);
306
+ set(0xF9, "SBC", 10 /* Mode.AbsY */);
307
+ set(0xFA, "NOP", 0 /* Mode.Imp */);
308
+ set(0xFB, "INS", 10 /* Mode.AbsY */);
309
+ set(0xFC, "NOP", 9 /* Mode.AbsX */);
310
+ set(0xFD, "SBC", 9 /* Mode.AbsX */);
311
+ set(0xFE, "INC", 9 /* Mode.AbsX */);
312
+ set(0xFF, "INS", 9 /* Mode.AbsX */);
313
+ return t;
314
+ })();
315
+ function modeSize(mode) {
316
+ switch (mode) {
317
+ case 0 /* Mode.Imp */:
318
+ case 1 /* Mode.Acc */:
319
+ return 1;
320
+ case 2 /* Mode.Imm */:
321
+ case 3 /* Mode.Zp */:
322
+ case 4 /* Mode.ZpX */:
323
+ case 5 /* Mode.ZpY */:
324
+ case 6 /* Mode.ZpS */:
325
+ case 7 /* Mode.Rel */:
326
+ case 12 /* Mode.IndX */:
327
+ case 13 /* Mode.IndY */:
328
+ return 2;
329
+ case 8 /* Mode.Abs */:
330
+ case 9 /* Mode.AbsX */:
331
+ case 10 /* Mode.AbsY */:
332
+ case 11 /* Mode.Ind */:
333
+ return 3;
334
+ }
335
+ }
336
+ function hex2(v) {
337
+ return v.toString(16).toUpperCase().padStart(2, "0");
338
+ }
339
+ function hex4(v) {
340
+ return v.toString(16).toUpperCase().padStart(4, "0");
341
+ }
342
+ function labelOrHex4(addr, symbols) {
343
+ const label = symbols?.get(addr);
344
+ return label ? `${label} ($${hex4(addr)})` : `$${hex4(addr)}`;
345
+ }
346
+ function formatOperand(mode, bytes, offset, instrAddr, symbols) {
347
+ switch (mode) {
348
+ case 0 /* Mode.Imp */:
349
+ return "";
350
+ case 1 /* Mode.Acc */:
351
+ return "A";
352
+ case 2 /* Mode.Imm */:
353
+ return `#$${hex2(bytes[offset + 1] ?? 0)}`;
354
+ case 3 /* Mode.Zp */:
355
+ return `$${hex2(bytes[offset + 1] ?? 0)}`;
356
+ case 4 /* Mode.ZpX */:
357
+ return `$${hex2(bytes[offset + 1] ?? 0)},X`;
358
+ case 5 /* Mode.ZpY */:
359
+ return `$${hex2(bytes[offset + 1] ?? 0)},Y`;
360
+ case 6 /* Mode.ZpS */:
361
+ return `$${hex2(bytes[offset + 1] ?? 0)},S`;
362
+ case 7 /* Mode.Rel */: {
363
+ const rel = bytes[offset + 1] ?? 0;
364
+ const signed = rel >= 0x80 ? rel - 0x100 : rel;
365
+ const target = (instrAddr + 2 + signed) & 0xffff;
366
+ return labelOrHex4(target, symbols);
367
+ }
368
+ case 8 /* Mode.Abs */: {
369
+ const lo = bytes[offset + 1] ?? 0;
370
+ const hi = bytes[offset + 2] ?? 0;
371
+ const addr = lo | (hi << 8);
372
+ return labelOrHex4(addr, symbols);
373
+ }
374
+ case 9 /* Mode.AbsX */: {
375
+ const lo = bytes[offset + 1] ?? 0;
376
+ const hi = bytes[offset + 2] ?? 0;
377
+ const addr = lo | (hi << 8);
378
+ return `${labelOrHex4(addr, symbols)},X`;
379
+ }
380
+ case 10 /* Mode.AbsY */: {
381
+ const lo = bytes[offset + 1] ?? 0;
382
+ const hi = bytes[offset + 2] ?? 0;
383
+ const addr = lo | (hi << 8);
384
+ return `${labelOrHex4(addr, symbols)},Y`;
385
+ }
386
+ case 11 /* Mode.Ind */: {
387
+ const lo = bytes[offset + 1] ?? 0;
388
+ const hi = bytes[offset + 2] ?? 0;
389
+ const addr = lo | (hi << 8);
390
+ return `($${hex4(addr)})`;
391
+ }
392
+ case 12 /* Mode.IndX */:
393
+ return `($${hex2(bytes[offset + 1] ?? 0)},X)`;
394
+ case 13 /* Mode.IndY */:
395
+ return `($${hex2(bytes[offset + 1] ?? 0)}),Y`;
396
+ }
397
+ }
398
+ /**
399
+ * Disassemble a block of 6502/6510 bytes.
400
+ *
401
+ * @param bytes Raw memory bytes (may be longer than needed)
402
+ * @param baseAddress The C64 memory address of `bytes[0]`
403
+ * @param countOrOptions Either a max-instruction count (legacy form) or an options object
404
+ * @param symbols Optional address->label map (legacy positional form)
405
+ */
406
+ export function disassemble(bytes, baseAddress, countOrOptions, symbols) {
407
+ const options = typeof countOrOptions === "object" && countOrOptions !== null
408
+ ? countOrOptions
409
+ : { count: countOrOptions, symbols };
410
+ const limit = options.count ?? Infinity;
411
+ const symMap = options.symbols ?? symbols;
412
+ const allowUndocumented = options.allowUndocumented !== false;
413
+ const lines = [];
414
+ let offset = 0;
415
+ while (offset < bytes.length && lines.length < limit) {
416
+ const instrAddr = (baseAddress + offset) & 0xffff;
417
+ const opcode = bytes[offset] ?? 0;
418
+ const op = OPCODES[opcode];
419
+ const label = symMap?.get(instrAddr);
420
+ if (op.illegal && !allowUndocumented) {
421
+ lines.push({
422
+ address: instrAddr,
423
+ bytes: [opcode],
424
+ label,
425
+ mnemonic: "???",
426
+ operand: `$${hex2(opcode)}`,
427
+ undocumented: true,
428
+ });
429
+ offset += 1;
430
+ continue;
431
+ }
432
+ const size = modeSize(op.mode);
433
+ const instrBytes = [];
434
+ for (let i = 0; i < size && offset + i < bytes.length; i++) {
435
+ instrBytes.push(bytes[offset + i] ?? 0);
436
+ }
437
+ const operand = formatOperand(op.mode, bytes, offset, instrAddr, symMap);
438
+ lines.push({
439
+ address: instrAddr,
440
+ bytes: instrBytes,
441
+ label,
442
+ mnemonic: op.mnemonic,
443
+ operand,
444
+ undocumented: op.illegal,
445
+ });
446
+ offset += size;
447
+ }
448
+ return lines;
449
+ }
450
+ /**
451
+ * Render disassembly lines as a human-readable string.
452
+ * Format: [label:\n] $ADDR XX XX XX MNEM operand ; *undocumented*
453
+ */
454
+ export function formatDisassembly(lines) {
455
+ const parts = [];
456
+ for (const line of lines) {
457
+ if (line.label) {
458
+ parts.push(`${line.label}:`);
459
+ }
460
+ const addrStr = `$${hex4(line.address)}`;
461
+ const byteStr = line.bytes.map((b) => hex2(b)).join(" ").padEnd(8);
462
+ const mnemonic = line.undocumented ? `${line.mnemonic}*` : line.mnemonic;
463
+ const instrStr = line.operand
464
+ ? `${mnemonic} ${line.operand}`
465
+ : mnemonic;
466
+ parts.push(` ${addrStr} ${byteStr} ${instrStr}`);
467
+ }
468
+ return parts.join("\n");
469
+ }
470
+ /** Returns true when the opcode is undocumented per the 1541U reference. */
471
+ export function isUndocumentedOpcode(opcode) {
472
+ return OPCODES[opcode & 0xff].illegal;
473
+ }
474
+ /** Lookup helper used by tests to verify table coverage. */
475
+ export function opcodeMetadata(opcode) {
476
+ const entry = OPCODES[opcode & 0xff];
477
+ return { mnemonic: entry.mnemonic, undocumented: entry.illegal, size: modeSize(entry.mode) };
478
+ }