diff options
Diffstat (limited to 'src/libxineadec/nosefart/nes6502.c')
-rw-r--r-- | src/libxineadec/nosefart/nes6502.c | 2564 |
1 files changed, 0 insertions, 2564 deletions
diff --git a/src/libxineadec/nosefart/nes6502.c b/src/libxineadec/nosefart/nes6502.c deleted file mode 100644 index d84bae912..000000000 --- a/src/libxineadec/nosefart/nes6502.c +++ /dev/null @@ -1,2564 +0,0 @@ -/* -** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) -** -** -** This program is free software; you can redistribute it and/or -** modify it under the terms of version 2 of the GNU Library General -** Public License as published by the Free Software Foundation. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -** Library General Public License for more details. To obtain a -** copy of the GNU Library General Public License, write to the Free -** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -** -** Any permitted reproduction of these routines, in whole or in part, -** must bear this legend. -** -** -** nes6502.c -** -** NES custom 6502 (2A03) CPU implementation -** $Id: nes6502.c,v 1.2 2003/01/09 19:50:03 jkeil Exp $ -*/ - - -#include "types.h" -#include "nes6502.h" -#include "dis6502.h" -#include <stdio.h> - - -#define ADD_CYCLES(x) instruction_cycles += (x) -#define INC_CYCLES() instruction_cycles++ -//#define ADD_CYCLES(x) remaining_cycles -= (x) -//#define INC_CYCLES() remaining_cycles-- - -/* -** Check to see if an index reg addition overflowed to next page -*/ -#define CHECK_INDEX_OVERFLOW(addr, reg) \ -{ \ - if ((uint8) (addr) < (reg)) \ - INC_CYCLES(); \ -} - -/* -** Addressing mode macros -*/ - -#define NO_READ(value) /* empty */ - -#define IMMEDIATE_BYTE(value) \ -{ \ - value = bank_readbyte(PC++); \ -} - - -#define ABSOLUTE_ADDR(address) \ -{ \ - address = bank_readaddress(PC); \ - PC += 2; \ -} - -#define ABSOLUTE(address, value) \ -{ \ - ABSOLUTE_ADDR(address); \ - value = mem_read(address); \ -} - -#define ABSOLUTE_BYTE(value) \ -{ \ - ABSOLUTE(temp, value); \ -} - -#define ABS_IND_X_ADDR(address) \ -{ \ - address = (bank_readaddress(PC) + X) & 0xFFFF; \ - PC += 2; \ - CHECK_INDEX_OVERFLOW(address, X); \ -} - -#define ABS_IND_X(address, value) \ -{ \ - ABS_IND_X_ADDR(address); \ - value = mem_read(address); \ -} - -#define ABS_IND_X_BYTE(value) \ -{ \ - ABS_IND_X(temp, value); \ -} - -#define ABS_IND_Y_ADDR(address) \ -{ \ - address = (bank_readaddress(PC) + Y) & 0xFFFF; \ - PC += 2; \ - CHECK_INDEX_OVERFLOW(address, Y); \ -} - -#define ABS_IND_Y(address, value) \ -{ \ - ABS_IND_Y_ADDR(address); \ - value = mem_read(address); \ -} - -#define ABS_IND_Y_BYTE(value) \ -{ \ - ABS_IND_Y(temp, value); \ -} - -#define ZERO_PAGE_ADDR(address) \ -{ \ - IMMEDIATE_BYTE(address); \ -} - -#define ZERO_PAGE(address, value) \ -{ \ - ZERO_PAGE_ADDR(address); \ - value = ZP_READ(address); \ -} - -#define ZERO_PAGE_BYTE(value) \ -{ \ - ZERO_PAGE(btemp, value); \ -} - -/* Zero-page indexed Y doesn't really exist, just for LDX / STX */ -#define ZP_IND_X_ADDR(address) \ -{ \ - address = bank_readbyte(PC++) + X; \ -} - -#define ZP_IND_X(bAddr, value) \ -{ \ - ZP_IND_X_ADDR(bAddr); \ - value = ZP_READ(bAddr); \ -} - -#define ZP_IND_X_BYTE(value) \ -{ \ - ZP_IND_X(btemp, value); \ -} - -#define ZP_IND_Y_ADDR(address) \ -{ \ - address = bank_readbyte(PC++) + Y; \ -} - -#define ZP_IND_Y(address, value) \ -{ \ - ZP_IND_Y_ADDR(address); \ - value = ZP_READ(address); \ -} - -#define ZP_IND_Y_BYTE(value) \ -{ \ - ZP_IND_Y(btemp, value); \ -} - -/* -** For conditional jump relative instructions -** (BCC, BCS, BEQ, BMI, BNE, BPL, BVC, BVS) -*/ -#define RELATIVE_JUMP(cond) \ -{ \ - if (cond) \ - { \ - IMMEDIATE_BYTE(btemp); \ - if (((int8) btemp + (uint8) PC) & 0xFF00) \ - ADD_CYCLES(4); \ - else \ - ADD_CYCLES(3); \ - PC += ((int8) btemp); \ - } \ - else \ - { \ - PC++; \ - ADD_CYCLES(2); \ - } \ -} - -/* -** This is actually indexed indirect, but I call it -** indirect X to avoid confusion -*/ -#define INDIR_X_ADDR(address) \ -{ \ - btemp = bank_readbyte(PC++) + X; \ - address = zp_address(btemp); \ -} - -#define INDIR_X(address, value) \ -{ \ - INDIR_X_ADDR(address); \ - value = mem_read(address); \ -} - -#define INDIR_X_BYTE(value) \ -{ \ - INDIR_X(temp, value); \ -} - -/* -** This is actually indirect indexed, but I call it -** indirect y to avoid confusion -*/ -#define INDIR_Y_ADDR(address) \ -{ \ - IMMEDIATE_BYTE(btemp); \ - address = (zp_address(btemp) + Y) & 0xFFFF; \ - /* ???? */ \ - CHECK_INDEX_OVERFLOW(address, Y); \ -} - -#define INDIR_Y(address, value) \ -{ \ - INDIR_Y_ADDR(address); \ - value = mem_read(address); \ -} - -#define INDIR_Y_BYTE(value) \ -{ \ - /*IMMEDIATE_BYTE(btemp); \ - temp = zp_address(btemp) + Y; \ - CHECK_INDEX_OVERFLOW(temp, Y); \ - value = mem_read(temp);*/ \ - INDIR_Y(temp, value); \ -} - - -#define JUMP(address) PC = bank_readaddress((address)) - -/* -** Interrupt macros -*/ -#define NMI() \ -{ \ - PUSH(PC >> 8); \ - PUSH(PC & 0xFF); \ - CLEAR_FLAG(B_FLAG); \ - PUSH(P); \ - SET_FLAG(I_FLAG); \ - JUMP(NMI_VECTOR); \ - int_pending &= ~NMI_MASK; \ - ADD_CYCLES(INT_CYCLES); \ -} - -#define IRQ() \ -{ \ - PUSH(PC >> 8); \ - PUSH(PC & 0xFF); \ - CLEAR_FLAG(B_FLAG); \ - PUSH(P); \ - SET_FLAG(I_FLAG); \ - JUMP(IRQ_VECTOR); \ - int_pending &= ~IRQ_MASK; \ - ADD_CYCLES(INT_CYCLES); \ -} - -/* -** Instruction macros -*/ - -/* Warning! NES CPU has no decimal mode, so by default this does no BCD! */ -#ifdef NES6502_DECIMAL -#define ADC(cycles, read_func) \ -{ \ - read_func(data); \ - if (P & D_FLAG) \ - { \ - temp = (A & 0x0F) + (data & 0x0F) + (P & C_FLAG); \ - if (temp >= 10) \ - temp = (temp - 10) | 0x10; \ - temp += (A & 0xF0) + (data & 0xF0); \ - TEST_AND_FLAG(0 == ((A + data + (P & C_FLAG)) & 0xFF), Z_FLAG); \ - TEST_AND_FLAG(temp & 0x80, N_FLAG); \ - TEST_AND_FLAG(((~(A ^ data)) & (A ^ temp) & 0x80), V_FLAG); \ - if (temp > 0x9F) \ - temp += 0x60; \ - TEST_AND_FLAG(temp > 0xFF, C_FLAG); \ - A = (uint8) temp; \ - } \ - else \ - { \ - temp = A + data + (P & C_FLAG); \ - /* Set C on carry */ \ - TEST_AND_FLAG(temp > 0xFF, C_FLAG); \ - /* Set V on overflow */ \ - TEST_AND_FLAG(((~(A ^ data)) & (A ^ temp) & 0x80), V_FLAG); \ - A = (uint8) temp; \ - SET_NZ_FLAGS(A); \ - }\ - ADD_CYCLES(cycles); \ -} -#else -#define ADC(cycles, read_func) \ -{ \ - read_func(data); \ - temp = A + data + (P & C_FLAG); \ - /* Set C on carry */ \ - TEST_AND_FLAG(temp > 0xFF, C_FLAG); \ - /* Set V on overflow */ \ - TEST_AND_FLAG(((~(A ^ data)) & (A ^ temp) & 0x80), V_FLAG); \ - A = (uint8) temp; \ - SET_NZ_FLAGS(A); \ - ADD_CYCLES(cycles); \ -} -#endif /* NES6502_DECIMAL */ - -/* undocumented */ -#define ANC(cycles, read_func) \ -{ \ - read_func(data); \ - A &= data; \ - SET_NZ_FLAGS(A); \ - TEST_AND_FLAG(P & N_FLAG, C_FLAG); \ - ADD_CYCLES(cycles); \ -} - -#define AND(cycles, read_func) \ -{ \ - read_func(data); \ - A &= data; \ - SET_NZ_FLAGS(A); \ - ADD_CYCLES(cycles); \ -} - -/* undocumented */ -#define ANE(cycles, read_func) \ -{ \ - read_func(data); \ - A = (A | 0xEE) & X & data; \ - SET_NZ_FLAGS(A); \ - ADD_CYCLES(cycles); \ -} - -/* undocumented */ -#ifdef NES6502_DECIMAL -#define ARR(cycles, read_func) \ -{ \ - read_func(data); \ - data &= A; \ - if (P & D_FLAG) \ - { \ - temp = (data >> 1) | ((P & C_FLAG) << 7); \ - SET_NZ_FLAGS(temp); \ - TEST_AND_FLAG((temp ^ data) & 0x40, V_FLAG); \ - if (((data & 0x0F) + (data & 0x01)) > 5) \ - temp = (temp & 0xF0) | ((temp + 0x6) & 0x0F); \ - if (((data & 0xF0) + (data & 0x10)) > 0x50) \ - { \ - temp = (temp & 0x0F) | ((temp + 0x60) & 0xF0); \ - SET_FLAG(C_FLAG); \ - } \ - else \ - CLEAR_FLAG(C_FLAG); \ - A = (uint8) temp; \ - } \ - else \ - { \ - A = (data >> 1) | ((P & C_FLAG) << 7); \ - SET_NZ_FLAGS(A); \ - TEST_AND_FLAG(A & 0x40, C_FLAG); \ - TEST_AND_FLAG(((A >> 6) ^ (A >> 5)) & 1, V_FLAG); \ - }\ - ADD_CYCLES(cycles); \ -} -#else -#define ARR(cycles, read_func) \ -{ \ - read_func(data); \ - data &= A; \ - A = (data >> 1) | ((P & C_FLAG) << 7); \ - SET_NZ_FLAGS(A); \ - TEST_AND_FLAG(A & 0x40, C_FLAG); \ - TEST_AND_FLAG((A >> 6) ^ (A >> 5), V_FLAG); \ - ADD_CYCLES(cycles); \ -} -#endif /* NES6502_DECIMAL */ - -#define ASL(cycles, read_func, write_func, addr) \ -{ \ - read_func(addr, data); \ - TEST_AND_FLAG(data & 0x80, C_FLAG); \ - data <<= 1; \ - write_func(addr, data); \ - SET_NZ_FLAGS(data); \ - ADD_CYCLES(cycles); \ -} - -#define ASL_A() \ -{ \ - TEST_AND_FLAG(A & 0x80, C_FLAG); \ - A <<= 1; \ - SET_NZ_FLAGS(A); \ - ADD_CYCLES(2); \ -} - -/* undocumented */ -#define ASR(cycles, read_func) \ -{ \ - read_func(data); \ - data &= A; \ - TEST_AND_FLAG(data & 0x01, C_FLAG); \ - A = data >> 1; \ - SET_NZ_FLAGS(A); \ - ADD_CYCLES(cycles); \ -} - -#define BCC() \ -{ \ - RELATIVE_JUMP((IS_FLAG_CLEAR(C_FLAG))); \ -} - -#define BCS() \ -{ \ - RELATIVE_JUMP((IS_FLAG_SET(C_FLAG))); \ -} - -#define BEQ() \ -{ \ - RELATIVE_JUMP((IS_FLAG_SET(Z_FLAG))); \ -} - -#define BIT(cycles, read_func) \ -{ \ - read_func(data); \ - TEST_AND_FLAG(0 == (data & A), Z_FLAG);\ - CLEAR_FLAG(N_FLAG | V_FLAG); \ - /* move bit 7/6 of data into N/V flags */ \ - SET_FLAG(data & (N_FLAG | V_FLAG)); \ - ADD_CYCLES(cycles); \ -} - -#define BMI() \ -{ \ - RELATIVE_JUMP((IS_FLAG_SET(N_FLAG))); \ -} - -#define BNE() \ -{ \ - RELATIVE_JUMP((IS_FLAG_CLEAR(Z_FLAG))); \ -} - -#define BPL() \ -{ \ - RELATIVE_JUMP((IS_FLAG_CLEAR(N_FLAG))); \ -} - -/* Software interrupt type thang */ -#define BRK() \ -{ \ - PC++; \ - PUSH(PC >> 8); \ - PUSH(PC & 0xFF); \ - SET_FLAG(B_FLAG); \ - PUSH(P); \ - SET_FLAG(I_FLAG); \ - JUMP(IRQ_VECTOR); \ - ADD_CYCLES(7); \ -} - -#define BVC() \ -{ \ - RELATIVE_JUMP((IS_FLAG_CLEAR(V_FLAG))); \ -} - -#define BVS() \ -{ \ - RELATIVE_JUMP((IS_FLAG_SET(V_FLAG))); \ -} - -#define CLC() \ -{ \ - CLEAR_FLAG(C_FLAG); \ - ADD_CYCLES(2); \ -} - -#define CLD() \ -{ \ - CLEAR_FLAG(D_FLAG); \ - ADD_CYCLES(2); \ -} - -#define CLI() \ -{ \ - CLEAR_FLAG(I_FLAG); \ - ADD_CYCLES(2); \ -} - -#define CLV() \ -{ \ - CLEAR_FLAG(V_FLAG); \ - ADD_CYCLES(2); \ -} - -/* TODO: ick! */ -#define _COMPARE(reg, value) \ -{ \ - temp = (reg) - (value); \ - /* C is clear when data > A */ \ - TEST_AND_FLAG(0 == (temp & 0x8000), C_FLAG); \ - SET_NZ_FLAGS((uint8) temp); /* handles Z flag */ \ -} - -#define CMP(cycles, read_func) \ -{ \ - read_func(data); \ - _COMPARE(A, data); \ - ADD_CYCLES(cycles); \ -} - -#define CPX(cycles, read_func) \ -{ \ - read_func(data); \ - _COMPARE(X, data); \ - ADD_CYCLES(cycles); \ -} - -#define CPY(cycles, read_func) \ -{ \ - read_func(data); \ - _COMPARE(Y, data); \ - ADD_CYCLES(cycles); \ -} - -/* undocumented */ -#define DCP(cycles, read_func, write_func, addr) \ -{ \ - read_func(addr, data); \ - data--; \ - write_func(addr, data); \ - CMP(cycles, NO_READ); \ -} - -#define DEC(cycles, read_func, write_func, addr) \ -{ \ - read_func(addr, data); \ - data--; \ - write_func(addr, data); \ - SET_NZ_FLAGS(data); \ - ADD_CYCLES(cycles); \ -} - -#define DEX() \ -{ \ - X--; \ - SET_NZ_FLAGS(X); \ - ADD_CYCLES(2); \ -} - -#define DEY() \ -{ \ - Y--; \ - SET_NZ_FLAGS(Y); \ - ADD_CYCLES(2); \ -} - -/* undocumented (double-NOP) */ -#define DOP(cycles) \ -{ \ - PC++; \ - ADD_CYCLES(cycles); \ -} - -#define EOR(cycles, read_func) \ -{ \ - read_func(data); \ - A ^= data; \ - SET_NZ_FLAGS(A); \ - ADD_CYCLES(cycles); \ -} - -#define INC(cycles, read_func, write_func, addr) \ -{ \ - read_func(addr, data); \ - data++; \ - write_func(addr, data); \ - SET_NZ_FLAGS(data); \ - ADD_CYCLES(cycles); \ -} - -#define INX() \ -{ \ - X++; \ - SET_NZ_FLAGS(X); \ - ADD_CYCLES(2); \ -} - -#define INY() \ -{ \ - Y++; \ - SET_NZ_FLAGS(Y); \ - ADD_CYCLES(2); \ -} - -/* undocumented */ -#define ISB(cycles, read_func, write_func, addr) \ -{ \ - read_func(addr, data); \ - data++; \ - write_func(addr, data); \ - SBC(cycles, NO_READ); \ -} - -#ifdef NES6502_TESTOPS -#define JAM() \ -{ \ - cpu_Jam(); \ -} -#elif defined(NSF_PLAYER) -#define JAM() \ -{ \ -} -#else -#define JAM() \ -{ \ - char jambuf[20]; \ - sprintf(jambuf, "JAM: PC=$%04X", PC); \ - ASSERT_MSG(jambuf); \ - ADD_CYCLES(2); \ -} -#endif /* NES6502_TESTOPS */ - -#define JMP_INDIRECT() \ -{ \ - temp = bank_readaddress(PC); \ - /* bug in crossing page boundaries */ \ - if (0xFF == (uint8) temp) \ - PC = (bank_readbyte(temp & ~0xFF) << 8) | bank_readbyte(temp); \ - else \ - JUMP(temp); \ - ADD_CYCLES(5); \ -} - -#define JMP_ABSOLUTE() \ -{ \ - JUMP(PC); \ - ADD_CYCLES(3); \ -} - -#define JSR() \ -{ \ - PC++; \ - PUSH(PC >> 8); \ - PUSH(PC & 0xFF); \ - JUMP(PC - 1); \ - ADD_CYCLES(6); \ -} - -/* undocumented */ -#define LAS(cycles, read_func) \ -{ \ - read_func(data); \ - A = X = S = (S & data); \ - SET_NZ_FLAGS(A); \ - ADD_CYCLES(cycles); \ -} - -/* undocumented */ -#define LAX(cycles, read_func) \ -{ \ - read_func(A); \ - X = A; \ - SET_NZ_FLAGS(A); \ - ADD_CYCLES(cycles); \ -} - -#define LDA(cycles, read_func) \ -{ \ - read_func(A); \ - SET_NZ_FLAGS(A); \ - ADD_CYCLES(cycles); \ -} - -#define LDX(cycles, read_func) \ -{ \ - read_func(X); \ - SET_NZ_FLAGS(X);\ - ADD_CYCLES(cycles); \ -} - -#define LDY(cycles, read_func) \ -{ \ - read_func(Y); \ - SET_NZ_FLAGS(Y);\ - ADD_CYCLES(cycles); \ -} - -#define LSR(cycles, read_func, write_func, addr) \ -{ \ - read_func(addr, data); \ - TEST_AND_FLAG(data & 0x01, C_FLAG); \ - data >>= 1; \ - write_func(addr, data); \ - SET_NZ_FLAGS(data); \ - ADD_CYCLES(cycles); \ -} - -#define LSR_A() \ -{ \ - TEST_AND_FLAG(A & 0x01, C_FLAG); \ - A >>= 1; \ - SET_NZ_FLAGS(A); \ - ADD_CYCLES(2); \ -} - -/* undocumented */ -#define LXA(cycles, read_func) \ -{ \ - read_func(data); \ - A = X = ((A | 0xEE) & data); \ - SET_NZ_FLAGS(A); \ - ADD_CYCLES(cycles); \ -} - -#define NOP() \ -{ \ - ADD_CYCLES(2); \ -} - -#define ORA(cycles, read_func) \ -{ \ - read_func(data); \ - A |= data; \ - SET_NZ_FLAGS(A);\ - ADD_CYCLES(cycles); \ -} - -#define PHA() \ -{ \ - PUSH(A); \ - ADD_CYCLES(3); \ -} - -#define PHP() \ -{ \ - /* B flag is pushed on stack as well */ \ - PUSH((P | B_FLAG)); \ - ADD_CYCLES(3); \ -} - -#define PLA() \ -{ \ - A = PULL(); \ - SET_NZ_FLAGS(A); \ - ADD_CYCLES(4); \ -} - -#define PLP() \ -{ \ - P = PULL(); \ - SET_FLAG(R_FLAG); /* ensure reserved flag is set */ \ - ADD_CYCLES(4); \ -} - -/* undocumented */ -#define RLA(cycles, read_func, write_func, addr) \ -{ \ - read_func(addr, data); \ - if (P & C_FLAG) \ - { \ - TEST_AND_FLAG(data & 0x80, C_FLAG); \ - data = (data << 1) | 1; \ - } \ - else \ - { \ - TEST_AND_FLAG(data & 0x80, C_FLAG); \ - data <<= 1; \ - } \ - write_func(addr, data); \ - A &= data; \ - SET_NZ_FLAGS(A); \ - ADD_CYCLES(cycles); \ -} - -/* 9-bit rotation (carry flag used for rollover) */ -#define ROL(cycles, read_func, write_func, addr) \ -{ \ - read_func(addr, data); \ - if (P & C_FLAG) \ - { \ - TEST_AND_FLAG(data & 0x80, C_FLAG); \ - data = (data << 1) | 1; \ - } \ - else \ - { \ - TEST_AND_FLAG(data & 0x80, C_FLAG); \ - data <<= 1; \ - } \ - write_func(addr, data); \ - SET_NZ_FLAGS(data); \ - ADD_CYCLES(cycles); \ -} - -#define ROL_A() \ -{ \ - if (P & C_FLAG) \ - { \ - TEST_AND_FLAG(A & 0x80, C_FLAG); \ - A = (A << 1) | 1; \ - } \ - else \ - { \ - TEST_AND_FLAG(A & 0x80, C_FLAG); \ - A <<= 1; \ - } \ - SET_NZ_FLAGS(A); \ - ADD_CYCLES(2); \ -} - -#define ROR(cycles, read_func, write_func, addr) \ -{ \ - read_func(addr, data); \ - if (P & C_FLAG) \ - { \ - TEST_AND_FLAG(data & 1, C_FLAG); \ - data = (data >> 1) | 0x80; \ - } \ - else \ - { \ - TEST_AND_FLAG(data & 1, C_FLAG); \ - data >>= 1; \ - } \ - write_func(addr, data); \ - SET_NZ_FLAGS(data); \ - ADD_CYCLES(cycles); \ -} - -#define ROR_A() \ -{ \ - if (P & C_FLAG) \ - { \ - TEST_AND_FLAG(A & 1, C_FLAG); \ - A = (A >> 1) | 0x80; \ - } \ - else \ - { \ - TEST_AND_FLAG(A & 1, C_FLAG); \ - A >>= 1; \ - } \ - SET_NZ_FLAGS(A); \ - ADD_CYCLES(2); \ -} - -/* undocumented */ -#define RRA(cycles, read_func, write_func, addr) \ -{ \ - read_func(addr, data); \ - if (P & C_FLAG) \ - { \ - TEST_AND_FLAG(data & 1, C_FLAG); \ - data = (data >> 1) | 0x80; \ - } \ - else \ - { \ - TEST_AND_FLAG(data & 1, C_FLAG); \ - data >>= 1; \ - } \ - write_func(addr, data); \ - ADC(cycles, NO_READ); \ -} - -#define RTI() \ -{ \ - P = PULL(); \ - SET_FLAG(R_FLAG); /* ensure reserved flag is set */ \ - PC = PULL(); \ - PC |= PULL() << 8; \ - ADD_CYCLES(6); \ -} - -#define RTS() \ -{ \ - PC = PULL(); \ - PC = (PC | (PULL() << 8)) + 1; \ - ADD_CYCLES(6); \ -} - -/* undocumented */ -#define SAX(cycles, read_func, write_func, addr) \ -{ \ - read_func(addr); \ - data = A & X; \ - write_func(addr, data); \ - ADD_CYCLES(cycles); \ -} - -/* Warning! NES CPU has no decimal mode, so by default this does no BCD! */ -#ifdef NES6502_DECIMAL -#define SBC(cycles, read_func) \ -{ \ - read_func(data); \ - /* NOT(C) is considered borrow */ \ - temp = A - data - ((P & C_FLAG) ^ C_FLAG); \ - if (P & D_FLAG) \ - { \ - uint8 al, ah; \ - al = (A & 0x0F) - (data & 0x0F) - ((P & C_FLAG) ^ C_FLAG); \ - ah = (A >> 4) - (data >> 4); \ - if (al & 0x10) \ - { \ - al -= 6; \ - ah--; \ - } \ - if (ah & 0x10) \ - ah -= 6; \ - TEST_AND_FLAG(temp < 0x100, C_FLAG); \ - TEST_AND_FLAG(((A ^ temp) & 0x80) && ((A ^ data) & 0x80), V_FLAG); \ - SET_NZ_FLAGS(temp & 0xFF); \ - A = (ah << 4) | (al & 0x0F); \ - } \ - else \ - { \ - TEST_AND_FLAG(((A ^ temp) & 0x80) && ((A ^ data) & 0x80), V_FLAG); \ - TEST_AND_FLAG(temp < 0x100, C_FLAG); \ - A = (uint8) temp; \ - SET_NZ_FLAGS(A & 0xFF); \ - } \ - ADD_CYCLES(cycles); \ -} -#else -#define SBC(cycles, read_func) \ -{ \ - read_func(data); \ - temp = A - data - ((P & C_FLAG) ^ C_FLAG); \ - TEST_AND_FLAG(((A ^ data) & (A ^ temp) & 0x80), V_FLAG); \ - TEST_AND_FLAG(temp < 0x100, C_FLAG); \ - A = (uint8) temp; \ - SET_NZ_FLAGS(A); \ - ADD_CYCLES(cycles); \ -} -#endif /* NES6502_DECIMAL */ - -/* undocumented */ -#define SBX(cycles, read_func) \ -{ \ - read_func(data); \ - temp = (A & X) - data; \ - TEST_AND_FLAG(temp < 0x100, C_FLAG); \ - X = temp & 0xFF; \ - SET_NZ_FLAGS(X); \ - ADD_CYCLES(cycles); \ -} - -#define SEC() \ -{ \ - SET_FLAG(C_FLAG); \ - ADD_CYCLES(2); \ -} - -#define SED() \ -{ \ - SET_FLAG(D_FLAG); \ - ADD_CYCLES(2); \ -} - -#define SEI() \ -{ \ - SET_FLAG(I_FLAG); \ - ADD_CYCLES(2); \ -} - -/* undocumented */ -#define SHA(cycles, read_func, write_func, addr) \ -{ \ - read_func(addr); \ - data = A & X & ((uint8) ((addr >> 8) + 1)); \ - write_func(addr, data); \ - ADD_CYCLES(cycles); \ -} - -/* undocumented */ -#define SHS(cycles, read_func, write_func, addr) \ -{ \ - read_func(addr); \ - S = A & X; \ - data = S & ((uint8) ((addr >> 8) + 1)); \ - write_func(addr, data); \ - ADD_CYCLES(cycles); \ -} - -/* undocumented */ -#define SHX(cycles, read_func, write_func, addr) \ -{ \ - read_func(addr); \ - data = X & ((uint8) ((addr >> 8) + 1)); \ - write_func(addr, data); \ - ADD_CYCLES(cycles); \ -} - -/* undocumented */ -#define SHY(cycles, read_func, write_func, addr) \ -{ \ - read_func(addr); \ - data = Y & ((uint8) ((addr >> 8 ) + 1)); \ - write_func(addr, data); \ - ADD_CYCLES(cycles); \ -} - -/* undocumented */ -#define SLO(cycles, read_func, write_func, addr) \ -{ \ - read_func(addr, data); \ - TEST_AND_FLAG(data & 0x80, C_FLAG); \ - data <<= 1; \ - write_func(addr, data); \ - A |= data; \ - SET_NZ_FLAGS(A); \ - ADD_CYCLES(cycles); \ -} - -/* unoffical */ -#define SRE(cycles, read_func, write_func, addr) \ -{ \ - read_func(addr, data); \ - TEST_AND_FLAG(data & 1, C_FLAG); \ - data >>= 1; \ - write_func(addr, data); \ - A ^= data; \ - SET_NZ_FLAGS(A); \ - ADD_CYCLES(cycles); \ -} - -#define STA(cycles, read_func, write_func, addr) \ -{ \ - read_func(addr); \ - write_func(addr, A); \ - ADD_CYCLES(cycles); \ -} - -#define STX(cycles, read_func, write_func, addr) \ -{ \ - read_func(addr); \ - write_func(addr, X); \ - ADD_CYCLES(cycles); \ -} - -#define STY(cycles, read_func, write_func, addr) \ -{ \ - read_func(addr); \ - write_func(addr, Y); \ - ADD_CYCLES(cycles); \ -} - -#define TAX() \ -{ \ - X = A; \ - SET_NZ_FLAGS(X);\ - ADD_CYCLES(2); \ -} - -#define TAY() \ -{ \ - Y = A; \ - SET_NZ_FLAGS(Y);\ - ADD_CYCLES(2); \ -} - -/* undocumented (triple-NOP) */ -#define TOP() \ -{ \ - PC += 2; \ - ADD_CYCLES(4); \ -} - -#define TSX() \ -{ \ - X = S; \ - SET_NZ_FLAGS(X);\ - ADD_CYCLES(2); \ -} - -#define TXA() \ -{ \ - A = X; \ - SET_NZ_FLAGS(A);\ - ADD_CYCLES(2); \ -} - -#define TXS() \ -{ \ - S = X; \ - ADD_CYCLES(2); \ -} - -#define TYA() \ -{ \ - A = Y; \ - SET_NZ_FLAGS(A); \ - ADD_CYCLES(2); \ -} - - -/* -** Stack and data fetching macros -*/ - -/* Set/clear/test bits in the flags register */ -#define SET_FLAG(mask) P |= (mask) -#define CLEAR_FLAG(mask) P &= ~(mask) -#define IS_FLAG_SET(mask) (P & (mask)) -#define IS_FLAG_CLEAR(mask) (0 == IS_FLAG_SET((mask))) - -#define TEST_AND_FLAG(test, mask) \ -{ \ - if ((test)) \ - SET_FLAG((mask)); \ - else \ - CLEAR_FLAG((mask)); \ -} - - -/* -** flag register helper macros -*/ - -/* register push/pull */ -#ifdef NES6502_MEM_ACCESS_CTRL - -# define PUSH(value) stack_push((S--),(value)) -# define PULL() stack_pull((++S)) - -#else - -# define PUSH(value) stack_page[S--] = (uint8) (value) -# define PULL() stack_page[++S] - -#endif /* #ifdef NES6502_MEM_ACCESS_CTRL */ - -/* Sets the Z and N flags based on given data, taken from precomputed table */ -#define SET_NZ_FLAGS(value) P &= ~(N_FLAG | Z_FLAG); \ - P |= flag_table[(value)] - -#define GET_GLOBAL_REGS() \ -{ \ - PC = reg_PC; \ - A = reg_A; \ - X = reg_X; \ - Y = reg_Y; \ - P = reg_P; \ - S = reg_S; \ -} - -#define SET_LOCAL_REGS() \ -{ \ - reg_PC = PC; \ - reg_A = A; \ - reg_X = X; \ - reg_Y = Y; \ - reg_P = P; \ - reg_S = S; \ -} - - -/* static data */ -static nes6502_memread *pmem_read, *pmr; -static nes6502_memwrite *pmem_write, *pmw; - -/* lookup table for N/Z flags */ -static uint8 flag_table[256]; - -/* internal critical CPU vars */ -static uint32 reg_PC; -static uint8 reg_A, reg_P, reg_X, reg_Y, reg_S; -static uint8 int_pending; -static int dma_cycles; - -/* execution cycle count (can be reset by user) */ -static uint32 total_cycles = 0; - -/* memory region pointers */ -static uint8 *nes6502_banks[NES6502_NUMBANKS]; -static uint8 *ram = NULL; -static uint8 *stack_page = NULL; - -/* access flag for memory - * $$$ ben : I add this for the playing time calculation. - * Only if compiled with NES6502_MEM_ACCESS. - */ -#ifdef NES6502_MEM_ACCESS_CTRL - -uint8 *acc_nes6502_banks[NES6502_NUMBANKS]; -static uint8 *acc_ram = NULL; -static uint8 *acc_stack_page = NULL; -uint8 nes6502_mem_access = 0; - -/* $$$ ben : - * Set memory access check flags, and store ORed frame global check - * for music time calculation. - */ -static void chk_mem_access(uint8 * access, int flags) -{ - uint8 oldchk = * access; - if ((oldchk&flags) != flags) { - nes6502_mem_access |= flags; - *access = oldchk|flags; - } -} - -INLINE void stack_push(uint8 s, uint8 v) -{ - chk_mem_access(acc_stack_page+s, NES6502_WRITE_ACCESS); - stack_page[s] = v; -} - -INLINE uint8 stack_pull(uint8 s) -{ - chk_mem_access(acc_stack_page+s, NES6502_READ_ACCESS); - return stack_page[s]; -} - -INLINE uint8 zp_read(register uint32 addr) -{ - chk_mem_access(acc_ram+addr, NES6502_READ_ACCESS); - return ram[addr]; -} - -INLINE void zp_write(register uint32 addr, uint8 v) -{ - chk_mem_access(acc_ram+addr, NES6502_WRITE_ACCESS); - ram[addr] = v; -} - -#define ZP_READ(addr) zp_read((addr)) -#define ZP_WRITE(addr, value) zp_write((addr),(value)) - -#define bank_readbyte(address) _bank_readbyte((address), NES6502_READ_ACCESS) -#define bank_readbyte_pc(address) _bank_readbyte((address), NES6502_EXE_ACCESS) - -#else -# define chk_mem_access(access, flags) - -/* -** Zero-page helper macros -*/ -#define ZP_READ(addr) ram[(addr)] -#define ZP_WRITE(addr, value) ram[(addr)] = (uint8) (value) - -#define bank_readbyte(address) _bank_readbyte((address)) -#define bank_readbyte_pc(address) _bank_readbyte((address)) - -#endif /* #ifdef NES6502_MEM_ACCESS_CTRL */ - -#ifdef NES6502_MEM_ACCESS_CTRL -int max_access[NES6502_NUMBANKS] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - -INLINE uint8 _bank_readbyte(register uint32 address, const uint8 flags) -#else -INLINE uint8 _bank_readbyte(register uint32 address) -#endif -{ - ASSERT(nes6502_banks[address >> NES6502_BANKSHIFT]); - -#ifdef NES6502_MEM_ACCESS_CTRL - //printf("chk_mem_access(acc_nes6502_banks[%d] + %d, %d)\n", address>>NES6502_BANKSHIFT, address & NES6502_BANKMASK, flags); - - if((address & NES6502_BANKMASK) > max_access[address>>NES6502_BANKSHIFT]) - { - max_access[address>>NES6502_BANKSHIFT] = address & NES6502_BANKMASK; - //printf("max_access[%d] increased to %d\n", address>>NES6502_BANKSHIFT, max_access[address>>NES6502_BANKSHIFT]); - } -#endif - chk_mem_access(acc_nes6502_banks[address>>NES6502_BANKSHIFT] - + (address & NES6502_BANKMASK), - flags); - - return nes6502_banks[address >> NES6502_BANKSHIFT][address & NES6502_BANKMASK]; -} - - -INLINE void bank_writebyte(register uint32 address, register uint8 value) -{ - ASSERT(nes6502_banks[address >> NES6502_BANKSHIFT]); - -#ifdef NES6502_MEM_ACCESS_CTRL - //printf("chk_mem_access(acc_nes6502_banks[%d] + %d, %d)\n", address>>NES6502_BANKSHIFT, address & NES6502_BANKMASK, NES6502_WRITE_ACCESS); - - if((address & NES6502_BANKMASK) > max_access[address>>NES6502_BANKSHIFT]) - { - max_access[address>>NES6502_BANKSHIFT] = address & NES6502_BANKMASK; - //printf("max_access[%d] increased to %d\n", address>>NES6502_BANKSHIFT, max_access[address>>NES6502_BANKSHIFT]); - } -#endif - - chk_mem_access(acc_nes6502_banks[address>>NES6502_BANKSHIFT] - + (address & NES6502_BANKMASK), - NES6502_WRITE_ACCESS); - - nes6502_banks[address >> NES6502_BANKSHIFT][address & NES6502_BANKMASK] = value; -} - -/* Read a 16bit word */ -#define READ_SNES_16(bank,offset) \ -(\ - (offset) [ (uint8 *) (bank) ] |\ - ((unsigned int)( ((offset)+1) [ (uint8 *) (bank) ] ) << 8)\ -) - -INLINE uint32 zp_address(register uint8 address) -{ - chk_mem_access(acc_ram+address, NES6502_READ_ACCESS); - chk_mem_access(acc_ram+address+1, NES6502_READ_ACCESS); - -#if defined (HOST_LITTLE_ENDIAN) && defined(HOST_UNALIGN_WORD) - /* TODO: this fails if src address is $xFFF */ - /* TODO: this fails if host architecture doesn't support byte alignment */ - /* $$$ ben : DONE */ - return (uint32) (*(uint16 *)(ram + address)); -#elif defined(TARGET_CPU_PPC) - return __lhbrx(ram, address); -#else - return READ_SNES_16(ram,address); -/* uint32 x = (uint32) *(uint16 *)(ram + address); */ -/* return (x << 8) | (x >> 8); */ -//#endif /* TARGET_CPU_PPC */ -#endif /* HOST_LITTLE_ENDIAN */ -} - -INLINE uint32 bank_readaddress(register uint32 address) -{ - -#ifdef NES6502_MEM_ACCESS_CTRL - { - const unsigned int offset = address & NES6502_BANKMASK; - uint8 * addr = acc_nes6502_banks[address >> NES6502_BANKSHIFT]; - chk_mem_access(addr+offset+0, NES6502_READ_ACCESS); - chk_mem_access(addr+offset+1, NES6502_READ_ACCESS); - } -#endif - -#if defined (HOST_LITTLE_ENDIAN) && defined(HOST_UNALIGN_WORD) - /* TODO: this fails if src address is $xFFF */ - /* TODO: this fails if host architecture doesn't support byte alignment */ - /* $$$ ben : DONE */ - return (uint32) (*(uint16 *)(nes6502_banks[address >> NES6502_BANKSHIFT] + (address & NES6502_BANKMASK))); -#elif defined(TARGET_CPU_PPC) - return __lhbrx(nes6502_banks[address >> NES6502_BANKSHIFT], address & NES6502_BANKMASK); -#else - { - const unsigned int offset = address & NES6502_BANKMASK; - return READ_SNES_16(nes6502_banks[address >> NES6502_BANKSHIFT], offset); - } -/* uint32 x = (uint32) *(uint16 *)(nes6502_banks[address >> NES6502_BANKSHIFT] + (address & NES6502_BANKMASK)); */ -/* return (x << 8) | (x >> 8); */ -//#endif /* TARGET_CPU_PPC */ -#endif /* HOST_LITTLE_ENDIAN */ -} - - -/* read a byte of 6502 memory */ -static uint8 mem_read(uint32 address) -{ - /* TODO: following cases are N2A03-specific */ - /* RAM */ - if (address < 0x800) { - chk_mem_access(acc_ram + address, NES6502_READ_ACCESS); - return ram[address]; - } - /* always paged memory */ -// else if (address >= 0x6000) - else if (address >= 0x8000) { - return bank_readbyte(address); - } - /* check memory range handlers */ - else - { - for (pmr = pmem_read; pmr->min_range != 0xFFFFFFFF; pmr++) - { - if ((address >= pmr->min_range) && (address <= pmr->max_range)) - return pmr->read_func(address); - } - } - - /* return paged memory */ - return bank_readbyte(address); -} - -/* write a byte of data to 6502 memory */ -static void mem_write(uint32 address, uint8 value) -{ - /* RAM */ - if (address < 0x800) - { - chk_mem_access(acc_ram + address, NES6502_WRITE_ACCESS); - ram[address] = value; - return; - } - /* check memory range handlers */ - else - { - for (pmw = pmem_write; pmw->min_range != 0xFFFFFFFF; pmw++) - { - if ((address >= pmw->min_range) && (address <= pmw->max_range)) - { - pmw->write_func(address, value); - return; - } - } - } - - /* write to paged memory */ - bank_writebyte(address, value); -} - -/* set the current context */ -void nes6502_setcontext(nes6502_context *cpu) -{ - int loop; - - ASSERT(cpu); - - /* Set the page pointers */ - for (loop = 0; loop < NES6502_NUMBANKS; loop++) { - nes6502_banks[loop] = cpu->mem_page[loop]; -#ifdef NES6502_MEM_ACCESS_CTRL - acc_nes6502_banks[loop] = cpu->acc_mem_page[loop]; -#endif - } - - ram = nes6502_banks[0]; /* quicker zero-page/RAM references */ - stack_page = ram + STACK_OFFSET; -#ifdef NES6502_MEM_ACCESS_CTRL - acc_ram = acc_nes6502_banks[0]; /* quicker zero-page/RAM references */ - acc_stack_page = acc_ram + STACK_OFFSET; -#endif - - pmem_read = cpu->read_handler; - pmem_write = cpu->write_handler; - - reg_PC = cpu->pc_reg; - reg_A = cpu->a_reg; - reg_P = cpu->p_reg; - reg_X = cpu->x_reg; - reg_Y = cpu->y_reg; - reg_S = cpu->s_reg; - int_pending = cpu->int_pending; - dma_cycles = cpu->dma_cycles; -} - -/* get the current context */ -void nes6502_getcontext(nes6502_context *cpu) -{ - int loop; - - /* Set the page pointers */ - for (loop = 0; loop < NES6502_NUMBANKS; loop++) { - cpu->mem_page[loop] = nes6502_banks[loop]; -#ifdef NES6502_MEM_ACCESS_CTRL - cpu->acc_mem_page[loop] = acc_nes6502_banks[loop]; -#endif - } - - cpu->read_handler = pmem_read; - cpu->write_handler = pmem_write; - - cpu->pc_reg = reg_PC; - cpu->a_reg = reg_A; - cpu->p_reg = reg_P; - cpu->x_reg = reg_X; - cpu->y_reg = reg_Y; - cpu->s_reg = reg_S; - cpu->int_pending = int_pending; - cpu->dma_cycles = dma_cycles; -} - -/* DMA a byte of data from ROM */ -uint8 nes6502_getbyte(uint32 address) -{ - return bank_readbyte(address); -} - -/* get number of elapsed cycles */ -uint32 nes6502_getcycles(boolean reset_flag) -{ - uint32 cycles = total_cycles; - - if (reset_flag) - total_cycles = 0; - - return cycles; -} - - -/* Execute instructions until count expires -** -** Returns the number of cycles *actually* executed -** (note that this can be from 0-6 cycles more than you wanted) -*/ -int nes6502_execute(int remaining_cycles) -{ - int instruction_cycles, old_cycles = total_cycles; - uint32 temp, addr; /* for macros */ - uint32 PC; - uint8 A, X, Y, P, S; - uint8 opcode, data; - uint8 btemp, baddr; /* for macros */ - - GET_GLOBAL_REGS(); - -#ifdef NES6502_MEM_ACCESS_CTRL - /* reset global memory access for this execute loop. */ - nes6502_mem_access = 0; -#endif - - /* Continue until we run out of cycles */ - - - while (remaining_cycles > 0) - { - instruction_cycles = 0; - - /* check for DMA cycle burning */ - if (dma_cycles) - { - if (remaining_cycles <= dma_cycles) - { - dma_cycles -= remaining_cycles; - total_cycles += remaining_cycles; - goto _execute_done; - } - else - { - remaining_cycles -= dma_cycles; - total_cycles += dma_cycles; - dma_cycles = 0; - } - } - - if (int_pending) - { - /* NMI has highest priority */ - if (int_pending & NMI_MASK) - { - NMI(); - } - /* IRQ has lowest priority */ - else /* if (int_pending & IRQ_MASK) */ - { - if (IS_FLAG_CLEAR(I_FLAG)) - IRQ(); - } - } - - /* Fetch instruction */ - //nes6502_disasm(PC, P, A, X, Y, S); - - opcode = bank_readbyte_pc(PC++); - - /* Execute instruction */ - - switch (opcode) - { - case 0x00: /* BRK */ - BRK(); - break; - - case 0x01: /* ORA ($nn,X) */ - ORA(6, INDIR_X_BYTE); - break; - - /* JAM */ - case 0x02: /* JAM */ - case 0x12: /* JAM */ - case 0x22: /* JAM */ - case 0x32: /* JAM */ - case 0x42: /* JAM */ - case 0x52: /* JAM */ - case 0x62: /* JAM */ - case 0x72: /* JAM */ - case 0x92: /* JAM */ - case 0xB2: /* JAM */ - case 0xD2: /* JAM */ - case 0xF2: /* JAM */ - JAM(); - /* kill switch for CPU emulation */ - goto _execute_done; - - case 0x03: /* SLO ($nn,X) */ - SLO(8, INDIR_X, mem_write, addr); - break; - - case 0x04: /* NOP $nn */ - case 0x44: /* NOP $nn */ - case 0x64: /* NOP $nn */ - DOP(3); - break; - - case 0x05: /* ORA $nn */ - ORA(3, ZERO_PAGE_BYTE); - break; - - case 0x06: /* ASL $nn */ - ASL(5, ZERO_PAGE, ZP_WRITE, baddr); - break; - - case 0x07: /* SLO $nn */ - SLO(5, ZERO_PAGE, ZP_WRITE, baddr); - break; - - case 0x08: /* PHP */ - PHP(); - break; - - case 0x09: /* ORA #$nn */ - ORA(2, IMMEDIATE_BYTE); - break; - - case 0x0A: /* ASL A */ - ASL_A(); - break; - - case 0x0B: /* ANC #$nn */ - ANC(2, IMMEDIATE_BYTE); - break; - - case 0x0C: /* NOP $nnnn */ - TOP(); - break; - - case 0x0D: /* ORA $nnnn */ - ORA(4, ABSOLUTE_BYTE); - break; - - case 0x0E: /* ASL $nnnn */ - ASL(6, ABSOLUTE, mem_write, addr); - break; - - case 0x0F: /* SLO $nnnn */ - SLO(6, ABSOLUTE, mem_write, addr); - break; - - case 0x10: /* BPL $nnnn */ - BPL(); - break; - - case 0x11: /* ORA ($nn),Y */ - ORA(5, INDIR_Y_BYTE); - break; - - case 0x13: /* SLO ($nn),Y */ - SLO(8, INDIR_Y, mem_write, addr); - break; - - case 0x14: /* NOP $nn,X */ - case 0x34: /* NOP */ - case 0x54: /* NOP $nn,X */ - case 0x74: /* NOP $nn,X */ - case 0xD4: /* NOP $nn,X */ - case 0xF4: /* NOP ($nn,X) */ - DOP(4); - break; - - case 0x15: /* ORA $nn,X */ - ORA(4, ZP_IND_X_BYTE); - break; - - case 0x16: /* ASL $nn,X */ - ASL(6, ZP_IND_X, ZP_WRITE, baddr); - break; - - case 0x17: /* SLO $nn,X */ - SLO(6, ZP_IND_X, ZP_WRITE, baddr); - break; - - case 0x18: /* CLC */ - CLC(); - break; - - case 0x19: /* ORA $nnnn,Y */ - ORA(4, ABS_IND_Y_BYTE); - break; - - case 0x1A: /* NOP */ - case 0x3A: /* NOP */ - case 0x5A: /* NOP */ - case 0x7A: /* NOP */ - case 0xDA: /* NOP */ - case 0xFA: /* NOP */ - NOP(); - break; - - case 0x1B: /* SLO $nnnn,Y */ - SLO(7, ABS_IND_Y, mem_write, addr); - break; - - case 0x1C: /* NOP $nnnn,X */ - case 0x3C: /* NOP $nnnn,X */ - case 0x5C: /* NOP $nnnn,X */ - case 0x7C: /* NOP $nnnn,X */ - case 0xDC: /* NOP $nnnn,X */ - case 0xFC: /* NOP $nnnn,X */ - TOP(); - break; - - case 0x1D: /* ORA $nnnn,X */ - ORA(4, ABS_IND_X_BYTE); - break; - - case 0x1E: /* ASL $nnnn,X */ - ASL(7, ABS_IND_X, mem_write, addr); - break; - - case 0x1F: /* SLO $nnnn,X */ - SLO(7, ABS_IND_X, mem_write, addr); - break; - - case 0x20: /* JSR $nnnn */ - JSR(); - break; - - case 0x21: /* AND ($nn,X) */ - AND(6, INDIR_X_BYTE); - break; - - case 0x23: /* RLA ($nn,X) */ - RLA(8, INDIR_X, mem_write, addr); - break; - - case 0x24: /* BIT $nn */ - BIT(3, ZERO_PAGE_BYTE); - break; - - case 0x25: /* AND $nn */ - AND(3, ZERO_PAGE_BYTE); - break; - - case 0x26: /* ROL $nn */ - ROL(5, ZERO_PAGE, ZP_WRITE, baddr); - break; - - case 0x27: /* RLA $nn */ - RLA(5, ZERO_PAGE, ZP_WRITE, baddr); - break; - - case 0x28: /* PLP */ - PLP(); - break; - - case 0x29: /* AND #$nn */ - AND(2, IMMEDIATE_BYTE); - break; - - case 0x2A: /* ROL A */ - ROL_A(); - break; - - case 0x2B: /* ANC #$nn */ - ANC(2, IMMEDIATE_BYTE); - break; - - case 0x2C: /* BIT $nnnn */ - BIT(4, ABSOLUTE_BYTE); - break; - - case 0x2D: /* AND $nnnn */ - AND(4, ABSOLUTE_BYTE); - break; - - case 0x2E: /* ROL $nnnn */ - ROL(6, ABSOLUTE, mem_write, addr); - break; - - case 0x2F: /* RLA $nnnn */ - RLA(6, ABSOLUTE, mem_write, addr); - break; - - case 0x30: /* BMI $nnnn */ - BMI(); - break; - - case 0x31: /* AND ($nn),Y */ - AND(5, INDIR_Y_BYTE); - break; - - case 0x33: /* RLA ($nn),Y */ - RLA(8, INDIR_Y, mem_write, addr); - break; - - case 0x35: /* AND $nn,X */ - AND(4, ZP_IND_X_BYTE); - break; - - case 0x36: /* ROL $nn,X */ - ROL(6, ZP_IND_X, ZP_WRITE, baddr); - break; - - case 0x37: /* RLA $nn,X */ - RLA(6, ZP_IND_X, ZP_WRITE, baddr); - break; - - case 0x38: /* SEC */ - SEC(); - break; - - case 0x39: /* AND $nnnn,Y */ - AND(4, ABS_IND_Y_BYTE); - break; - - case 0x3B: /* RLA $nnnn,Y */ - RLA(7, ABS_IND_Y, mem_write, addr); - break; - - case 0x3D: /* AND $nnnn,X */ - AND(4, ABS_IND_X_BYTE); - break; - - case 0x3E: /* ROL $nnnn,X */ - ROL(7, ABS_IND_X, mem_write, addr); - break; - - case 0x3F: /* RLA $nnnn,X */ - RLA(7, ABS_IND_X, mem_write, addr); - break; - - case 0x40: /* RTI */ - RTI(); - break; - - case 0x41: /* EOR ($nn,X) */ - EOR(6, INDIR_X_BYTE); - break; - - case 0x43: /* SRE ($nn,X) */ - SRE(8, INDIR_X, mem_write, addr); - break; - - case 0x45: /* EOR $nn */ - EOR(3, ZERO_PAGE_BYTE); - break; - - case 0x46: /* LSR $nn */ - LSR(5, ZERO_PAGE, ZP_WRITE, baddr); - break; - - case 0x47: /* SRE $nn */ - SRE(5, ZERO_PAGE, ZP_WRITE, baddr); - break; - - case 0x48: /* PHA */ - PHA(); - break; - - case 0x49: /* EOR #$nn */ - EOR(2, IMMEDIATE_BYTE); - break; - - case 0x4A: /* LSR A */ - LSR_A(); - break; - - case 0x4B: /* ASR #$nn */ - ASR(2, IMMEDIATE_BYTE); - break; - - case 0x4C: /* JMP $nnnn */ - JMP_ABSOLUTE(); - break; - - case 0x4D: /* EOR $nnnn */ - EOR(4, ABSOLUTE_BYTE); - break; - - case 0x4E: /* LSR $nnnn */ - LSR(6, ABSOLUTE, mem_write, addr); - break; - - case 0x4F: /* SRE $nnnn */ - SRE(6, ABSOLUTE, mem_write, addr); - break; - - case 0x50: /* BVC $nnnn */ - BVC(); - break; - - case 0x51: /* EOR ($nn),Y */ - EOR(5, INDIR_Y_BYTE); - break; - - case 0x53: /* SRE ($nn),Y */ - SRE(8, INDIR_Y, mem_write, addr); - break; - - case 0x55: /* EOR $nn,X */ - EOR(4, ZP_IND_X_BYTE); - break; - - case 0x56: /* LSR $nn,X */ - LSR(6, ZP_IND_X, ZP_WRITE, baddr); - break; - - case 0x57: /* SRE $nn,X */ - SRE(6, ZP_IND_X, ZP_WRITE, baddr); - break; - - case 0x58: /* CLI */ - CLI(); - break; - - case 0x59: /* EOR $nnnn,Y */ - EOR(4, ABS_IND_Y_BYTE); - break; - - case 0x5B: /* SRE $nnnn,Y */ - SRE(7, ABS_IND_Y, mem_write, addr); - break; - - case 0x5D: /* EOR $nnnn,X */ - EOR(4, ABS_IND_X_BYTE); - break; - - case 0x5E: /* LSR $nnnn,X */ - LSR(7, ABS_IND_X, mem_write, addr); - break; - - case 0x5F: /* SRE $nnnn,X */ - SRE(7, ABS_IND_X, mem_write, addr); - break; - - case 0x60: /* RTS */ - RTS(); - break; - - case 0x61: /* ADC ($nn,X) */ - ADC(6, INDIR_X_BYTE); - break; - - case 0x63: /* RRA ($nn,X) */ - RRA(8, INDIR_X, mem_write, addr); - break; - - case 0x65: /* ADC $nn */ - ADC(3, ZERO_PAGE_BYTE); - break; - - case 0x66: /* ROR $nn */ - ROR(5, ZERO_PAGE, ZP_WRITE, baddr); - break; - - case 0x67: /* RRA $nn */ - RRA(5, ZERO_PAGE, ZP_WRITE, baddr); - break; - - case 0x68: /* PLA */ - PLA(); - break; - - case 0x69: /* ADC #$nn */ - ADC(2, IMMEDIATE_BYTE); - break; - - case 0x6A: /* ROR A */ - ROR_A(); - break; - - case 0x6B: /* ARR #$nn */ - ARR(2, IMMEDIATE_BYTE); - break; - - case 0x6C: /* JMP ($nnnn) */ - JMP_INDIRECT(); - break; - - case 0x6D: /* ADC $nnnn */ - ADC(4, ABSOLUTE_BYTE); - break; - - case 0x6E: /* ROR $nnnn */ - ROR(6, ABSOLUTE, mem_write, addr); - break; - - case 0x6F: /* RRA $nnnn */ - RRA(6, ABSOLUTE, mem_write, addr); - break; - - case 0x70: /* BVS $nnnn */ - BVS(); - break; - - case 0x71: /* ADC ($nn),Y */ - ADC(5, INDIR_Y_BYTE); - break; - - case 0x73: /* RRA ($nn),Y */ - RRA(8, INDIR_Y, mem_write, addr); - break; - - case 0x75: /* ADC $nn,X */ - ADC(4, ZP_IND_X_BYTE); - break; - - case 0x76: /* ROR $nn,X */ - ROR(6, ZP_IND_X, ZP_WRITE, baddr); - break; - - case 0x77: /* RRA $nn,X */ - RRA(6, ZP_IND_X, ZP_WRITE, baddr); - break; - - case 0x78: /* SEI */ - SEI(); - break; - - case 0x79: /* ADC $nnnn,Y */ - ADC(4, ABS_IND_Y_BYTE); - break; - - case 0x7B: /* RRA $nnnn,Y */ - RRA(7, ABS_IND_Y, mem_write, addr); - break; - - case 0x7D: /* ADC $nnnn,X */ - ADC(4, ABS_IND_X_BYTE); - break; - - case 0x7E: /* ROR $nnnn,X */ - ROR(7, ABS_IND_X, mem_write, addr); - break; - - case 0x7F: /* RRA $nnnn,X */ - RRA(7, ABS_IND_X, mem_write, addr); - break; - - case 0x80: /* NOP #$nn */ - case 0x82: /* NOP #$nn */ - case 0x89: /* NOP #$nn */ - case 0xC2: /* NOP #$nn */ - case 0xE2: /* NOP #$nn */ - DOP(2); - break; - - case 0x81: /* STA ($nn,X) */ - STA(6, INDIR_X_ADDR, mem_write, addr); - break; - - case 0x83: /* SAX ($nn,X) */ - SAX(6, INDIR_X_ADDR, mem_write, addr); - break; - - case 0x84: /* STY $nn */ - STY(3, ZERO_PAGE_ADDR, ZP_WRITE, baddr); - break; - - case 0x85: /* STA $nn */ - STA(3, ZERO_PAGE_ADDR, ZP_WRITE, baddr); - break; - - case 0x86: /* STX $nn */ - STX(3, ZERO_PAGE_ADDR, ZP_WRITE, baddr); - break; - - case 0x87: /* SAX $nn */ - SAX(3, ZERO_PAGE_ADDR, ZP_WRITE, baddr); - break; - - case 0x88: /* DEY */ - DEY(); - break; - - case 0x8A: /* TXA */ - TXA(); - break; - - case 0x8B: /* ANE #$nn */ - ANE(2, IMMEDIATE_BYTE); - break; - - case 0x8C: /* STY $nnnn */ - STY(4, ABSOLUTE_ADDR, mem_write, addr); - break; - - case 0x8D: /* STA $nnnn */ - STA(4, ABSOLUTE_ADDR, mem_write, addr); - break; - - case 0x8E: /* STX $nnnn */ - STX(4, ABSOLUTE_ADDR, mem_write, addr); - break; - - case 0x8F: /* SAX $nnnn */ - SAX(4, ABSOLUTE_ADDR, mem_write, addr); - break; - - case 0x90: /* BCC $nnnn */ - BCC(); - break; - - case 0x91: /* STA ($nn),Y */ - STA(6, INDIR_Y_ADDR, mem_write, addr); - break; - - case 0x93: /* SHA ($nn),Y */ - SHA(6, INDIR_Y_ADDR, mem_write, addr); - break; - - case 0x94: /* STY $nn,X */ - STY(4, ZP_IND_X_ADDR, ZP_WRITE, baddr); - break; - - case 0x95: /* STA $nn,X */ - STA(4, ZP_IND_X_ADDR, ZP_WRITE, baddr); - break; - - case 0x96: /* STX $nn,Y */ - STX(4, ZP_IND_Y_ADDR, ZP_WRITE, baddr); - break; - - case 0x97: /* SAX $nn,Y */ - SAX(4, ZP_IND_Y_ADDR, ZP_WRITE, baddr); - break; - - case 0x98: /* TYA */ - TYA(); - break; - - case 0x99: /* STA $nnnn,Y */ - STA(5, ABS_IND_Y_ADDR, mem_write, addr); - break; - - case 0x9A: /* TXS */ - TXS(); - break; - - case 0x9B: /* SHS $nnnn,Y */ - SHS(5, ABS_IND_Y_ADDR, mem_write, addr); - break; - - case 0x9C: /* SHY $nnnn,X */ - SHY(5, ABS_IND_X_ADDR, mem_write, addr); - break; - - case 0x9D: /* STA $nnnn,X */ - STA(5, ABS_IND_X_ADDR, mem_write, addr); - break; - - case 0x9E: /* SHX $nnnn,Y */ - SHX(5, ABS_IND_Y_ADDR, mem_write, addr); - break; - - case 0x9F: /* SHA $nnnn,Y */ - SHA(5, ABS_IND_Y_ADDR, mem_write, addr); - break; - - case 0xA0: /* LDY #$nn */ - LDY(2, IMMEDIATE_BYTE); - break; - - case 0xA1: /* LDA ($nn,X) */ - LDA(6, INDIR_X_BYTE); - break; - - case 0xA2: /* LDX #$nn */ - LDX(2, IMMEDIATE_BYTE); - break; - - case 0xA3: /* LAX ($nn,X) */ - LAX(6, INDIR_X_BYTE); - break; - - case 0xA4: /* LDY $nn */ - LDY(3, ZERO_PAGE_BYTE); - break; - - case 0xA5: /* LDA $nn */ - LDA(3, ZERO_PAGE_BYTE); - break; - - case 0xA6: /* LDX $nn */ - LDX(3, ZERO_PAGE_BYTE); - break; - - case 0xA7: /* LAX $nn */ - LAX(3, ZERO_PAGE_BYTE); - break; - - case 0xA8: /* TAY */ - TAY(); - break; - - case 0xA9: /* LDA #$nn */ - LDA(2, IMMEDIATE_BYTE); - break; - - case 0xAA: /* TAX */ - TAX(); - break; - - case 0xAB: /* LXA #$nn */ - LXA(2, IMMEDIATE_BYTE); - break; - - case 0xAC: /* LDY $nnnn */ - LDY(4, ABSOLUTE_BYTE); - break; - - case 0xAD: /* LDA $nnnn */ - LDA(4, ABSOLUTE_BYTE); - break; - - case 0xAE: /* LDX $nnnn */ - LDX(4, ABSOLUTE_BYTE); - break; - - case 0xAF: /* LAX $nnnn */ - LAX(4, ABSOLUTE_BYTE); - break; - - case 0xB0: /* BCS $nnnn */ - BCS(); - break; - - case 0xB1: /* LDA ($nn),Y */ - LDA(5, INDIR_Y_BYTE); - break; - - case 0xB3: /* LAX ($nn),Y */ - LAX(5, INDIR_Y_BYTE); - break; - - case 0xB4: /* LDY $nn,X */ - LDY(4, ZP_IND_X_BYTE); - break; - - case 0xB5: /* LDA $nn,X */ - LDA(4, ZP_IND_X_BYTE); - break; - - case 0xB6: /* LDX $nn,Y */ - LDX(4, ZP_IND_Y_BYTE); - break; - - case 0xB7: /* LAX $nn,Y */ - LAX(4, ZP_IND_Y_BYTE); - break; - - case 0xB8: /* CLV */ - CLV(); - break; - - case 0xB9: /* LDA $nnnn,Y */ - LDA(4, ABS_IND_Y_BYTE); - break; - - case 0xBA: /* TSX */ - TSX(); - break; - - case 0xBB: /* LAS $nnnn,Y */ - LAS(4, ABS_IND_Y_BYTE); - break; - - case 0xBC: /* LDY $nnnn,X */ - LDY(4, ABS_IND_X_BYTE); - break; - - case 0xBD: /* LDA $nnnn,X */ - LDA(4, ABS_IND_X_BYTE); - break; - - case 0xBE: /* LDX $nnnn,Y */ - LDX(4, ABS_IND_Y_BYTE); - break; - - case 0xBF: /* LAX $nnnn,Y */ - LAX(4, ABS_IND_Y_BYTE); - break; - - case 0xC0: /* CPY #$nn */ - CPY(2, IMMEDIATE_BYTE); - break; - - case 0xC1: /* CMP ($nn,X) */ - CMP(6, INDIR_X_BYTE); - break; - - case 0xC3: /* DCP ($nn,X) */ - DCP(8, INDIR_X, mem_write, addr); - break; - - case 0xC4: /* CPY $nn */ - CPY(3, ZERO_PAGE_BYTE); - break; - - case 0xC5: /* CMP $nn */ - CMP(3, ZERO_PAGE_BYTE); - break; - - case 0xC6: /* DEC $nn */ - DEC(5, ZERO_PAGE, ZP_WRITE, baddr); - break; - - case 0xC7: /* DCP $nn */ - DCP(5, ZERO_PAGE, ZP_WRITE, baddr); - break; - - case 0xC8: /* INY */ - INY(); - break; - - case 0xC9: /* CMP #$nn */ - CMP(2, IMMEDIATE_BYTE); - break; - - case 0xCA: /* DEX */ - DEX(); - break; - - case 0xCB: /* SBX #$nn */ - SBX(2, IMMEDIATE_BYTE); - break; - - case 0xCC: /* CPY $nnnn */ - CPY(4, ABSOLUTE_BYTE); - break; - - case 0xCD: /* CMP $nnnn */ - CMP(4, ABSOLUTE_BYTE); - break; - - case 0xCE: /* DEC $nnnn */ - DEC(6, ABSOLUTE, mem_write, addr); - break; - - case 0xCF: /* DCP $nnnn */ - DCP(6, ABSOLUTE, mem_write, addr); - break; - - case 0xD0: /* BNE $nnnn */ - BNE(); - break; - - case 0xD1: /* CMP ($nn),Y */ - CMP(5, INDIR_Y_BYTE); - break; - - case 0xD3: /* DCP ($nn),Y */ - DCP(8, INDIR_Y, mem_write, addr); - break; - - case 0xD5: /* CMP $nn,X */ - CMP(4, ZP_IND_X_BYTE); - break; - - case 0xD6: /* DEC $nn,X */ - DEC(6, ZP_IND_X, ZP_WRITE, baddr); - break; - - case 0xD7: /* DCP $nn,X */ - DCP(6, ZP_IND_X, ZP_WRITE, baddr); - break; - - case 0xD8: /* CLD */ - CLD(); - break; - - case 0xD9: /* CMP $nnnn,Y */ - CMP(4, ABS_IND_Y_BYTE); - break; - - case 0xDB: /* DCP $nnnn,Y */ - DCP(7, ABS_IND_Y, mem_write, addr); - break; - - case 0xDD: /* CMP $nnnn,X */ - CMP(4, ABS_IND_X_BYTE); - break; - - case 0xDE: /* DEC $nnnn,X */ - DEC(7, ABS_IND_X, mem_write, addr); - break; - - case 0xDF: /* DCP $nnnn,X */ - DCP(7, ABS_IND_X, mem_write, addr); - break; - - case 0xE0: /* CPX #$nn */ - CPX(2, IMMEDIATE_BYTE); - break; - - case 0xE1: /* SBC ($nn,X) */ - SBC(6, INDIR_X_BYTE); - break; - - case 0xE3: /* ISB ($nn,X) */ - ISB(8, INDIR_X, mem_write, addr); - break; - - case 0xE4: /* CPX $nn */ - CPX(3, ZERO_PAGE_BYTE); - break; - - case 0xE5: /* SBC $nn */ - SBC(3, ZERO_PAGE_BYTE); - break; - - case 0xE6: /* INC $nn */ - INC(5, ZERO_PAGE, ZP_WRITE, baddr); - break; - - case 0xE7: /* ISB $nn */ - ISB(5, ZERO_PAGE, ZP_WRITE, baddr); - break; - - case 0xE8: /* INX */ - INX(); - break; - - case 0xE9: /* SBC #$nn */ - case 0xEB: /* USBC #$nn */ - SBC(2, IMMEDIATE_BYTE); - break; - - case 0xEA: /* NOP */ - NOP(); - break; - - case 0xEC: /* CPX $nnnn */ - CPX(4, ABSOLUTE_BYTE); - break; - - case 0xED: /* SBC $nnnn */ - SBC(4, ABSOLUTE_BYTE); - break; - - case 0xEE: /* INC $nnnn */ - INC(6, ABSOLUTE, mem_write, addr); - break; - - case 0xEF: /* ISB $nnnn */ - ISB(6, ABSOLUTE, mem_write, addr); - break; - - case 0xF0: /* BEQ $nnnn */ - BEQ(); - break; - - case 0xF1: /* SBC ($nn),Y */ - SBC(5, INDIR_Y_BYTE); - break; - - case 0xF3: /* ISB ($nn),Y */ - ISB(8, INDIR_Y, mem_write, addr); - break; - - case 0xF5: /* SBC $nn,X */ - SBC(4, ZP_IND_X_BYTE); - break; - - case 0xF6: /* INC $nn,X */ - INC(6, ZP_IND_X, ZP_WRITE, baddr); - break; - - case 0xF7: /* ISB $nn,X */ - ISB(6, ZP_IND_X, ZP_WRITE, baddr); - break; - - case 0xF8: /* SED */ - SED(); - break; - - case 0xF9: /* SBC $nnnn,Y */ - SBC(4, ABS_IND_Y_BYTE); - break; - - case 0xFB: /* ISB $nnnn,Y */ - ISB(7, ABS_IND_Y, mem_write, addr); - break; - - case 0xFD: /* SBC $nnnn,X */ - SBC(4, ABS_IND_X_BYTE); - break; - - case 0xFE: /* INC $nnnn,X */ - INC(7, ABS_IND_X, mem_write, addr); - break; - - case 0xFF: /* ISB $nnnn,X */ - ISB(7, ABS_IND_X, mem_write, addr); - break; - } - - /* Calculate remaining/elapsed clock cycles */ - remaining_cycles -= instruction_cycles; - total_cycles += instruction_cycles; - } - -_execute_done: - - /* restore local copy of regs */ - SET_LOCAL_REGS(); - - /* Return our actual amount of executed cycles */ - return (total_cycles - old_cycles); -} - -/* Initialize tables, etc. */ -void nes6502_init(void) -{ - int index; - - /* Build the N / Z flag lookup table */ - flag_table[0] = Z_FLAG; - - for (index = 1; index < 256; index++) - flag_table[index] = (index & 0x80) ? N_FLAG : 0; - - reg_A = reg_X = reg_Y = 0; - reg_S = 0xFF; /* Stack grows down */ -} - - -/* Issue a CPU Reset */ -void nes6502_reset(void) -{ - reg_P = Z_FLAG | R_FLAG | I_FLAG; /* Reserved bit always 1 */ - int_pending = dma_cycles = 0; /* No pending interrupts */ - reg_PC = bank_readaddress(RESET_VECTOR); /* Fetch reset vector */ - /* TODO: 6 cycles for RESET? */ -} - -/* Non-maskable interrupt */ -void nes6502_nmi(void) -{ - int_pending |= NMI_MASK; -} - -/* Interrupt request */ -void nes6502_irq(void) -{ - int_pending |= IRQ_MASK; -} - -/* Set dma period (in cycles) */ -void nes6502_setdma(int cycles) -{ - dma_cycles += cycles; -} - -#ifdef NES6502_MEM_ACCESS_CTRL -void nes6502_chk_mem_access(uint8 * access, int flags) -{ - chk_mem_access(access, flags); -} -#endif - -/* -** $Log: nes6502.c,v $ -** Revision 1.2 2003/05/01 22:34:19 benjihan -** New NSF plugin -** -** Revision 1.1 2003/04/08 20:53:00 ben -** Adding more files... -** -** Revision 1.6 2000/07/04 04:50:07 matt -** minor change to includes -** -** Revision 1.5 2000/07/03 02:18:16 matt -** added a few notes about potential failure cases -** -** Revision 1.4 2000/06/09 15:12:25 matt -** initial revision -** -*/ |