blob: ce9c5cc38add231d9d2f0227420822b28b331606 [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"
4
swissChilic6b4f7e2020-08-09 16:36:36 -07005#include "dbg.h"
6#include <errno.h>
swissChili6c61a792020-07-28 16:29:20 -07007#include <endian.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11
swissChili6c61a792020-07-28 16:29:20 -070012
swissChili6264a3b2020-07-30 19:02:07 -070013#define warn(m, ...) \
14 printf("\033[33m" m "\033[0m\n", ##__VA_ARGS__);
15
swissChili94ba1f52020-08-08 11:39:10 -070016
swissChilidbbd5402020-08-07 15:07:39 -070017void reset(cpu_t *cpu)
18{
swissChilib04a4022020-08-09 12:51:00 -070019 cpu->regs[SP] = 0xFF; // stack at is 0x100 + SP
swissChilibb478f12020-08-07 20:45:07 -070020 cpu->pc = 0x600; // arbitrary program counter start
swissChilidbbd5402020-08-07 15:07:39 -070021 cpu->running = true;
swissChilie7ee6da2020-08-08 16:14:21 -070022 memset(cpu->mem + 0x100, 0, 0xFE);
swissChilidbbd5402020-08-07 15:07:39 -070023}
24
swissChili6c61a792020-07-28 16:29:20 -070025cpu_t new_cpu()
26{
27 cpu_t cpu = { 0 };
swissChilib04a4022020-08-09 12:51:00 -070028 cpu.regs[SP] = 0xFF; // stack at is 0x100 + SP
swissChilibb478f12020-08-07 20:45:07 -070029 cpu.pc = 0x600; // arbitrary program counter start
swissChili6264a3b2020-07-30 19:02:07 -070030 cpu.running = true;
swissChili6c61a792020-07-28 16:29:20 -070031 cpu.mem = malloc(0xFFFF);
swissChilicc27cfe2020-08-08 12:57:57 -070032 cpu.screen_dirty = true;
swissChili6c61a792020-07-28 16:29:20 -070033 memset(cpu.mem, 0, 0xFFFF);
34
swissChilib71e0272020-08-08 15:56:14 -070035 ASSERT("Allocate memory for CPU", cpu.mem);
swissChili6c61a792020-07-28 16:29:20 -070036
37 return cpu;
38}
39
swissChilida4803e2020-08-06 20:06:04 -070040uint16_t le_to_native(uint8_t a, uint8_t b)
41{
42#ifdef LITTLE_ENDIAN
swissChili6a923012020-08-18 17:47:27 -070043 //printf("Little Endian\n");
swissChilida4803e2020-08-06 20:06:04 -070044 return b << 8 | a;
45#else
swissChili6a923012020-08-18 17:47:27 -070046 //printf("Big Endian\n");
47 return a << 8 | b;
swissChilida4803e2020-08-06 20:06:04 -070048#endif
49}
50
51void native_to_le(uint16_t n, uint8_t *a, uint8_t *b)
52{
53#ifdef LITTLE_ENDIAN
swissChilida4803e2020-08-06 20:06:04 -070054 *b = n >> 8;
swissChili6a923012020-08-18 17:47:27 -070055 *a = n & 0xFF;
56#else
57 *b = n & 0xFF;
58 *a = n >> 8;
swissChilida4803e2020-08-06 20:06:04 -070059#endif
60}
61
swissChili6264a3b2020-07-30 19:02:07 -070062void stack_push(cpu_t *cpu, uint8_t v)
63{
64 cpu->mem[cpu->regs[SP]-- + 0x100] = v;
65}
66
swissChilida4803e2020-08-06 20:06:04 -070067void stack_pushle(cpu_t *cpu, uint16_t v)
68{
69 uint8_t a, b;
70 native_to_le(v, &a, &b);
71 // push in "reverse" order so that the address is stored as LE
72 stack_push(cpu, b);
73 stack_push(cpu, a);
74}
75
swissChili6264a3b2020-07-30 19:02:07 -070076uint8_t stack_pop(cpu_t *cpu)
77{
78 return cpu->mem[cpu->regs[SP]++ + 0x100];
79}
80
swissChilida4803e2020-08-06 20:06:04 -070081uint16_t stack_pople(cpu_t *cpu)
82{
83 uint8_t a = stack_pop(cpu);
84 uint8_t b = stack_pop(cpu);
swissChili6a923012020-08-18 17:47:27 -070085 return le_to_native(b, a);
swissChilida4803e2020-08-06 20:06:04 -070086}
87
swissChili6c61a792020-07-28 16:29:20 -070088void free_cpu(cpu_t *cpu)
89{
90 free(cpu->mem);
91}
92
swissChilida4803e2020-08-06 20:06:04 -070093// rotate right
swissChilicc27cfe2020-08-08 12:57:57 -070094uint8_t ror(uint8_t a, uint8_t n)
swissChilida4803e2020-08-06 20:06:04 -070095{
96 return (a >> n) | (a << (8 - n));
97}
98
99// rotate left
swissChilicc27cfe2020-08-08 12:57:57 -0700100uint8_t rol(uint8_t a, uint8_t n)
swissChilida4803e2020-08-06 20:06:04 -0700101{
102 return (a << n) | (a >> (8 - n));
103}
104
swissChilicc27cfe2020-08-08 12:57:57 -0700105void stat_nz(cpu_t *cpu, int8_t v)
swissChili6c61a792020-07-28 16:29:20 -0700106{
swissChili6264a3b2020-07-30 19:02:07 -0700107 cpu->status.negative = v < 0;
108 cpu->status.zero = v == 0;
109}
110
111// Used to check for overflow, is c unique?
swissChilicc27cfe2020-08-08 12:57:57 -0700112bool last_unique(bool a, bool b, bool c)
swissChili6264a3b2020-07-30 19:02:07 -0700113{
114 return a == b && a != c;
115}
116
swissChilicc27cfe2020-08-08 12:57:57 -0700117void stat_cv(cpu_t *cpu, uint8_t a, uint8_t b, uint8_t c)
swissChili6264a3b2020-07-30 19:02:07 -0700118{
119 cpu->status.overflow = last_unique(a >> 7, b >> 7, c >> 7);
120 cpu->status.carry = c < a || c < b;
121}
122
swissChilicc27cfe2020-08-08 12:57:57 -0700123void cmp(cpu_t *cpu, uint8_t reg, uint8_t mem)
swissChilida4803e2020-08-06 20:06:04 -0700124{
125 cpu->status.negative = 0;
126 cpu->status.zero = 0;
127 cpu->status.carry = 0;
128 if (cpu->regs[reg] < mem)
129 {
130 cpu->status.negative = 1;
131 }
132 else if (cpu->regs[reg] == mem)
133 {
134 cpu->status.zero = 1;
135 cpu->status.carry = 1;
136 }
137 else
138 {
139 cpu->status.carry = 1;
140 }
141}
142
143void execute(cpu_t *cpu, const char *mnemonic, uint8_t op, arg_t a, uint8_t am)
swissChili6264a3b2020-07-30 19:02:07 -0700144{
145 // used to save space
146 #define REGS \
147 R(X) R(A) R(Y)
148
swissChili710d18d2020-07-29 19:43:20 -0700149 switch (op) {
swissChili6264a3b2020-07-30 19:02:07 -0700150 // Load and store instructions:
151 #define R(reg) \
152 case LD##reg: \
153 cpu->regs[reg] = a.val; \
154 stat_nz(cpu, a.val); \
155 break;
156
157 REGS
158
159 #undef R
160
161 #define R(reg) \
162 case ST##reg: \
swissChili1970cb82020-08-10 13:22:39 -0700163 cpu->mem[a.ptr] = cpu->regs[reg]; \
swissChili6264a3b2020-07-30 19:02:07 -0700164 break; \
165
166 REGS
167
168 #undef R
169
170 // Arithmetic instructions:
171 // NOTE: binary coded decimals are NOT SUPPORTED because I don't want
172 // to implement them.
173 case ADC:
174 {
175 uint8_t sum = cpu->regs[A] + a.val + cpu->status.carry;
176 // signed overflow
177 stat_cv(cpu, cpu->regs[A], a.val + cpu->status.carry, sum);
178 stat_nz(cpu, sum);
179 cpu->regs[A] = sum;
180 break;
181 }
182
183 case SBC:
184 {
185 uint8_t diff = cpu->regs[A] - a.val - !cpu->status.carry;
186 stat_cv(cpu, cpu->regs[A], a.val - !cpu->status.carry, diff);
187 stat_nz(cpu, diff);
188 cpu->regs[A] = diff;
189 break;
190 }
191
192 case INC:
swissChili1970cb82020-08-10 13:22:39 -0700193 cpu->mem[a.ptr]++;
194 stat_nz(cpu, cpu->mem[a.ptr]);
swissChili6264a3b2020-07-30 19:02:07 -0700195 break;
196
197 case INX:
198 cpu->regs[X]++;
199 stat_nz(cpu, cpu->regs[X]);
200 break;
201
202 case INY:
203 cpu->regs[Y]++;
204 stat_nz(cpu, cpu->regs[Y]);
205 break;
206
207 case DEC:
swissChili1970cb82020-08-10 13:22:39 -0700208 cpu->mem[a.ptr]--;
209 stat_nz(cpu, cpu->mem[a.ptr]);
swissChili6264a3b2020-07-30 19:02:07 -0700210 break;
swissChilida4803e2020-08-06 20:06:04 -0700211
212 case DEX:
213 cpu->regs[X]--;
214 stat_nz(cpu, cpu->regs[X]);
215 break;
216
217 case DEY:
218 cpu->regs[Y]--;
219 stat_nz(cpu, cpu->regs[Y]);
220 break;
221
222 case ASL:
223 // This check must be done here unfortunately, it would be nice
224 // to do this while decoding operands but it would require
225 // a substantial change to the architecture of the emulator
226 if (am == AM_ACC)
227 {
228 cpu->status.carry = cpu->regs[A] >> 7;
229 cpu->regs[A] <<= 1;
230 stat_nz(cpu, cpu->regs[A]);
231 }
232 else
233 {
swissChili1970cb82020-08-10 13:22:39 -0700234 cpu->status.carry = cpu->mem[a.val] >> 7;
235 cpu->mem[a.ptr] <<= 1;
236 stat_nz(cpu, cpu->mem[a.ptr]);
swissChilida4803e2020-08-06 20:06:04 -0700237 }
238 break;
239
240 case LSR:
241 if (am == AM_ACC)
242 {
243 cpu->status.carry = cpu->regs[A] & 1;
244 cpu->regs[A] >>= 1;
245 stat_nz(cpu, cpu->regs[A]);
246 }
247 else
248 {
swissChili1970cb82020-08-10 13:22:39 -0700249 cpu->status.carry = cpu->mem[a.val] & 7;
250 cpu->mem[a.ptr] >>= 1;
251 stat_nz(cpu, cpu->mem[a.ptr]);
swissChilida4803e2020-08-06 20:06:04 -0700252 }
253 break;
254
255 case ROL:
256 if (am == AM_ACC)
257 {
258 cpu->status.carry = cpu->regs[A] >> 7;
259 cpu->regs[A] = rol(cpu->regs[A], 1);
260 stat_nz(cpu, cpu->regs[A]);
261 }
262 else
263 {
swissChili1970cb82020-08-10 13:22:39 -0700264 cpu->status.carry = cpu->mem[a.val] >> 7;
265 cpu->mem[a.ptr] = rol(a.val, 1);
266 stat_nz(cpu, cpu->mem[a.ptr]);
swissChilida4803e2020-08-06 20:06:04 -0700267 }
268 break;
269
270 case ROR:
271 if (am == AM_ACC)
272 {
273 cpu->status.carry = cpu->regs[A] & 1;
274 cpu->regs[A] = ror(cpu->regs[A], 1);
275 stat_nz(cpu, cpu->regs[A]);
276 }
277 else
278 {
swissChili1970cb82020-08-10 13:22:39 -0700279 cpu->status.carry = cpu->mem[a.val] & 1;
280 cpu->mem[a.ptr] = ror(a.val, 1);
281 stat_nz(cpu, cpu->mem[a.ptr]);
swissChilida4803e2020-08-06 20:06:04 -0700282 }
283 break;
284
285 case AND:
286 cpu->regs[A] &= a.val;
287 stat_nz(cpu, cpu->regs[A]);
288 break;
289
290 case ORA:
291 cpu->regs[A] |= a.val;
292 stat_nz(cpu, cpu->regs[A]);
293 break;
294
295 case EOR:
296 cpu->regs[A] ^= a.val;
297 stat_nz(cpu, cpu->regs[A]);
298 break;
299
300 case CMP:
301 cmp(cpu, A, a.val);
302 break;
303
304 case CPX:
305 cmp(cpu, X, a.val);
306 break;
307
308 case CPY:
309 cmp(cpu, Y, a.val);
310 break;
311
312 // TODO: implement BIT here
313
314 #define BRANCHES \
315 B(BCC, carry == 0) \
316 B(BCS, carry == 1) \
317 B(BNE, zero == 0) \
318 B(BEQ, zero == 1) \
319 B(BPL, negative == 0) \
320 B(BMI, negative == 1) \
321 B(BVC, overflow == 0) \
322 B(BVS, overflow == 1)
323
324 #define B(i, c) \
325 case i: \
326 if (cpu->status . c) \
327 cpu->pc = a.ptr;\
328 break;
329
330 BRANCHES
331
332 #undef B
333 #undef BRANCHES
334
335 #define TRANSFERS \
336 T(A, X) \
337 T(X, A) \
338 T(A, Y) \
339 T(Y, A)
340
341 #define T(a, b) \
342 case T ## a ## b: \
343 cpu->regs[b] = cpu->regs[a]; \
344 stat_nz(cpu, cpu->regs[b]); \
345 break;
346
347 TRANSFERS
348
349 #undef T
350 #undef TRANSFERS
351
352 case TSX:
353 cpu->regs[X] = cpu->regs[SP];
354 stat_nz(cpu, cpu->regs[X]);
355 break;
356
357 case TXS:
358 cpu->regs[SP] = cpu->regs[X];
359 stat_nz(cpu, cpu->regs[X]);
360 break;
361
362 case PHA:
363 stack_push(cpu, cpu->regs[A]);
364 break;
365
366 case PLA:
367 cpu->regs[A] = stack_pop(cpu);
368 stat_nz(cpu, cpu->regs[A]);
369 break;
370
371 case PHP:
372 stack_push(cpu, *(uint8_t *)(&cpu->status));
373 break;
374
375 case PLP:
376 {
377 uint8_t s = stack_pop(cpu);
378 *(uint8_t *)(&cpu->status) = s;
379 }
380
381 case JMP:
382 cpu->pc = a.ptr;
383 break;
384
385 case JSR:
386 stack_pushle(cpu, cpu->pc);
swissChilib04a4022020-08-09 12:51:00 -0700387 cpu->pc = a.ptr;
swissChilida4803e2020-08-06 20:06:04 -0700388 break;
389
390 case RTS:
391 cpu->pc = stack_pople(cpu);
392 break;
393
394 // TODO: implement RTI
395 // TODO: implement flag instructions
396
397 case BRK:
398 // TODO: trigger an interrupt
399 cpu->running = false;
400 break;
401
402 case NOP:
403 break;
404
405 default:
swissChilib71e0272020-08-08 15:56:14 -0700406 warn("Unsupported opcode: %x\n", op);
407 THROW("Unsupported opcode");
swissChili710d18d2020-07-29 19:43:20 -0700408 }
swissChili6264a3b2020-07-30 19:02:07 -0700409 #undef REGS
swissChili6c61a792020-07-28 16:29:20 -0700410}
411
swissChili1970cb82020-08-10 13:22:39 -0700412uint16_t fetch_le(cpu_t *cpu, uint16_t *pc)
swissChili6c61a792020-07-28 16:29:20 -0700413{
swissChili1970cb82020-08-10 13:22:39 -0700414 uint8_t a = cpu->mem[(*pc)++];
415 uint8_t b = cpu->mem[(*pc)++];
swissChili6c61a792020-07-28 16:29:20 -0700416 return le_to_native(a, b);
417}
418
swissChilicc27cfe2020-08-08 12:57:57 -0700419arg_t arg_imm(uint16_t a)
swissChili710d18d2020-07-29 19:43:20 -0700420{
421 return (arg_t){ a, a };
422}
423
swissChilicc27cfe2020-08-08 12:57:57 -0700424arg_t arg_ptr(cpu_t *c, uint flags, uint16_t p)
swissChili710d18d2020-07-29 19:43:20 -0700425{
426 if (flags & FETCH_NO_INDIRECTION)
427 return arg_imm(p);
428
429 return (arg_t){ c->mem[p], p };
430}
431
swissChilicc27cfe2020-08-08 12:57:57 -0700432arg_t arg(uint16_t v, uint16_t a)
swissChili710d18d2020-07-29 19:43:20 -0700433{
434 return (arg_t){ v, a };
435}
436
swissChili1970cb82020-08-10 13:22:39 -0700437arg_t fetch_addr(cpu_t *cpu, uint8_t am, uint f, uint16_t *pc)
swissChili6c61a792020-07-28 16:29:20 -0700438{
439 switch (am)
440 {
441 case AM_ACC:
442 case AM_IMP:
swissChili710d18d2020-07-29 19:43:20 -0700443 return arg_imm(0);
swissChili6c61a792020-07-28 16:29:20 -0700444
445 // In both cases return immediate 8 bit value
446 case AM_IMM:
447 case AM_ZP:
swissChili1970cb82020-08-10 13:22:39 -0700448 return arg_imm(cpu->mem[(*pc)++]);
swissChili6c61a792020-07-28 16:29:20 -0700449
450 case AM_ABS:
swissChili1970cb82020-08-10 13:22:39 -0700451 return arg_ptr(cpu, f, fetch_le(cpu, pc));
swissChili6c61a792020-07-28 16:29:20 -0700452
453 case AM_REL:
454 {
swissChili1970cb82020-08-10 13:22:39 -0700455 uint16_t pc_hi = * pc + 1;
456 return arg_ptr(cpu, f, (int8_t)cpu->mem[(*pc)++] + pc_hi);
swissChili6c61a792020-07-28 16:29:20 -0700457 }
458
459 case AM_IND:
460 {
swissChili1970cb82020-08-10 13:22:39 -0700461 uint16_t addr = fetch_le(cpu, pc);
swissChili6264a3b2020-07-30 19:02:07 -0700462
463 if (f & FETCH_NO_INDIRECTION)
464 return arg_imm(addr);
465
swissChili1970cb82020-08-10 13:22:39 -0700466 uint8_t low = cpu->mem[addr],
467 high = cpu->mem[addr + 1];
swissChili6c61a792020-07-28 16:29:20 -0700468
swissChili710d18d2020-07-29 19:43:20 -0700469 return arg_ptr(cpu, f, le_to_native(low, high));
swissChili6c61a792020-07-28 16:29:20 -0700470 }
471
472 case AM_AX:
swissChili94ba1f52020-08-08 11:39:10 -0700473 if (f & FETCH_NO_INDIRECTION)
swissChili1970cb82020-08-10 13:22:39 -0700474 return arg_ptr(cpu, f, fetch_le(cpu, pc));
swissChili94ba1f52020-08-08 11:39:10 -0700475
swissChili1970cb82020-08-10 13:22:39 -0700476 return arg_ptr(cpu, f, fetch_le(cpu, pc) + cpu->regs[X]);
swissChili6c61a792020-07-28 16:29:20 -0700477
478 case AM_AY:
swissChili94ba1f52020-08-08 11:39:10 -0700479 if (f & FETCH_NO_INDIRECTION)
swissChili1970cb82020-08-10 13:22:39 -0700480 return arg_ptr(cpu, f, fetch_le(cpu, pc));
swissChili94ba1f52020-08-08 11:39:10 -0700481
swissChili1970cb82020-08-10 13:22:39 -0700482 return arg_ptr(cpu, f, fetch_le(cpu, pc) + cpu->regs[Y]);
swissChili6c61a792020-07-28 16:29:20 -0700483
484 case AM_ZPX:
swissChili94ba1f52020-08-08 11:39:10 -0700485 if (f & FETCH_NO_INDIRECTION)
swissChili1970cb82020-08-10 13:22:39 -0700486 return arg_ptr(cpu, f, cpu->mem[(*pc)++]);
487 return arg_ptr(cpu, f, cpu->mem[(*pc)++] + cpu->regs[X]);
swissChili6c61a792020-07-28 16:29:20 -0700488
489 case AM_ZPY:
swissChili94ba1f52020-08-08 11:39:10 -0700490 if (f & FETCH_NO_INDIRECTION)
swissChili1970cb82020-08-10 13:22:39 -0700491 return arg_ptr(cpu, f, cpu->mem[(*pc)++]);
492 return arg_ptr(cpu, f, cpu->mem[(*pc)++] + cpu->regs[Y]);
swissChili6c61a792020-07-28 16:29:20 -0700493
494 case AM_ZIX:
495 {
swissChili1970cb82020-08-10 13:22:39 -0700496 uint8_t zp = cpu->mem[(*pc)++];
swissChili6264a3b2020-07-30 19:02:07 -0700497
498 if (f & FETCH_NO_INDIRECTION)
499 return arg_imm(zp);
500
swissChili710d18d2020-07-29 19:43:20 -0700501 uint16_t addr = zp + cpu->regs[X];
swissChilib71e0272020-08-08 15:56:14 -0700502 uint16_t indirect = le_to_native(cpu->mem[addr], cpu->mem[addr + 1]);
swissChili710d18d2020-07-29 19:43:20 -0700503 return arg_ptr(cpu, f, indirect);
swissChili6c61a792020-07-28 16:29:20 -0700504 }
505
506 case AM_ZIY:
507 {
swissChili1970cb82020-08-10 13:22:39 -0700508 uint8_t zp = cpu->mem[(*pc)++];
swissChili6264a3b2020-07-30 19:02:07 -0700509
510 if (f & FETCH_NO_INDIRECTION)
511 return arg_imm(zp);
512
swissChili1970cb82020-08-10 13:22:39 -0700513 uint16_t base = le_to_native(cpu->mem[zp], cpu->mem[zp + 1]);
swissChili710d18d2020-07-29 19:43:20 -0700514 return arg_ptr(cpu, f, base + cpu->regs[Y]);
swissChili6c61a792020-07-28 16:29:20 -0700515 }
516
517 default:
swissChilib71e0272020-08-08 15:56:14 -0700518 warn("Unknown address mode %x", am);
519 THROW("Unknowng address mode");
swissChili710d18d2020-07-29 19:43:20 -0700520 __builtin_unreachable();
swissChili6c61a792020-07-28 16:29:20 -0700521 }
522}
523
swissChilicc27cfe2020-08-08 12:57:57 -0700524void step(cpu_t *cpu)
swissChili6c61a792020-07-28 16:29:20 -0700525{
swissChilicc27cfe2020-08-08 12:57:57 -0700526 cpu->screen_dirty = false;
swissChilib71e0272020-08-08 15:56:14 -0700527 uint8_t pc = cpu->pc;
528 uint8_t op = cpu->mem[cpu->pc++];
529 switch (op)
swissChili6c61a792020-07-28 16:29:20 -0700530 {
swissChili97b5d8b2020-08-15 20:00:54 -0700531#define INST(mn, am, op, len) \
swissChili6c61a792020-07-28 16:29:20 -0700532 case op: \
swissChili1970cb82020-08-10 13:22:39 -0700533 execute(cpu, #mn, mn, fetch_addr(cpu, am, 0, &cpu->pc), am); \
swissChili6c61a792020-07-28 16:29:20 -0700534 break;
535
536 INSTRUCTIONS
537
538#undef INST
539
540 default:
swissChilib71e0272020-08-08 15:56:14 -0700541 warn("Undefined opcode %x near %x [%x]", op, pc, cpu->mem[pc]);
542 THROW("Undefined opcode");
swissChili6c61a792020-07-28 16:29:20 -0700543 }
544}
545
swissChilic51e9222020-08-07 16:09:14 -0700546int dump_inst(cpu_t *cpu, char *buf, const char *mn, uint16_t addr, uint8_t am)
swissChili6c61a792020-07-28 16:29:20 -0700547{
swissChilic51e9222020-08-07 16:09:14 -0700548 char *end = buf;
549 end += sprintf(end, "%s ", mn);
swissChili6c61a792020-07-28 16:29:20 -0700550
551 switch (am)
552 {
553 case AM_IMM:
swissChilic51e9222020-08-07 16:09:14 -0700554 end += sprintf(end, "#");
swissChili6c61a792020-07-28 16:29:20 -0700555 case AM_REL:
556 case AM_ABS:
557 case AM_ZP:
swissChilic51e9222020-08-07 16:09:14 -0700558 end += sprintf(end, "$%x", addr);
swissChili6c61a792020-07-28 16:29:20 -0700559 break;
560
561 case AM_IND:
swissChilic51e9222020-08-07 16:09:14 -0700562 end += sprintf(end, "($%x)", addr);
swissChili6c61a792020-07-28 16:29:20 -0700563 break;
564
565 case AM_AX:
566 case AM_ZPX:
swissChilic51e9222020-08-07 16:09:14 -0700567 end += sprintf(end, "$%x, X", addr);
swissChili6c61a792020-07-28 16:29:20 -0700568 break;
569
570 case AM_AY:
571 case AM_ZPY:
swissChilic51e9222020-08-07 16:09:14 -0700572 end += sprintf(end, "$%x, Y", addr);
swissChili6c61a792020-07-28 16:29:20 -0700573 break;
574
575 case AM_ZIX:
swissChilic51e9222020-08-07 16:09:14 -0700576 end += sprintf(end, "($%x, X)", addr);
swissChili6c61a792020-07-28 16:29:20 -0700577 break;
578
579 case AM_ZIY:
swissChilic51e9222020-08-07 16:09:14 -0700580 end += sprintf(end, "($%x), Y", addr);
swissChili6c61a792020-07-28 16:29:20 -0700581 break;
582 }
583
swissChilic51e9222020-08-07 16:09:14 -0700584 return end - buf;
swissChili6c61a792020-07-28 16:29:20 -0700585}
586
swissChili1970cb82020-08-10 13:22:39 -0700587char *disas_step(cpu_t *cpu, uint16_t *pc)
swissChili6c61a792020-07-28 16:29:20 -0700588{
swissChilic51e9222020-08-07 16:09:14 -0700589 char *buffer = malloc(80);
590 char *end = buffer;
591
592 // end += sprintf(buffer, "$%x", cpu->pc);
swissChili1970cb82020-08-10 13:22:39 -0700593 uint8_t op = cpu->mem[(*pc)++];
swissChili6c61a792020-07-28 16:29:20 -0700594 switch (op)
595 {
swissChili97b5d8b2020-08-15 20:00:54 -0700596#define INST(mn, am, op, len) \
swissChili6c61a792020-07-28 16:29:20 -0700597 case op: \
swissChilic51e9222020-08-07 16:09:14 -0700598 end += dump_inst(cpu, end, #mn, \
swissChili1970cb82020-08-10 13:22:39 -0700599 fetch_addr(cpu, am, FETCH_NO_INDIRECTION, pc).ptr, am); \
swissChili6c61a792020-07-28 16:29:20 -0700600 break;
601
602 INSTRUCTIONS
603
604#undef INST
605
606 default:
swissChilic51e9222020-08-07 16:09:14 -0700607 end += sprintf(end, "Undefined opcode %x", op);
swissChili6c61a792020-07-28 16:29:20 -0700608 }
swissChilic51e9222020-08-07 16:09:14 -0700609
610 *end = 0;
611
612 return buffer;
swissChili6c61a792020-07-28 16:29:20 -0700613}
614
swissChilida4803e2020-08-06 20:06:04 -0700615void disas_num(cpu_t *cpu, uint16_t num)
616{
swissChili1970cb82020-08-10 13:22:39 -0700617 uint16_t pc = 0x600;
swissChilida4803e2020-08-06 20:06:04 -0700618 for (int i = 0; i < num; i++)
619 {
swissChili1970cb82020-08-10 13:22:39 -0700620 uint16_t last_pc = pc;
621 char *line = disas_step(cpu, &pc);
swissChilic51e9222020-08-07 16:09:14 -0700622 printf("$%x\t%s\n", last_pc, line);
623 free(line);
swissChilida4803e2020-08-06 20:06:04 -0700624 }
625}
626
swissChili6c61a792020-07-28 16:29:20 -0700627void disas(cpu_t *cpu)
628{
swissChili1970cb82020-08-10 13:22:39 -0700629 uint16_t pc = 0x600;
swissChili6264a3b2020-07-30 19:02:07 -0700630 // Raw binary, no way to know what's code what isn't
swissChili6c61a792020-07-28 16:29:20 -0700631 while (cpu->pc < 0xFFFF)
632 {
swissChili1970cb82020-08-10 13:22:39 -0700633 uint16_t last_pc = pc;
634 char *line = disas_step(cpu, &pc);
swissChilic51e9222020-08-07 16:09:14 -0700635 printf("$%x\t%s\n", last_pc, line);
636 free(line);
swissChili6c61a792020-07-28 16:29:20 -0700637 }
638}
swissChilic51e9222020-08-07 16:09:14 -0700639
swissChilida4803e2020-08-06 20:06:04 -0700640void run(cpu_t *cpu)
641{
642 while (cpu->running)
643 {
644 step(cpu);
645 }
646
647 printf("CPU Halted\n");
648}
swissChilic6b4f7e2020-08-09 16:36:36 -0700649
650void run_mq(cpu_t *cpu, mqd_t mq)
651{
652 char buf[MQ_BUF_LEN];
653 bool running;
654
655 while (true)
656 {
657 if (running)
658 {
659 if (cpu->running)
660 step(cpu);
661 else
662 running = false;
663 }
664
665 ssize_t recvd = mq_receive(mq, buf, MQ_BUF_LEN * 2, NULL);
666
667 if (recvd == -1 && errno != EAGAIN)
668 {
669 printf("errno = %d\n", errno);
670 THROW("mq_receive returned -1");
671 }
672
673 if (recvd > 0)
674 {
675 if (debug_stmt(cpu, buf, &running))
676 break;
677 }
678 }
679}