diff --git a/cpu.c b/cpu.c index f018a44..08c6119 100644 --- a/cpu.c +++ b/cpu.c @@ -1,7 +1,10 @@ #include #include +#include #include +#define MAX(a, b) ((a > b) ? a : b) + #define STATUS_UPDATE_ZERO(r) \ (regs.status.zero = r == 0) #define STATUS_UPDATE_NEGATIVE(r) \ @@ -47,18 +50,70 @@ 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) */ return (uint16_t)memory[addr] | ((uint16_t)memory[addr + 1] << 8); } +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) { @@ -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;