diff --git a/.gitignore b/.gitignore index 4d0dfab..567a3fd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ a.out +nes *.core *~ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a7f070a --- /dev/null +++ b/Makefile @@ -0,0 +1,8 @@ +nes: + ${CC} -o nes cpu.c rom.c + +test: nes + ./nes ${HOME}/src/other/nes-test-roms/other/nestest.nes + +clean: + rm -f *.o nes diff --git a/cpu.c b/cpu.c index 594c462..862ba67 100644 --- a/cpu.c +++ b/cpu.c @@ -12,6 +12,11 @@ (regs.status.zero = r == 0) #define STATUS_UPDATE_NEGATIVE(r) \ (regs.status.negative = ((r & (1 << 7)) != 0)) +#define STATUS_TO_INT() \ + ((regs.status.carry << 7) | (regs.status.zero << 6) \ + | (regs.status.interrupt_disable << 5) | (regs.status.decimal_mode << 4) \ + | (regs.status.brk << 3) | (regs.status.unused << 2) \ + | (regs.status.overflow << 1) | regs.status.negative) #define MEMORY_MIRROR(addr) \ if (addr < 0x2000) \ @@ -108,10 +113,14 @@ opcode_arg(enum addressing_mode mode) { uint16_t arg, val; - if (mode != AM_ABS && mode != AM_ABS_X && mode != AM_ABS_Y) + if (mode != AM_ABS && mode != AM_ABS_X && mode != AM_ABS_Y) { arg = peek(regs.pc++); - else - arg = peek16(regs.pc), regs.pc += 2; + printf(" %02X\t", arg); + } else { + arg = peek16(regs.pc); + printf(" %02X %02X\t", peek(regs.pc), peek(regs.pc + 1)); + regs.pc += 2; + } switch (mode) { case AM_IMM: @@ -129,12 +138,15 @@ opcode_arg(enum addressing_mode mode) break; case AM_ABS: val = peek16(arg); + printf("$%04X", arg); break; case AM_ABS_X: val = peek16(arg + regs.x); + printf("$%04X", arg); break; case AM_ABS_Y: val = peek16(arg + regs.y); + printf("$%04X", arg); break; case AM_IND_X: val = peek(peek((arg + regs.x) % 256) + peek((arg + regs.x + 1) % 256) * 256); @@ -147,8 +159,6 @@ opcode_arg(enum addressing_mode mode) abort(); } - printf("arg: $%04X $%04X\n", arg, val); - return val; } @@ -157,10 +167,14 @@ opcode_mem(enum addressing_mode mode) { uint16_t arg, val; - if (mode != AM_ABS && mode != AM_ABS_X && mode != AM_ABS_Y) + if (mode != AM_ABS && mode != AM_ABS_X && mode != AM_ABS_Y) { arg = peek(regs.pc++); - else - arg = peek16(regs.pc), regs.pc += 2; + printf(" %02X\t", arg); + } else { + arg = peek16(regs.pc); + printf(" %02X %02X\t", peek(regs.pc), peek(regs.pc + 1)); + regs.pc += 2; + } switch (mode) { case AM_ZP: @@ -301,6 +315,7 @@ brk(void) { /* TODO: push regs.pc and regs.status to stack and load IRQ vector */ regs.status.brk = 1; + putchar('\n'); exit(0); } @@ -542,10 +557,7 @@ php(void) { uint8_t status; - status = (regs.status.carry << 7) | (regs.status.zero << 6) - | (regs.status.interrupt_disable << 5) | (regs.status.decimal_mode << 4) - | (regs.status.brk << 3) | (regs.status.unused << 2) - | (regs.status.overflow << 1) | regs.status.negative; + status = STATUS_TO_INT(); PUSH(status); } @@ -742,678 +754,837 @@ tya(void) static void interpret(void) { - uint8_t opcode; + uint8_t opcode, cycles_; for (;;) { opcode = peek(regs.pc++); + cycles_ = cycles; - printf("opcode: $%02X @ $%04X\n", opcode, regs.pc - 1); + printf("%04X %02X", regs.pc - 1, opcode); switch (opcode) { case 0x69: adc(opcode_arg(AM_IMM)); cycles += 2; + printf("ADC"); break; case 0x65: adc(opcode_arg(AM_ZP)); cycles += 3; + printf("ADC"); break; case 0x75: adc(opcode_arg(AM_ZP_X)); cycles += 4; + printf("ADC"); break; case 0x6d: adc(opcode_arg(AM_ABS)); cycles += 4; + printf("ADC"); break; case 0x7d: adc(opcode_arg(AM_ABS_X)); cycles += 4; + printf("ADC"); break; case 0x79: adc(opcode_arg(AM_ABS_Y)); cycles += 4; + printf("ADC"); break; case 0x72: adc(opcode_arg(AM_IND)); cycles += 5; + printf("ADC"); break; case 0x61: adc(opcode_arg(AM_IND_X)); cycles += 6; + printf("ADC"); break; case 0x71: adc(opcode_arg(AM_IND_Y)); cycles += 5; + printf("ADC"); break; case 0x29: and(opcode_arg(AM_IMM)); cycles += 2; + printf("AND"); break; case 0x25: and(opcode_arg(AM_ZP)); cycles += 3; + printf("AND"); break; case 0x35: and(opcode_arg(AM_ZP_X)); cycles += 4; + printf("AND"); break; case 0x2d: and(opcode_arg(AM_ABS)); cycles += 4; + printf("AND"); break; case 0x3d: and(opcode_arg(AM_ABS_X)); cycles += 4; + printf("AND"); break; case 0x39: and(opcode_arg(AM_ABS_Y)); cycles += 4; + printf("AND"); break; case 0x32: and(opcode_arg(AM_IND)); cycles += 5; + printf("AND"); break; case 0x21: and(opcode_arg(AM_IND_X)); cycles += 6; + printf("AND"); break; case 0x31: and(opcode_arg(AM_IND_Y)); cycles += 5; + printf("AND"); break; case 0x0a: asl_acc(); cycles += 2; + printf("\tASL"); break; case 0x06: asl(opcode_arg(AM_ZP)); cycles += 5; + printf("ASL"); break; case 0x16: asl(opcode_arg(AM_ZP_X)); cycles += 6; + printf("ASL"); break; case 0x0e: asl(opcode_arg(AM_ABS)); cycles += 6; + printf("ASL"); break; case 0x1e: asl(opcode_arg(AM_ABS_X)); cycles += 6; + printf("ASL"); break; case 0x90: bcc(opcode_arg(AM_IMM)); cycles += 2; + printf("BCC"); break; case 0xb0: bcs(opcode_arg(AM_IMM)); cycles += 2; + printf("BCS"); break; case 0xf0: beq(opcode_arg(AM_IMM)); cycles += 2; + printf("BEQ"); break; case 0x89: bit(opcode_arg(AM_IMM)); cycles += 2; + printf("BIT"); break; case 0x24: bit(opcode_arg(AM_ZP)); cycles += 3; + printf("BIT"); break; case 0x34: bit(opcode_arg(AM_ZP_X)); cycles += 4; + printf("BIT"); break; case 0x2c: bit(opcode_arg(AM_ABS)); cycles += 4; + printf("BIT"); break; case 0x3c: bit(opcode_arg(AM_ABS_X)); cycles += 4; + printf("BIT"); break; case 0x30: bmi(opcode_arg(AM_IMM)); cycles += 2; + printf("BMI"); break; case 0xd0: bne(opcode_arg(AM_IMM)); cycles += 2; + printf("BNE"); break; case 0x10: bpl(opcode_arg(AM_IMM)); cycles += 2; + printf("BPL"); break; case 0x00: brk(); cycles += 7; + printf("\tBRK"); break; case 0x50: bvc(opcode_arg(AM_IMM)); cycles += 2; + printf("BVC"); break; case 0x70: bvs(opcode_arg(AM_IMM)); cycles += 2; + printf("BVS"); break; case 0x18: clc(); cycles += 2; + printf("\tCLC"); break; case 0xd8: cld(); cycles += 2; + printf("\tCLD"); break; case 0x58: cli(); cycles += 2; + printf("\tCLI"); break; case 0xb8: clv(); cycles += 2; + printf("\tCLV"); break; case 0xc9: cmp(opcode_arg(AM_IMM)); cycles += 2; + printf("CMP"); break; case 0xc5: cmp(opcode_arg(AM_ZP)); cycles += 3; + printf("CMP"); break; case 0xd5: cmp(opcode_arg(AM_ZP_X)); cycles += 4; + printf("CMP"); break; case 0xcd: cmp(opcode_arg(AM_ABS)); cycles += 4; + printf("CMP"); break; case 0xdd: cmp(opcode_arg(AM_ABS_X)); cycles += 4; + printf("CMP"); break; case 0xd9: cmp(opcode_arg(AM_ABS_Y)); cycles += 4; + printf("CMP"); break; case 0xd2: cmp(opcode_arg(AM_IND)); cycles += 5; + printf("CMP"); break; case 0xc1: cmp(opcode_arg(AM_IND_X)); cycles += 6; + printf("CMP"); break; case 0xd1: cmp(opcode_arg(AM_IND_Y)); cycles += 5; + printf("CMP"); break; case 0xe0: cpx(opcode_arg(AM_IMM)); cycles += 2; + printf("CPX"); break; case 0xe4: cpx(opcode_arg(AM_ZP)); cycles += 3; + printf("CPX"); break; case 0xec: cpx(opcode_arg(AM_ABS)); cycles += 4; + printf("CPX"); break; case 0xc0: cpy(opcode_arg(AM_IMM)); cycles += 2; + printf("CPY"); break; case 0xc4: cpy(opcode_arg(AM_ZP)); cycles += 3; + printf("CPY"); break; case 0xcc: cpy(opcode_arg(AM_ABS)); cycles += 4; + printf("CPY"); break; case 0xc6: dec(opcode_mem(AM_ZP)); cycles += 5; + printf("DEC"); break; case 0xd6: dec(opcode_mem(AM_ZP_X)); cycles += 6; + printf("DEC"); break; case 0xce: dec(opcode_mem(AM_ABS)); cycles += 6; + printf("DEC"); break; case 0xde: dec(opcode_mem(AM_ABS_X)); cycles += 7; + printf("DEC"); break; case 0xca: dex(); cycles += 2; + printf("\tDEX"); break; case 0x88: dey(); cycles += 2; + printf("\tDEY"); break; case 0x49: eor(opcode_arg(AM_IMM)); cycles += 2; + printf("EOR"); break; case 0x45: eor(opcode_arg(AM_ZP)); cycles += 3; + printf("EOR"); break; case 0x55: eor(opcode_arg(AM_ZP_X)); cycles += 4; + printf("EOR"); break; case 0x4d: eor(opcode_arg(AM_ABS)); cycles += 4; + printf("EOR"); break; case 0x5d: eor(opcode_arg(AM_ABS_X)); cycles += 4; + printf("EOR"); break; case 0x59: eor(opcode_arg(AM_ABS_Y)); cycles += 4; + printf("EOR"); break; case 0x52: eor(opcode_arg(AM_IND)); cycles += 5; + printf("EOR"); break; case 0x41: eor(opcode_arg(AM_IND_X)); cycles += 6; + printf("EOR"); break; case 0x51: eor(opcode_arg(AM_IND_Y)); cycles += 5; + printf("EOR"); break; case 0xe6: inc(opcode_arg(AM_ZP)); cycles += 5; + printf("INC"); break; case 0xf6: inc(opcode_arg(AM_ZP_X)); cycles += 6; + printf("INC"); break; case 0xee: inc(opcode_arg(AM_ABS)); cycles += 6; + printf("INC"); break; case 0xfe: inc(opcode_arg(AM_ABS_X)); cycles += 7; + printf("INC"); break; case 0xe8: inx(); cycles += 2; + printf("\tINX"); break; case 0xc8: iny(); cycles += 2; + printf("\tINY"); break; case 0x4c: jmp(opcode_mem(AM_ABS)); cycles += 3; + printf("JMP"); break; case 0x6c: jmp(opcode_arg(AM_IND)); cycles += 6; + printf("JMP"); break; case 0x7c: jmp(opcode_arg(AM_ABS_X)); cycles += 6; + printf("JMP"); break; case 0x20: jsr(opcode_arg(AM_ABS)); cycles += 6; + printf("JSR"); break; case 0xa9: lda(opcode_arg(AM_IMM)); cycles += 2; + printf("LDA"); break; case 0xa5: lda(opcode_arg(AM_ZP)); cycles += 3; + printf("LDA"); break; case 0xb5: lda(opcode_arg(AM_ZP_X)); cycles += 4; + printf("LDA"); break; case 0xad: lda(opcode_arg(AM_ABS)); cycles += 4; + printf("LDA"); break; case 0xbd: lda(opcode_arg(AM_ABS_X)); cycles += 4; + printf("LDA"); break; case 0xb9: lda(opcode_arg(AM_ABS_Y)); cycles += 4; + printf("LDA"); break; case 0xb2: lda(opcode_arg(AM_IND)); cycles += 5; + printf("LDA"); break; case 0xa1: lda(opcode_arg(AM_IND_X)); cycles += 6; + printf("LDA"); break; case 0xb1: lda(opcode_arg(AM_IND_Y)); cycles += 5; + printf("LDA"); break; case 0xa2: ldx(opcode_mem(AM_IMM)); cycles += 2; + printf("LDX"); break; case 0xa6: ldx(opcode_arg(AM_ZP)); cycles += 3; + printf("LDX"); break; case 0xb6: ldx(opcode_arg(AM_ZP_Y)); cycles += 4; + printf("LDX"); break; case 0xae: ldx(opcode_arg(AM_ABS)); cycles += 4; + printf("LDX"); break; case 0xbe: ldx(opcode_arg(AM_ABS_Y)); cycles += 4; + printf("LDX"); break; case 0xa0: ldy(opcode_arg(AM_IMM)); cycles += 2; + printf("LDY"); break; case 0xa4: ldy(opcode_arg(AM_ZP)); cycles += 3; + printf("LDY"); break; case 0xb4: ldy(opcode_arg(AM_ZP_X)); cycles += 4; + printf("LDY"); break; case 0xac: ldy(opcode_arg(AM_ABS)); cycles += 4; + printf("LDY"); break; case 0xbc: ldy(opcode_arg(AM_ABS_X)); cycles += 4; + printf("LDY"); break; case 0x4a: lsr_acc(); cycles += 2; + printf("\tLSR"); break; case 0x46: lsr(opcode_arg(AM_ZP)); cycles += 5; + printf("LSR"); break; case 0x56: lsr(opcode_arg(AM_ZP_X)); cycles += 6; + printf("LSR"); break; case 0x4e: lsr(opcode_arg(AM_ABS)); cycles += 6; + printf("LSR"); break; case 0x5e: lsr(opcode_arg(AM_ABS_X)); cycles += 6; + printf("LSR"); break; case 0xea: nop(); cycles += 2; + printf("\tNOP"); break; case 0x09: ora(opcode_arg(AM_IMM)); cycles += 2; + printf("ORA"); break; case 0x05: ora(opcode_arg(AM_ZP)); cycles += 3; + printf("ORA"); break; case 0x15: ora(opcode_arg(AM_ZP_X)); cycles += 4; + printf("ORA"); break; case 0x0d: ora(opcode_arg(AM_ABS)); cycles += 4; + printf("ORA"); break; case 0x1d: ora(opcode_arg(AM_ABS_X)); cycles += 4; + printf("ORA"); break; case 0x19: ora(opcode_arg(AM_ABS_Y)); cycles += 4; + printf("ORA"); break; case 0x12: ora(opcode_arg(AM_IND)); cycles += 5; + printf("ORA"); break; case 0x01: ora(opcode_arg(AM_IND_X)); cycles += 6; + printf("ORA"); break; case 0x11: ora(opcode_arg(AM_IND_Y)); cycles += 5; + printf("ORA"); break; case 0x48: pha(); cycles += 3; + printf("\tPHA"); break; case 0x08: php(); cycles += 3; + printf("\tPHP"); break; case 0x68: pla(); cycles += 4; + printf("\tPLA"); break; case 0x28: plp(); cycles += 4; + printf("\tPLP"); break; case 0x2a: rol_acc(); cycles += 2; + printf("\tROL"); break; case 0x26: rol(opcode_arg(AM_ZP)); cycles += 5; + printf("ROL"); break; case 0x36: rol(opcode_arg(AM_ZP_X)); cycles += 6; + printf("ROL"); break; case 0x2e: rol(opcode_arg(AM_ABS)); cycles += 6; + printf("ROL"); break; case 0x3e: rol(opcode_arg(AM_ABS_X)); cycles += 6; + printf("ROL"); break; case 0x6a: ror_acc(); cycles += 2; + printf("\tROR"); break; case 0x66: ror(opcode_arg(AM_ZP)); cycles += 5; + printf("ROR"); break; case 0x76: ror(opcode_arg(AM_ZP_X)); cycles += 6; + printf("ROR"); break; case 0x6e: ror(opcode_arg(AM_ABS)); cycles += 6; + printf("ROR"); break; case 0x7e: ror(opcode_arg(AM_ABS_X)); cycles += 6; + printf("ROR"); break; case 0x40: rti(); cycles += 6; + printf("\tRTI"); break; case 0x60: rts(); cycles += 6; + printf("\tRTS"); break; case 0xe9: sbc(opcode_arg(AM_IMM)); cycles += 2; + printf("SBC"); break; case 0xe5: sbc(opcode_arg(AM_ZP)); cycles += 3; + printf("SBC"); break; case 0xf5: sbc(opcode_arg(AM_ZP_X)); cycles += 4; + printf("SBC"); break; case 0xed: sbc(opcode_arg(AM_ABS)); cycles += 4; + printf("SBC"); break; case 0xfd: sbc(opcode_arg(AM_ABS_X)); cycles += 4; + printf("SBC"); break; case 0xf9: sbc(opcode_arg(AM_ABS_Y)); cycles += 4; + printf("SBC"); break; case 0xf2: sbc(opcode_arg(AM_IND)); cycles += 5; + printf("SBC"); break; case 0xe1: sbc(opcode_arg(AM_IND_X)); cycles += 6; + printf("SBC"); break; case 0xf1: sbc(opcode_arg(AM_IND_Y)); cycles += 5; + printf("SBC"); break; case 0x38: sec(); cycles += 2; + printf("\tSEC"); break; case 0xf8: sed(); cycles += 2; + printf("\tSED"); break; case 0x78: sei(); cycles += 2; + printf("\tSEI"); break; case 0x85: sta(opcode_mem(AM_ZP)); cycles += 4; + printf("STA"); break; case 0x95: sta(opcode_mem(AM_ZP_X)); cycles += 5; + printf("STA"); break; case 0x8d: sta(opcode_mem(AM_ABS)); cycles += 5; + printf("STA"); break; case 0x9d: sta(opcode_mem(AM_ABS_X)); cycles += 6; + printf("STA"); break; case 0x99: sta(opcode_mem(AM_ABS_Y)); cycles += 6; + printf("STA"); break; case 0x92: sta(opcode_mem(AM_IND)); cycles += 6; + printf("STA"); break; case 0x81: sta(opcode_mem(AM_IND_X)); cycles += 7; + printf("STA"); break; case 0x91: sta(opcode_mem(AM_IND_Y)); cycles += 7; + printf("STA"); break; case 0x86: stx(opcode_mem(AM_ZP)); cycles += 4; + printf("STX"); break; case 0x96: stx(opcode_mem(AM_ZP_Y)); cycles += 5; + printf("STX"); break; case 0x8e: stx(opcode_mem(AM_ABS)); cycles += 5; + printf("STX"); break; case 0x84: sty(opcode_mem(AM_ZP)); cycles += 4; + printf("STY"); break; case 0x94: sty(opcode_mem(AM_ZP_X)); cycles += 5; + printf("STY"); break; case 0x8c: sty(opcode_mem(AM_ABS)); cycles += 5; + printf("STY"); break; case 0xaa: tax(); cycles += 2; + printf("\tTAX"); break; case 0xa8: tay(); cycles += 2; + printf("\tTAY"); break; case 0xba: tsx(); cycles += 2; + printf("\tTSX"); break; case 0x8a: txa(); cycles += 2; + printf("\tTXA"); break; case 0x9a: txs(); cycles += 2; + printf("\tTXS"); break; case 0x98: tya(); cycles += 2; + printf("\tTYA"); 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: $%04X\n", - regs.a, regs.x, regs.y, regs.sp, regs.pc); + printf("%50c:%02X X:%02X Y:%02X P:%02X SP:%02X CYC:%d\n", 'A', + regs.a, regs.x, regs.y, STATUS_TO_INT(), regs.sp, cycles_); } } @@ -1470,16 +1641,6 @@ main(int argc, char *argv[]) memwrite16(0xFFFC, 0xC000); regs.pc = 0xC000; - 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(); free_rom(&rom);