#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) \ (regs.status.negative = ((r & (1 << 7)) > 0)) struct cpu_flags { uint8_t carry : 1; uint8_t zero : 1; uint8_t interrupt_disable : 1; uint8_t decimal_mode : 1; uint8_t brk : 1; uint8_t unused : 1; uint8_t overflow : 1; uint8_t negative : 1; }; struct registers { uint8_t a, x, y, sp; struct cpu_flags status; uint16_t pc; }; struct registers regs; enum addressing_mode { AM_ACC, AM_IMM, AM_ZP, AM_ZP_X, AM_ZP_Y, AM_REL, AM_ABS, AM_ABS_X, AM_ABS_Y, AM_IND, AM_IND_X, AM_IND_Y, }; /* 64K address space, 16bit words */ uint8_t memory[0x16000]; /* example program taken from https://bugzmanov.github.io/nes_ebook/chapter_3_1.html */ uint8_t program[] = { 0xa9, 0xc0, 0xaa, 0xe8, 0x00 }; uint32_t cycles = 0; uint8_t peek(uint16_t addr) { return memory[addr]; } 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); } uint8_t opcode_arg(enum addressing_mode mode) { uint8_t arg, val; if (mode != AM_ABS && mode != AM_ABS_X && mode != AM_ABS_Y) arg = peek(regs.pc++); else arg = peek16(regs.pc), regs.pc += 2; switch (mode) { case AM_IMM: val = arg; break; case AM_ZP: val = peek(arg % 256); break; case AM_ZP_X: val = peek((arg + regs.x) % 256); break; case AM_ZP_Y: val = peek((arg + regs.y) % 256); break; case AM_ABS: val = peek16(arg); break; case AM_ABS_X: val = peek16(arg + regs.x); break; case AM_ABS_Y: val = peek16(arg + regs.y); break; case AM_IND_X: val = peek(peek((arg + regs.x) % 256) + peek((arg + regs.x + 1) % 256) * 256); break; case AM_IND_Y: val = peek(peek(arg) + peek((arg + 1) % 256) * 256 + regs.y); break; default: fprintf(stderr, "INVALID ADDRESSING MODE\n"); abort(); } return val; } void adc(uint8_t arg) { uint16_t sum; // 16-bit sum makes it easier to determine carry flag sum = regs.a + arg + 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 sbc(uint8_t arg) { /* SBC is described online as ADC with argument as two's complement */ adc(~arg + 1); } void brk(void) { /* $00 */ /* TODO: push regs.pc and regs.status to stack and load IRQ vector */ regs.status.brk = 1; return; } void tax(void) { /* $AA */ regs.x = regs.a; STATUS_UPDATE_ZERO(regs.x); STATUS_UPDATE_NEGATIVE(regs.x); } void inx(void) { /* $E8 */ regs.x++; STATUS_UPDATE_ZERO(regs.x); STATUS_UPDATE_NEGATIVE(regs.x); } void lda(uint8_t arg) { printf("arg1 $%02X\n", arg); regs.a = arg; STATUS_UPDATE_ZERO(regs.a); STATUS_UPDATE_NEGATIVE(regs.a); } void interpret(void) { uint8_t opcode; for (;;) { opcode = peek(regs.pc++); printf("opcode: $%02X\n", opcode); switch (opcode) { case 0x69: adc(opcode_arg(AM_IMM)); cycles += 2; break; case 0x65: adc(opcode_arg(AM_ZP)); cycles += 3; break; case 0x75: adc(opcode_arg(AM_ZP_X)); cycles += 4; break; case 0x6d: adc(opcode_arg(AM_ABS)); cycles += 4; break; case 0x7d: adc(opcode_arg(AM_ABS_X)); cycles += 4; break; case 0x79: adc(opcode_arg(AM_ABS_Y)); cycles += 4; break; case 0x72: adc(opcode_arg(AM_IND)); cycles += 5; break; case 0x61: adc(opcode_arg(AM_IND_X)); cycles += 6; break; case 0x71: adc(opcode_arg(AM_IND_Y)); cycles += 5; break; case 0x29: and(opcode_arg(AM_IMM)); cycles += 2; break; case 0x25: and(opcode_arg(AM_ZP)); cycles += 3; break; case 0x35: and(opcode_arg(AM_ZP_X)); cycles += 4; break; case 0x2d: and(opcode_arg(AM_ABS)); cycles += 4; break; case 0x3d: and(opcode_arg(AM_ABS_X)); cycles += 4; break; case 0x39: and(opcode_arg(AM_ABS_Y)); cycles += 4; break; case 0x32: and(opcode_arg(AM_IND)); cycles += 5; break; case 0x21: and(opcode_arg(AM_IND_X)); cycles += 6; break; case 0x31: and(opcode_arg(AM_IND_Y)); cycles += 5; break; case 0x0a: asl(opcode_arg(AM_ACC)); cycles += 2; break; case 0x06: asl(opcode_arg(AM_ZP)); cycles += 5; break; case 0x16: asl(opcode_arg(AM_ZP_X)); cycles += 6; break; case 0x0e: asl(opcode_arg(AM_ABS)); cycles += 6; break; case 0x1e: asl(opcode_arg(AM_ABS_X)); cycles += 6; break; case 0x0f: bbr(opcode_arg(AM_REL)); cycles += 4; break; case 0x1f: bbr(opcode_arg(AM_REL)); cycles += 4; break; case 0x2f: bbr(opcode_arg(AM_REL)); cycles += 4; break; case 0x3f: bbr(opcode_arg(AM_REL)); cycles += 4; break; case 0x4f: bbr(opcode_arg(AM_REL)); cycles += 4; break; case 0x5f: bbr(opcode_arg(AM_REL)); cycles += 4; break; case 0x6f: bbr(opcode_arg(AM_REL)); cycles += 4; break; case 0x7f: bbr(opcode_arg(AM_REL)); cycles += 4; break; case 0x8f: bbs(opcode_arg(AM_REL)); cycles += 4; break; case 0x9f: bbs(opcode_arg(AM_REL)); cycles += 4; break; case 0xaf: bbs(opcode_arg(AM_REL)); cycles += 4; break; case 0xbf: bbs(opcode_arg(AM_REL)); cycles += 4; break; case 0xcf: bbs(opcode_arg(AM_REL)); cycles += 4; break; case 0xdf: bbs(opcode_arg(AM_REL)); cycles += 4; break; case 0xef: bbs(opcode_arg(AM_REL)); cycles += 4; break; case 0xff: bbs(opcode_arg(AM_REL)); cycles += 4; break; case 0x90: bcc(opcode_arg(AM_IMM)); cycles += 2; break; case 0xb0: bcs(opcode_arg(AM_IMM)); cycles += 2; break; case 0xf0: beq(opcode_arg(AM_IMM)); cycles += 2; break; case 0x89: bit(opcode_arg(AM_IMM)); cycles += 2; break; case 0x24: bit(opcode_arg(AM_ZP)); cycles += 3; break; case 0x34: bit(opcode_arg(AM_ZP_X)); cycles += 4; break; case 0x2c: bit(opcode_arg(AM_ABS)); cycles += 4; break; case 0x3c: bit(opcode_arg(AM_ABS_X)); cycles += 4; break; case 0x30: bmi(opcode_arg(AM_IMM)); cycles += 2; break; case 0xd0: bne(opcode_arg(AM_IMM)); cycles += 2; break; case 0x10: bpl(opcode_arg(AM_IMM)); cycles += 2; break; case 0x80: bra(opcode_arg(AM_IMM)); cycles += 3; break; case 0x00: brk(); cycles += 7; break; case 0x50: bvc(opcode_arg(AM_IMM)); cycles += 2; break; case 0x70: bvs(opcode_arg(AM_IMM)); cycles += 2; break; case 0x18: clc(opcode_arg(AM_ACC)); cycles += 2; break; case 0xd8: cld(opcode_arg(AM_ACC)); cycles += 2; break; case 0x58: cli(opcode_arg(AM_ACC)); cycles += 2; break; case 0xb8: clv(opcode_arg(AM_ACC)); cycles += 2; break; case 0xc9: cmp(opcode_arg(AM_IMM)); cycles += 2; break; case 0xc5: cmp(opcode_arg(AM_ZP)); cycles += 3; break; case 0xd5: cmp(opcode_arg(AM_ZP_X)); cycles += 4; break; case 0xcd: cmp(opcode_arg(AM_ABS)); cycles += 4; break; case 0xdd: cmp(opcode_arg(AM_ABS_X)); cycles += 4; break; case 0xd9: cmp(opcode_arg(AM_ABS_Y)); cycles += 4; break; case 0xd2: cmp(opcode_arg(AM_IND)); cycles += 5; break; case 0xc1: cmp(opcode_arg(AM_IND_X)); cycles += 6; break; case 0xd1: cmp(opcode_arg(AM_IND_Y)); cycles += 5; break; case 0xe0: cpx(opcode_arg(AM_IMM)); cycles += 2; break; case 0xe4: cpx(opcode_arg(AM_ZP)); cycles += 3; break; case 0xec: cpx(opcode_arg(AM_ABS)); cycles += 4; break; case 0xc0: cpy(opcode_arg(AM_IMM)); cycles += 2; break; case 0xc4: cpy(opcode_arg(AM_ZP)); cycles += 3; break; case 0xcc: cpy(opcode_arg(AM_ABS)); cycles += 4; break; case 0x3a: dec(opcode_arg(AM_ACC)); cycles += 2; break; case 0xc6: dec(opcode_arg(AM_ZP)); cycles += 5; break; case 0xd6: dec(opcode_arg(AM_ZP_X)); cycles += 6; break; case 0xce: dec(opcode_arg(AM_ABS)); cycles += 6; break; case 0xde: dec(opcode_arg(AM_ABS_X)); cycles += 7; break; case 0xca: dex(opcode_arg(AM_ACC)); cycles += 2; break; case 0x88: dey(opcode_arg(AM_ACC)); cycles += 2; break; case 0x49: eor(opcode_arg(AM_IMM)); cycles += 2; break; case 0x45: eor(opcode_arg(AM_ZP)); cycles += 3; break; case 0x55: eor(opcode_arg(AM_ZP_X)); cycles += 4; break; case 0x4d: eor(opcode_arg(AM_ABS)); cycles += 4; break; case 0x5d: eor(opcode_arg(AM_ABS_X)); cycles += 4; break; case 0x59: eor(opcode_arg(AM_ABS_Y)); cycles += 4; break; case 0x52: eor(opcode_arg(AM_IND)); cycles += 5; break; case 0x41: eor(opcode_arg(AM_IND_X)); cycles += 6; break; case 0x51: eor(opcode_arg(AM_IND_Y)); cycles += 5; break; case 0x1a: inc(opcode_arg(AM_ACC)); cycles += 2; break; case 0xe6: inc(opcode_arg(AM_ZP)); cycles += 5; break; case 0xf6: inc(opcode_arg(AM_ZP_X)); cycles += 6; break; case 0xee: inc(opcode_arg(AM_ABS)); cycles += 6; break; case 0xfe: inc(opcode_arg(AM_ABS_X)); cycles += 7; break; case 0xe8: inx(); cycles += 2; break; case 0xc8: iny(opcode_arg(AM_ACC)); cycles += 2; break; case 0x4c: jmp(opcode_arg(AM_ABS)); cycles += 3; break; case 0x6c: jmp(opcode_arg(AM_IND)); cycles += 6; break; case 0x7c: jmp(opcode_arg(AM_ABS_X)); cycles += 6; break; case 0x20: jsr(opcode_arg(AM_ABS)); cycles += 6; break; case 0xa9: lda(opcode_arg(AM_IMM)); cycles += 2; break; case 0xa5: lda(opcode_arg(AM_ZP)); cycles += 3; break; case 0xb5: lda(opcode_arg(AM_ZP_X)); cycles += 4; break; case 0xad: lda(opcode_arg(AM_ABS)); cycles += 4; break; case 0xbd: lda(opcode_arg(AM_ABS_X)); cycles += 4; break; case 0xb9: lda(opcode_arg(AM_ABS_Y)); cycles += 4; break; case 0xb2: lda(opcode_arg(AM_IND)); cycles += 5; break; case 0xa1: lda(opcode_arg(AM_IND_X)); cycles += 6; break; case 0xb1: lda(opcode_arg(AM_IND_Y)); cycles += 5; break; case 0xa2: ldx(opcode_arg(AM_IMM)); cycles += 2; break; case 0xa6: ldx(opcode_arg(AM_ZP)); cycles += 3; break; case 0xb6: ldx(opcode_arg(AM_ZP_Y)); cycles += 4; break; case 0xae: ldx(opcode_arg(AM_ABS)); cycles += 4; break; case 0xbe: ldx(opcode_arg(AM_ABS_Y)); cycles += 4; break; case 0xa0: ldy(opcode_arg(AM_IMM)); cycles += 2; break; case 0xa4: ldy(opcode_arg(AM_ZP)); cycles += 3; break; case 0xb4: ldy(opcode_arg(AM_ZP_X)); cycles += 4; break; case 0xac: ldy(opcode_arg(AM_ABS)); cycles += 4; break; case 0xbc: ldy(opcode_arg(AM_ABS_X)); cycles += 4; break; case 0x4a: lsr(opcode_arg(AM_ACC)); cycles += 2; break; case 0x46: lsr(opcode_arg(AM_ZP)); cycles += 5; break; case 0x56: lsr(opcode_arg(AM_ZP_X)); cycles += 6; break; case 0x4e: lsr(opcode_arg(AM_ABS)); cycles += 6; break; case 0x5e: lsr(opcode_arg(AM_ABS_X)); cycles += 6; break; case 0xea: nop(opcode_arg(AM_ACC)); cycles += 2; break; case 0x09: ora(opcode_arg(AM_IMM)); cycles += 2; break; case 0x05: ora(opcode_arg(AM_ZP)); cycles += 3; break; case 0x15: ora(opcode_arg(AM_ZP_X)); cycles += 4; break; case 0x0d: ora(opcode_arg(AM_ABS)); cycles += 4; break; case 0x1d: ora(opcode_arg(AM_ABS_X)); cycles += 4; break; case 0x19: ora(opcode_arg(AM_ABS_Y)); cycles += 4; break; case 0x12: ora(opcode_arg(AM_IND)); cycles += 5; break; case 0x01: ora(opcode_arg(AM_IND_X)); cycles += 6; break; case 0x11: ora(opcode_arg(AM_IND_Y)); cycles += 5; break; case 0x48: pha(opcode_arg(AM_ACC)); cycles += 3; break; case 0x08: php(opcode_arg(AM_ACC)); cycles += 3; break; case 0xda: phx(opcode_arg(AM_ACC)); cycles += 3; break; case 0x5a: phy(opcode_arg(AM_ACC)); cycles += 3; break; case 0x68: pla(opcode_arg(AM_ACC)); cycles += 4; break; case 0x28: plp(opcode_arg(AM_ACC)); cycles += 4; break; case 0xfa: plx(opcode_arg(AM_ACC)); cycles += 4; break; case 0x7a: ply(opcode_arg(AM_ACC)); cycles += 4; break; case 0x07: rmb(opcode_arg(AM_REL)); cycles += 5; break; case 0x17: rmb(opcode_arg(AM_REL)); cycles += 5; break; case 0x27: rmb(opcode_arg(AM_REL)); cycles += 5; break; case 0x37: rmb(opcode_arg(AM_REL)); cycles += 5; break; case 0x47: rmb(opcode_arg(AM_REL)); cycles += 5; break; case 0x57: rmb(opcode_arg(AM_REL)); cycles += 5; break; case 0x67: rmb(opcode_arg(AM_REL)); cycles += 5; break; case 0x77: rmb(opcode_arg(AM_REL)); cycles += 5; break; case 0x2a: rol(opcode_arg(AM_ACC)); cycles += 2; break; case 0x26: rol(opcode_arg(AM_ZP)); cycles += 5; break; case 0x36: rol(opcode_arg(AM_ZP_X)); cycles += 6; break; case 0x2e: rol(opcode_arg(AM_ABS)); cycles += 6; break; case 0x3e: rol(opcode_arg(AM_ABS_X)); cycles += 6; break; case 0x6a: ror(opcode_arg(AM_ACC)); cycles += 2; break; case 0x66: ror(opcode_arg(AM_ZP)); cycles += 5; break; case 0x76: ror(opcode_arg(AM_ZP_X)); cycles += 6; break; case 0x6e: ror(opcode_arg(AM_ABS)); cycles += 6; break; case 0x7e: ror(opcode_arg(AM_ABS_X)); cycles += 6; break; case 0x40: rti(opcode_arg(AM_ACC)); cycles += 6; break; case 0x60: rts(opcode_arg(AM_ACC)); cycles += 6; break; case 0xe9: sbc(opcode_arg(AM_IMM)); cycles += 2; break; case 0xe5: sbc(opcode_arg(AM_ZP)); cycles += 3; break; case 0xf5: sbc(opcode_arg(AM_ZP_X)); cycles += 4; break; case 0xed: sbc(opcode_arg(AM_ABS)); cycles += 4; break; case 0xfd: sbc(opcode_arg(AM_ABS_X)); cycles += 4; break; case 0xf9: sbc(opcode_arg(AM_ABS_Y)); cycles += 4; break; case 0xf2: sbc(opcode_arg(AM_IND)); cycles += 5; break; case 0xe1: sbc(opcode_arg(AM_IND_X)); cycles += 6; break; case 0xf1: sbc(opcode_arg(AM_IND_Y)); cycles += 5; break; case 0x38: sec(opcode_arg(AM_ACC)); cycles += 2; break; case 0xf8: sed(opcode_arg(AM_ACC)); cycles += 2; break; case 0x78: sei(opcode_arg(AM_ACC)); cycles += 2; break; case 0x87: smb(opcode_arg(AM_REL)); cycles += 5; break; case 0x97: smb(opcode_arg(AM_REL)); cycles += 5; break; case 0xa7: smb(opcode_arg(AM_REL)); cycles += 5; break; case 0xb7: smb(opcode_arg(AM_REL)); cycles += 5; break; case 0xc7: smb(opcode_arg(AM_REL)); cycles += 5; break; case 0xd7: smb(opcode_arg(AM_REL)); cycles += 5; break; case 0xe7: smb(opcode_arg(AM_REL)); cycles += 5; break; case 0xf7: smb(opcode_arg(AM_REL)); cycles += 5; break; case 0x85: sta(opcode_arg(AM_ZP)); cycles += 4; break; case 0x95: sta(opcode_arg(AM_ZP_X)); cycles += 5; break; case 0x8d: sta(opcode_arg(AM_ABS)); cycles += 5; break; case 0x9d: sta(opcode_arg(AM_ABS_X)); cycles += 6; break; case 0x99: sta(opcode_arg(AM_ABS_Y)); cycles += 6; break; case 0x92: sta(opcode_arg(AM_IND)); cycles += 6; break; case 0x81: sta(opcode_arg(AM_IND_X)); cycles += 7; break; case 0x91: sta(opcode_arg(AM_IND_Y)); cycles += 7; break; case 0xdb: stp(opcode_arg(AM_ACC)); cycles += 2; break; case 0x86: stx(opcode_arg(AM_ZP)); cycles += 4; break; case 0x96: stx(opcode_arg(AM_ZP_Y)); cycles += 5; break; case 0x8e: stx(opcode_arg(AM_ABS)); cycles += 5; break; case 0x84: sty(opcode_arg(AM_ZP)); cycles += 4; break; case 0x94: sty(opcode_arg(AM_ZP_X)); cycles += 5; break; case 0x8c: sty(opcode_arg(AM_ABS)); cycles += 5; break; case 0x64: stz(opcode_arg(AM_ZP)); cycles += 4; break; case 0x74: stz(opcode_arg(AM_ZP_X)); cycles += 5; break; case 0x9c: stz(opcode_arg(AM_ABS)); cycles += 5; break; case 0x9e: stz(opcode_arg(AM_ABS_X)); cycles += 6; break; case 0xaa: tax(); cycles += 2; break; case 0xa8: tay(opcode_arg(AM_ACC)); cycles += 2; break; case 0x14: trb(opcode_arg(AM_ZP)); cycles += 5; break; case 0x1c: trb(opcode_arg(AM_ABS)); cycles += 6; break; case 0x04: tsb(opcode_arg(AM_ZP)); cycles += 5; break; case 0x0c: tsb(opcode_arg(AM_ABS)); cycles += 6; break; case 0xba: tsx(opcode_arg(AM_ACC)); cycles += 2; break; case 0x8a: txa(opcode_arg(AM_ACC)); cycles += 2; break; case 0x9a: txs(opcode_arg(AM_ACC)); cycles += 2; break; case 0x98: tya(opcode_arg(AM_ACC)); cycles += 2; break; case 0xcb: wai(opcode_arg(AM_ACC)); cycles += 5; break; case 0x03: unp(opcode_arg(AM_ACC)); cycles += 1; break; case 0x0b: unp(opcode_arg(AM_ACC)); cycles += 1; break; case 0x13: unp(opcode_arg(AM_ACC)); cycles += 1; break; case 0x1b: unp(opcode_arg(AM_ACC)); cycles += 1; break; case 0x23: unp(opcode_arg(AM_ACC)); cycles += 1; break; case 0x2b: unp(opcode_arg(AM_ACC)); cycles += 1; break; case 0x33: unp(opcode_arg(AM_ACC)); cycles += 1; break; case 0x3b: unp(opcode_arg(AM_ACC)); cycles += 1; break; case 0x43: unp(opcode_arg(AM_ACC)); cycles += 1; break; case 0x4b: unp(opcode_arg(AM_ACC)); cycles += 1; break; case 0x53: unp(opcode_arg(AM_ACC)); cycles += 1; break; case 0x5b: unp(opcode_arg(AM_ACC)); cycles += 1; break; case 0x63: unp(opcode_arg(AM_ACC)); cycles += 1; break; case 0x6b: unp(opcode_arg(AM_ACC)); cycles += 1; break; case 0x73: unp(opcode_arg(AM_ACC)); cycles += 1; break; case 0x7b: unp(opcode_arg(AM_ACC)); cycles += 1; break; case 0x83: unp(opcode_arg(AM_ACC)); cycles += 1; break; case 0x8b: unp(opcode_arg(AM_ACC)); cycles += 1; break; case 0x93: unp(opcode_arg(AM_ACC)); cycles += 1; break; case 0x9b: unp(opcode_arg(AM_ACC)); cycles += 1; break; case 0xa3: unp(opcode_arg(AM_ACC)); cycles += 1; break; case 0xab: unp(opcode_arg(AM_ACC)); cycles += 1; break; case 0xb3: unp(opcode_arg(AM_ACC)); cycles += 1; break; case 0xbb: unp(opcode_arg(AM_ACC)); cycles += 1; break; case 0xc3: unp(opcode_arg(AM_ACC)); cycles += 1; break; case 0xd3: unp(opcode_arg(AM_ACC)); cycles += 1; break; case 0xe3: unp(opcode_arg(AM_ACC)); cycles += 1; break; case 0xeb: unp(opcode_arg(AM_ACC)); cycles += 1; break; case 0xf3: unp(opcode_arg(AM_ACC)); cycles += 1; break; case 0xfb: unp(opcode_arg(AM_ACC)); cycles += 1; break; case 0x02: unp(opcode_arg(AM_IMM)); cycles += 2; break; case 0x22: unp(opcode_arg(AM_IMM)); cycles += 2; break; case 0x42: unp(opcode_arg(AM_IMM)); cycles += 2; break; case 0x62: unp(opcode_arg(AM_IMM)); cycles += 2; break; case 0x82: unp(opcode_arg(AM_IMM)); cycles += 2; break; case 0xc2: unp(opcode_arg(AM_IMM)); cycles += 2; break; case 0xe2: unp(opcode_arg(AM_IMM)); cycles += 2; break; case 0x44: unp(opcode_arg(AM_ZP)); cycles += 3; break; case 0x54: unp(opcode_arg(AM_ZP_X)); cycles += 4; break; case 0xd4: unp(opcode_arg(AM_ZP_X)); cycles += 4; break; case 0xf4: unp(opcode_arg(AM_ZP_X)); cycles += 4; break; case 0x5c: unp(opcode_arg(AM_ABS)); cycles += 8; break; case 0xdc: unp(opcode_arg(AM_ABS_X)); cycles += 4; break; case 0xfc: unp(opcode_arg(AM_ABS_X)); cycles += 4; break; default: printf("opcode $%02X not implemented\n", opcode); break; } printf("status: %i%i%i%i%i%i%i%i\n", regs.status.carry, regs.status.zero, regs.status.interrupt_disable, regs.status.decimal_mode, regs.status.brk, regs.status.unused, regs.status.overflow, regs.status.negative); printf("A: $%02X, X: $%02X, Y: $%02X, SP: $%02X, PC: $%02X\n", regs.a, regs.x, regs.y, regs.sp, regs.pc); } } /* https://www.nesdev.org/wiki/CPU_power_up_state */ void cpu_init(void) { regs.a = regs.x = regs.y = 0; regs.pc = 0xFFFC; regs.sp = 0xFD; memset(®s.status, 0, sizeof(regs.status)); regs.status.unused = 1; } int main(void) { cpu_init(); if (sizeof(program) > (0x10000 - 0x8000)) { fprintf(stderr, "program is too big for memory\n"); return 1; } memcpy(memory + 0x8000, program, sizeof(program)); regs.pc = 0x8000; printf("Initial State:\n"); printf("status: %i%i%i%i%i%i%i%i\n", regs.status.carry, regs.status.zero, regs.status.interrupt_disable, regs.status.decimal_mode, regs.status.brk, regs.status.unused, regs.status.overflow, regs.status.negative); printf("A: $%02X, X: $%02X, Y: $%02X, SP: $%02X, PC: $%02X\n", regs.a, regs.x, regs.y, regs.sp, regs.pc); putchar('\n'); interpret(); return 0; }