blob: d4578680a585255b8feb1562d2dd887555e94392 [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;
28}
29
swissChili6c61a792020-07-28 16:29:20 -070030cpu_t new_cpu()
31{
32 cpu_t cpu = { 0 };
swissChili6c61a792020-07-28 16:29:20 -070033 cpu.regs[SP] = 0xFD; // stack at is 0x100 + SP
swissChilibb478f12020-08-07 20:45:07 -070034 cpu.pc = 0x600; // arbitrary program counter start
swissChili6264a3b2020-07-30 19:02:07 -070035 cpu.running = true;
swissChili6c61a792020-07-28 16:29:20 -070036 cpu.mem = malloc(0xFFFF);
swissChilicc27cfe2020-08-08 12:57:57 -070037 cpu.screen_dirty = true;
swissChili6c61a792020-07-28 16:29:20 -070038 memset(cpu.mem, 0, 0xFFFF);
39
swissChilib71e0272020-08-08 15:56:14 -070040 ASSERT("Allocate memory for CPU", cpu.mem);
swissChili6c61a792020-07-28 16:29:20 -070041
42 return cpu;
43}
44
swissChilida4803e2020-08-06 20:06:04 -070045uint16_t le_to_native(uint8_t a, uint8_t b)
46{
47#ifdef LITTLE_ENDIAN
48 return b << 8 | a;
49#else
50 return a << 8 | b;
51#endif
52}
53
54void native_to_le(uint16_t n, uint8_t *a, uint8_t *b)
55{
56#ifdef LITTLE_ENDIAN
57 *a = n >> 8;
58 *b = n & 0xFF;
59#else
60 *a = n & 0xFF;
61 *b = n >> 8;
62#endif
63}
64
swissChili6264a3b2020-07-30 19:02:07 -070065void stack_push(cpu_t *cpu, uint8_t v)
66{
67 cpu->mem[cpu->regs[SP]-- + 0x100] = v;
68}
69
swissChilida4803e2020-08-06 20:06:04 -070070void stack_pushle(cpu_t *cpu, uint16_t v)
71{
72 uint8_t a, b;
73 native_to_le(v, &a, &b);
74 // push in "reverse" order so that the address is stored as LE
75 stack_push(cpu, b);
76 stack_push(cpu, a);
77}
78
swissChili6264a3b2020-07-30 19:02:07 -070079uint8_t stack_pop(cpu_t *cpu)
80{
81 return cpu->mem[cpu->regs[SP]++ + 0x100];
82}
83
swissChilida4803e2020-08-06 20:06:04 -070084uint16_t stack_pople(cpu_t *cpu)
85{
86 uint8_t a = stack_pop(cpu);
87 uint8_t b = stack_pop(cpu);
88 return le_to_native(a, b);
89}
90
swissChili6c61a792020-07-28 16:29:20 -070091void free_cpu(cpu_t *cpu)
92{
93 free(cpu->mem);
94}
95
swissChilida4803e2020-08-06 20:06:04 -070096// rotate right
swissChilicc27cfe2020-08-08 12:57:57 -070097uint8_t ror(uint8_t a, uint8_t n)
swissChilida4803e2020-08-06 20:06:04 -070098{
99 return (a >> n) | (a << (8 - n));
100}
101
102// rotate left
swissChilicc27cfe2020-08-08 12:57:57 -0700103uint8_t rol(uint8_t a, uint8_t n)
swissChilida4803e2020-08-06 20:06:04 -0700104{
105 return (a << n) | (a >> (8 - n));
106}
107
swissChilicc27cfe2020-08-08 12:57:57 -0700108void stat_nz(cpu_t *cpu, int8_t v)
swissChili6c61a792020-07-28 16:29:20 -0700109{
swissChili6264a3b2020-07-30 19:02:07 -0700110 cpu->status.negative = v < 0;
111 cpu->status.zero = v == 0;
112}
113
114// Used to check for overflow, is c unique?
swissChilicc27cfe2020-08-08 12:57:57 -0700115bool last_unique(bool a, bool b, bool c)
swissChili6264a3b2020-07-30 19:02:07 -0700116{
117 return a == b && a != c;
118}
119
swissChilicc27cfe2020-08-08 12:57:57 -0700120void stat_cv(cpu_t *cpu, uint8_t a, uint8_t b, uint8_t c)
swissChili6264a3b2020-07-30 19:02:07 -0700121{
122 cpu->status.overflow = last_unique(a >> 7, b >> 7, c >> 7);
123 cpu->status.carry = c < a || c < b;
124}
125
swissChilicc27cfe2020-08-08 12:57:57 -0700126void cmp(cpu_t *cpu, uint8_t reg, uint8_t mem)
swissChilida4803e2020-08-06 20:06:04 -0700127{
128 cpu->status.negative = 0;
129 cpu->status.zero = 0;
130 cpu->status.carry = 0;
131 if (cpu->regs[reg] < mem)
132 {
133 cpu->status.negative = 1;
134 }
135 else if (cpu->regs[reg] == mem)
136 {
137 cpu->status.zero = 1;
138 cpu->status.carry = 1;
139 }
140 else
141 {
142 cpu->status.carry = 1;
143 }
144}
145
swissChilicc27cfe2020-08-08 12:57:57 -0700146uint16_t scr_dirty(cpu_t *cpu, uint16_t mem)
147{
148 if (mem >= 0x200 && mem <= 0x200 + 32 * 32)
149 cpu->screen_dirty = true;
150
151 return mem;
152}
153
swissChilida4803e2020-08-06 20:06:04 -0700154void execute(cpu_t *cpu, const char *mnemonic, uint8_t op, arg_t a, uint8_t am)
swissChili6264a3b2020-07-30 19:02:07 -0700155{
156 // used to save space
157 #define REGS \
158 R(X) R(A) R(Y)
159
swissChili710d18d2020-07-29 19:43:20 -0700160 switch (op) {
swissChili6264a3b2020-07-30 19:02:07 -0700161 // Load and store instructions:
162 #define R(reg) \
163 case LD##reg: \
164 cpu->regs[reg] = a.val; \
165 stat_nz(cpu, a.val); \
166 break;
167
168 REGS
169
170 #undef R
171
172 #define R(reg) \
173 case ST##reg: \
swissChilicc27cfe2020-08-08 12:57:57 -0700174 cpu->mem[scr_dirty(cpu, a.ptr)] = cpu->regs[reg]; \
swissChili6264a3b2020-07-30 19:02:07 -0700175 break; \
176
177 REGS
178
179 #undef R
180
181 // Arithmetic instructions:
182 // NOTE: binary coded decimals are NOT SUPPORTED because I don't want
183 // to implement them.
184 case ADC:
185 {
186 uint8_t sum = cpu->regs[A] + a.val + cpu->status.carry;
187 // signed overflow
188 stat_cv(cpu, cpu->regs[A], a.val + cpu->status.carry, sum);
189 stat_nz(cpu, sum);
190 cpu->regs[A] = sum;
191 break;
192 }
193
194 case SBC:
195 {
196 uint8_t diff = cpu->regs[A] - a.val - !cpu->status.carry;
197 stat_cv(cpu, cpu->regs[A], a.val - !cpu->status.carry, diff);
198 stat_nz(cpu, diff);
199 cpu->regs[A] = diff;
200 break;
201 }
202
203 case INC:
swissChilicc27cfe2020-08-08 12:57:57 -0700204 cpu->mem[scr_dirty(cpu, scr_dirty(cpu, a.ptr))]++;
205 stat_nz(cpu, cpu->mem[scr_dirty(cpu, a.ptr)]);
swissChili6264a3b2020-07-30 19:02:07 -0700206 break;
207
208 case INX:
209 cpu->regs[X]++;
210 stat_nz(cpu, cpu->regs[X]);
211 break;
212
213 case INY:
214 cpu->regs[Y]++;
215 stat_nz(cpu, cpu->regs[Y]);
216 break;
217
218 case DEC:
swissChilicc27cfe2020-08-08 12:57:57 -0700219 cpu->mem[scr_dirty(cpu, a.ptr)]--;
220 stat_nz(cpu, cpu->mem[scr_dirty(cpu, a.ptr)]);
swissChili6264a3b2020-07-30 19:02:07 -0700221 break;
swissChilida4803e2020-08-06 20:06:04 -0700222
223 case DEX:
224 cpu->regs[X]--;
225 stat_nz(cpu, cpu->regs[X]);
226 break;
227
228 case DEY:
229 cpu->regs[Y]--;
230 stat_nz(cpu, cpu->regs[Y]);
231 break;
232
233 case ASL:
234 // This check must be done here unfortunately, it would be nice
235 // to do this while decoding operands but it would require
236 // a substantial change to the architecture of the emulator
237 if (am == AM_ACC)
238 {
239 cpu->status.carry = cpu->regs[A] >> 7;
240 cpu->regs[A] <<= 1;
241 stat_nz(cpu, cpu->regs[A]);
242 }
243 else
244 {
swissChilicc27cfe2020-08-08 12:57:57 -0700245 cpu->status.carry = cpu->mem[scr_dirty(cpu, a.val)] >> 7;
246 cpu->mem[scr_dirty(cpu, a.ptr)] <<= 1;
247 stat_nz(cpu, cpu->mem[scr_dirty(cpu, a.ptr)]);
swissChilida4803e2020-08-06 20:06:04 -0700248 }
249 break;
250
251 case LSR:
252 if (am == AM_ACC)
253 {
254 cpu->status.carry = cpu->regs[A] & 1;
255 cpu->regs[A] >>= 1;
256 stat_nz(cpu, cpu->regs[A]);
257 }
258 else
259 {
swissChilicc27cfe2020-08-08 12:57:57 -0700260 cpu->status.carry = cpu->mem[scr_dirty(cpu, a.val)] & 7;
261 cpu->mem[scr_dirty(cpu, a.ptr)] >>= 1;
262 stat_nz(cpu, cpu->mem[scr_dirty(cpu, a.ptr)]);
swissChilida4803e2020-08-06 20:06:04 -0700263 }
264 break;
265
266 case ROL:
267 if (am == AM_ACC)
268 {
269 cpu->status.carry = cpu->regs[A] >> 7;
270 cpu->regs[A] = rol(cpu->regs[A], 1);
271 stat_nz(cpu, cpu->regs[A]);
272 }
273 else
274 {
swissChilicc27cfe2020-08-08 12:57:57 -0700275 cpu->status.carry = cpu->mem[scr_dirty(cpu, a.val)] >> 7;
276 cpu->mem[scr_dirty(cpu, a.ptr)] = rol(a.val, 1);
277 stat_nz(cpu, cpu->mem[scr_dirty(cpu, a.ptr)]);
swissChilida4803e2020-08-06 20:06:04 -0700278 }
279 break;
280
281 case ROR:
282 if (am == AM_ACC)
283 {
284 cpu->status.carry = cpu->regs[A] & 1;
285 cpu->regs[A] = ror(cpu->regs[A], 1);
286 stat_nz(cpu, cpu->regs[A]);
287 }
288 else
289 {
swissChilicc27cfe2020-08-08 12:57:57 -0700290 cpu->status.carry = cpu->mem[scr_dirty(cpu, a.val)] & 1;
291 cpu->mem[scr_dirty(cpu, a.ptr)] = ror(a.val, 1);
292 stat_nz(cpu, cpu->mem[scr_dirty(cpu, a.ptr)]);
swissChilida4803e2020-08-06 20:06:04 -0700293 }
294 break;
295
296 case AND:
297 cpu->regs[A] &= a.val;
298 stat_nz(cpu, cpu->regs[A]);
299 break;
300
301 case ORA:
302 cpu->regs[A] |= a.val;
303 stat_nz(cpu, cpu->regs[A]);
304 break;
305
306 case EOR:
307 cpu->regs[A] ^= a.val;
308 stat_nz(cpu, cpu->regs[A]);
309 break;
310
311 case CMP:
312 cmp(cpu, A, a.val);
313 break;
314
315 case CPX:
316 cmp(cpu, X, a.val);
317 break;
318
319 case CPY:
320 cmp(cpu, Y, a.val);
321 break;
322
323 // TODO: implement BIT here
324
325 #define BRANCHES \
326 B(BCC, carry == 0) \
327 B(BCS, carry == 1) \
328 B(BNE, zero == 0) \
329 B(BEQ, zero == 1) \
330 B(BPL, negative == 0) \
331 B(BMI, negative == 1) \
332 B(BVC, overflow == 0) \
333 B(BVS, overflow == 1)
334
335 #define B(i, c) \
336 case i: \
337 if (cpu->status . c) \
338 cpu->pc = a.ptr;\
339 break;
340
341 BRANCHES
342
343 #undef B
344 #undef BRANCHES
345
346 #define TRANSFERS \
347 T(A, X) \
348 T(X, A) \
349 T(A, Y) \
350 T(Y, A)
351
352 #define T(a, b) \
353 case T ## a ## b: \
354 cpu->regs[b] = cpu->regs[a]; \
355 stat_nz(cpu, cpu->regs[b]); \
356 break;
357
358 TRANSFERS
359
360 #undef T
361 #undef TRANSFERS
362
363 case TSX:
364 cpu->regs[X] = cpu->regs[SP];
365 stat_nz(cpu, cpu->regs[X]);
366 break;
367
368 case TXS:
369 cpu->regs[SP] = cpu->regs[X];
370 stat_nz(cpu, cpu->regs[X]);
371 break;
372
373 case PHA:
374 stack_push(cpu, cpu->regs[A]);
375 break;
376
377 case PLA:
378 cpu->regs[A] = stack_pop(cpu);
379 stat_nz(cpu, cpu->regs[A]);
380 break;
381
382 case PHP:
383 stack_push(cpu, *(uint8_t *)(&cpu->status));
384 break;
385
386 case PLP:
387 {
388 uint8_t s = stack_pop(cpu);
389 *(uint8_t *)(&cpu->status) = s;
390 }
391
392 case JMP:
393 cpu->pc = a.ptr;
394 break;
395
396 case JSR:
397 stack_pushle(cpu, cpu->pc);
398 break;
399
400 case RTS:
401 cpu->pc = stack_pople(cpu);
402 break;
403
404 // TODO: implement RTI
405 // TODO: implement flag instructions
406
407 case BRK:
408 // TODO: trigger an interrupt
409 cpu->running = false;
410 break;
411
412 case NOP:
413 break;
414
415 default:
swissChilib71e0272020-08-08 15:56:14 -0700416 warn("Unsupported opcode: %x\n", op);
417 THROW("Unsupported opcode");
swissChili710d18d2020-07-29 19:43:20 -0700418 }
swissChili6264a3b2020-07-30 19:02:07 -0700419 #undef REGS
swissChili6c61a792020-07-28 16:29:20 -0700420}
421
swissChilicc27cfe2020-08-08 12:57:57 -0700422uint16_t fetch_le(cpu_t *cpu)
swissChili6c61a792020-07-28 16:29:20 -0700423{
swissChilicc27cfe2020-08-08 12:57:57 -0700424 uint8_t a = cpu->mem[scr_dirty(cpu, cpu->pc++)];
425 uint8_t b = cpu->mem[scr_dirty(cpu, cpu->pc++)];
swissChili6c61a792020-07-28 16:29:20 -0700426 return le_to_native(a, b);
427}
428
swissChilicc27cfe2020-08-08 12:57:57 -0700429arg_t arg_imm(uint16_t a)
swissChili710d18d2020-07-29 19:43:20 -0700430{
431 return (arg_t){ a, a };
432}
433
swissChilicc27cfe2020-08-08 12:57:57 -0700434arg_t arg_ptr(cpu_t *c, uint flags, uint16_t p)
swissChili710d18d2020-07-29 19:43:20 -0700435{
436 if (flags & FETCH_NO_INDIRECTION)
437 return arg_imm(p);
438
439 return (arg_t){ c->mem[p], p };
440}
441
swissChilicc27cfe2020-08-08 12:57:57 -0700442arg_t arg(uint16_t v, uint16_t a)
swissChili710d18d2020-07-29 19:43:20 -0700443{
444 return (arg_t){ v, a };
445}
446
447arg_t fetch_addr(cpu_t *cpu, uint8_t am, uint f)
swissChili6c61a792020-07-28 16:29:20 -0700448{
449 switch (am)
450 {
451 case AM_ACC:
452 case AM_IMP:
swissChili710d18d2020-07-29 19:43:20 -0700453 return arg_imm(0);
swissChili6c61a792020-07-28 16:29:20 -0700454
455 // In both cases return immediate 8 bit value
456 case AM_IMM:
457 case AM_ZP:
swissChilicc27cfe2020-08-08 12:57:57 -0700458 return arg_imm(cpu->mem[scr_dirty(cpu, cpu->pc++)]);
swissChili6c61a792020-07-28 16:29:20 -0700459
460 case AM_ABS:
swissChili710d18d2020-07-29 19:43:20 -0700461 return arg_ptr(cpu, f, fetch_le(cpu));
swissChili6c61a792020-07-28 16:29:20 -0700462
463 case AM_REL:
464 {
swissChili6264a3b2020-07-30 19:02:07 -0700465 // Aparently, PC should will point to the NEXT opcode
466 // I can't find any documentation on this unfortunately, but
467 // I have discovered this through testing the output of other
468 // assemblers.
469 uint16_t pc = cpu->pc + 1;
swissChilicc27cfe2020-08-08 12:57:57 -0700470 return arg_ptr(cpu, f, (int8_t)cpu->mem[scr_dirty(cpu, cpu->pc++)] + pc);
swissChili6c61a792020-07-28 16:29:20 -0700471 }
472
473 case AM_IND:
474 {
475 uint16_t addr = fetch_le(cpu);
swissChili6264a3b2020-07-30 19:02:07 -0700476
477 if (f & FETCH_NO_INDIRECTION)
478 return arg_imm(addr);
479
swissChilicc27cfe2020-08-08 12:57:57 -0700480 uint8_t low = cpu->mem[scr_dirty(cpu, addr)],
481 high = cpu->mem[scr_dirty(cpu, addr + 1)];
swissChili6c61a792020-07-28 16:29:20 -0700482
swissChili710d18d2020-07-29 19:43:20 -0700483 return arg_ptr(cpu, f, le_to_native(low, high));
swissChili6c61a792020-07-28 16:29:20 -0700484 }
485
486 case AM_AX:
swissChili94ba1f52020-08-08 11:39:10 -0700487 if (f & FETCH_NO_INDIRECTION)
488 return arg_ptr(cpu, f, fetch_le(cpu));
489
swissChili710d18d2020-07-29 19:43:20 -0700490 return arg_ptr(cpu, f, fetch_le(cpu) + cpu->regs[X]);
swissChili6c61a792020-07-28 16:29:20 -0700491
492 case AM_AY:
swissChili94ba1f52020-08-08 11:39:10 -0700493 if (f & FETCH_NO_INDIRECTION)
494 return arg_ptr(cpu, f, fetch_le(cpu));
495
swissChili710d18d2020-07-29 19:43:20 -0700496 return arg_ptr(cpu, f, fetch_le(cpu) + cpu->regs[Y]);
swissChili6c61a792020-07-28 16:29:20 -0700497
498 case AM_ZPX:
swissChili94ba1f52020-08-08 11:39:10 -0700499 if (f & FETCH_NO_INDIRECTION)
swissChilib71e0272020-08-08 15:56:14 -0700500 return arg_ptr(cpu, f, cpu->mem[cpu->pc++]);
501 return arg_ptr(cpu, f, cpu->mem[cpu->pc++] + cpu->regs[X]);
swissChili6c61a792020-07-28 16:29:20 -0700502
503 case AM_ZPY:
swissChili94ba1f52020-08-08 11:39:10 -0700504 if (f & FETCH_NO_INDIRECTION)
swissChilib71e0272020-08-08 15:56:14 -0700505 return arg_ptr(cpu, f, cpu->mem[cpu->pc++]);
506 return arg_ptr(cpu, f, cpu->mem[cpu->pc++] + cpu->regs[Y]);
swissChili6c61a792020-07-28 16:29:20 -0700507
508 case AM_ZIX:
509 {
swissChilib71e0272020-08-08 15:56:14 -0700510 uint8_t zp = cpu->mem[cpu->pc++];
swissChili6264a3b2020-07-30 19:02:07 -0700511
512 if (f & FETCH_NO_INDIRECTION)
513 return arg_imm(zp);
514
swissChili710d18d2020-07-29 19:43:20 -0700515 uint16_t addr = zp + cpu->regs[X];
swissChilib71e0272020-08-08 15:56:14 -0700516 uint16_t indirect = le_to_native(cpu->mem[addr], cpu->mem[addr + 1]);
swissChili710d18d2020-07-29 19:43:20 -0700517 return arg_ptr(cpu, f, indirect);
swissChili6c61a792020-07-28 16:29:20 -0700518 }
519
520 case AM_ZIY:
521 {
swissChilicc27cfe2020-08-08 12:57:57 -0700522 uint8_t zp = cpu->mem[scr_dirty(cpu, cpu->pc++)];
swissChili6264a3b2020-07-30 19:02:07 -0700523
524 if (f & FETCH_NO_INDIRECTION)
525 return arg_imm(zp);
526
swissChilib71e0272020-08-08 15:56:14 -0700527 uint16_t base = le_to_native(cpu->mem[zp], cpu->mem[scr_dirty(cpu, zp + 1)]);
swissChili710d18d2020-07-29 19:43:20 -0700528 return arg_ptr(cpu, f, base + cpu->regs[Y]);
swissChili6c61a792020-07-28 16:29:20 -0700529 }
530
531 default:
swissChilib71e0272020-08-08 15:56:14 -0700532 warn("Unknown address mode %x", am);
533 THROW("Unknowng address mode");
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;
swissChilib71e0272020-08-08 15:56:14 -0700543 uint8_t pc = cpu->pc;
544 uint8_t op = cpu->mem[cpu->pc++];
545 switch (op)
swissChili6c61a792020-07-28 16:29:20 -0700546 {
547#define INST(mn, am, op) \
548 case op: \
swissChilida4803e2020-08-06 20:06:04 -0700549 execute(cpu, #mn, mn, fetch_addr(cpu, am, 0), am); \
swissChili6c61a792020-07-28 16:29:20 -0700550 break;
551
552 INSTRUCTIONS
553
554#undef INST
555
556 default:
swissChilib71e0272020-08-08 15:56:14 -0700557 warn("Undefined opcode %x near %x [%x]", op, pc, cpu->mem[pc]);
558 THROW("Undefined opcode");
swissChili6c61a792020-07-28 16:29:20 -0700559 }
swissChili94ba1f52020-08-08 11:39:10 -0700560
561 if (steps % 100 == 0)
562 printf("%d\n", steps);
563
swissChilicc27cfe2020-08-08 12:57:57 -0700564// If can't run screen in seperate thread, just run it here (bad)
565#ifdef NO_PTHREAD
swissChili94ba1f52020-08-08 11:39:10 -0700566 if (g_scr)
567 {
swissChilicc27cfe2020-08-08 12:57:57 -0700568 sdl_screen(g_scr, cpu->mem + CPU_FB_ADDR, cpu->screen_dirty);
swissChili94ba1f52020-08-08 11:39:10 -0700569 }
swissChilicc27cfe2020-08-08 12:57:57 -0700570#endif
swissChili6c61a792020-07-28 16:29:20 -0700571}
572
swissChilic51e9222020-08-07 16:09:14 -0700573int dump_inst(cpu_t *cpu, char *buf, const char *mn, uint16_t addr, uint8_t am)
swissChili6c61a792020-07-28 16:29:20 -0700574{
swissChilic51e9222020-08-07 16:09:14 -0700575 char *end = buf;
576 end += sprintf(end, "%s ", mn);
swissChili6c61a792020-07-28 16:29:20 -0700577
578 switch (am)
579 {
580 case AM_IMM:
swissChilic51e9222020-08-07 16:09:14 -0700581 end += sprintf(end, "#");
swissChili6c61a792020-07-28 16:29:20 -0700582 case AM_REL:
583 case AM_ABS:
584 case AM_ZP:
swissChilic51e9222020-08-07 16:09:14 -0700585 end += sprintf(end, "$%x", addr);
swissChili6c61a792020-07-28 16:29:20 -0700586 break;
587
588 case AM_IND:
swissChilic51e9222020-08-07 16:09:14 -0700589 end += sprintf(end, "($%x)", addr);
swissChili6c61a792020-07-28 16:29:20 -0700590 break;
591
592 case AM_AX:
593 case AM_ZPX:
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_AY:
598 case AM_ZPY:
swissChilic51e9222020-08-07 16:09:14 -0700599 end += sprintf(end, "$%x, Y", addr);
swissChili6c61a792020-07-28 16:29:20 -0700600 break;
601
602 case AM_ZIX:
swissChilic51e9222020-08-07 16:09:14 -0700603 end += sprintf(end, "($%x, X)", addr);
swissChili6c61a792020-07-28 16:29:20 -0700604 break;
605
606 case AM_ZIY:
swissChilic51e9222020-08-07 16:09:14 -0700607 end += sprintf(end, "($%x), Y", addr);
swissChili6c61a792020-07-28 16:29:20 -0700608 break;
609 }
610
swissChilic51e9222020-08-07 16:09:14 -0700611 return end - buf;
swissChili6c61a792020-07-28 16:29:20 -0700612}
613
swissChilic51e9222020-08-07 16:09:14 -0700614char *disas_step(cpu_t *cpu)
swissChili6c61a792020-07-28 16:29:20 -0700615{
swissChilic51e9222020-08-07 16:09:14 -0700616 char *buffer = malloc(80);
617 char *end = buffer;
618
619 // end += sprintf(buffer, "$%x", cpu->pc);
swissChilicc27cfe2020-08-08 12:57:57 -0700620 uint8_t op = cpu->mem[scr_dirty(cpu, cpu->pc++)];
swissChili6c61a792020-07-28 16:29:20 -0700621 switch (op)
622 {
623#define INST(mn, am, op) \
624 case op: \
swissChilic51e9222020-08-07 16:09:14 -0700625 end += dump_inst(cpu, end, #mn, \
swissChili710d18d2020-07-29 19:43:20 -0700626 fetch_addr(cpu, am, FETCH_NO_INDIRECTION).ptr, am); \
swissChili6c61a792020-07-28 16:29:20 -0700627 break;
628
629 INSTRUCTIONS
630
631#undef INST
632
633 default:
swissChilic51e9222020-08-07 16:09:14 -0700634 end += sprintf(end, "Undefined opcode %x", op);
swissChili6c61a792020-07-28 16:29:20 -0700635 }
swissChilic51e9222020-08-07 16:09:14 -0700636
637 *end = 0;
638
639 return buffer;
swissChili6c61a792020-07-28 16:29:20 -0700640}
641
swissChilida4803e2020-08-06 20:06:04 -0700642void disas_num(cpu_t *cpu, uint16_t num)
643{
swissChilic51e9222020-08-07 16:09:14 -0700644 uint16_t pc = cpu->pc;
swissChilida4803e2020-08-06 20:06:04 -0700645 for (int i = 0; i < num; i++)
646 {
swissChilic51e9222020-08-07 16:09:14 -0700647 uint16_t last_pc = cpu->pc;
648 char *line = disas_step(cpu);
649 printf("$%x\t%s\n", last_pc, line);
650 free(line);
swissChilida4803e2020-08-06 20:06:04 -0700651 }
swissChilic51e9222020-08-07 16:09:14 -0700652 cpu->pc = pc;
swissChilida4803e2020-08-06 20:06:04 -0700653}
654
swissChili6c61a792020-07-28 16:29:20 -0700655void disas(cpu_t *cpu)
656{
swissChilic51e9222020-08-07 16:09:14 -0700657 uint16_t pc = cpu->pc;
swissChili6264a3b2020-07-30 19:02:07 -0700658 // Raw binary, no way to know what's code what isn't
swissChili6c61a792020-07-28 16:29:20 -0700659 while (cpu->pc < 0xFFFF)
660 {
swissChilic51e9222020-08-07 16:09:14 -0700661 uint16_t last_pc = cpu->pc;
662 char *line = disas_step(cpu);
663 printf("$%x\t%s\n", last_pc, line);
664 free(line);
swissChili6c61a792020-07-28 16:29:20 -0700665 }
swissChilic51e9222020-08-07 16:09:14 -0700666 cpu->pc = pc;
swissChili6c61a792020-07-28 16:29:20 -0700667}
swissChilic51e9222020-08-07 16:09:14 -0700668
swissChilida4803e2020-08-06 20:06:04 -0700669void run(cpu_t *cpu)
670{
671 while (cpu->running)
672 {
673 step(cpu);
674 }
675
676 printf("CPU Halted\n");
677}