blob: 6e561343575a049ad255fd2e77d8585391eca653 [file] [log] [blame]
swissChili6c61a792020-07-28 16:29:20 -07001#include "cpu.h"
2#include "instructions.h"
swissChili94ba1f52020-08-08 11:39:10 -07003#define SCREEN_ONLY_SDL
4#include "screen.h"
swissChili6c61a792020-07-28 16:29:20 -07005
6#include <endian.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10
11#define die(m, ...) \
swissChili6264a3b2020-07-30 19:02:07 -070012 printf("\033[31m" m "\033[0m\n", ##__VA_ARGS__); \
swissChili6c61a792020-07-28 16:29:20 -070013 exit(1);
14
swissChili6264a3b2020-07-30 19:02:07 -070015#define warn(m, ...) \
16 printf("\033[33m" m "\033[0m\n", ##__VA_ARGS__);
17
swissChili94ba1f52020-08-08 11:39:10 -070018
19sdl_screen_t *g_scr = NULL;
20
21
swissChilidbbd5402020-08-07 15:07:39 -070022void reset(cpu_t *cpu)
23{
24 cpu->regs[SP] = 0xFD; // stack at is 0x100 + SP
swissChilibb478f12020-08-07 20:45:07 -070025 cpu->pc = 0x600; // arbitrary program counter start
swissChilidbbd5402020-08-07 15:07:39 -070026 cpu->running = true;
27}
28
swissChili6c61a792020-07-28 16:29:20 -070029cpu_t new_cpu()
30{
31 cpu_t cpu = { 0 };
swissChili6c61a792020-07-28 16:29:20 -070032 cpu.regs[SP] = 0xFD; // stack at is 0x100 + SP
swissChilibb478f12020-08-07 20:45:07 -070033 cpu.pc = 0x600; // arbitrary program counter start
swissChili6264a3b2020-07-30 19:02:07 -070034 cpu.running = true;
swissChili6c61a792020-07-28 16:29:20 -070035 cpu.mem = malloc(0xFFFF);
swissChilicc27cfe2020-08-08 12:57:57 -070036 cpu.screen_dirty = true;
swissChili6c61a792020-07-28 16:29:20 -070037 memset(cpu.mem, 0, 0xFFFF);
38
39 if (!cpu.mem)
40 {
41 die("Could not allocate memory for CPU");
42 }
43
44 return cpu;
45}
46
swissChilida4803e2020-08-06 20:06:04 -070047uint16_t le_to_native(uint8_t a, uint8_t b)
48{
49#ifdef LITTLE_ENDIAN
50 return b << 8 | a;
51#else
52 return a << 8 | b;
53#endif
54}
55
56void native_to_le(uint16_t n, uint8_t *a, uint8_t *b)
57{
58#ifdef LITTLE_ENDIAN
59 *a = n >> 8;
60 *b = n & 0xFF;
61#else
62 *a = n & 0xFF;
63 *b = n >> 8;
64#endif
65}
66
swissChili6264a3b2020-07-30 19:02:07 -070067void stack_push(cpu_t *cpu, uint8_t v)
68{
69 cpu->mem[cpu->regs[SP]-- + 0x100] = v;
70}
71
swissChilida4803e2020-08-06 20:06:04 -070072void stack_pushle(cpu_t *cpu, uint16_t v)
73{
74 uint8_t a, b;
75 native_to_le(v, &a, &b);
76 // push in "reverse" order so that the address is stored as LE
77 stack_push(cpu, b);
78 stack_push(cpu, a);
79}
80
swissChili6264a3b2020-07-30 19:02:07 -070081uint8_t stack_pop(cpu_t *cpu)
82{
83 return cpu->mem[cpu->regs[SP]++ + 0x100];
84}
85
swissChilida4803e2020-08-06 20:06:04 -070086uint16_t stack_pople(cpu_t *cpu)
87{
88 uint8_t a = stack_pop(cpu);
89 uint8_t b = stack_pop(cpu);
90 return le_to_native(a, b);
91}
92
swissChili6c61a792020-07-28 16:29:20 -070093void free_cpu(cpu_t *cpu)
94{
95 free(cpu->mem);
96}
97
swissChilida4803e2020-08-06 20:06:04 -070098// rotate right
swissChilicc27cfe2020-08-08 12:57:57 -070099uint8_t ror(uint8_t a, uint8_t n)
swissChilida4803e2020-08-06 20:06:04 -0700100{
101 return (a >> n) | (a << (8 - n));
102}
103
104// rotate left
swissChilicc27cfe2020-08-08 12:57:57 -0700105uint8_t rol(uint8_t a, uint8_t n)
swissChilida4803e2020-08-06 20:06:04 -0700106{
107 return (a << n) | (a >> (8 - n));
108}
109
swissChilicc27cfe2020-08-08 12:57:57 -0700110void stat_nz(cpu_t *cpu, int8_t v)
swissChili6c61a792020-07-28 16:29:20 -0700111{
swissChili6264a3b2020-07-30 19:02:07 -0700112 cpu->status.negative = v < 0;
113 cpu->status.zero = v == 0;
114}
115
116// Used to check for overflow, is c unique?
swissChilicc27cfe2020-08-08 12:57:57 -0700117bool last_unique(bool a, bool b, bool c)
swissChili6264a3b2020-07-30 19:02:07 -0700118{
119 return a == b && a != c;
120}
121
swissChilicc27cfe2020-08-08 12:57:57 -0700122void stat_cv(cpu_t *cpu, uint8_t a, uint8_t b, uint8_t c)
swissChili6264a3b2020-07-30 19:02:07 -0700123{
124 cpu->status.overflow = last_unique(a >> 7, b >> 7, c >> 7);
125 cpu->status.carry = c < a || c < b;
126}
127
swissChilicc27cfe2020-08-08 12:57:57 -0700128void cmp(cpu_t *cpu, uint8_t reg, uint8_t mem)
swissChilida4803e2020-08-06 20:06:04 -0700129{
130 cpu->status.negative = 0;
131 cpu->status.zero = 0;
132 cpu->status.carry = 0;
133 if (cpu->regs[reg] < mem)
134 {
135 cpu->status.negative = 1;
136 }
137 else if (cpu->regs[reg] == mem)
138 {
139 cpu->status.zero = 1;
140 cpu->status.carry = 1;
141 }
142 else
143 {
144 cpu->status.carry = 1;
145 }
146}
147
swissChilicc27cfe2020-08-08 12:57:57 -0700148uint16_t scr_dirty(cpu_t *cpu, uint16_t mem)
149{
150 if (mem >= 0x200 && mem <= 0x200 + 32 * 32)
151 cpu->screen_dirty = true;
152
153 return mem;
154}
155
swissChilida4803e2020-08-06 20:06:04 -0700156void execute(cpu_t *cpu, const char *mnemonic, uint8_t op, arg_t a, uint8_t am)
swissChili6264a3b2020-07-30 19:02:07 -0700157{
158 // used to save space
159 #define REGS \
160 R(X) R(A) R(Y)
161
swissChili710d18d2020-07-29 19:43:20 -0700162 switch (op) {
swissChili6264a3b2020-07-30 19:02:07 -0700163 // Load and store instructions:
164 #define R(reg) \
165 case LD##reg: \
166 cpu->regs[reg] = a.val; \
167 stat_nz(cpu, a.val); \
168 break;
169
170 REGS
171
172 #undef R
173
174 #define R(reg) \
175 case ST##reg: \
swissChilicc27cfe2020-08-08 12:57:57 -0700176 cpu->mem[scr_dirty(cpu, a.ptr)] = cpu->regs[reg]; \
swissChili6264a3b2020-07-30 19:02:07 -0700177 break; \
178
179 REGS
180
181 #undef R
182
183 // Arithmetic instructions:
184 // NOTE: binary coded decimals are NOT SUPPORTED because I don't want
185 // to implement them.
186 case ADC:
187 {
188 uint8_t sum = cpu->regs[A] + a.val + cpu->status.carry;
189 // signed overflow
190 stat_cv(cpu, cpu->regs[A], a.val + cpu->status.carry, sum);
191 stat_nz(cpu, sum);
192 cpu->regs[A] = sum;
193 break;
194 }
195
196 case SBC:
197 {
198 uint8_t diff = cpu->regs[A] - a.val - !cpu->status.carry;
199 stat_cv(cpu, cpu->regs[A], a.val - !cpu->status.carry, diff);
200 stat_nz(cpu, diff);
201 cpu->regs[A] = diff;
202 break;
203 }
204
205 case INC:
swissChilicc27cfe2020-08-08 12:57:57 -0700206 cpu->mem[scr_dirty(cpu, scr_dirty(cpu, a.ptr))]++;
207 stat_nz(cpu, cpu->mem[scr_dirty(cpu, a.ptr)]);
swissChili6264a3b2020-07-30 19:02:07 -0700208 break;
209
210 case INX:
211 cpu->regs[X]++;
212 stat_nz(cpu, cpu->regs[X]);
213 break;
214
215 case INY:
216 cpu->regs[Y]++;
217 stat_nz(cpu, cpu->regs[Y]);
218 break;
219
220 case DEC:
swissChilicc27cfe2020-08-08 12:57:57 -0700221 cpu->mem[scr_dirty(cpu, a.ptr)]--;
222 stat_nz(cpu, cpu->mem[scr_dirty(cpu, a.ptr)]);
swissChili6264a3b2020-07-30 19:02:07 -0700223 break;
swissChilida4803e2020-08-06 20:06:04 -0700224
225 case DEX:
226 cpu->regs[X]--;
227 stat_nz(cpu, cpu->regs[X]);
228 break;
229
230 case DEY:
231 cpu->regs[Y]--;
232 stat_nz(cpu, cpu->regs[Y]);
233 break;
234
235 case ASL:
236 // This check must be done here unfortunately, it would be nice
237 // to do this while decoding operands but it would require
238 // a substantial change to the architecture of the emulator
239 if (am == AM_ACC)
240 {
241 cpu->status.carry = cpu->regs[A] >> 7;
242 cpu->regs[A] <<= 1;
243 stat_nz(cpu, cpu->regs[A]);
244 }
245 else
246 {
swissChilicc27cfe2020-08-08 12:57:57 -0700247 cpu->status.carry = cpu->mem[scr_dirty(cpu, a.val)] >> 7;
248 cpu->mem[scr_dirty(cpu, a.ptr)] <<= 1;
249 stat_nz(cpu, cpu->mem[scr_dirty(cpu, a.ptr)]);
swissChilida4803e2020-08-06 20:06:04 -0700250 }
251 break;
252
253 case LSR:
254 if (am == AM_ACC)
255 {
256 cpu->status.carry = cpu->regs[A] & 1;
257 cpu->regs[A] >>= 1;
258 stat_nz(cpu, cpu->regs[A]);
259 }
260 else
261 {
swissChilicc27cfe2020-08-08 12:57:57 -0700262 cpu->status.carry = cpu->mem[scr_dirty(cpu, a.val)] & 7;
263 cpu->mem[scr_dirty(cpu, a.ptr)] >>= 1;
264 stat_nz(cpu, cpu->mem[scr_dirty(cpu, a.ptr)]);
swissChilida4803e2020-08-06 20:06:04 -0700265 }
266 break;
267
268 case ROL:
269 if (am == AM_ACC)
270 {
271 cpu->status.carry = cpu->regs[A] >> 7;
272 cpu->regs[A] = rol(cpu->regs[A], 1);
273 stat_nz(cpu, cpu->regs[A]);
274 }
275 else
276 {
swissChilicc27cfe2020-08-08 12:57:57 -0700277 cpu->status.carry = cpu->mem[scr_dirty(cpu, a.val)] >> 7;
278 cpu->mem[scr_dirty(cpu, a.ptr)] = rol(a.val, 1);
279 stat_nz(cpu, cpu->mem[scr_dirty(cpu, a.ptr)]);
swissChilida4803e2020-08-06 20:06:04 -0700280 }
281 break;
282
283 case ROR:
284 if (am == AM_ACC)
285 {
286 cpu->status.carry = cpu->regs[A] & 1;
287 cpu->regs[A] = ror(cpu->regs[A], 1);
288 stat_nz(cpu, cpu->regs[A]);
289 }
290 else
291 {
swissChilicc27cfe2020-08-08 12:57:57 -0700292 cpu->status.carry = cpu->mem[scr_dirty(cpu, a.val)] & 1;
293 cpu->mem[scr_dirty(cpu, a.ptr)] = ror(a.val, 1);
294 stat_nz(cpu, cpu->mem[scr_dirty(cpu, a.ptr)]);
swissChilida4803e2020-08-06 20:06:04 -0700295 }
296 break;
297
298 case AND:
299 cpu->regs[A] &= a.val;
300 stat_nz(cpu, cpu->regs[A]);
301 break;
302
303 case ORA:
304 cpu->regs[A] |= a.val;
305 stat_nz(cpu, cpu->regs[A]);
306 break;
307
308 case EOR:
309 cpu->regs[A] ^= a.val;
310 stat_nz(cpu, cpu->regs[A]);
311 break;
312
313 case CMP:
314 cmp(cpu, A, a.val);
315 break;
316
317 case CPX:
318 cmp(cpu, X, a.val);
319 break;
320
321 case CPY:
322 cmp(cpu, Y, a.val);
323 break;
324
325 // TODO: implement BIT here
326
327 #define BRANCHES \
328 B(BCC, carry == 0) \
329 B(BCS, carry == 1) \
330 B(BNE, zero == 0) \
331 B(BEQ, zero == 1) \
332 B(BPL, negative == 0) \
333 B(BMI, negative == 1) \
334 B(BVC, overflow == 0) \
335 B(BVS, overflow == 1)
336
337 #define B(i, c) \
338 case i: \
339 if (cpu->status . c) \
340 cpu->pc = a.ptr;\
341 break;
342
343 BRANCHES
344
345 #undef B
346 #undef BRANCHES
347
348 #define TRANSFERS \
349 T(A, X) \
350 T(X, A) \
351 T(A, Y) \
352 T(Y, A)
353
354 #define T(a, b) \
355 case T ## a ## b: \
356 cpu->regs[b] = cpu->regs[a]; \
357 stat_nz(cpu, cpu->regs[b]); \
358 break;
359
360 TRANSFERS
361
362 #undef T
363 #undef TRANSFERS
364
365 case TSX:
366 cpu->regs[X] = cpu->regs[SP];
367 stat_nz(cpu, cpu->regs[X]);
368 break;
369
370 case TXS:
371 cpu->regs[SP] = cpu->regs[X];
372 stat_nz(cpu, cpu->regs[X]);
373 break;
374
375 case PHA:
376 stack_push(cpu, cpu->regs[A]);
377 break;
378
379 case PLA:
380 cpu->regs[A] = stack_pop(cpu);
381 stat_nz(cpu, cpu->regs[A]);
382 break;
383
384 case PHP:
385 stack_push(cpu, *(uint8_t *)(&cpu->status));
386 break;
387
388 case PLP:
389 {
390 uint8_t s = stack_pop(cpu);
391 *(uint8_t *)(&cpu->status) = s;
392 }
393
394 case JMP:
395 cpu->pc = a.ptr;
396 break;
397
398 case JSR:
399 stack_pushle(cpu, cpu->pc);
400 break;
401
402 case RTS:
403 cpu->pc = stack_pople(cpu);
404 break;
405
406 // TODO: implement RTI
407 // TODO: implement flag instructions
408
409 case BRK:
410 // TODO: trigger an interrupt
411 cpu->running = false;
412 break;
413
414 case NOP:
415 break;
416
417 default:
418 die("Unsupported opcode: %x\n", op);
swissChili710d18d2020-07-29 19:43:20 -0700419 }
swissChili6264a3b2020-07-30 19:02:07 -0700420 #undef REGS
swissChili6c61a792020-07-28 16:29:20 -0700421}
422
swissChilicc27cfe2020-08-08 12:57:57 -0700423uint16_t fetch_le(cpu_t *cpu)
swissChili6c61a792020-07-28 16:29:20 -0700424{
swissChilicc27cfe2020-08-08 12:57:57 -0700425 uint8_t a = cpu->mem[scr_dirty(cpu, cpu->pc++)];
426 uint8_t b = cpu->mem[scr_dirty(cpu, cpu->pc++)];
swissChili6c61a792020-07-28 16:29:20 -0700427 return le_to_native(a, b);
428}
429
swissChilicc27cfe2020-08-08 12:57:57 -0700430arg_t arg_imm(uint16_t a)
swissChili710d18d2020-07-29 19:43:20 -0700431{
432 return (arg_t){ a, a };
433}
434
swissChilicc27cfe2020-08-08 12:57:57 -0700435arg_t arg_ptr(cpu_t *c, uint flags, uint16_t p)
swissChili710d18d2020-07-29 19:43:20 -0700436{
437 if (flags & FETCH_NO_INDIRECTION)
438 return arg_imm(p);
439
440 return (arg_t){ c->mem[p], p };
441}
442
swissChilicc27cfe2020-08-08 12:57:57 -0700443arg_t arg(uint16_t v, uint16_t a)
swissChili710d18d2020-07-29 19:43:20 -0700444{
445 return (arg_t){ v, a };
446}
447
448arg_t fetch_addr(cpu_t *cpu, uint8_t am, uint f)
swissChili6c61a792020-07-28 16:29:20 -0700449{
450 switch (am)
451 {
452 case AM_ACC:
453 case AM_IMP:
swissChili710d18d2020-07-29 19:43:20 -0700454 return arg_imm(0);
swissChili6c61a792020-07-28 16:29:20 -0700455
456 // In both cases return immediate 8 bit value
457 case AM_IMM:
458 case AM_ZP:
swissChilicc27cfe2020-08-08 12:57:57 -0700459 return arg_imm(cpu->mem[scr_dirty(cpu, cpu->pc++)]);
swissChili6c61a792020-07-28 16:29:20 -0700460
461 case AM_ABS:
swissChili710d18d2020-07-29 19:43:20 -0700462 return arg_ptr(cpu, f, fetch_le(cpu));
swissChili6c61a792020-07-28 16:29:20 -0700463
464 case AM_REL:
465 {
swissChili6264a3b2020-07-30 19:02:07 -0700466 // Aparently, PC should will point to the NEXT opcode
467 // I can't find any documentation on this unfortunately, but
468 // I have discovered this through testing the output of other
469 // assemblers.
470 uint16_t pc = cpu->pc + 1;
swissChilicc27cfe2020-08-08 12:57:57 -0700471 return arg_ptr(cpu, f, (int8_t)cpu->mem[scr_dirty(cpu, cpu->pc++)] + pc);
swissChili6c61a792020-07-28 16:29:20 -0700472 }
473
474 case AM_IND:
475 {
476 uint16_t addr = fetch_le(cpu);
swissChili6264a3b2020-07-30 19:02:07 -0700477
478 if (f & FETCH_NO_INDIRECTION)
479 return arg_imm(addr);
480
swissChilicc27cfe2020-08-08 12:57:57 -0700481 uint8_t low = cpu->mem[scr_dirty(cpu, addr)],
482 high = cpu->mem[scr_dirty(cpu, addr + 1)];
swissChili6c61a792020-07-28 16:29:20 -0700483
swissChili710d18d2020-07-29 19:43:20 -0700484 return arg_ptr(cpu, f, le_to_native(low, high));
swissChili6c61a792020-07-28 16:29:20 -0700485 }
486
487 case AM_AX:
swissChili94ba1f52020-08-08 11:39:10 -0700488 if (f & FETCH_NO_INDIRECTION)
489 return arg_ptr(cpu, f, fetch_le(cpu));
490
swissChili710d18d2020-07-29 19:43:20 -0700491 return arg_ptr(cpu, f, fetch_le(cpu) + cpu->regs[X]);
swissChili6c61a792020-07-28 16:29:20 -0700492
493 case AM_AY:
swissChili94ba1f52020-08-08 11:39:10 -0700494 if (f & FETCH_NO_INDIRECTION)
495 return arg_ptr(cpu, f, fetch_le(cpu));
496
swissChili710d18d2020-07-29 19:43:20 -0700497 return arg_ptr(cpu, f, fetch_le(cpu) + cpu->regs[Y]);
swissChili6c61a792020-07-28 16:29:20 -0700498
499 case AM_ZPX:
swissChili94ba1f52020-08-08 11:39:10 -0700500 if (f & FETCH_NO_INDIRECTION)
swissChilicc27cfe2020-08-08 12:57:57 -0700501 return arg_ptr(cpu, f, cpu->mem[scr_dirty(cpu, cpu->pc++)]);
502 return arg_ptr(cpu, f, cpu->mem[scr_dirty(cpu, cpu->pc++)] + cpu->regs[X]);
swissChili6c61a792020-07-28 16:29:20 -0700503
504 case AM_ZPY:
swissChili94ba1f52020-08-08 11:39:10 -0700505 if (f & FETCH_NO_INDIRECTION)
swissChilicc27cfe2020-08-08 12:57:57 -0700506 return arg_ptr(cpu, f, cpu->mem[scr_dirty(cpu, cpu->pc++)]);
507 return arg_ptr(cpu, f, cpu->mem[scr_dirty(cpu, cpu->pc++)] + cpu->regs[Y]);
swissChili6c61a792020-07-28 16:29:20 -0700508
509 case AM_ZIX:
510 {
swissChilicc27cfe2020-08-08 12:57:57 -0700511 uint8_t zp = cpu->mem[scr_dirty(cpu, cpu->pc++)];
swissChili6264a3b2020-07-30 19:02:07 -0700512
513 if (f & FETCH_NO_INDIRECTION)
514 return arg_imm(zp);
515
swissChili710d18d2020-07-29 19:43:20 -0700516 uint16_t addr = zp + cpu->regs[X];
swissChilicc27cfe2020-08-08 12:57:57 -0700517 uint16_t indirect = le_to_native(cpu->mem[scr_dirty(cpu, addr)], cpu->mem[scr_dirty(cpu, addr + 1)]);
swissChili710d18d2020-07-29 19:43:20 -0700518 return arg_ptr(cpu, f, indirect);
swissChili6c61a792020-07-28 16:29:20 -0700519 }
520
521 case AM_ZIY:
522 {
swissChilicc27cfe2020-08-08 12:57:57 -0700523 uint8_t zp = cpu->mem[scr_dirty(cpu, cpu->pc++)];
swissChili6264a3b2020-07-30 19:02:07 -0700524
525 if (f & FETCH_NO_INDIRECTION)
526 return arg_imm(zp);
527
swissChilicc27cfe2020-08-08 12:57:57 -0700528 uint16_t base = le_to_native(cpu->mem[scr_dirty(cpu, zp)], cpu->mem[scr_dirty(cpu, zp + 1)]);
swissChili710d18d2020-07-29 19:43:20 -0700529 return arg_ptr(cpu, f, base + cpu->regs[Y]);
swissChili6c61a792020-07-28 16:29:20 -0700530 }
531
532 default:
533 die("Unknown address mode %x", am);
swissChili710d18d2020-07-29 19:43:20 -0700534 __builtin_unreachable();
swissChili6c61a792020-07-28 16:29:20 -0700535 }
536}
537
swissChilicc27cfe2020-08-08 12:57:57 -0700538void step(cpu_t *cpu)
swissChili6c61a792020-07-28 16:29:20 -0700539{
swissChili94ba1f52020-08-08 11:39:10 -0700540 static int steps;
541 steps++;
swissChilicc27cfe2020-08-08 12:57:57 -0700542 cpu->screen_dirty = false;
543 switch (cpu->mem[scr_dirty(cpu, cpu->pc++)])
swissChili6c61a792020-07-28 16:29:20 -0700544 {
545#define INST(mn, am, op) \
546 case op: \
swissChilida4803e2020-08-06 20:06:04 -0700547 execute(cpu, #mn, mn, fetch_addr(cpu, am, 0), am); \
swissChili6c61a792020-07-28 16:29:20 -0700548 break;
549
550 INSTRUCTIONS
551
552#undef INST
553
554 default:
555 die("Undefined opcode");
556 }
swissChili94ba1f52020-08-08 11:39:10 -0700557
558 if (steps % 100 == 0)
559 printf("%d\n", steps);
560
swissChilicc27cfe2020-08-08 12:57:57 -0700561// If can't run screen in seperate thread, just run it here (bad)
562#ifdef NO_PTHREAD
swissChili94ba1f52020-08-08 11:39:10 -0700563 if (g_scr)
564 {
swissChilicc27cfe2020-08-08 12:57:57 -0700565 sdl_screen(g_scr, cpu->mem + CPU_FB_ADDR, cpu->screen_dirty);
swissChili94ba1f52020-08-08 11:39:10 -0700566 }
swissChilicc27cfe2020-08-08 12:57:57 -0700567#endif
swissChili6c61a792020-07-28 16:29:20 -0700568}
569
swissChilic51e9222020-08-07 16:09:14 -0700570int dump_inst(cpu_t *cpu, char *buf, const char *mn, uint16_t addr, uint8_t am)
swissChili6c61a792020-07-28 16:29:20 -0700571{
swissChilic51e9222020-08-07 16:09:14 -0700572 char *end = buf;
573 end += sprintf(end, "%s ", mn);
swissChili6c61a792020-07-28 16:29:20 -0700574
575 switch (am)
576 {
577 case AM_IMM:
swissChilic51e9222020-08-07 16:09:14 -0700578 end += sprintf(end, "#");
swissChili6c61a792020-07-28 16:29:20 -0700579 case AM_REL:
580 case AM_ABS:
581 case AM_ZP:
swissChilic51e9222020-08-07 16:09:14 -0700582 end += sprintf(end, "$%x", addr);
swissChili6c61a792020-07-28 16:29:20 -0700583 break;
584
585 case AM_IND:
swissChilic51e9222020-08-07 16:09:14 -0700586 end += sprintf(end, "($%x)", addr);
swissChili6c61a792020-07-28 16:29:20 -0700587 break;
588
589 case AM_AX:
590 case AM_ZPX:
swissChilic51e9222020-08-07 16:09:14 -0700591 end += sprintf(end, "$%x, X", addr);
swissChili6c61a792020-07-28 16:29:20 -0700592 break;
593
594 case AM_AY:
595 case AM_ZPY:
swissChilic51e9222020-08-07 16:09:14 -0700596 end += sprintf(end, "$%x, Y", addr);
swissChili6c61a792020-07-28 16:29:20 -0700597 break;
598
599 case AM_ZIX:
swissChilic51e9222020-08-07 16:09:14 -0700600 end += sprintf(end, "($%x, X)", addr);
swissChili6c61a792020-07-28 16:29:20 -0700601 break;
602
603 case AM_ZIY:
swissChilic51e9222020-08-07 16:09:14 -0700604 end += sprintf(end, "($%x), Y", addr);
swissChili6c61a792020-07-28 16:29:20 -0700605 break;
606 }
607
swissChilic51e9222020-08-07 16:09:14 -0700608 return end - buf;
swissChili6c61a792020-07-28 16:29:20 -0700609}
610
swissChilic51e9222020-08-07 16:09:14 -0700611char *disas_step(cpu_t *cpu)
swissChili6c61a792020-07-28 16:29:20 -0700612{
swissChilic51e9222020-08-07 16:09:14 -0700613 char *buffer = malloc(80);
614 char *end = buffer;
615
616 // end += sprintf(buffer, "$%x", cpu->pc);
swissChilicc27cfe2020-08-08 12:57:57 -0700617 uint8_t op = cpu->mem[scr_dirty(cpu, cpu->pc++)];
swissChili6c61a792020-07-28 16:29:20 -0700618 switch (op)
619 {
620#define INST(mn, am, op) \
621 case op: \
swissChilic51e9222020-08-07 16:09:14 -0700622 end += dump_inst(cpu, end, #mn, \
swissChili710d18d2020-07-29 19:43:20 -0700623 fetch_addr(cpu, am, FETCH_NO_INDIRECTION).ptr, am); \
swissChili6c61a792020-07-28 16:29:20 -0700624 break;
625
626 INSTRUCTIONS
627
628#undef INST
629
630 default:
swissChilic51e9222020-08-07 16:09:14 -0700631 end += sprintf(end, "Undefined opcode %x", op);
swissChili6c61a792020-07-28 16:29:20 -0700632 }
swissChilic51e9222020-08-07 16:09:14 -0700633
634 *end = 0;
635
636 return buffer;
swissChili6c61a792020-07-28 16:29:20 -0700637}
638
swissChilida4803e2020-08-06 20:06:04 -0700639void disas_num(cpu_t *cpu, uint16_t num)
640{
swissChilic51e9222020-08-07 16:09:14 -0700641 uint16_t pc = cpu->pc;
swissChilida4803e2020-08-06 20:06:04 -0700642 for (int i = 0; i < num; i++)
643 {
swissChilic51e9222020-08-07 16:09:14 -0700644 uint16_t last_pc = cpu->pc;
645 char *line = disas_step(cpu);
646 printf("$%x\t%s\n", last_pc, line);
647 free(line);
swissChilida4803e2020-08-06 20:06:04 -0700648 }
swissChilic51e9222020-08-07 16:09:14 -0700649 cpu->pc = pc;
swissChilida4803e2020-08-06 20:06:04 -0700650}
651
swissChili6c61a792020-07-28 16:29:20 -0700652void disas(cpu_t *cpu)
653{
swissChilic51e9222020-08-07 16:09:14 -0700654 uint16_t pc = cpu->pc;
swissChili6264a3b2020-07-30 19:02:07 -0700655 // Raw binary, no way to know what's code what isn't
swissChili6c61a792020-07-28 16:29:20 -0700656 while (cpu->pc < 0xFFFF)
657 {
swissChilic51e9222020-08-07 16:09:14 -0700658 uint16_t last_pc = cpu->pc;
659 char *line = disas_step(cpu);
660 printf("$%x\t%s\n", last_pc, line);
661 free(line);
swissChili6c61a792020-07-28 16:29:20 -0700662 }
swissChilic51e9222020-08-07 16:09:14 -0700663 cpu->pc = pc;
swissChili6c61a792020-07-28 16:29:20 -0700664}
swissChilic51e9222020-08-07 16:09:14 -0700665
swissChilida4803e2020-08-06 20:06:04 -0700666void run(cpu_t *cpu)
667{
668 while (cpu->running)
669 {
670 step(cpu);
671 }
672
673 printf("CPU Halted\n");
674}