blob: 8b5eda8c9a061399bf469e75bc6e4d28c84cfa4c [file] [log] [blame]
swissChili6c61a792020-07-28 16:29:20 -07001#include "cpu.h"
swissChilib71e0272020-08-08 15:56:14 -07002#include "common.h"
swissChili6c61a792020-07-28 16:29:20 -07003#include "instructions.h"
swissChili94ba1f52020-08-08 11:39:10 -07004#define SCREEN_ONLY_SDL
5#include "screen.h"
swissChili6c61a792020-07-28 16:29:20 -07006
swissChilic6b4f7e2020-08-09 16:36:36 -07007#include "dbg.h"
8#include <errno.h>
swissChili6c61a792020-07-28 16:29:20 -07009#include <endian.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13
14#define die(m, ...) \
swissChili6264a3b2020-07-30 19:02:07 -070015 printf("\033[31m" m "\033[0m\n", ##__VA_ARGS__); \
swissChili6c61a792020-07-28 16:29:20 -070016 exit(1);
17
swissChili6264a3b2020-07-30 19:02:07 -070018#define warn(m, ...) \
19 printf("\033[33m" m "\033[0m\n", ##__VA_ARGS__);
20
swissChili94ba1f52020-08-08 11:39:10 -070021
22sdl_screen_t *g_scr = NULL;
23
24
swissChilidbbd5402020-08-07 15:07:39 -070025void reset(cpu_t *cpu)
26{
swissChilib04a4022020-08-09 12:51:00 -070027 cpu->regs[SP] = 0xFF; // stack at is 0x100 + SP
swissChilibb478f12020-08-07 20:45:07 -070028 cpu->pc = 0x600; // arbitrary program counter start
swissChilidbbd5402020-08-07 15:07:39 -070029 cpu->running = true;
swissChilie7ee6da2020-08-08 16:14:21 -070030 memset(cpu->mem + 0x100, 0, 0xFE);
swissChilidbbd5402020-08-07 15:07:39 -070031}
32
swissChili6c61a792020-07-28 16:29:20 -070033cpu_t new_cpu()
34{
35 cpu_t cpu = { 0 };
swissChilib04a4022020-08-09 12:51:00 -070036 cpu.regs[SP] = 0xFF; // stack at is 0x100 + SP
swissChilibb478f12020-08-07 20:45:07 -070037 cpu.pc = 0x600; // arbitrary program counter start
swissChili6264a3b2020-07-30 19:02:07 -070038 cpu.running = true;
swissChili6c61a792020-07-28 16:29:20 -070039 cpu.mem = malloc(0xFFFF);
swissChilicc27cfe2020-08-08 12:57:57 -070040 cpu.screen_dirty = true;
swissChili6c61a792020-07-28 16:29:20 -070041 memset(cpu.mem, 0, 0xFFFF);
42
swissChilib71e0272020-08-08 15:56:14 -070043 ASSERT("Allocate memory for CPU", cpu.mem);
swissChili6c61a792020-07-28 16:29:20 -070044
45 return cpu;
46}
47
swissChilida4803e2020-08-06 20:06:04 -070048uint16_t le_to_native(uint8_t a, uint8_t b)
49{
50#ifdef LITTLE_ENDIAN
51 return b << 8 | a;
52#else
53 return a << 8 | b;
54#endif
55}
56
57void native_to_le(uint16_t n, uint8_t *a, uint8_t *b)
58{
59#ifdef LITTLE_ENDIAN
60 *a = n >> 8;
61 *b = n & 0xFF;
62#else
63 *a = n & 0xFF;
64 *b = n >> 8;
65#endif
66}
67
swissChili6264a3b2020-07-30 19:02:07 -070068void stack_push(cpu_t *cpu, uint8_t v)
69{
70 cpu->mem[cpu->regs[SP]-- + 0x100] = v;
71}
72
swissChilida4803e2020-08-06 20:06:04 -070073void stack_pushle(cpu_t *cpu, uint16_t v)
74{
75 uint8_t a, b;
76 native_to_le(v, &a, &b);
77 // push in "reverse" order so that the address is stored as LE
78 stack_push(cpu, b);
79 stack_push(cpu, a);
80}
81
swissChili6264a3b2020-07-30 19:02:07 -070082uint8_t stack_pop(cpu_t *cpu)
83{
84 return cpu->mem[cpu->regs[SP]++ + 0x100];
85}
86
swissChilida4803e2020-08-06 20:06:04 -070087uint16_t stack_pople(cpu_t *cpu)
88{
89 uint8_t a = stack_pop(cpu);
90 uint8_t b = stack_pop(cpu);
91 return le_to_native(a, b);
92}
93
swissChili6c61a792020-07-28 16:29:20 -070094void free_cpu(cpu_t *cpu)
95{
96 free(cpu->mem);
97}
98
swissChilida4803e2020-08-06 20:06:04 -070099// rotate right
swissChilicc27cfe2020-08-08 12:57:57 -0700100uint8_t ror(uint8_t a, uint8_t n)
swissChilida4803e2020-08-06 20:06:04 -0700101{
102 return (a >> n) | (a << (8 - n));
103}
104
105// rotate left
swissChilicc27cfe2020-08-08 12:57:57 -0700106uint8_t rol(uint8_t a, uint8_t n)
swissChilida4803e2020-08-06 20:06:04 -0700107{
108 return (a << n) | (a >> (8 - n));
109}
110
swissChilicc27cfe2020-08-08 12:57:57 -0700111void stat_nz(cpu_t *cpu, int8_t v)
swissChili6c61a792020-07-28 16:29:20 -0700112{
swissChili6264a3b2020-07-30 19:02:07 -0700113 cpu->status.negative = v < 0;
114 cpu->status.zero = v == 0;
115}
116
117// Used to check for overflow, is c unique?
swissChilicc27cfe2020-08-08 12:57:57 -0700118bool last_unique(bool a, bool b, bool c)
swissChili6264a3b2020-07-30 19:02:07 -0700119{
120 return a == b && a != c;
121}
122
swissChilicc27cfe2020-08-08 12:57:57 -0700123void stat_cv(cpu_t *cpu, uint8_t a, uint8_t b, uint8_t c)
swissChili6264a3b2020-07-30 19:02:07 -0700124{
125 cpu->status.overflow = last_unique(a >> 7, b >> 7, c >> 7);
126 cpu->status.carry = c < a || c < b;
127}
128
swissChilicc27cfe2020-08-08 12:57:57 -0700129void cmp(cpu_t *cpu, uint8_t reg, uint8_t mem)
swissChilida4803e2020-08-06 20:06:04 -0700130{
131 cpu->status.negative = 0;
132 cpu->status.zero = 0;
133 cpu->status.carry = 0;
134 if (cpu->regs[reg] < mem)
135 {
136 cpu->status.negative = 1;
137 }
138 else if (cpu->regs[reg] == mem)
139 {
140 cpu->status.zero = 1;
141 cpu->status.carry = 1;
142 }
143 else
144 {
145 cpu->status.carry = 1;
146 }
147}
148
swissChilicc27cfe2020-08-08 12:57:57 -0700149uint16_t scr_dirty(cpu_t *cpu, uint16_t mem)
150{
151 if (mem >= 0x200 && mem <= 0x200 + 32 * 32)
152 cpu->screen_dirty = true;
153
154 return mem;
155}
156
swissChilida4803e2020-08-06 20:06:04 -0700157void execute(cpu_t *cpu, const char *mnemonic, uint8_t op, arg_t a, uint8_t am)
swissChili6264a3b2020-07-30 19:02:07 -0700158{
159 // used to save space
160 #define REGS \
161 R(X) R(A) R(Y)
162
swissChili710d18d2020-07-29 19:43:20 -0700163 switch (op) {
swissChili6264a3b2020-07-30 19:02:07 -0700164 // Load and store instructions:
165 #define R(reg) \
166 case LD##reg: \
167 cpu->regs[reg] = a.val; \
168 stat_nz(cpu, a.val); \
169 break;
170
171 REGS
172
173 #undef R
174
175 #define R(reg) \
176 case ST##reg: \
swissChilicc27cfe2020-08-08 12:57:57 -0700177 cpu->mem[scr_dirty(cpu, a.ptr)] = cpu->regs[reg]; \
swissChili6264a3b2020-07-30 19:02:07 -0700178 break; \
179
180 REGS
181
182 #undef R
183
184 // Arithmetic instructions:
185 // NOTE: binary coded decimals are NOT SUPPORTED because I don't want
186 // to implement them.
187 case ADC:
188 {
189 uint8_t sum = cpu->regs[A] + a.val + cpu->status.carry;
190 // signed overflow
191 stat_cv(cpu, cpu->regs[A], a.val + cpu->status.carry, sum);
192 stat_nz(cpu, sum);
193 cpu->regs[A] = sum;
194 break;
195 }
196
197 case SBC:
198 {
199 uint8_t diff = cpu->regs[A] - a.val - !cpu->status.carry;
200 stat_cv(cpu, cpu->regs[A], a.val - !cpu->status.carry, diff);
201 stat_nz(cpu, diff);
202 cpu->regs[A] = diff;
203 break;
204 }
205
206 case INC:
swissChilicc27cfe2020-08-08 12:57:57 -0700207 cpu->mem[scr_dirty(cpu, scr_dirty(cpu, a.ptr))]++;
208 stat_nz(cpu, cpu->mem[scr_dirty(cpu, a.ptr)]);
swissChili6264a3b2020-07-30 19:02:07 -0700209 break;
210
211 case INX:
212 cpu->regs[X]++;
213 stat_nz(cpu, cpu->regs[X]);
214 break;
215
216 case INY:
217 cpu->regs[Y]++;
218 stat_nz(cpu, cpu->regs[Y]);
219 break;
220
221 case DEC:
swissChilicc27cfe2020-08-08 12:57:57 -0700222 cpu->mem[scr_dirty(cpu, a.ptr)]--;
223 stat_nz(cpu, cpu->mem[scr_dirty(cpu, a.ptr)]);
swissChili6264a3b2020-07-30 19:02:07 -0700224 break;
swissChilida4803e2020-08-06 20:06:04 -0700225
226 case DEX:
227 cpu->regs[X]--;
228 stat_nz(cpu, cpu->regs[X]);
229 break;
230
231 case DEY:
232 cpu->regs[Y]--;
233 stat_nz(cpu, cpu->regs[Y]);
234 break;
235
236 case ASL:
237 // This check must be done here unfortunately, it would be nice
238 // to do this while decoding operands but it would require
239 // a substantial change to the architecture of the emulator
240 if (am == AM_ACC)
241 {
242 cpu->status.carry = cpu->regs[A] >> 7;
243 cpu->regs[A] <<= 1;
244 stat_nz(cpu, cpu->regs[A]);
245 }
246 else
247 {
swissChilicc27cfe2020-08-08 12:57:57 -0700248 cpu->status.carry = cpu->mem[scr_dirty(cpu, a.val)] >> 7;
249 cpu->mem[scr_dirty(cpu, a.ptr)] <<= 1;
250 stat_nz(cpu, cpu->mem[scr_dirty(cpu, a.ptr)]);
swissChilida4803e2020-08-06 20:06:04 -0700251 }
252 break;
253
254 case LSR:
255 if (am == AM_ACC)
256 {
257 cpu->status.carry = cpu->regs[A] & 1;
258 cpu->regs[A] >>= 1;
259 stat_nz(cpu, cpu->regs[A]);
260 }
261 else
262 {
swissChilicc27cfe2020-08-08 12:57:57 -0700263 cpu->status.carry = cpu->mem[scr_dirty(cpu, a.val)] & 7;
264 cpu->mem[scr_dirty(cpu, a.ptr)] >>= 1;
265 stat_nz(cpu, cpu->mem[scr_dirty(cpu, a.ptr)]);
swissChilida4803e2020-08-06 20:06:04 -0700266 }
267 break;
268
269 case ROL:
270 if (am == AM_ACC)
271 {
272 cpu->status.carry = cpu->regs[A] >> 7;
273 cpu->regs[A] = rol(cpu->regs[A], 1);
274 stat_nz(cpu, cpu->regs[A]);
275 }
276 else
277 {
swissChilicc27cfe2020-08-08 12:57:57 -0700278 cpu->status.carry = cpu->mem[scr_dirty(cpu, a.val)] >> 7;
279 cpu->mem[scr_dirty(cpu, a.ptr)] = rol(a.val, 1);
280 stat_nz(cpu, cpu->mem[scr_dirty(cpu, a.ptr)]);
swissChilida4803e2020-08-06 20:06:04 -0700281 }
282 break;
283
284 case ROR:
285 if (am == AM_ACC)
286 {
287 cpu->status.carry = cpu->regs[A] & 1;
288 cpu->regs[A] = ror(cpu->regs[A], 1);
289 stat_nz(cpu, cpu->regs[A]);
290 }
291 else
292 {
swissChilicc27cfe2020-08-08 12:57:57 -0700293 cpu->status.carry = cpu->mem[scr_dirty(cpu, a.val)] & 1;
294 cpu->mem[scr_dirty(cpu, a.ptr)] = ror(a.val, 1);
295 stat_nz(cpu, cpu->mem[scr_dirty(cpu, a.ptr)]);
swissChilida4803e2020-08-06 20:06:04 -0700296 }
297 break;
298
299 case AND:
300 cpu->regs[A] &= a.val;
301 stat_nz(cpu, cpu->regs[A]);
302 break;
303
304 case ORA:
305 cpu->regs[A] |= a.val;
306 stat_nz(cpu, cpu->regs[A]);
307 break;
308
309 case EOR:
310 cpu->regs[A] ^= a.val;
311 stat_nz(cpu, cpu->regs[A]);
312 break;
313
314 case CMP:
315 cmp(cpu, A, a.val);
316 break;
317
318 case CPX:
319 cmp(cpu, X, a.val);
320 break;
321
322 case CPY:
323 cmp(cpu, Y, a.val);
324 break;
325
326 // TODO: implement BIT here
327
328 #define BRANCHES \
329 B(BCC, carry == 0) \
330 B(BCS, carry == 1) \
331 B(BNE, zero == 0) \
332 B(BEQ, zero == 1) \
333 B(BPL, negative == 0) \
334 B(BMI, negative == 1) \
335 B(BVC, overflow == 0) \
336 B(BVS, overflow == 1)
337
338 #define B(i, c) \
339 case i: \
340 if (cpu->status . c) \
341 cpu->pc = a.ptr;\
342 break;
343
344 BRANCHES
345
346 #undef B
347 #undef BRANCHES
348
349 #define TRANSFERS \
350 T(A, X) \
351 T(X, A) \
352 T(A, Y) \
353 T(Y, A)
354
355 #define T(a, b) \
356 case T ## a ## b: \
357 cpu->regs[b] = cpu->regs[a]; \
358 stat_nz(cpu, cpu->regs[b]); \
359 break;
360
361 TRANSFERS
362
363 #undef T
364 #undef TRANSFERS
365
366 case TSX:
367 cpu->regs[X] = cpu->regs[SP];
368 stat_nz(cpu, cpu->regs[X]);
369 break;
370
371 case TXS:
372 cpu->regs[SP] = cpu->regs[X];
373 stat_nz(cpu, cpu->regs[X]);
374 break;
375
376 case PHA:
377 stack_push(cpu, cpu->regs[A]);
378 break;
379
380 case PLA:
381 cpu->regs[A] = stack_pop(cpu);
382 stat_nz(cpu, cpu->regs[A]);
383 break;
384
385 case PHP:
386 stack_push(cpu, *(uint8_t *)(&cpu->status));
387 break;
388
389 case PLP:
390 {
391 uint8_t s = stack_pop(cpu);
392 *(uint8_t *)(&cpu->status) = s;
393 }
394
395 case JMP:
396 cpu->pc = a.ptr;
397 break;
398
399 case JSR:
400 stack_pushle(cpu, cpu->pc);
swissChilib04a4022020-08-09 12:51:00 -0700401 cpu->pc = a.ptr;
swissChilida4803e2020-08-06 20:06:04 -0700402 break;
403
404 case RTS:
405 cpu->pc = stack_pople(cpu);
406 break;
407
408 // TODO: implement RTI
409 // TODO: implement flag instructions
410
411 case BRK:
412 // TODO: trigger an interrupt
413 cpu->running = false;
414 break;
415
416 case NOP:
417 break;
418
419 default:
swissChilib71e0272020-08-08 15:56:14 -0700420 warn("Unsupported opcode: %x\n", op);
421 THROW("Unsupported opcode");
swissChili710d18d2020-07-29 19:43:20 -0700422 }
swissChili6264a3b2020-07-30 19:02:07 -0700423 #undef REGS
swissChili6c61a792020-07-28 16:29:20 -0700424}
425
swissChilicc27cfe2020-08-08 12:57:57 -0700426uint16_t fetch_le(cpu_t *cpu)
swissChili6c61a792020-07-28 16:29:20 -0700427{
swissChilicc27cfe2020-08-08 12:57:57 -0700428 uint8_t a = cpu->mem[scr_dirty(cpu, cpu->pc++)];
429 uint8_t b = cpu->mem[scr_dirty(cpu, cpu->pc++)];
swissChili6c61a792020-07-28 16:29:20 -0700430 return le_to_native(a, b);
431}
432
swissChilicc27cfe2020-08-08 12:57:57 -0700433arg_t arg_imm(uint16_t a)
swissChili710d18d2020-07-29 19:43:20 -0700434{
435 return (arg_t){ a, a };
436}
437
swissChilicc27cfe2020-08-08 12:57:57 -0700438arg_t arg_ptr(cpu_t *c, uint flags, uint16_t p)
swissChili710d18d2020-07-29 19:43:20 -0700439{
440 if (flags & FETCH_NO_INDIRECTION)
441 return arg_imm(p);
442
443 return (arg_t){ c->mem[p], p };
444}
445
swissChilicc27cfe2020-08-08 12:57:57 -0700446arg_t arg(uint16_t v, uint16_t a)
swissChili710d18d2020-07-29 19:43:20 -0700447{
448 return (arg_t){ v, a };
449}
450
451arg_t fetch_addr(cpu_t *cpu, uint8_t am, uint f)
swissChili6c61a792020-07-28 16:29:20 -0700452{
453 switch (am)
454 {
455 case AM_ACC:
456 case AM_IMP:
swissChili710d18d2020-07-29 19:43:20 -0700457 return arg_imm(0);
swissChili6c61a792020-07-28 16:29:20 -0700458
459 // In both cases return immediate 8 bit value
460 case AM_IMM:
461 case AM_ZP:
swissChilicc27cfe2020-08-08 12:57:57 -0700462 return arg_imm(cpu->mem[scr_dirty(cpu, cpu->pc++)]);
swissChili6c61a792020-07-28 16:29:20 -0700463
464 case AM_ABS:
swissChili710d18d2020-07-29 19:43:20 -0700465 return arg_ptr(cpu, f, fetch_le(cpu));
swissChili6c61a792020-07-28 16:29:20 -0700466
467 case AM_REL:
468 {
swissChili6264a3b2020-07-30 19:02:07 -0700469 // Aparently, PC should will point to the NEXT opcode
470 // I can't find any documentation on this unfortunately, but
471 // I have discovered this through testing the output of other
472 // assemblers.
473 uint16_t pc = cpu->pc + 1;
swissChilicc27cfe2020-08-08 12:57:57 -0700474 return arg_ptr(cpu, f, (int8_t)cpu->mem[scr_dirty(cpu, cpu->pc++)] + pc);
swissChili6c61a792020-07-28 16:29:20 -0700475 }
476
477 case AM_IND:
478 {
479 uint16_t addr = fetch_le(cpu);
swissChili6264a3b2020-07-30 19:02:07 -0700480
481 if (f & FETCH_NO_INDIRECTION)
482 return arg_imm(addr);
483
swissChilicc27cfe2020-08-08 12:57:57 -0700484 uint8_t low = cpu->mem[scr_dirty(cpu, addr)],
485 high = cpu->mem[scr_dirty(cpu, addr + 1)];
swissChili6c61a792020-07-28 16:29:20 -0700486
swissChili710d18d2020-07-29 19:43:20 -0700487 return arg_ptr(cpu, f, le_to_native(low, high));
swissChili6c61a792020-07-28 16:29:20 -0700488 }
489
490 case AM_AX:
swissChili94ba1f52020-08-08 11:39:10 -0700491 if (f & FETCH_NO_INDIRECTION)
492 return arg_ptr(cpu, f, fetch_le(cpu));
493
swissChili710d18d2020-07-29 19:43:20 -0700494 return arg_ptr(cpu, f, fetch_le(cpu) + cpu->regs[X]);
swissChili6c61a792020-07-28 16:29:20 -0700495
496 case AM_AY:
swissChili94ba1f52020-08-08 11:39:10 -0700497 if (f & FETCH_NO_INDIRECTION)
498 return arg_ptr(cpu, f, fetch_le(cpu));
499
swissChili710d18d2020-07-29 19:43:20 -0700500 return arg_ptr(cpu, f, fetch_le(cpu) + cpu->regs[Y]);
swissChili6c61a792020-07-28 16:29:20 -0700501
502 case AM_ZPX:
swissChili94ba1f52020-08-08 11:39:10 -0700503 if (f & FETCH_NO_INDIRECTION)
swissChilib71e0272020-08-08 15:56:14 -0700504 return arg_ptr(cpu, f, cpu->mem[cpu->pc++]);
505 return arg_ptr(cpu, f, cpu->mem[cpu->pc++] + cpu->regs[X]);
swissChili6c61a792020-07-28 16:29:20 -0700506
507 case AM_ZPY:
swissChili94ba1f52020-08-08 11:39:10 -0700508 if (f & FETCH_NO_INDIRECTION)
swissChilib71e0272020-08-08 15:56:14 -0700509 return arg_ptr(cpu, f, cpu->mem[cpu->pc++]);
510 return arg_ptr(cpu, f, cpu->mem[cpu->pc++] + cpu->regs[Y]);
swissChili6c61a792020-07-28 16:29:20 -0700511
512 case AM_ZIX:
513 {
swissChilib71e0272020-08-08 15:56:14 -0700514 uint8_t zp = cpu->mem[cpu->pc++];
swissChili6264a3b2020-07-30 19:02:07 -0700515
516 if (f & FETCH_NO_INDIRECTION)
517 return arg_imm(zp);
518
swissChili710d18d2020-07-29 19:43:20 -0700519 uint16_t addr = zp + cpu->regs[X];
swissChilib71e0272020-08-08 15:56:14 -0700520 uint16_t indirect = le_to_native(cpu->mem[addr], cpu->mem[addr + 1]);
swissChili710d18d2020-07-29 19:43:20 -0700521 return arg_ptr(cpu, f, indirect);
swissChili6c61a792020-07-28 16:29:20 -0700522 }
523
524 case AM_ZIY:
525 {
swissChilicc27cfe2020-08-08 12:57:57 -0700526 uint8_t zp = cpu->mem[scr_dirty(cpu, cpu->pc++)];
swissChili6264a3b2020-07-30 19:02:07 -0700527
528 if (f & FETCH_NO_INDIRECTION)
529 return arg_imm(zp);
530
swissChilib71e0272020-08-08 15:56:14 -0700531 uint16_t base = le_to_native(cpu->mem[zp], cpu->mem[scr_dirty(cpu, zp + 1)]);
swissChili710d18d2020-07-29 19:43:20 -0700532 return arg_ptr(cpu, f, base + cpu->regs[Y]);
swissChili6c61a792020-07-28 16:29:20 -0700533 }
534
535 default:
swissChilib71e0272020-08-08 15:56:14 -0700536 warn("Unknown address mode %x", am);
537 THROW("Unknowng address mode");
swissChili710d18d2020-07-29 19:43:20 -0700538 __builtin_unreachable();
swissChili6c61a792020-07-28 16:29:20 -0700539 }
540}
541
swissChilicc27cfe2020-08-08 12:57:57 -0700542void step(cpu_t *cpu)
swissChili6c61a792020-07-28 16:29:20 -0700543{
swissChilicc27cfe2020-08-08 12:57:57 -0700544 cpu->screen_dirty = false;
swissChilib71e0272020-08-08 15:56:14 -0700545 uint8_t pc = cpu->pc;
546 uint8_t op = cpu->mem[cpu->pc++];
547 switch (op)
swissChili6c61a792020-07-28 16:29:20 -0700548 {
549#define INST(mn, am, op) \
550 case op: \
swissChilida4803e2020-08-06 20:06:04 -0700551 execute(cpu, #mn, mn, fetch_addr(cpu, am, 0), am); \
swissChili6c61a792020-07-28 16:29:20 -0700552 break;
553
554 INSTRUCTIONS
555
556#undef INST
557
558 default:
swissChilib71e0272020-08-08 15:56:14 -0700559 warn("Undefined opcode %x near %x [%x]", op, pc, cpu->mem[pc]);
560 THROW("Undefined opcode");
swissChili6c61a792020-07-28 16:29:20 -0700561 }
562}
563
swissChilic51e9222020-08-07 16:09:14 -0700564int dump_inst(cpu_t *cpu, char *buf, const char *mn, uint16_t addr, uint8_t am)
swissChili6c61a792020-07-28 16:29:20 -0700565{
swissChilic51e9222020-08-07 16:09:14 -0700566 char *end = buf;
567 end += sprintf(end, "%s ", mn);
swissChili6c61a792020-07-28 16:29:20 -0700568
569 switch (am)
570 {
571 case AM_IMM:
swissChilic51e9222020-08-07 16:09:14 -0700572 end += sprintf(end, "#");
swissChili6c61a792020-07-28 16:29:20 -0700573 case AM_REL:
574 case AM_ABS:
575 case AM_ZP:
swissChilic51e9222020-08-07 16:09:14 -0700576 end += sprintf(end, "$%x", addr);
swissChili6c61a792020-07-28 16:29:20 -0700577 break;
578
579 case AM_IND:
swissChilic51e9222020-08-07 16:09:14 -0700580 end += sprintf(end, "($%x)", addr);
swissChili6c61a792020-07-28 16:29:20 -0700581 break;
582
583 case AM_AX:
584 case AM_ZPX:
swissChilic51e9222020-08-07 16:09:14 -0700585 end += sprintf(end, "$%x, X", addr);
swissChili6c61a792020-07-28 16:29:20 -0700586 break;
587
588 case AM_AY:
589 case AM_ZPY:
swissChilic51e9222020-08-07 16:09:14 -0700590 end += sprintf(end, "$%x, Y", addr);
swissChili6c61a792020-07-28 16:29:20 -0700591 break;
592
593 case AM_ZIX:
swissChilic51e9222020-08-07 16:09:14 -0700594 end += sprintf(end, "($%x, X)", addr);
swissChili6c61a792020-07-28 16:29:20 -0700595 break;
596
597 case AM_ZIY:
swissChilic51e9222020-08-07 16:09:14 -0700598 end += sprintf(end, "($%x), Y", addr);
swissChili6c61a792020-07-28 16:29:20 -0700599 break;
600 }
601
swissChilic51e9222020-08-07 16:09:14 -0700602 return end - buf;
swissChili6c61a792020-07-28 16:29:20 -0700603}
604
swissChilic51e9222020-08-07 16:09:14 -0700605char *disas_step(cpu_t *cpu)
swissChili6c61a792020-07-28 16:29:20 -0700606{
swissChilic51e9222020-08-07 16:09:14 -0700607 char *buffer = malloc(80);
608 char *end = buffer;
609
610 // end += sprintf(buffer, "$%x", cpu->pc);
swissChilicc27cfe2020-08-08 12:57:57 -0700611 uint8_t op = cpu->mem[scr_dirty(cpu, cpu->pc++)];
swissChili6c61a792020-07-28 16:29:20 -0700612 switch (op)
613 {
614#define INST(mn, am, op) \
615 case op: \
swissChilic51e9222020-08-07 16:09:14 -0700616 end += dump_inst(cpu, end, #mn, \
swissChili710d18d2020-07-29 19:43:20 -0700617 fetch_addr(cpu, am, FETCH_NO_INDIRECTION).ptr, am); \
swissChili6c61a792020-07-28 16:29:20 -0700618 break;
619
620 INSTRUCTIONS
621
622#undef INST
623
624 default:
swissChilic51e9222020-08-07 16:09:14 -0700625 end += sprintf(end, "Undefined opcode %x", op);
swissChili6c61a792020-07-28 16:29:20 -0700626 }
swissChilic51e9222020-08-07 16:09:14 -0700627
628 *end = 0;
629
630 return buffer;
swissChili6c61a792020-07-28 16:29:20 -0700631}
632
swissChilida4803e2020-08-06 20:06:04 -0700633void disas_num(cpu_t *cpu, uint16_t num)
634{
swissChilic51e9222020-08-07 16:09:14 -0700635 uint16_t pc = cpu->pc;
swissChilida4803e2020-08-06 20:06:04 -0700636 for (int i = 0; i < num; i++)
637 {
swissChilic51e9222020-08-07 16:09:14 -0700638 uint16_t last_pc = cpu->pc;
639 char *line = disas_step(cpu);
640 printf("$%x\t%s\n", last_pc, line);
641 free(line);
swissChilida4803e2020-08-06 20:06:04 -0700642 }
swissChilic51e9222020-08-07 16:09:14 -0700643 cpu->pc = pc;
swissChilida4803e2020-08-06 20:06:04 -0700644}
645
swissChili6c61a792020-07-28 16:29:20 -0700646void disas(cpu_t *cpu)
647{
swissChilic51e9222020-08-07 16:09:14 -0700648 uint16_t pc = cpu->pc;
swissChili6264a3b2020-07-30 19:02:07 -0700649 // Raw binary, no way to know what's code what isn't
swissChili6c61a792020-07-28 16:29:20 -0700650 while (cpu->pc < 0xFFFF)
651 {
swissChilic51e9222020-08-07 16:09:14 -0700652 uint16_t last_pc = cpu->pc;
653 char *line = disas_step(cpu);
654 printf("$%x\t%s\n", last_pc, line);
655 free(line);
swissChili6c61a792020-07-28 16:29:20 -0700656 }
swissChilic51e9222020-08-07 16:09:14 -0700657 cpu->pc = pc;
swissChili6c61a792020-07-28 16:29:20 -0700658}
swissChilic51e9222020-08-07 16:09:14 -0700659
swissChilida4803e2020-08-06 20:06:04 -0700660void run(cpu_t *cpu)
661{
662 while (cpu->running)
663 {
664 step(cpu);
665 }
666
667 printf("CPU Halted\n");
668}
swissChilic6b4f7e2020-08-09 16:36:36 -0700669
670void run_mq(cpu_t *cpu, mqd_t mq)
671{
672 char buf[MQ_BUF_LEN];
673 bool running;
674
675 while (true)
676 {
677 if (running)
678 {
679 if (cpu->running)
680 step(cpu);
681 else
682 running = false;
683 }
684
685 ssize_t recvd = mq_receive(mq, buf, MQ_BUF_LEN * 2, NULL);
686
687 if (recvd == -1 && errno != EAGAIN)
688 {
689 printf("errno = %d\n", errno);
690 THROW("mq_receive returned -1");
691 }
692
693 if (recvd > 0)
694 {
695 if (debug_stmt(cpu, buf, &running))
696 break;
697 }
698 }
699}