blob: f58d1817a072fb4c9d36bcc4061d0a8e16f42809 [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{
25 cpu->regs[SP] = 0xFD; // 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 };
swissChili6c61a792020-07-28 16:29:20 -070034 cpu.regs[SP] = 0xFD; // 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);
399 break;
400
401 case RTS:
402 cpu->pc = stack_pople(cpu);
403 break;
404
405 // TODO: implement RTI
406 // TODO: implement flag instructions
407
408 case BRK:
409 // TODO: trigger an interrupt
410 cpu->running = false;
411 break;
412
413 case NOP:
414 break;
415
416 default:
swissChilib71e0272020-08-08 15:56:14 -0700417 warn("Unsupported opcode: %x\n", op);
418 THROW("Unsupported opcode");
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)
swissChilib71e0272020-08-08 15:56:14 -0700501 return arg_ptr(cpu, f, cpu->mem[cpu->pc++]);
502 return arg_ptr(cpu, f, cpu->mem[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)
swissChilib71e0272020-08-08 15:56:14 -0700506 return arg_ptr(cpu, f, cpu->mem[cpu->pc++]);
507 return arg_ptr(cpu, f, cpu->mem[cpu->pc++] + cpu->regs[Y]);
swissChili6c61a792020-07-28 16:29:20 -0700508
509 case AM_ZIX:
510 {
swissChilib71e0272020-08-08 15:56:14 -0700511 uint8_t zp = cpu->mem[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];
swissChilib71e0272020-08-08 15:56:14 -0700517 uint16_t indirect = le_to_native(cpu->mem[addr], cpu->mem[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
swissChilib71e0272020-08-08 15:56:14 -0700528 uint16_t base = le_to_native(cpu->mem[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:
swissChilib71e0272020-08-08 15:56:14 -0700533 warn("Unknown address mode %x", am);
534 THROW("Unknowng address mode");
swissChili710d18d2020-07-29 19:43:20 -0700535 __builtin_unreachable();
swissChili6c61a792020-07-28 16:29:20 -0700536 }
537}
538
swissChilicc27cfe2020-08-08 12:57:57 -0700539void step(cpu_t *cpu)
swissChili6c61a792020-07-28 16:29:20 -0700540{
swissChili94ba1f52020-08-08 11:39:10 -0700541 static int steps;
542 steps++;
swissChilicc27cfe2020-08-08 12:57:57 -0700543 cpu->screen_dirty = false;
swissChilib71e0272020-08-08 15:56:14 -0700544 uint8_t pc = cpu->pc;
545 uint8_t op = cpu->mem[cpu->pc++];
546 switch (op)
swissChili6c61a792020-07-28 16:29:20 -0700547 {
548#define INST(mn, am, op) \
549 case op: \
swissChilida4803e2020-08-06 20:06:04 -0700550 execute(cpu, #mn, mn, fetch_addr(cpu, am, 0), am); \
swissChili6c61a792020-07-28 16:29:20 -0700551 break;
552
553 INSTRUCTIONS
554
555#undef INST
556
557 default:
swissChilib71e0272020-08-08 15:56:14 -0700558 warn("Undefined opcode %x near %x [%x]", op, pc, cpu->mem[pc]);
559 THROW("Undefined opcode");
swissChili6c61a792020-07-28 16:29:20 -0700560 }
swissChili94ba1f52020-08-08 11:39:10 -0700561
562 if (steps % 100 == 0)
563 printf("%d\n", steps);
564
swissChilicc27cfe2020-08-08 12:57:57 -0700565// If can't run screen in seperate thread, just run it here (bad)
566#ifdef NO_PTHREAD
swissChili94ba1f52020-08-08 11:39:10 -0700567 if (g_scr)
568 {
swissChilicc27cfe2020-08-08 12:57:57 -0700569 sdl_screen(g_scr, cpu->mem + CPU_FB_ADDR, cpu->screen_dirty);
swissChili94ba1f52020-08-08 11:39:10 -0700570 }
swissChilicc27cfe2020-08-08 12:57:57 -0700571#endif
swissChili6c61a792020-07-28 16:29:20 -0700572}
573
swissChilic51e9222020-08-07 16:09:14 -0700574int dump_inst(cpu_t *cpu, char *buf, const char *mn, uint16_t addr, uint8_t am)
swissChili6c61a792020-07-28 16:29:20 -0700575{
swissChilic51e9222020-08-07 16:09:14 -0700576 char *end = buf;
577 end += sprintf(end, "%s ", mn);
swissChili6c61a792020-07-28 16:29:20 -0700578
579 switch (am)
580 {
581 case AM_IMM:
swissChilic51e9222020-08-07 16:09:14 -0700582 end += sprintf(end, "#");
swissChili6c61a792020-07-28 16:29:20 -0700583 case AM_REL:
584 case AM_ABS:
585 case AM_ZP:
swissChilic51e9222020-08-07 16:09:14 -0700586 end += sprintf(end, "$%x", addr);
swissChili6c61a792020-07-28 16:29:20 -0700587 break;
588
589 case AM_IND:
swissChilic51e9222020-08-07 16:09:14 -0700590 end += sprintf(end, "($%x)", addr);
swissChili6c61a792020-07-28 16:29:20 -0700591 break;
592
593 case AM_AX:
594 case AM_ZPX:
swissChilic51e9222020-08-07 16:09:14 -0700595 end += sprintf(end, "$%x, X", addr);
swissChili6c61a792020-07-28 16:29:20 -0700596 break;
597
598 case AM_AY:
599 case AM_ZPY:
swissChilic51e9222020-08-07 16:09:14 -0700600 end += sprintf(end, "$%x, Y", addr);
swissChili6c61a792020-07-28 16:29:20 -0700601 break;
602
603 case AM_ZIX:
swissChilic51e9222020-08-07 16:09:14 -0700604 end += sprintf(end, "($%x, X)", addr);
swissChili6c61a792020-07-28 16:29:20 -0700605 break;
606
607 case AM_ZIY:
swissChilic51e9222020-08-07 16:09:14 -0700608 end += sprintf(end, "($%x), Y", addr);
swissChili6c61a792020-07-28 16:29:20 -0700609 break;
610 }
611
swissChilic51e9222020-08-07 16:09:14 -0700612 return end - buf;
swissChili6c61a792020-07-28 16:29:20 -0700613}
614
swissChilic51e9222020-08-07 16:09:14 -0700615char *disas_step(cpu_t *cpu)
swissChili6c61a792020-07-28 16:29:20 -0700616{
swissChilic51e9222020-08-07 16:09:14 -0700617 char *buffer = malloc(80);
618 char *end = buffer;
619
620 // end += sprintf(buffer, "$%x", cpu->pc);
swissChilicc27cfe2020-08-08 12:57:57 -0700621 uint8_t op = cpu->mem[scr_dirty(cpu, cpu->pc++)];
swissChili6c61a792020-07-28 16:29:20 -0700622 switch (op)
623 {
624#define INST(mn, am, op) \
625 case op: \
swissChilic51e9222020-08-07 16:09:14 -0700626 end += dump_inst(cpu, end, #mn, \
swissChili710d18d2020-07-29 19:43:20 -0700627 fetch_addr(cpu, am, FETCH_NO_INDIRECTION).ptr, am); \
swissChili6c61a792020-07-28 16:29:20 -0700628 break;
629
630 INSTRUCTIONS
631
632#undef INST
633
634 default:
swissChilic51e9222020-08-07 16:09:14 -0700635 end += sprintf(end, "Undefined opcode %x", op);
swissChili6c61a792020-07-28 16:29:20 -0700636 }
swissChilic51e9222020-08-07 16:09:14 -0700637
638 *end = 0;
639
640 return buffer;
swissChili6c61a792020-07-28 16:29:20 -0700641}
642
swissChilida4803e2020-08-06 20:06:04 -0700643void disas_num(cpu_t *cpu, uint16_t num)
644{
swissChilic51e9222020-08-07 16:09:14 -0700645 uint16_t pc = cpu->pc;
swissChilida4803e2020-08-06 20:06:04 -0700646 for (int i = 0; i < num; i++)
647 {
swissChilic51e9222020-08-07 16:09:14 -0700648 uint16_t last_pc = cpu->pc;
649 char *line = disas_step(cpu);
650 printf("$%x\t%s\n", last_pc, line);
651 free(line);
swissChilida4803e2020-08-06 20:06:04 -0700652 }
swissChilic51e9222020-08-07 16:09:14 -0700653 cpu->pc = pc;
swissChilida4803e2020-08-06 20:06:04 -0700654}
655
swissChili6c61a792020-07-28 16:29:20 -0700656void disas(cpu_t *cpu)
657{
swissChilic51e9222020-08-07 16:09:14 -0700658 uint16_t pc = cpu->pc;
swissChili6264a3b2020-07-30 19:02:07 -0700659 // Raw binary, no way to know what's code what isn't
swissChili6c61a792020-07-28 16:29:20 -0700660 while (cpu->pc < 0xFFFF)
661 {
swissChilic51e9222020-08-07 16:09:14 -0700662 uint16_t last_pc = cpu->pc;
663 char *line = disas_step(cpu);
664 printf("$%x\t%s\n", last_pc, line);
665 free(line);
swissChili6c61a792020-07-28 16:29:20 -0700666 }
swissChilic51e9222020-08-07 16:09:14 -0700667 cpu->pc = pc;
swissChili6c61a792020-07-28 16:29:20 -0700668}
swissChilic51e9222020-08-07 16:09:14 -0700669
swissChilida4803e2020-08-06 20:06:04 -0700670void run(cpu_t *cpu)
671{
672 while (cpu->running)
673 {
674 step(cpu);
675 }
676
677 printf("CPU Halted\n");
678}