diff options
author | vin <git@vineetk.net> | 2024-06-08 17:41:06 +0530 |
---|---|---|
committer | vin <git@vineetk.net> | 2024-06-08 17:41:17 +0530 |
commit | 1ac30a026b7877ca6b295c661d91b20eaddb01c9 (patch) | |
tree | 22b23ab204390641e84ce42581ee5408444dd993 | |
parent | bd85b80ba7a7919a80ce6fd742b37d3e183f2e3a (diff) |
add adc and actually fix peek/16
-rw-r--r-- | cpu.c | 84 |
1 files changed, 82 insertions, 2 deletions
@@ -1,7 +1,10 @@ #include <stdint.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> +#define MAX(a, b) ((a > b) ? a : b) + #define STATUS_UPDATE_ZERO(r) \ (regs.status.zero = r == 0) #define STATUS_UPDATE_NEGATIVE(r) \ @@ -47,12 +50,12 @@ uint8_t memory[0x16000]; uint8_t program[] = { 0xa9, 0xc0, 0xaa, 0xe8, 0x00 }; uint8_t -peek(uint8_t addr) +peek(uint16_t addr) { return memory[addr]; } -uint8_t +uint16_t peek16(uint16_t addr) { /* bytes are stored in little-endian (low then high) */ @@ -60,6 +63,58 @@ peek16(uint16_t addr) } void +adc(enum addressing_mode mode) +{ + uint8_t arg, val; + uint16_t sum; // 16-bit sum makes it easier to determine carry flag + + if (mode != AM_ABS && mode != AM_ABS_X && mode != AM_ABS_Y) + arg = peek(regs.pc++); + else + arg = peek16(regs.pc++); + + switch (mode) { + case AM_IMM: /* $69 */ + val = arg; + break; + case AM_ZP: /* $65 */ + val = peek(arg % 256); + break; + case AM_ABS: /* $6D */ + val = peek16(arg); + break; + case AM_ZP_X: /* $75 */ + val = peek((arg + regs.x) % 256); + break; + case AM_ABS_X: /* $7D */ + val = peek16(arg + regs.x); + break; + case AM_ABS_Y: /* $79 */ + val = peek16(arg + regs.y); + break; + case AM_IND_X: /* $61 */ + val = peek(peek((arg + regs.x) % 256) + peek((arg + regs.x + 1) % 256) * 256); + break; + case AM_IND_Y: /* $71 */ + val = peek(peek(arg) + peek((arg + 1) % 256) * 256 + regs.y); + break; + default: + fprintf(stderr, "INVALID ADC ADDRESSING MODE\n"); + abort(); + return; + } + + sum = regs.a + val + regs.status.carry; + regs.a = sum & 0xFF; + + regs.status.carry = sum > 0xFF; + /* overflow flag formula: https://stackoverflow.com/a/29224684 */ + regs.status.overflow = ~(regs.a ^ arg) & (regs.a ^ sum) & 0x80; + STATUS_UPDATE_ZERO(regs.a); + STATUS_UPDATE_NEGATIVE(regs.a); +} + +void brk(void) { /* $00 */ @@ -150,6 +205,30 @@ interpret(void) case 0x00: brk(); return; + case 0x61: + adc(AM_IND_X); + break; + case 0x65: + adc(AM_ZP); + break; + case 0x69: + adc(AM_IMM); + break; + case 0x6D: + adc(AM_ABS); + break; + case 0x71: + adc(AM_IND_Y); + break; + case 0x75: + adc(AM_ZP_X); + break; + case 0x79: + adc(AM_ABS_Y); + break; + case 0x7D: + adc(AM_ABS_X); + break; case 0xa1: lda(AM_IND_X); break; @@ -216,6 +295,7 @@ main(void) fprintf(stderr, "program is too big for memory\n"); return 1; } + memcpy(memory + 0x8000, program, sizeof(program)); regs.pc = 0x8000; |