blob: 9d85261b71411ccbffef4e8c94e635dcde381c15 [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
7#include <endian.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11
12#define die(m, ...) \
swissChili6264a3b2020-07-30 19:02:07 -070013 printf("\033[31m" m "\033[0m\n", ##__VA_ARGS__); \
swissChili6c61a792020-07-28 16:29:20 -070014 exit(1);
15
swissChili6264a3b2020-07-30 19:02:07 -070016#define warn(m, ...) \
17 printf("\033[33m" m "\033[0m\n", ##__VA_ARGS__);
18
swissChili94ba1f52020-08-08 11:39:10 -070019
20sdl_screen_t *g_scr = NULL;
21
22
swissChilidbbd5402020-08-07 15:07:39 -070023void reset(cpu_t *cpu)
24{
swissChilib04a4022020-08-09 12:51:00 -070025 cpu->regs[SP] = 0xFF; // stack at is 0x100 + SP
swissChilibb478f12020-08-07 20:45:07 -070026 cpu->pc = 0x600; // arbitrary program counter start
swissChilidbbd5402020-08-07 15:07:39 -070027 cpu->running = true;
swissChilie7ee6da2020-08-08 16:14:21 -070028 memset(cpu->mem + 0x100, 0, 0xFE);
swissChilidbbd5402020-08-07 15:07:39 -070029}
30
swissChili6c61a792020-07-28 16:29:20 -070031cpu_t new_cpu()
32{
33 cpu_t cpu = { 0 };
swissChilib04a4022020-08-09 12:51:00 -070034 cpu.regs[SP] = 0xFF; // stack at is 0x100 + SP
swissChilibb478f12020-08-07 20:45:07 -070035 cpu.pc = 0x600; // arbitrary program counter start
swissChili6264a3b2020-07-30 19:02:07 -070036 cpu.running = true;
swissChili6c61a792020-07-28 16:29:20 -070037 cpu.mem = malloc(0xFFFF);
swissChilicc27cfe2020-08-08 12:57:57 -070038 cpu.screen_dirty = true;
swissChili6c61a792020-07-28 16:29:20 -070039 memset(cpu.mem, 0, 0xFFFF);
40
swissChilib71e0272020-08-08 15:56:14 -070041 ASSERT("Allocate memory for CPU", cpu.mem);
swissChili6c61a792020-07-28 16:29:20 -070042
43 return cpu;
44}
45
swissChilida4803e2020-08-06 20:06:04 -070046uint16_t le_to_native(uint8_t a, uint8_t b)
47{
48#ifdef LITTLE_ENDIAN
49 return b << 8 | a;
50#else
51 return a << 8 | b;
52#endif
53}
54
55void native_to_le(uint16_t n, uint8_t *a, uint8_t *b)
56{
57#ifdef LITTLE_ENDIAN
58 *a = n >> 8;
59 *b = n & 0xFF;
60#else
61 *a = n & 0xFF;
62 *b = n >> 8;
63#endif
64}
65
swissChili6264a3b2020-07-30 19:02:07 -070066void stack_push(cpu_t *cpu, uint8_t v)
67{
68 cpu->mem[cpu->regs[SP]-- + 0x100] = v;
69}
70
swissChilida4803e2020-08-06 20:06:04 -070071void stack_pushle(cpu_t *cpu, uint16_t v)
72{
73 uint8_t a, b;
74 native_to_le(v, &a, &b);
75 // push in "reverse" order so that the address is stored as LE
76 stack_push(cpu, b);
77 stack_push(cpu, a);
78}
79
swissChili6264a3b2020-07-30 19:02:07 -070080uint8_t stack_pop(cpu_t *cpu)
81{
82 return cpu->mem[cpu->regs[SP]++ + 0x100];
83}
84
swissChilida4803e2020-08-06 20:06:04 -070085uint16_t stack_pople(cpu_t *cpu)
86{
87 uint8_t a = stack_pop(cpu);
88 uint8_t b = stack_pop(cpu);
89 return le_to_native(a, b);
90}
91
swissChili6c61a792020-07-28 16:29:20 -070092void free_cpu(cpu_t *cpu)
93{
94 free(cpu->mem);
95}
96
swissChilida4803e2020-08-06 20:06:04 -070097// rotate right
swissChilicc27cfe2020-08-08 12:57:57 -070098uint8_t ror(uint8_t a, uint8_t n)
swissChilida4803e2020-08-06 20:06:04 -070099{
100 return (a >> n) | (a << (8 - n));
101}
102
103// rotate left
swissChilicc27cfe2020-08-08 12:57:57 -0700104uint8_t rol(uint8_t a, uint8_t n)
swissChilida4803e2020-08-06 20:06:04 -0700105{
106 return (a << n) | (a >> (8 - n));
107}
108
swissChilicc27cfe2020-08-08 12:57:57 -0700109void stat_nz(cpu_t *cpu, int8_t v)
swissChili6c61a792020-07-28 16:29:20 -0700110{
swissChili6264a3b2020-07-30 19:02:07 -0700111 cpu->status.negative = v < 0;
112 cpu->status.zero = v == 0;
113}
114
115// Used to check for overflow, is c unique?
swissChilicc27cfe2020-08-08 12:57:57 -0700116bool last_unique(bool a, bool b, bool c)
swissChili6264a3b2020-07-30 19:02:07 -0700117{
118 return a == b && a != c;
119}
120
swissChilicc27cfe2020-08-08 12:57:57 -0700121void stat_cv(cpu_t *cpu, uint8_t a, uint8_t b, uint8_t c)
swissChili6264a3b2020-07-30 19:02:07 -0700122{
123 cpu->status.overflow = last_unique(a >> 7, b >> 7, c >> 7);
124 cpu->status.carry = c < a || c < b;
125}
126
swissChilicc27cfe2020-08-08 12:57:57 -0700127void cmp(cpu_t *cpu, uint8_t reg, uint8_t mem)
swissChilida4803e2020-08-06 20:06:04 -0700128{
129 cpu->status.negative = 0;
130 cpu->status.zero = 0;
131 cpu->status.carry = 0;
132 if (cpu->regs[reg] < mem)
133 {
134 cpu->status.negative = 1;
135 }
136 else if (cpu->regs[reg] == mem)
137 {
138 cpu->status.zero = 1;
139 cpu->status.carry = 1;
140 }
141 else
142 {
143 cpu->status.carry = 1;
144 }
145}
146
swissChilicc27cfe2020-08-08 12:57:57 -0700147uint16_t scr_dirty(cpu_t *cpu, uint16_t mem)
148{
149 if (mem >= 0x200 && mem <= 0x200 + 32 * 32)
150 cpu->screen_dirty = true;
151
152 return mem;
153}
154
swissChilida4803e2020-08-06 20:06:04 -0700155void execute(cpu_t *cpu, const char *mnemonic, uint8_t op, arg_t a, uint8_t am)
swissChili6264a3b2020-07-30 19:02:07 -0700156{
157 // used to save space
158 #define REGS \
159 R(X) R(A) R(Y)
160
swissChili710d18d2020-07-29 19:43:20 -0700161 switch (op) {
swissChili6264a3b2020-07-30 19:02:07 -0700162 // Load and store instructions:
163 #define R(reg) \
164 case LD##reg: \
165 cpu->regs[reg] = a.val; \
166 stat_nz(cpu, a.val); \
167 break;
168
169 REGS
170
171 #undef R
172
173 #define R(reg) \
174 case ST##reg: \
swissChilicc27cfe2020-08-08 12:57:57 -0700175 cpu->mem[scr_dirty(cpu, a.ptr)] = cpu->regs[reg]; \
swissChili6264a3b2020-07-30 19:02:07 -0700176 break; \
177
178 REGS
179
180 #undef R
181
182 // Arithmetic instructions:
183 // NOTE: binary coded decimals are NOT SUPPORTED because I don't want
184 // to implement them.
185 case ADC:
186 {
187 uint8_t sum = cpu->regs[A] + a.val + cpu->status.carry;
188 // signed overflow
189 stat_cv(cpu, cpu->regs[A], a.val + cpu->status.carry, sum);
190 stat_nz(cpu, sum);
191 cpu->regs[A] = sum;
192 break;
193 }
194
195 case SBC:
196 {
197 uint8_t diff = cpu->regs[A] - a.val - !cpu->status.carry;
198 stat_cv(cpu, cpu->regs[A], a.val - !cpu->status.carry, diff);
199 stat_nz(cpu, diff);
200 cpu->regs[A] = diff;
201 break;
202 }
203
204 case INC:
swissChilicc27cfe2020-08-08 12:57:57 -0700205 cpu->mem[scr_dirty(cpu, scr_dirty(cpu, a.ptr))]++;
206 stat_nz(cpu, cpu->mem[scr_dirty(cpu, a.ptr)]);
swissChili6264a3b2020-07-30 19:02:07 -0700207 break;
208
209 case INX:
210 cpu->regs[X]++;
211 stat_nz(cpu, cpu->regs[X]);
212 break;
213
214 case INY:
215 cpu->regs[Y]++;
216 stat_nz(cpu, cpu->regs[Y]);
217 break;
218
219 case DEC:
swissChilicc27cfe2020-08-08 12:57:57 -0700220 cpu->mem[scr_dirty(cpu, a.ptr)]--;
221 stat_nz(cpu, cpu->mem[scr_dirty(cpu, a.ptr)]);
swissChili6264a3b2020-07-30 19:02:07 -0700222 break;
swissChilida4803e2020-08-06 20:06:04 -0700223
224 case DEX:
225 cpu->regs[X]--;
226 stat_nz(cpu, cpu->regs[X]);
227 break;
228
229 case DEY:
230 cpu->regs[Y]--;
231 stat_nz(cpu, cpu->regs[Y]);
232 break;
233
234 case ASL:
235 // This check must be done here unfortunately, it would be nice
236 // to do this while decoding operands but it would require
237 // a substantial change to the architecture of the emulator
238 if (am == AM_ACC)
239 {
240 cpu->status.carry = cpu->regs[A] >> 7;
241 cpu->regs[A] <<= 1;
242 stat_nz(cpu, cpu->regs[A]);
243 }
244 else
245 {
swissChilicc27cfe2020-08-08 12:57:57 -0700246 cpu->status.carry = cpu->mem[scr_dirty(cpu, a.val)] >> 7;
247 cpu->mem[scr_dirty(cpu, a.ptr)] <<= 1;
248 stat_nz(cpu, cpu->mem[scr_dirty(cpu, a.ptr)]);
swissChilida4803e2020-08-06 20:06:04 -0700249 }
250 break;
251
252 case LSR:
253 if (am == AM_ACC)
254 {
255 cpu->status.carry = cpu->regs[A] & 1;
256 cpu->regs[A] >>= 1;
257 stat_nz(cpu, cpu->regs[A]);
258 }
259 else
260 {
swissChilicc27cfe2020-08-08 12:57:57 -0700261 cpu->status.carry = cpu->mem[scr_dirty(cpu, a.val)] & 7;
262 cpu->mem[scr_dirty(cpu, a.ptr)] >>= 1;
263 stat_nz(cpu, cpu->mem[scr_dirty(cpu, a.ptr)]);
swissChilida4803e2020-08-06 20:06:04 -0700264 }
265 break;
266
267 case ROL:
268 if (am == AM_ACC)
269 {
270 cpu->status.carry = cpu->regs[A] >> 7;
271 cpu->regs[A] = rol(cpu->regs[A], 1);
272 stat_nz(cpu, cpu->regs[A]);
273 }
274 else
275 {
swissChilicc27cfe2020-08-08 12:57:57 -0700276 cpu->status.carry = cpu->mem[scr_dirty(cpu, a.val)] >> 7;
277 cpu->mem[scr_dirty(cpu, a.ptr)] = rol(a.val, 1);
278 stat_nz(cpu, cpu->mem[scr_dirty(cpu, a.ptr)]);
swissChilida4803e2020-08-06 20:06:04 -0700279 }
280 break;
281
282 case ROR:
283 if (am == AM_ACC)
284 {
285 cpu->status.carry = cpu->regs[A] & 1;
286 cpu->regs[A] = ror(cpu->regs[A], 1);
287 stat_nz(cpu, cpu->regs[A]);
288 }
289 else
290 {
swissChilicc27cfe2020-08-08 12:57:57 -0700291 cpu->status.carry = cpu->mem[scr_dirty(cpu, a.val)] & 1;
292 cpu->mem[scr_dirty(cpu, a.ptr)] = ror(a.val, 1);
293 stat_nz(cpu, cpu->mem[scr_dirty(cpu, a.ptr)]);
swissChilida4803e2020-08-06 20:06:04 -0700294 }
295 break;
296
297 case AND:
298 cpu->regs[A] &= a.val;
299 stat_nz(cpu, cpu->regs[A]);
300 break;
301
302 case ORA:
303 cpu->regs[A] |= a.val;
304 stat_nz(cpu, cpu->regs[A]);
305 break;
306
307 case EOR:
308 cpu->regs[A] ^= a.val;
309 stat_nz(cpu, cpu->regs[A]);
310 break;
311
312 case CMP:
313 cmp(cpu, A, a.val);
314 break;
315
316 case CPX:
317 cmp(cpu, X, a.val);
318 break;
319
320 case CPY:
321 cmp(cpu, Y, a.val);
322 break;
323
324 // TODO: implement BIT here
325
326 #define BRANCHES \
327 B(BCC, carry == 0) \
328 B(BCS, carry == 1) \
329 B(BNE, zero == 0) \
330 B(BEQ, zero == 1) \
331 B(BPL, negative == 0) \
332 B(BMI, negative == 1) \
333 B(BVC, overflow == 0) \
334 B(BVS, overflow == 1)
335
336 #define B(i, c) \
337 case i: \
338 if (cpu->status . c) \
339 cpu->pc = a.ptr;\
340 break;
341
342 BRANCHES
343
344 #undef B
345 #undef BRANCHES
346
347 #define TRANSFERS \
348 T(A, X) \
349 T(X, A) \
350 T(A, Y) \
351 T(Y, A)
352
353 #define T(a, b) \
354 case T ## a ## b: \
355 cpu->regs[b] = cpu->regs[a]; \
356 stat_nz(cpu, cpu->regs[b]); \
357 break;
358
359 TRANSFERS
360
361 #undef T
362 #undef TRANSFERS
363
364 case TSX:
365 cpu->regs[X] = cpu->regs[SP];
366 stat_nz(cpu, cpu->regs[X]);
367 break;
368
369 case TXS:
370 cpu->regs[SP] = cpu->regs[X];
371 stat_nz(cpu, cpu->regs[X]);
372 break;
373
374 case PHA:
375 stack_push(cpu, cpu->regs[A]);
376 break;
377
378 case PLA:
379 cpu->regs[A] = stack_pop(cpu);
380 stat_nz(cpu, cpu->regs[A]);
381 break;
382
383 case PHP:
384 stack_push(cpu, *(uint8_t *)(&cpu->status));
385 break;
386
387 case PLP:
388 {
389 uint8_t s = stack_pop(cpu);
390 *(uint8_t *)(&cpu->status) = s;
391 }
392
393 case JMP:
394 cpu->pc = a.ptr;
395 break;
396
397 case JSR:
398 stack_pushle(cpu, cpu->pc);
swissChilib04a4022020-08-09 12:51:00 -0700399 cpu->pc = a.ptr;
swissChilida4803e2020-08-06 20:06:04 -0700400 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:
swissChilib71e0272020-08-08 15:56:14 -0700418 warn("Unsupported opcode: %x\n", op);
419 THROW("Unsupported opcode");
swissChili710d18d2020-07-29 19:43:20 -0700420 }
swissChili6264a3b2020-07-30 19:02:07 -0700421 #undef REGS
swissChili6c61a792020-07-28 16:29:20 -0700422}
423
swissChilicc27cfe2020-08-08 12:57:57 -0700424uint16_t fetch_le(cpu_t *cpu)
swissChili6c61a792020-07-28 16:29:20 -0700425{
swissChilicc27cfe2020-08-08 12:57:57 -0700426 uint8_t a = cpu->mem[scr_dirty(cpu, cpu->pc++)];
427 uint8_t b = cpu->mem[scr_dirty(cpu, cpu->pc++)];
swissChili6c61a792020-07-28 16:29:20 -0700428 return le_to_native(a, b);
429}
430
swissChilicc27cfe2020-08-08 12:57:57 -0700431arg_t arg_imm(uint16_t a)
swissChili710d18d2020-07-29 19:43:20 -0700432{
433 return (arg_t){ a, a };
434}
435
swissChilicc27cfe2020-08-08 12:57:57 -0700436arg_t arg_ptr(cpu_t *c, uint flags, uint16_t p)
swissChili710d18d2020-07-29 19:43:20 -0700437{
438 if (flags & FETCH_NO_INDIRECTION)
439 return arg_imm(p);
440
441 return (arg_t){ c->mem[p], p };
442}
443
swissChilicc27cfe2020-08-08 12:57:57 -0700444arg_t arg(uint16_t v, uint16_t a)
swissChili710d18d2020-07-29 19:43:20 -0700445{
446 return (arg_t){ v, a };
447}
448
449arg_t fetch_addr(cpu_t *cpu, uint8_t am, uint f)
swissChili6c61a792020-07-28 16:29:20 -0700450{
451 switch (am)
452 {
453 case AM_ACC:
454 case AM_IMP:
swissChili710d18d2020-07-29 19:43:20 -0700455 return arg_imm(0);
swissChili6c61a792020-07-28 16:29:20 -0700456
457 // In both cases return immediate 8 bit value
458 case AM_IMM:
459 case AM_ZP:
swissChilicc27cfe2020-08-08 12:57:57 -0700460 return arg_imm(cpu->mem[scr_dirty(cpu, cpu->pc++)]);
swissChili6c61a792020-07-28 16:29:20 -0700461
462 case AM_ABS:
swissChili710d18d2020-07-29 19:43:20 -0700463 return arg_ptr(cpu, f, fetch_le(cpu));
swissChili6c61a792020-07-28 16:29:20 -0700464
465 case AM_REL:
466 {
swissChili6264a3b2020-07-30 19:02:07 -0700467 // Aparently, PC should will point to the NEXT opcode
468 // I can't find any documentation on this unfortunately, but
469 // I have discovered this through testing the output of other
470 // assemblers.
471 uint16_t pc = cpu->pc + 1;
swissChilicc27cfe2020-08-08 12:57:57 -0700472 return arg_ptr(cpu, f, (int8_t)cpu->mem[scr_dirty(cpu, cpu->pc++)] + pc);
swissChili6c61a792020-07-28 16:29:20 -0700473 }
474
475 case AM_IND:
476 {
477 uint16_t addr = fetch_le(cpu);
swissChili6264a3b2020-07-30 19:02:07 -0700478
479 if (f & FETCH_NO_INDIRECTION)
480 return arg_imm(addr);
481
swissChilicc27cfe2020-08-08 12:57:57 -0700482 uint8_t low = cpu->mem[scr_dirty(cpu, addr)],
483 high = cpu->mem[scr_dirty(cpu, addr + 1)];
swissChili6c61a792020-07-28 16:29:20 -0700484
swissChili710d18d2020-07-29 19:43:20 -0700485 return arg_ptr(cpu, f, le_to_native(low, high));
swissChili6c61a792020-07-28 16:29:20 -0700486 }
487
488 case AM_AX:
swissChili94ba1f52020-08-08 11:39:10 -0700489 if (f & FETCH_NO_INDIRECTION)
490 return arg_ptr(cpu, f, fetch_le(cpu));
491
swissChili710d18d2020-07-29 19:43:20 -0700492 return arg_ptr(cpu, f, fetch_le(cpu) + cpu->regs[X]);
swissChili6c61a792020-07-28 16:29:20 -0700493
494 case AM_AY:
swissChili94ba1f52020-08-08 11:39:10 -0700495 if (f & FETCH_NO_INDIRECTION)
496 return arg_ptr(cpu, f, fetch_le(cpu));
497
swissChili710d18d2020-07-29 19:43:20 -0700498 return arg_ptr(cpu, f, fetch_le(cpu) + cpu->regs[Y]);
swissChili6c61a792020-07-28 16:29:20 -0700499
500 case AM_ZPX:
swissChili94ba1f52020-08-08 11:39:10 -0700501 if (f & FETCH_NO_INDIRECTION)
swissChilib71e0272020-08-08 15:56:14 -0700502 return arg_ptr(cpu, f, cpu->mem[cpu->pc++]);
503 return arg_ptr(cpu, f, cpu->mem[cpu->pc++] + cpu->regs[X]);
swissChili6c61a792020-07-28 16:29:20 -0700504
505 case AM_ZPY:
swissChili94ba1f52020-08-08 11:39:10 -0700506 if (f & FETCH_NO_INDIRECTION)
swissChilib71e0272020-08-08 15:56:14 -0700507 return arg_ptr(cpu, f, cpu->mem[cpu->pc++]);
508 return arg_ptr(cpu, f, cpu->mem[cpu->pc++] + cpu->regs[Y]);
swissChili6c61a792020-07-28 16:29:20 -0700509
510 case AM_ZIX:
511 {
swissChilib71e0272020-08-08 15:56:14 -0700512 uint8_t zp = cpu->mem[cpu->pc++];
swissChili6264a3b2020-07-30 19:02:07 -0700513
514 if (f & FETCH_NO_INDIRECTION)
515 return arg_imm(zp);
516
swissChili710d18d2020-07-29 19:43:20 -0700517 uint16_t addr = zp + cpu->regs[X];
swissChilib71e0272020-08-08 15:56:14 -0700518 uint16_t indirect = le_to_native(cpu->mem[addr], cpu->mem[addr + 1]);
swissChili710d18d2020-07-29 19:43:20 -0700519 return arg_ptr(cpu, f, indirect);
swissChili6c61a792020-07-28 16:29:20 -0700520 }
521
522 case AM_ZIY:
523 {
swissChilicc27cfe2020-08-08 12:57:57 -0700524 uint8_t zp = cpu->mem[scr_dirty(cpu, cpu->pc++)];
swissChili6264a3b2020-07-30 19:02:07 -0700525
526 if (f & FETCH_NO_INDIRECTION)
527 return arg_imm(zp);
528
swissChilib71e0272020-08-08 15:56:14 -0700529 uint16_t base = le_to_native(cpu->mem[zp], cpu->mem[scr_dirty(cpu, zp + 1)]);
swissChili710d18d2020-07-29 19:43:20 -0700530 return arg_ptr(cpu, f, base + cpu->regs[Y]);
swissChili6c61a792020-07-28 16:29:20 -0700531 }
532
533 default:
swissChilib71e0272020-08-08 15:56:14 -0700534 warn("Unknown address mode %x", am);
535 THROW("Unknowng address mode");
swissChili710d18d2020-07-29 19:43:20 -0700536 __builtin_unreachable();
swissChili6c61a792020-07-28 16:29:20 -0700537 }
538}
539
swissChilicc27cfe2020-08-08 12:57:57 -0700540void step(cpu_t *cpu)
swissChili6c61a792020-07-28 16:29:20 -0700541{
swissChili94ba1f52020-08-08 11:39:10 -0700542 static int steps;
543 steps++;
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 }
swissChili94ba1f52020-08-08 11:39:10 -0700562
563 if (steps % 100 == 0)
564 printf("%d\n", steps);
565
swissChilicc27cfe2020-08-08 12:57:57 -0700566// If can't run screen in seperate thread, just run it here (bad)
567#ifdef NO_PTHREAD
swissChili94ba1f52020-08-08 11:39:10 -0700568 if (g_scr)
569 {
swissChilicc27cfe2020-08-08 12:57:57 -0700570 sdl_screen(g_scr, cpu->mem + CPU_FB_ADDR, cpu->screen_dirty);
swissChili94ba1f52020-08-08 11:39:10 -0700571 }
swissChilicc27cfe2020-08-08 12:57:57 -0700572#endif
swissChili6c61a792020-07-28 16:29:20 -0700573}
574
swissChilic51e9222020-08-07 16:09:14 -0700575int dump_inst(cpu_t *cpu, char *buf, const char *mn, uint16_t addr, uint8_t am)
swissChili6c61a792020-07-28 16:29:20 -0700576{
swissChilic51e9222020-08-07 16:09:14 -0700577 char *end = buf;
578 end += sprintf(end, "%s ", mn);
swissChili6c61a792020-07-28 16:29:20 -0700579
580 switch (am)
581 {
582 case AM_IMM:
swissChilic51e9222020-08-07 16:09:14 -0700583 end += sprintf(end, "#");
swissChili6c61a792020-07-28 16:29:20 -0700584 case AM_REL:
585 case AM_ABS:
586 case AM_ZP:
swissChilic51e9222020-08-07 16:09:14 -0700587 end += sprintf(end, "$%x", addr);
swissChili6c61a792020-07-28 16:29:20 -0700588 break;
589
590 case AM_IND:
swissChilic51e9222020-08-07 16:09:14 -0700591 end += sprintf(end, "($%x)", addr);
swissChili6c61a792020-07-28 16:29:20 -0700592 break;
593
594 case AM_AX:
595 case AM_ZPX:
swissChilic51e9222020-08-07 16:09:14 -0700596 end += sprintf(end, "$%x, X", addr);
swissChili6c61a792020-07-28 16:29:20 -0700597 break;
598
599 case AM_AY:
600 case AM_ZPY:
swissChilic51e9222020-08-07 16:09:14 -0700601 end += sprintf(end, "$%x, Y", addr);
swissChili6c61a792020-07-28 16:29:20 -0700602 break;
603
604 case AM_ZIX:
swissChilic51e9222020-08-07 16:09:14 -0700605 end += sprintf(end, "($%x, X)", addr);
swissChili6c61a792020-07-28 16:29:20 -0700606 break;
607
608 case AM_ZIY:
swissChilic51e9222020-08-07 16:09:14 -0700609 end += sprintf(end, "($%x), Y", addr);
swissChili6c61a792020-07-28 16:29:20 -0700610 break;
611 }
612
swissChilic51e9222020-08-07 16:09:14 -0700613 return end - buf;
swissChili6c61a792020-07-28 16:29:20 -0700614}
615
swissChilic51e9222020-08-07 16:09:14 -0700616char *disas_step(cpu_t *cpu)
swissChili6c61a792020-07-28 16:29:20 -0700617{
swissChilic51e9222020-08-07 16:09:14 -0700618 char *buffer = malloc(80);
619 char *end = buffer;
620
621 // end += sprintf(buffer, "$%x", cpu->pc);
swissChilicc27cfe2020-08-08 12:57:57 -0700622 uint8_t op = cpu->mem[scr_dirty(cpu, cpu->pc++)];
swissChili6c61a792020-07-28 16:29:20 -0700623 switch (op)
624 {
625#define INST(mn, am, op) \
626 case op: \
swissChilic51e9222020-08-07 16:09:14 -0700627 end += dump_inst(cpu, end, #mn, \
swissChili710d18d2020-07-29 19:43:20 -0700628 fetch_addr(cpu, am, FETCH_NO_INDIRECTION).ptr, am); \
swissChili6c61a792020-07-28 16:29:20 -0700629 break;
630
631 INSTRUCTIONS
632
633#undef INST
634
635 default:
swissChilic51e9222020-08-07 16:09:14 -0700636 end += sprintf(end, "Undefined opcode %x", op);
swissChili6c61a792020-07-28 16:29:20 -0700637 }
swissChilic51e9222020-08-07 16:09:14 -0700638
639 *end = 0;
640
641 return buffer;
swissChili6c61a792020-07-28 16:29:20 -0700642}
643
swissChilida4803e2020-08-06 20:06:04 -0700644void disas_num(cpu_t *cpu, uint16_t num)
645{
swissChilic51e9222020-08-07 16:09:14 -0700646 uint16_t pc = cpu->pc;
swissChilida4803e2020-08-06 20:06:04 -0700647 for (int i = 0; i < num; i++)
648 {
swissChilic51e9222020-08-07 16:09:14 -0700649 uint16_t last_pc = cpu->pc;
650 char *line = disas_step(cpu);
651 printf("$%x\t%s\n", last_pc, line);
652 free(line);
swissChilida4803e2020-08-06 20:06:04 -0700653 }
swissChilic51e9222020-08-07 16:09:14 -0700654 cpu->pc = pc;
swissChilida4803e2020-08-06 20:06:04 -0700655}
656
swissChili6c61a792020-07-28 16:29:20 -0700657void disas(cpu_t *cpu)
658{
swissChilic51e9222020-08-07 16:09:14 -0700659 uint16_t pc = cpu->pc;
swissChili6264a3b2020-07-30 19:02:07 -0700660 // Raw binary, no way to know what's code what isn't
swissChili6c61a792020-07-28 16:29:20 -0700661 while (cpu->pc < 0xFFFF)
662 {
swissChilic51e9222020-08-07 16:09:14 -0700663 uint16_t last_pc = cpu->pc;
664 char *line = disas_step(cpu);
665 printf("$%x\t%s\n", last_pc, line);
666 free(line);
swissChili6c61a792020-07-28 16:29:20 -0700667 }
swissChilic51e9222020-08-07 16:09:14 -0700668 cpu->pc = pc;
swissChili6c61a792020-07-28 16:29:20 -0700669}
swissChilic51e9222020-08-07 16:09:14 -0700670
swissChilida4803e2020-08-06 20:06:04 -0700671void run(cpu_t *cpu)
672{
673 while (cpu->running)
674 {
675 step(cpu);
676 }
677
678 printf("CPU Halted\n");
679}