kopia lustrzana https://github.com/Jean-MarcHarvengt/MCUME
2574 wiersze
56 KiB
C
2574 wiersze
56 KiB
C
/*
|
|
** 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 2001/04/27 14:37:11 neil Exp $
|
|
*/
|
|
|
|
|
|
#include "noftypes.h"
|
|
#include "nes6502.h"
|
|
//#include "dis6502.h"
|
|
|
|
//#define NES6502_DISASM
|
|
|
|
#ifdef __GNUC__
|
|
#define NES6502_JUMPTABLE
|
|
#endif /* __GNUC__ */
|
|
|
|
|
|
#define ADD_CYCLES(x) \
|
|
{ \
|
|
remaining_cycles -= (x); \
|
|
cpu.total_cycles += (x); \
|
|
}
|
|
|
|
/*
|
|
** Check to see if an index reg addition overflowed to next page
|
|
*/
|
|
#define PAGE_CROSS_CHECK(addr, reg) \
|
|
{ \
|
|
if ((reg) > (uint8) (addr)) \
|
|
ADD_CYCLES(1); \
|
|
}
|
|
|
|
#define EMPTY_READ(value) /* empty */
|
|
|
|
/*
|
|
** Addressing mode macros
|
|
*/
|
|
|
|
/* Immediate */
|
|
#define IMMEDIATE_BYTE(value) \
|
|
{ \
|
|
value = bank_readbyte(PC++); \
|
|
}
|
|
|
|
/* Absolute */
|
|
#define ABSOLUTE_ADDR(address) \
|
|
{ \
|
|
address = bank_readword(PC); \
|
|
PC += 2; \
|
|
}
|
|
|
|
#define ABSOLUTE(address, value) \
|
|
{ \
|
|
ABSOLUTE_ADDR(address); \
|
|
value = mem_readbyte(address); \
|
|
}
|
|
|
|
#define ABSOLUTE_BYTE(value) \
|
|
{ \
|
|
ABSOLUTE(temp, value); \
|
|
}
|
|
|
|
/* Absolute indexed X */
|
|
#define ABS_IND_X_ADDR(address) \
|
|
{ \
|
|
ABSOLUTE_ADDR(address); \
|
|
address = (address + X) & 0xFFFF; \
|
|
}
|
|
|
|
#define ABS_IND_X(address, value) \
|
|
{ \
|
|
ABS_IND_X_ADDR(address); \
|
|
value = mem_readbyte(address); \
|
|
}
|
|
|
|
#define ABS_IND_X_BYTE(value) \
|
|
{ \
|
|
ABS_IND_X(temp, value); \
|
|
}
|
|
|
|
/* special page-cross check version for read instructions */
|
|
#define ABS_IND_X_BYTE_READ(value) \
|
|
{ \
|
|
ABS_IND_X_ADDR(temp); \
|
|
PAGE_CROSS_CHECK(temp, X); \
|
|
value = mem_readbyte(temp); \
|
|
}
|
|
|
|
/* Absolute indexed Y */
|
|
#define ABS_IND_Y_ADDR(address) \
|
|
{ \
|
|
ABSOLUTE_ADDR(address); \
|
|
address = (address + Y) & 0xFFFF; \
|
|
}
|
|
|
|
#define ABS_IND_Y(address, value) \
|
|
{ \
|
|
ABS_IND_Y_ADDR(address); \
|
|
value = mem_readbyte(address); \
|
|
}
|
|
|
|
#define ABS_IND_Y_BYTE(value) \
|
|
{ \
|
|
ABS_IND_Y(temp, value); \
|
|
}
|
|
|
|
/* special page-cross check version for read instructions */
|
|
#define ABS_IND_Y_BYTE_READ(value) \
|
|
{ \
|
|
ABS_IND_Y_ADDR(temp); \
|
|
PAGE_CROSS_CHECK(temp, Y); \
|
|
value = mem_readbyte(temp); \
|
|
}
|
|
|
|
/* Zero-page */
|
|
#define ZERO_PAGE_ADDR(address) \
|
|
{ \
|
|
IMMEDIATE_BYTE(address); \
|
|
}
|
|
|
|
#define ZERO_PAGE(address, value) \
|
|
{ \
|
|
ZERO_PAGE_ADDR(address); \
|
|
value = ZP_READBYTE(address); \
|
|
}
|
|
|
|
#define ZERO_PAGE_BYTE(value) \
|
|
{ \
|
|
ZERO_PAGE(btemp, value); \
|
|
}
|
|
|
|
/* Zero-page indexed X */
|
|
#define ZP_IND_X_ADDR(address) \
|
|
{ \
|
|
ZERO_PAGE_ADDR(address); \
|
|
address += X; \
|
|
}
|
|
|
|
#define ZP_IND_X(address, value) \
|
|
{ \
|
|
ZP_IND_X_ADDR(address); \
|
|
value = ZP_READBYTE(address); \
|
|
}
|
|
|
|
#define ZP_IND_X_BYTE(value) \
|
|
{ \
|
|
ZP_IND_X(btemp, value); \
|
|
}
|
|
|
|
/* Zero-page indexed Y */
|
|
/* Not really an adressing mode, just for LDx/STx */
|
|
#define ZP_IND_Y_ADDR(address) \
|
|
{ \
|
|
ZERO_PAGE_ADDR(address); \
|
|
address += Y; \
|
|
}
|
|
|
|
#define ZP_IND_Y_BYTE(value) \
|
|
{ \
|
|
ZP_IND_Y_ADDR(btemp); \
|
|
value = ZP_READBYTE(btemp); \
|
|
}
|
|
|
|
/* Indexed indirect */
|
|
#define INDIR_X_ADDR(address) \
|
|
{ \
|
|
ZERO_PAGE_ADDR(btemp); \
|
|
btemp += X; \
|
|
address = zp_readword(btemp); \
|
|
}
|
|
|
|
#define INDIR_X(address, value) \
|
|
{ \
|
|
INDIR_X_ADDR(address); \
|
|
value = mem_readbyte(address); \
|
|
}
|
|
|
|
#define INDIR_X_BYTE(value) \
|
|
{ \
|
|
INDIR_X(temp, value); \
|
|
}
|
|
|
|
/* Indirect indexed */
|
|
#define INDIR_Y_ADDR(address) \
|
|
{ \
|
|
ZERO_PAGE_ADDR(btemp); \
|
|
address = (zp_readword(btemp) + Y) & 0xFFFF; \
|
|
}
|
|
|
|
#define INDIR_Y(address, value) \
|
|
{ \
|
|
INDIR_Y_ADDR(address); \
|
|
value = mem_readbyte(address); \
|
|
}
|
|
|
|
#define INDIR_Y_BYTE(value) \
|
|
{ \
|
|
INDIR_Y(temp, value); \
|
|
}
|
|
|
|
/* special page-cross check version for read instructions */
|
|
#define INDIR_Y_BYTE_READ(value) \
|
|
{ \
|
|
INDIR_Y_ADDR(temp); \
|
|
PAGE_CROSS_CHECK(temp, Y); \
|
|
value = mem_readbyte(temp); \
|
|
}
|
|
|
|
|
|
|
|
/* Stack push/pull */
|
|
#define PUSH(value) stack[S--] = (uint8) (value)
|
|
#define PULL() stack[++S]
|
|
|
|
|
|
/*
|
|
** flag register helper macros
|
|
*/
|
|
|
|
/* Theory: Z and N flags are set in just about every
|
|
** instruction, so we will just store the value in those
|
|
** flag variables, and mask out the irrelevant data when
|
|
** we need to check them (branches, etc). This makes the
|
|
** zero flag only really be 'set' when z_flag == 0.
|
|
** The rest of the flags are stored as true booleans.
|
|
*/
|
|
|
|
/* Scatter flags to separate variables */
|
|
#define SCATTER_FLAGS(value) \
|
|
{ \
|
|
n_flag = (value) & N_FLAG; \
|
|
v_flag = (value) & V_FLAG; \
|
|
b_flag = (value) & B_FLAG; \
|
|
d_flag = (value) & D_FLAG; \
|
|
i_flag = (value) & I_FLAG; \
|
|
z_flag = (0 == ((value) & Z_FLAG)); \
|
|
c_flag = (value) & C_FLAG; \
|
|
}
|
|
|
|
/* Combine flags into flag register */
|
|
#define COMBINE_FLAGS() \
|
|
( \
|
|
(n_flag & N_FLAG) \
|
|
| (v_flag ? V_FLAG : 0) \
|
|
| R_FLAG \
|
|
| (b_flag ? B_FLAG : 0) \
|
|
| (d_flag ? D_FLAG : 0) \
|
|
| (i_flag ? I_FLAG : 0) \
|
|
| (z_flag ? 0 : Z_FLAG) \
|
|
| c_flag \
|
|
)
|
|
|
|
/* Set N and Z flags based on given value */
|
|
#define SET_NZ_FLAGS(value) n_flag = z_flag = (value);
|
|
|
|
/* For BCC, BCS, BEQ, BMI, BNE, BPL, BVC, BVS */
|
|
#define RELATIVE_BRANCH(condition) \
|
|
{ \
|
|
if (condition) \
|
|
{ \
|
|
IMMEDIATE_BYTE(btemp); \
|
|
if (((int8) btemp + (PC & 0x00FF)) & 0x100) \
|
|
ADD_CYCLES(1); \
|
|
ADD_CYCLES(3); \
|
|
PC += (int8) btemp; \
|
|
} \
|
|
else \
|
|
{ \
|
|
PC++; \
|
|
ADD_CYCLES(2); \
|
|
} \
|
|
}
|
|
|
|
#define JUMP(address) \
|
|
{ \
|
|
PC = bank_readword((address)); \
|
|
}
|
|
|
|
/*
|
|
** Interrupt macros
|
|
*/
|
|
#define NMI_PROC() \
|
|
{ \
|
|
PUSH(PC >> 8); \
|
|
PUSH(PC & 0xFF); \
|
|
b_flag = 0; \
|
|
PUSH(COMBINE_FLAGS()); \
|
|
i_flag = 1; \
|
|
JUMP(NMI_VECTOR); \
|
|
}
|
|
|
|
#define IRQ_PROC() \
|
|
{ \
|
|
PUSH(PC >> 8); \
|
|
PUSH(PC & 0xFF); \
|
|
b_flag = 0; \
|
|
PUSH(COMBINE_FLAGS()); \
|
|
i_flag = 1; \
|
|
JUMP(IRQ_VECTOR); \
|
|
}
|
|
|
|
/*
|
|
** 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 (d_flag) \
|
|
{ \
|
|
temp = (A & 0x0F) + (data & 0x0F) + c_flag; \
|
|
if (temp >= 10) \
|
|
temp = (temp - 10) | 0x10; \
|
|
temp += (A & 0xF0) + (data & 0xF0); \
|
|
z_flag = (A + data + c_flag) & 0xFF; \
|
|
n_flag = temp; \
|
|
v_flag = ((~(A ^ data)) & (A ^ temp) & 0x80); \
|
|
if (temp > 0x90) \
|
|
{ \
|
|
temp += 0x60; \
|
|
c_flag = 1; \
|
|
} \
|
|
else \
|
|
{ \
|
|
c_flag = 0; \
|
|
} \
|
|
A = (uint8) temp; \
|
|
} \
|
|
else \
|
|
{ \
|
|
temp = A + data + c_flag; \
|
|
c_flag = (temp >> 8) & 1; \
|
|
v_flag = ((~(A ^ data)) & (A ^ temp) & 0x80); \
|
|
A = (uint8) temp; \
|
|
SET_NZ_FLAGS(A); \
|
|
}\
|
|
ADD_CYCLES(cycles); \
|
|
}
|
|
#else
|
|
#define ADC(cycles, read_func) \
|
|
{ \
|
|
read_func(data); \
|
|
temp = A + data + c_flag; \
|
|
c_flag = (temp >> 8) & 1; \
|
|
v_flag = ((~(A ^ data)) & (A ^ temp) & 0x80); \
|
|
A = (uint8) temp; \
|
|
SET_NZ_FLAGS(A); \
|
|
ADD_CYCLES(cycles); \
|
|
}
|
|
#endif /* NES6502_DECIMAL */
|
|
|
|
/* undocumented */
|
|
#define ANC(cycles, read_func) \
|
|
{ \
|
|
read_func(data); \
|
|
A &= data; \
|
|
c_flag = (n_flag & N_FLAG) >> 7; \
|
|
SET_NZ_FLAGS(A); \
|
|
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 (d_flag) \
|
|
{ \
|
|
temp = (data >> 1) | (c_flag << 7); \
|
|
SET_NZ_FLAGS(temp); \
|
|
v_flag = (temp ^ data) & 0x40; \
|
|
if (((data & 0x0F) + (data & 0x01)) > 5) \
|
|
temp = (temp & 0xF0) | ((temp + 0x6) & 0x0F); \
|
|
if (((data & 0xF0) + (data & 0x10)) > 0x50) \
|
|
{ \
|
|
temp = (temp & 0x0F) | ((temp + 0x60) & 0xF0); \
|
|
c_flag = 1; \
|
|
} \
|
|
else \
|
|
{ \
|
|
c_flag = 0; \
|
|
} \
|
|
A = (uint8) temp; \
|
|
} \
|
|
else \
|
|
{ \
|
|
A = (data >> 1) | (c_flag << 7); \
|
|
SET_NZ_FLAGS(A); \
|
|
c_flag = (A & 0x40) >> 6; \
|
|
v_flag = ((A >> 6) ^ (A >> 5)) & 1; \
|
|
}\
|
|
ADD_CYCLES(cycles); \
|
|
}
|
|
#else
|
|
#define ARR(cycles, read_func) \
|
|
{ \
|
|
read_func(data); \
|
|
data &= A; \
|
|
A = (data >> 1) | (c_flag << 7); \
|
|
SET_NZ_FLAGS(A); \
|
|
c_flag = (A & 0x40) >> 6; \
|
|
v_flag = ((A >> 6) ^ (A >> 5)) & 1; \
|
|
ADD_CYCLES(cycles); \
|
|
}
|
|
#endif /* NES6502_DECIMAL */
|
|
|
|
#define ASL(cycles, read_func, write_func, addr) \
|
|
{ \
|
|
read_func(addr, data); \
|
|
c_flag = data >> 7; \
|
|
data <<= 1; \
|
|
write_func(addr, data); \
|
|
SET_NZ_FLAGS(data); \
|
|
ADD_CYCLES(cycles); \
|
|
}
|
|
|
|
#define ASL_A() \
|
|
{ \
|
|
c_flag = A >> 7; \
|
|
A <<= 1; \
|
|
SET_NZ_FLAGS(A); \
|
|
ADD_CYCLES(2); \
|
|
}
|
|
|
|
/* undocumented */
|
|
#define ASR(cycles, read_func) \
|
|
{ \
|
|
read_func(data); \
|
|
data &= A; \
|
|
c_flag = data & 1; \
|
|
A = data >> 1; \
|
|
SET_NZ_FLAGS(A); \
|
|
ADD_CYCLES(cycles); \
|
|
}
|
|
|
|
#define BCC() \
|
|
{ \
|
|
RELATIVE_BRANCH(0 == c_flag); \
|
|
}
|
|
|
|
#define BCS() \
|
|
{ \
|
|
RELATIVE_BRANCH(0 != c_flag); \
|
|
}
|
|
|
|
#define BEQ() \
|
|
{ \
|
|
RELATIVE_BRANCH(0 == z_flag); \
|
|
}
|
|
|
|
/* bit 7/6 of data move into N/V flags */
|
|
#define BIT(cycles, read_func) \
|
|
{ \
|
|
read_func(data); \
|
|
n_flag = data; \
|
|
v_flag = data & V_FLAG; \
|
|
z_flag = data & A; \
|
|
ADD_CYCLES(cycles); \
|
|
}
|
|
|
|
#define BMI() \
|
|
{ \
|
|
RELATIVE_BRANCH(n_flag & N_FLAG); \
|
|
}
|
|
|
|
#define BNE() \
|
|
{ \
|
|
RELATIVE_BRANCH(0 != z_flag); \
|
|
}
|
|
|
|
#define BPL() \
|
|
{ \
|
|
RELATIVE_BRANCH(0 == (n_flag & N_FLAG)); \
|
|
}
|
|
|
|
/* Software interrupt type thang */
|
|
#define BRK() \
|
|
{ \
|
|
PC++; \
|
|
PUSH(PC >> 8); \
|
|
PUSH(PC & 0xFF); \
|
|
b_flag = 1; \
|
|
PUSH(COMBINE_FLAGS()); \
|
|
i_flag = 1; \
|
|
JUMP(IRQ_VECTOR); \
|
|
ADD_CYCLES(7); \
|
|
}
|
|
|
|
#define BVC() \
|
|
{ \
|
|
RELATIVE_BRANCH(0 == v_flag); \
|
|
}
|
|
|
|
#define BVS() \
|
|
{ \
|
|
RELATIVE_BRANCH(0 != v_flag); \
|
|
}
|
|
|
|
#define CLC() \
|
|
{ \
|
|
c_flag = 0; \
|
|
ADD_CYCLES(2); \
|
|
}
|
|
|
|
#define CLD() \
|
|
{ \
|
|
d_flag = 0; \
|
|
ADD_CYCLES(2); \
|
|
}
|
|
|
|
#define CLI() \
|
|
{ \
|
|
i_flag = 0; \
|
|
ADD_CYCLES(2); \
|
|
if (cpu.int_pending && remaining_cycles > 0) \
|
|
{ \
|
|
cpu.int_pending = 0; \
|
|
IRQ_PROC(); \
|
|
ADD_CYCLES(INT_CYCLES); \
|
|
} \
|
|
}
|
|
|
|
#define CLV() \
|
|
{ \
|
|
v_flag = 0; \
|
|
ADD_CYCLES(2); \
|
|
}
|
|
|
|
/* C is clear when data > A */
|
|
#define _COMPARE(reg, value) \
|
|
{ \
|
|
temp = (reg) - (value); \
|
|
c_flag = ((temp & 0x100) >> 8) ^ 1; \
|
|
SET_NZ_FLAGS((uint8) temp); \
|
|
}
|
|
|
|
#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, EMPTY_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, EMPTY_READ); \
|
|
}
|
|
|
|
/* TODO: make this a function callback */
|
|
#ifdef NES6502_TESTOPS
|
|
#define JAM() \
|
|
{ \
|
|
cpu_Jam(); \
|
|
}
|
|
#else /* !NES6502_TESTOPS */
|
|
#define JAM() \
|
|
{ \
|
|
PC--; \
|
|
cpu.jammed = true; \
|
|
cpu.int_pending = 0; \
|
|
ADD_CYCLES(2); \
|
|
}
|
|
#endif /* !NES6502_TESTOPS */
|
|
|
|
#define JMP_INDIRECT() \
|
|
{ \
|
|
temp = bank_readword(PC); \
|
|
/* bug in crossing page boundaries */ \
|
|
if (0xFF == (temp & 0xFF)) \
|
|
PC = (bank_readbyte(temp & 0xFF00) << 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); \
|
|
c_flag = data & 1; \
|
|
data >>= 1; \
|
|
write_func(addr, data); \
|
|
SET_NZ_FLAGS(data); \
|
|
ADD_CYCLES(cycles); \
|
|
}
|
|
|
|
#define LSR_A() \
|
|
{ \
|
|
c_flag = A & 1; \
|
|
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(COMBINE_FLAGS() | B_FLAG); \
|
|
ADD_CYCLES(3); \
|
|
}
|
|
|
|
#define PLA() \
|
|
{ \
|
|
A = PULL(); \
|
|
SET_NZ_FLAGS(A); \
|
|
ADD_CYCLES(4); \
|
|
}
|
|
|
|
#define PLP() \
|
|
{ \
|
|
btemp = PULL(); \
|
|
SCATTER_FLAGS(btemp); \
|
|
ADD_CYCLES(4); \
|
|
}
|
|
|
|
/* undocumented */
|
|
#define RLA(cycles, read_func, write_func, addr) \
|
|
{ \
|
|
read_func(addr, data); \
|
|
btemp = c_flag; \
|
|
c_flag = data >> 7; \
|
|
data = (data << 1) | btemp; \
|
|
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); \
|
|
btemp = c_flag; \
|
|
c_flag = data >> 7; \
|
|
data = (data << 1) | btemp; \
|
|
write_func(addr, data); \
|
|
SET_NZ_FLAGS(data); \
|
|
ADD_CYCLES(cycles); \
|
|
}
|
|
|
|
#define ROL_A() \
|
|
{ \
|
|
btemp = c_flag; \
|
|
c_flag = A >> 7; \
|
|
A = (A << 1) | btemp; \
|
|
SET_NZ_FLAGS(A); \
|
|
ADD_CYCLES(2); \
|
|
}
|
|
|
|
#define ROR(cycles, read_func, write_func, addr) \
|
|
{ \
|
|
read_func(addr, data); \
|
|
btemp = c_flag << 7; \
|
|
c_flag = data & 1; \
|
|
data = (data >> 1) | btemp; \
|
|
write_func(addr, data); \
|
|
SET_NZ_FLAGS(data); \
|
|
ADD_CYCLES(cycles); \
|
|
}
|
|
|
|
#define ROR_A() \
|
|
{ \
|
|
btemp = c_flag << 7; \
|
|
c_flag = A & 1; \
|
|
A = (A >> 1) | btemp; \
|
|
SET_NZ_FLAGS(A); \
|
|
ADD_CYCLES(2); \
|
|
}
|
|
|
|
/* undocumented */
|
|
#define RRA(cycles, read_func, write_func, addr) \
|
|
{ \
|
|
read_func(addr, data); \
|
|
btemp = c_flag << 7; \
|
|
c_flag = data & 1; \
|
|
data = (data >> 1) | btemp; \
|
|
write_func(addr, data); \
|
|
ADC(cycles, EMPTY_READ); \
|
|
}
|
|
|
|
#define RTI() \
|
|
{ \
|
|
btemp = PULL(); \
|
|
SCATTER_FLAGS(btemp); \
|
|
PC = PULL(); \
|
|
PC |= PULL() << 8; \
|
|
ADD_CYCLES(6); \
|
|
if (0 == i_flag && cpu.int_pending && remaining_cycles > 0) \
|
|
{ \
|
|
cpu.int_pending = 0; \
|
|
IRQ_PROC(); \
|
|
ADD_CYCLES(INT_CYCLES); \
|
|
} \
|
|
}
|
|
|
|
#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); \
|
|
temp = A - data - (c_flag ^ 1); \
|
|
if (d_flag) \
|
|
{ \
|
|
uint8 al, ah; \
|
|
al = (A & 0x0F) - (data & 0x0F) - (c_flag ^ 1); \
|
|
ah = (A >> 4) - (data >> 4); \
|
|
if (al & 0x10) \
|
|
{ \
|
|
al -= 6; \
|
|
ah--; \
|
|
} \
|
|
if (ah & 0x10) \
|
|
{ \
|
|
ah -= 6; \
|
|
c_flag = 0; \
|
|
} \
|
|
else \
|
|
{ \
|
|
c_flag = 1; \
|
|
} \
|
|
v_flag = (A ^ temp) & (A ^ data) & 0x80; \
|
|
SET_NZ_FLAGS(temp & 0xFF); \
|
|
A = (ah << 4) | (al & 0x0F); \
|
|
} \
|
|
else \
|
|
{ \
|
|
v_flag = (A ^ temp) & (A ^ data) & 0x80; \
|
|
c_flag = ((temp & 0x100) >> 8) ^ 1; \
|
|
A = (uint8) temp; \
|
|
SET_NZ_FLAGS(A & 0xFF); \
|
|
} \
|
|
ADD_CYCLES(cycles); \
|
|
}
|
|
#else
|
|
#define SBC(cycles, read_func) \
|
|
{ \
|
|
read_func(data); \
|
|
temp = A - data - (c_flag ^ 1); \
|
|
v_flag = (A ^ data) & (A ^ temp) & 0x80; \
|
|
c_flag = ((temp >> 8) & 1) ^ 1; \
|
|
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; \
|
|
c_flag = ((temp >> 8) & 1) ^ 1; \
|
|
X = temp & 0xFF; \
|
|
SET_NZ_FLAGS(X); \
|
|
ADD_CYCLES(cycles); \
|
|
}
|
|
|
|
#define SEC() \
|
|
{ \
|
|
c_flag = 1; \
|
|
ADD_CYCLES(2); \
|
|
}
|
|
|
|
#define SED() \
|
|
{ \
|
|
d_flag = 1; \
|
|
ADD_CYCLES(2); \
|
|
}
|
|
|
|
#define SEI() \
|
|
{ \
|
|
i_flag = 1; \
|
|
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); \
|
|
c_flag = data >> 7; \
|
|
data <<= 1; \
|
|
write_func(addr, data); \
|
|
A |= data; \
|
|
SET_NZ_FLAGS(A); \
|
|
ADD_CYCLES(cycles); \
|
|
}
|
|
|
|
/* undocumented */
|
|
#define SRE(cycles, read_func, write_func, addr) \
|
|
{ \
|
|
read_func(addr, data); \
|
|
c_flag = data & 1; \
|
|
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); \
|
|
}
|
|
|
|
|
|
|
|
/* internal CPU context */
|
|
static nes6502_context cpu;
|
|
static int remaining_cycles = 0; /* so we can release timeslice */
|
|
/* memory region pointers */
|
|
static uint8 *ram = NULL, *stack = NULL;
|
|
static uint8 null_page[NES6502_BANKSIZE];
|
|
|
|
|
|
/*
|
|
** Zero-page helper macros
|
|
*/
|
|
|
|
#define ZP_READBYTE(addr) ram[(addr)]
|
|
#define ZP_WRITEBYTE(addr, value) ram[(addr)] = (uint8) (value)
|
|
|
|
#ifdef HOST_LITTLE_ENDIAN
|
|
|
|
/* NOTE: following two functions will fail on architectures
|
|
** which do not support byte alignment
|
|
*/
|
|
INLINE uint32 zp_readword(register uint8 address)
|
|
{
|
|
return (uint32) (*(uint16 *)(ram + address));
|
|
}
|
|
|
|
INLINE uint32 bank_readword(register uint32 address)
|
|
{
|
|
/* technically, this should fail if the address is $xFFF, but
|
|
** any code that does this would be suspect anyway, as it would
|
|
** be fetching a word across page boundaries, which only would
|
|
** make sense if the banks were physically consecutive.
|
|
*/
|
|
return (uint32) (*(uint16 *)(cpu.mem_page[address >> NES6502_BANKSHIFT] + (address & NES6502_BANKMASK)));
|
|
}
|
|
|
|
#else /* !HOST_LITTLE_ENDIAN */
|
|
|
|
INLINE uint32 zp_readword(register uint8 address)
|
|
{
|
|
#ifdef TARGET_CPU_PPC
|
|
return __lhbrx(ram, address);
|
|
#else /* !TARGET_CPU_PPC */
|
|
uint32 x = (uint32) *(uint16 *)(ram + address);
|
|
return (x << 8) | (x >> 8);
|
|
#endif /* !TARGET_CPU_PPC */
|
|
}
|
|
|
|
INLINE uint32 bank_readword(register uint32 address)
|
|
{
|
|
#ifdef TARGET_CPU_PPC
|
|
return __lhbrx(cpu.mem_page[address >> NES6502_BANKSHIFT], address & NES6502_BANKMASK);
|
|
#else /* !TARGET_CPU_PPC */
|
|
uint32 x = (uint32) *(uint16 *)(cpu.mem_page[address >> NES6502_BANKSHIFT] + (address & NES6502_BANKMASK));
|
|
return (x << 8) | (x >> 8);
|
|
#endif /* !TARGET_CPU_PPC */
|
|
}
|
|
|
|
#endif /* !HOST_LITTLE_ENDIAN */
|
|
|
|
INLINE uint8 bank_readbyte(register uint32 address)
|
|
{
|
|
return cpu.mem_page[address >> NES6502_BANKSHIFT][address & NES6502_BANKMASK];
|
|
}
|
|
|
|
INLINE void bank_writebyte(register uint32 address, register uint8 value)
|
|
{
|
|
cpu.mem_page[address >> NES6502_BANKSHIFT][address & NES6502_BANKMASK] = value;
|
|
}
|
|
|
|
/* read a byte of 6502 memory */
|
|
static uint8 mem_readbyte(uint32 address)
|
|
{
|
|
nes6502_memread *mr;
|
|
|
|
/* TODO: following 2 cases are N2A03-specific */
|
|
if (address < 0x800)
|
|
{
|
|
/* RAM */
|
|
return ram[address];
|
|
}
|
|
else if (address >= 0x8000)
|
|
{
|
|
/* always paged memory */
|
|
return bank_readbyte(address);
|
|
}
|
|
/* check memory range handlers */
|
|
else
|
|
{
|
|
for (mr = cpu.read_handler; mr->min_range != 0xFFFFFFFF; mr++)
|
|
{
|
|
if (address >= mr->min_range && address <= mr->max_range)
|
|
return mr->read_func(address);
|
|
}
|
|
}
|
|
|
|
/* return paged memory */
|
|
return bank_readbyte(address);
|
|
}
|
|
|
|
/* write a byte of data to 6502 memory */
|
|
static void mem_writebyte(uint32 address, uint8 value)
|
|
{
|
|
nes6502_memwrite *mw;
|
|
|
|
/* RAM */
|
|
if (address < 0x800)
|
|
{
|
|
ram[address] = value;
|
|
return;
|
|
}
|
|
/* check memory range handlers */
|
|
else
|
|
{
|
|
for (mw = cpu.write_handler; mw->min_range != 0xFFFFFFFF; mw++)
|
|
{
|
|
if (address >= mw->min_range && address <= mw->max_range)
|
|
{
|
|
mw->write_func(address, value);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* write to paged memory */
|
|
bank_writebyte(address, value);
|
|
}
|
|
|
|
/* set the current context */
|
|
void nes6502_setcontext(nes6502_context *context)
|
|
{
|
|
int loop;
|
|
|
|
ASSERT(context);
|
|
|
|
cpu = *context;
|
|
|
|
/* set dead page for all pages not pointed at anything */
|
|
for (loop = 0; loop < NES6502_NUMBANKS; loop++)
|
|
{
|
|
if (NULL == cpu.mem_page[loop])
|
|
cpu.mem_page[loop] = null_page;
|
|
}
|
|
|
|
ram = cpu.mem_page[0]; /* quick zero-page/RAM references */
|
|
stack = ram + STACK_OFFSET;
|
|
}
|
|
|
|
/* get the current context */
|
|
void nes6502_getcontext(nes6502_context *context)
|
|
{
|
|
int loop;
|
|
|
|
ASSERT(context);
|
|
|
|
*context = cpu;
|
|
|
|
/* reset dead pages to null */
|
|
for (loop = 0; loop < NES6502_NUMBANKS; loop++)
|
|
{
|
|
if (null_page == context->mem_page[loop])
|
|
context->mem_page[loop] = NULL;
|
|
}
|
|
}
|
|
|
|
/* DMA a byte of data from ROM */
|
|
uint8 nes6502_getbyte(uint32 address)
|
|
{
|
|
return bank_readbyte(address);
|
|
}
|
|
|
|
/* get number of elapsed cycles */
|
|
uint32 nes6502_getcycles(bool reset_flag)
|
|
{
|
|
uint32 cycles = cpu.total_cycles;
|
|
|
|
if (reset_flag)
|
|
cpu.total_cycles = 0;
|
|
|
|
return cycles;
|
|
}
|
|
|
|
#define GET_GLOBAL_REGS() \
|
|
{ \
|
|
PC = cpu.pc_reg; \
|
|
A = cpu.a_reg; \
|
|
X = cpu.x_reg; \
|
|
Y = cpu.y_reg; \
|
|
SCATTER_FLAGS(cpu.p_reg); \
|
|
S = cpu.s_reg; \
|
|
}
|
|
|
|
#define STORE_LOCAL_REGS() \
|
|
{ \
|
|
cpu.pc_reg = PC; \
|
|
cpu.a_reg = A; \
|
|
cpu.x_reg = X; \
|
|
cpu.y_reg = Y; \
|
|
cpu.p_reg = COMBINE_FLAGS(); \
|
|
cpu.s_reg = S; \
|
|
}
|
|
|
|
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
|
|
|
#ifdef NES6502_JUMPTABLE
|
|
|
|
#define OPCODE_BEGIN(xx) op##xx:
|
|
#ifdef NES6502_DISASM
|
|
|
|
#define OPCODE_END \
|
|
if (remaining_cycles <= 0) \
|
|
goto end_execute; \
|
|
log_printf(nes6502_disasm(PC, COMBINE_FLAGS(), A, X, Y, S)); \
|
|
goto *opcode_table[bank_readbyte(PC++)];
|
|
|
|
#else /* !NES6520_DISASM */
|
|
|
|
#define OPCODE_END \
|
|
if (remaining_cycles <= 0) \
|
|
goto end_execute; \
|
|
goto *opcode_table[bank_readbyte(PC++)];
|
|
|
|
#endif /* !NES6502_DISASM */
|
|
|
|
#else /* !NES6502_JUMPTABLE */
|
|
#define OPCODE_BEGIN(xx) case 0x##xx:
|
|
#define OPCODE_END break;
|
|
#endif /* !NES6502_JUMPTABLE */
|
|
|
|
|
|
/* Execute instructions until count expires
|
|
**
|
|
** Returns the number of cycles *actually* executed, which will be
|
|
** anywhere from zero to timeslice_cycles + 6
|
|
*/
|
|
int nes6502_execute(int timeslice_cycles)
|
|
{
|
|
int old_cycles = cpu.total_cycles;
|
|
|
|
uint32 temp, addr; /* for macros */
|
|
uint8 btemp, baddr; /* for macros */
|
|
uint8 data;
|
|
|
|
/* flags */
|
|
uint8 n_flag, v_flag, b_flag;
|
|
uint8 d_flag, i_flag, z_flag, c_flag;
|
|
|
|
/* local copies of regs */
|
|
uint32 PC;
|
|
uint8 A, X, Y, S;
|
|
|
|
#ifdef NES6502_JUMPTABLE
|
|
|
|
static const void *opcode_table[256] =
|
|
{
|
|
&&op00, &&op01, &&op02, &&op03, &&op04, &&op05, &&op06, &&op07,
|
|
&&op08, &&op09, &&op0A, &&op0B, &&op0C, &&op0D, &&op0E, &&op0F,
|
|
&&op10, &&op11, &&op12, &&op13, &&op14, &&op15, &&op16, &&op17,
|
|
&&op18, &&op19, &&op1A, &&op1B, &&op1C, &&op1D, &&op1E, &&op1F,
|
|
&&op20, &&op21, &&op22, &&op23, &&op24, &&op25, &&op26, &&op27,
|
|
&&op28, &&op29, &&op2A, &&op2B, &&op2C, &&op2D, &&op2E, &&op2F,
|
|
&&op30, &&op31, &&op32, &&op33, &&op34, &&op35, &&op36, &&op37,
|
|
&&op38, &&op39, &&op3A, &&op3B, &&op3C, &&op3D, &&op3E, &&op3F,
|
|
&&op40, &&op41, &&op42, &&op43, &&op44, &&op45, &&op46, &&op47,
|
|
&&op48, &&op49, &&op4A, &&op4B, &&op4C, &&op4D, &&op4E, &&op4F,
|
|
&&op50, &&op51, &&op52, &&op53, &&op54, &&op55, &&op56, &&op57,
|
|
&&op58, &&op59, &&op5A, &&op5B, &&op5C, &&op5D, &&op5E, &&op5F,
|
|
&&op60, &&op61, &&op62, &&op63, &&op64, &&op65, &&op66, &&op67,
|
|
&&op68, &&op69, &&op6A, &&op6B, &&op6C, &&op6D, &&op6E, &&op6F,
|
|
&&op70, &&op71, &&op72, &&op73, &&op74, &&op75, &&op76, &&op77,
|
|
&&op78, &&op79, &&op7A, &&op7B, &&op7C, &&op7D, &&op7E, &&op7F,
|
|
&&op80, &&op81, &&op82, &&op83, &&op84, &&op85, &&op86, &&op87,
|
|
&&op88, &&op89, &&op8A, &&op8B, &&op8C, &&op8D, &&op8E, &&op8F,
|
|
&&op90, &&op91, &&op92, &&op93, &&op94, &&op95, &&op96, &&op97,
|
|
&&op98, &&op99, &&op9A, &&op9B, &&op9C, &&op9D, &&op9E, &&op9F,
|
|
&&opA0, &&opA1, &&opA2, &&opA3, &&opA4, &&opA5, &&opA6, &&opA7,
|
|
&&opA8, &&opA9, &&opAA, &&opAB, &&opAC, &&opAD, &&opAE, &&opAF,
|
|
&&opB0, &&opB1, &&opB2, &&opB3, &&opB4, &&opB5, &&opB6, &&opB7,
|
|
&&opB8, &&opB9, &&opBA, &&opBB, &&opBC, &&opBD, &&opBE, &&opBF,
|
|
&&opC0, &&opC1, &&opC2, &&opC3, &&opC4, &&opC5, &&opC6, &&opC7,
|
|
&&opC8, &&opC9, &&opCA, &&opCB, &&opCC, &&opCD, &&opCE, &&opCF,
|
|
&&opD0, &&opD1, &&opD2, &&opD3, &&opD4, &&opD5, &&opD6, &&opD7,
|
|
&&opD8, &&opD9, &&opDA, &&opDB, &&opDC, &&opDD, &&opDE, &&opDF,
|
|
&&opE0, &&opE1, &&opE2, &&opE3, &&opE4, &&opE5, &&opE6, &&opE7,
|
|
&&opE8, &&opE9, &&opEA, &&opEB, &&opEC, &&opED, &&opEE, &&opEF,
|
|
&&opF0, &&opF1, &&opF2, &&opF3, &&opF4, &&opF5, &&opF6, &&opF7,
|
|
&&opF8, &&opF9, &&opFA, &&opFB, &&opFC, &&opFD, &&opFE, &&opFF
|
|
};
|
|
|
|
#endif /* NES6502_JUMPTABLE */
|
|
|
|
remaining_cycles = timeslice_cycles;
|
|
|
|
GET_GLOBAL_REGS();
|
|
|
|
/* check for DMA cycle burning */
|
|
if (cpu.burn_cycles && remaining_cycles > 0)
|
|
{
|
|
int burn_for;
|
|
|
|
burn_for = MIN(remaining_cycles, cpu.burn_cycles);
|
|
ADD_CYCLES(burn_for);
|
|
cpu.burn_cycles -= burn_for;
|
|
}
|
|
|
|
if (0 == i_flag && cpu.int_pending && remaining_cycles > 0)
|
|
{
|
|
cpu.int_pending = 0;
|
|
IRQ_PROC();
|
|
ADD_CYCLES(INT_CYCLES);
|
|
}
|
|
|
|
#ifdef NES6502_JUMPTABLE
|
|
/* fetch first instruction */
|
|
OPCODE_END
|
|
|
|
#else /* !NES6502_JUMPTABLE */
|
|
|
|
/* Continue until we run out of cycles */
|
|
while (remaining_cycles > 0)
|
|
{
|
|
#ifdef NES6502_DISASM
|
|
log_printf(nes6502_disasm(PC, COMBINE_FLAGS(), A, X, Y, S));
|
|
#endif /* NES6502_DISASM */
|
|
|
|
/* Fetch and execute instruction */
|
|
switch (bank_readbyte(PC++))
|
|
{
|
|
#endif /* !NES6502_JUMPTABLE */
|
|
|
|
OPCODE_BEGIN(00) /* BRK */
|
|
BRK();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(01) /* ORA ($nn,X) */
|
|
ORA(6, INDIR_X_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(02) /* JAM */
|
|
OPCODE_BEGIN(12) /* JAM */
|
|
OPCODE_BEGIN(22) /* JAM */
|
|
OPCODE_BEGIN(32) /* JAM */
|
|
OPCODE_BEGIN(42) /* JAM */
|
|
OPCODE_BEGIN(52) /* JAM */
|
|
OPCODE_BEGIN(62) /* JAM */
|
|
OPCODE_BEGIN(72) /* JAM */
|
|
OPCODE_BEGIN(92) /* JAM */
|
|
OPCODE_BEGIN(B2) /* JAM */
|
|
OPCODE_BEGIN(D2) /* JAM */
|
|
OPCODE_BEGIN(F2) /* JAM */
|
|
JAM();
|
|
/* kill the CPU */
|
|
remaining_cycles = 0;
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(03) /* SLO ($nn,X) */
|
|
SLO(8, INDIR_X, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(04) /* NOP $nn */
|
|
OPCODE_BEGIN(44) /* NOP $nn */
|
|
OPCODE_BEGIN(64) /* NOP $nn */
|
|
DOP(3);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(05) /* ORA $nn */
|
|
ORA(3, ZERO_PAGE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(06) /* ASL $nn */
|
|
ASL(5, ZERO_PAGE, ZP_WRITEBYTE, baddr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(07) /* SLO $nn */
|
|
SLO(5, ZERO_PAGE, ZP_WRITEBYTE, baddr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(08) /* PHP */
|
|
PHP();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(09) /* ORA #$nn */
|
|
ORA(2, IMMEDIATE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(0A) /* ASL A */
|
|
ASL_A();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(0B) /* ANC #$nn */
|
|
ANC(2, IMMEDIATE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(0C) /* NOP $nnnn */
|
|
TOP();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(0D) /* ORA $nnnn */
|
|
ORA(4, ABSOLUTE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(0E) /* ASL $nnnn */
|
|
ASL(6, ABSOLUTE, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(0F) /* SLO $nnnn */
|
|
SLO(6, ABSOLUTE, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(10) /* BPL $nnnn */
|
|
BPL();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(11) /* ORA ($nn),Y */
|
|
ORA(5, INDIR_Y_BYTE_READ);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(13) /* SLO ($nn),Y */
|
|
SLO(8, INDIR_Y, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(14) /* NOP $nn,X */
|
|
OPCODE_BEGIN(34) /* NOP */
|
|
OPCODE_BEGIN(54) /* NOP $nn,X */
|
|
OPCODE_BEGIN(74) /* NOP $nn,X */
|
|
OPCODE_BEGIN(D4) /* NOP $nn,X */
|
|
OPCODE_BEGIN(F4) /* NOP ($nn,X) */
|
|
DOP(4);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(15) /* ORA $nn,X */
|
|
ORA(4, ZP_IND_X_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(16) /* ASL $nn,X */
|
|
ASL(6, ZP_IND_X, ZP_WRITEBYTE, baddr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(17) /* SLO $nn,X */
|
|
SLO(6, ZP_IND_X, ZP_WRITEBYTE, baddr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(18) /* CLC */
|
|
CLC();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(19) /* ORA $nnnn,Y */
|
|
ORA(4, ABS_IND_Y_BYTE_READ);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(1A) /* NOP */
|
|
OPCODE_BEGIN(3A) /* NOP */
|
|
OPCODE_BEGIN(5A) /* NOP */
|
|
OPCODE_BEGIN(7A) /* NOP */
|
|
OPCODE_BEGIN(DA) /* NOP */
|
|
OPCODE_BEGIN(FA) /* NOP */
|
|
NOP();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(1B) /* SLO $nnnn,Y */
|
|
SLO(7, ABS_IND_Y, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(1C) /* NOP $nnnn,X */
|
|
OPCODE_BEGIN(3C) /* NOP $nnnn,X */
|
|
OPCODE_BEGIN(5C) /* NOP $nnnn,X */
|
|
OPCODE_BEGIN(7C) /* NOP $nnnn,X */
|
|
OPCODE_BEGIN(DC) /* NOP $nnnn,X */
|
|
OPCODE_BEGIN(FC) /* NOP $nnnn,X */
|
|
TOP();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(1D) /* ORA $nnnn,X */
|
|
ORA(4, ABS_IND_X_BYTE_READ);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(1E) /* ASL $nnnn,X */
|
|
ASL(7, ABS_IND_X, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(1F) /* SLO $nnnn,X */
|
|
SLO(7, ABS_IND_X, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(20) /* JSR $nnnn */
|
|
JSR();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(21) /* AND ($nn,X) */
|
|
AND(6, INDIR_X_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(23) /* RLA ($nn,X) */
|
|
RLA(8, INDIR_X, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(24) /* BIT $nn */
|
|
BIT(3, ZERO_PAGE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(25) /* AND $nn */
|
|
AND(3, ZERO_PAGE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(26) /* ROL $nn */
|
|
ROL(5, ZERO_PAGE, ZP_WRITEBYTE, baddr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(27) /* RLA $nn */
|
|
RLA(5, ZERO_PAGE, ZP_WRITEBYTE, baddr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(28) /* PLP */
|
|
PLP();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(29) /* AND #$nn */
|
|
AND(2, IMMEDIATE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(2A) /* ROL A */
|
|
ROL_A();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(2B) /* ANC #$nn */
|
|
ANC(2, IMMEDIATE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(2C) /* BIT $nnnn */
|
|
BIT(4, ABSOLUTE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(2D) /* AND $nnnn */
|
|
AND(4, ABSOLUTE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(2E) /* ROL $nnnn */
|
|
ROL(6, ABSOLUTE, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(2F) /* RLA $nnnn */
|
|
RLA(6, ABSOLUTE, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(30) /* BMI $nnnn */
|
|
BMI();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(31) /* AND ($nn),Y */
|
|
AND(5, INDIR_Y_BYTE_READ);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(33) /* RLA ($nn),Y */
|
|
RLA(8, INDIR_Y, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(35) /* AND $nn,X */
|
|
AND(4, ZP_IND_X_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(36) /* ROL $nn,X */
|
|
ROL(6, ZP_IND_X, ZP_WRITEBYTE, baddr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(37) /* RLA $nn,X */
|
|
RLA(6, ZP_IND_X, ZP_WRITEBYTE, baddr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(38) /* SEC */
|
|
SEC();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(39) /* AND $nnnn,Y */
|
|
AND(4, ABS_IND_Y_BYTE_READ);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(3B) /* RLA $nnnn,Y */
|
|
RLA(7, ABS_IND_Y, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(3D) /* AND $nnnn,X */
|
|
AND(4, ABS_IND_X_BYTE_READ);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(3E) /* ROL $nnnn,X */
|
|
ROL(7, ABS_IND_X, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(3F) /* RLA $nnnn,X */
|
|
RLA(7, ABS_IND_X, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(40) /* RTI */
|
|
RTI();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(41) /* EOR ($nn,X) */
|
|
EOR(6, INDIR_X_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(43) /* SRE ($nn,X) */
|
|
SRE(8, INDIR_X, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(45) /* EOR $nn */
|
|
EOR(3, ZERO_PAGE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(46) /* LSR $nn */
|
|
LSR(5, ZERO_PAGE, ZP_WRITEBYTE, baddr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(47) /* SRE $nn */
|
|
SRE(5, ZERO_PAGE, ZP_WRITEBYTE, baddr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(48) /* PHA */
|
|
PHA();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(49) /* EOR #$nn */
|
|
EOR(2, IMMEDIATE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(4A) /* LSR A */
|
|
LSR_A();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(4B) /* ASR #$nn */
|
|
ASR(2, IMMEDIATE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(4C) /* JMP $nnnn */
|
|
JMP_ABSOLUTE();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(4D) /* EOR $nnnn */
|
|
EOR(4, ABSOLUTE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(4E) /* LSR $nnnn */
|
|
LSR(6, ABSOLUTE, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(4F) /* SRE $nnnn */
|
|
SRE(6, ABSOLUTE, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(50) /* BVC $nnnn */
|
|
BVC();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(51) /* EOR ($nn),Y */
|
|
EOR(5, INDIR_Y_BYTE_READ);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(53) /* SRE ($nn),Y */
|
|
SRE(8, INDIR_Y, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(55) /* EOR $nn,X */
|
|
EOR(4, ZP_IND_X_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(56) /* LSR $nn,X */
|
|
LSR(6, ZP_IND_X, ZP_WRITEBYTE, baddr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(57) /* SRE $nn,X */
|
|
SRE(6, ZP_IND_X, ZP_WRITEBYTE, baddr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(58) /* CLI */
|
|
CLI();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(59) /* EOR $nnnn,Y */
|
|
EOR(4, ABS_IND_Y_BYTE_READ);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(5B) /* SRE $nnnn,Y */
|
|
SRE(7, ABS_IND_Y, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(5D) /* EOR $nnnn,X */
|
|
EOR(4, ABS_IND_X_BYTE_READ);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(5E) /* LSR $nnnn,X */
|
|
LSR(7, ABS_IND_X, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(5F) /* SRE $nnnn,X */
|
|
SRE(7, ABS_IND_X, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(60) /* RTS */
|
|
RTS();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(61) /* ADC ($nn,X) */
|
|
ADC(6, INDIR_X_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(63) /* RRA ($nn,X) */
|
|
RRA(8, INDIR_X, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(65) /* ADC $nn */
|
|
ADC(3, ZERO_PAGE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(66) /* ROR $nn */
|
|
ROR(5, ZERO_PAGE, ZP_WRITEBYTE, baddr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(67) /* RRA $nn */
|
|
RRA(5, ZERO_PAGE, ZP_WRITEBYTE, baddr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(68) /* PLA */
|
|
PLA();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(69) /* ADC #$nn */
|
|
ADC(2, IMMEDIATE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(6A) /* ROR A */
|
|
ROR_A();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(6B) /* ARR #$nn */
|
|
ARR(2, IMMEDIATE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(6C) /* JMP ($nnnn) */
|
|
JMP_INDIRECT();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(6D) /* ADC $nnnn */
|
|
ADC(4, ABSOLUTE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(6E) /* ROR $nnnn */
|
|
ROR(6, ABSOLUTE, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(6F) /* RRA $nnnn */
|
|
RRA(6, ABSOLUTE, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(70) /* BVS $nnnn */
|
|
BVS();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(71) /* ADC ($nn),Y */
|
|
ADC(5, INDIR_Y_BYTE_READ);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(73) /* RRA ($nn),Y */
|
|
RRA(8, INDIR_Y, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(75) /* ADC $nn,X */
|
|
ADC(4, ZP_IND_X_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(76) /* ROR $nn,X */
|
|
ROR(6, ZP_IND_X, ZP_WRITEBYTE, baddr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(77) /* RRA $nn,X */
|
|
RRA(6, ZP_IND_X, ZP_WRITEBYTE, baddr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(78) /* SEI */
|
|
SEI();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(79) /* ADC $nnnn,Y */
|
|
ADC(4, ABS_IND_Y_BYTE_READ);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(7B) /* RRA $nnnn,Y */
|
|
RRA(7, ABS_IND_Y, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(7D) /* ADC $nnnn,X */
|
|
ADC(4, ABS_IND_X_BYTE_READ);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(7E) /* ROR $nnnn,X */
|
|
ROR(7, ABS_IND_X, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(7F) /* RRA $nnnn,X */
|
|
RRA(7, ABS_IND_X, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(80) /* NOP #$nn */
|
|
OPCODE_BEGIN(82) /* NOP #$nn */
|
|
OPCODE_BEGIN(89) /* NOP #$nn */
|
|
OPCODE_BEGIN(C2) /* NOP #$nn */
|
|
OPCODE_BEGIN(E2) /* NOP #$nn */
|
|
DOP(2);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(81) /* STA ($nn,X) */
|
|
STA(6, INDIR_X_ADDR, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(83) /* SAX ($nn,X) */
|
|
SAX(6, INDIR_X_ADDR, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(84) /* STY $nn */
|
|
STY(3, ZERO_PAGE_ADDR, ZP_WRITEBYTE, baddr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(85) /* STA $nn */
|
|
STA(3, ZERO_PAGE_ADDR, ZP_WRITEBYTE, baddr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(86) /* STX $nn */
|
|
STX(3, ZERO_PAGE_ADDR, ZP_WRITEBYTE, baddr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(87) /* SAX $nn */
|
|
SAX(3, ZERO_PAGE_ADDR, ZP_WRITEBYTE, baddr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(88) /* DEY */
|
|
DEY();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(8A) /* TXA */
|
|
TXA();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(8B) /* ANE #$nn */
|
|
ANE(2, IMMEDIATE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(8C) /* STY $nnnn */
|
|
STY(4, ABSOLUTE_ADDR, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(8D) /* STA $nnnn */
|
|
STA(4, ABSOLUTE_ADDR, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(8E) /* STX $nnnn */
|
|
STX(4, ABSOLUTE_ADDR, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(8F) /* SAX $nnnn */
|
|
SAX(4, ABSOLUTE_ADDR, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(90) /* BCC $nnnn */
|
|
BCC();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(91) /* STA ($nn),Y */
|
|
STA(6, INDIR_Y_ADDR, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(93) /* SHA ($nn),Y */
|
|
SHA(6, INDIR_Y_ADDR, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(94) /* STY $nn,X */
|
|
STY(4, ZP_IND_X_ADDR, ZP_WRITEBYTE, baddr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(95) /* STA $nn,X */
|
|
STA(4, ZP_IND_X_ADDR, ZP_WRITEBYTE, baddr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(96) /* STX $nn,Y */
|
|
STX(4, ZP_IND_Y_ADDR, ZP_WRITEBYTE, baddr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(97) /* SAX $nn,Y */
|
|
SAX(4, ZP_IND_Y_ADDR, ZP_WRITEBYTE, baddr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(98) /* TYA */
|
|
TYA();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(99) /* STA $nnnn,Y */
|
|
STA(5, ABS_IND_Y_ADDR, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(9A) /* TXS */
|
|
TXS();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(9B) /* SHS $nnnn,Y */
|
|
SHS(5, ABS_IND_Y_ADDR, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(9C) /* SHY $nnnn,X */
|
|
SHY(5, ABS_IND_X_ADDR, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(9D) /* STA $nnnn,X */
|
|
STA(5, ABS_IND_X_ADDR, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(9E) /* SHX $nnnn,Y */
|
|
SHX(5, ABS_IND_Y_ADDR, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(9F) /* SHA $nnnn,Y */
|
|
SHA(5, ABS_IND_Y_ADDR, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(A0) /* LDY #$nn */
|
|
LDY(2, IMMEDIATE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(A1) /* LDA ($nn,X) */
|
|
LDA(6, INDIR_X_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(A2) /* LDX #$nn */
|
|
LDX(2, IMMEDIATE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(A3) /* LAX ($nn,X) */
|
|
LAX(6, INDIR_X_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(A4) /* LDY $nn */
|
|
LDY(3, ZERO_PAGE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(A5) /* LDA $nn */
|
|
LDA(3, ZERO_PAGE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(A6) /* LDX $nn */
|
|
LDX(3, ZERO_PAGE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(A7) /* LAX $nn */
|
|
LAX(3, ZERO_PAGE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(A8) /* TAY */
|
|
TAY();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(A9) /* LDA #$nn */
|
|
LDA(2, IMMEDIATE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(AA) /* TAX */
|
|
TAX();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(AB) /* LXA #$nn */
|
|
LXA(2, IMMEDIATE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(AC) /* LDY $nnnn */
|
|
LDY(4, ABSOLUTE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(AD) /* LDA $nnnn */
|
|
LDA(4, ABSOLUTE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(AE) /* LDX $nnnn */
|
|
LDX(4, ABSOLUTE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(AF) /* LAX $nnnn */
|
|
LAX(4, ABSOLUTE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(B0) /* BCS $nnnn */
|
|
BCS();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(B1) /* LDA ($nn),Y */
|
|
LDA(5, INDIR_Y_BYTE_READ);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(B3) /* LAX ($nn),Y */
|
|
LAX(5, INDIR_Y_BYTE_READ);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(B4) /* LDY $nn,X */
|
|
LDY(4, ZP_IND_X_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(B5) /* LDA $nn,X */
|
|
LDA(4, ZP_IND_X_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(B6) /* LDX $nn,Y */
|
|
LDX(4, ZP_IND_Y_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(B7) /* LAX $nn,Y */
|
|
LAX(4, ZP_IND_Y_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(B8) /* CLV */
|
|
CLV();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(B9) /* LDA $nnnn,Y */
|
|
LDA(4, ABS_IND_Y_BYTE_READ);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(BA) /* TSX */
|
|
TSX();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(BB) /* LAS $nnnn,Y */
|
|
LAS(4, ABS_IND_Y_BYTE_READ);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(BC) /* LDY $nnnn,X */
|
|
LDY(4, ABS_IND_X_BYTE_READ);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(BD) /* LDA $nnnn,X */
|
|
LDA(4, ABS_IND_X_BYTE_READ);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(BE) /* LDX $nnnn,Y */
|
|
LDX(4, ABS_IND_Y_BYTE_READ);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(BF) /* LAX $nnnn,Y */
|
|
LAX(4, ABS_IND_Y_BYTE_READ);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(C0) /* CPY #$nn */
|
|
CPY(2, IMMEDIATE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(C1) /* CMP ($nn,X) */
|
|
CMP(6, INDIR_X_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(C3) /* DCP ($nn,X) */
|
|
DCP(8, INDIR_X, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(C4) /* CPY $nn */
|
|
CPY(3, ZERO_PAGE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(C5) /* CMP $nn */
|
|
CMP(3, ZERO_PAGE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(C6) /* DEC $nn */
|
|
DEC(5, ZERO_PAGE, ZP_WRITEBYTE, baddr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(C7) /* DCP $nn */
|
|
DCP(5, ZERO_PAGE, ZP_WRITEBYTE, baddr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(C8) /* INY */
|
|
INY();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(C9) /* CMP #$nn */
|
|
CMP(2, IMMEDIATE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(CA) /* DEX */
|
|
DEX();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(CB) /* SBX #$nn */
|
|
SBX(2, IMMEDIATE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(CC) /* CPY $nnnn */
|
|
CPY(4, ABSOLUTE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(CD) /* CMP $nnnn */
|
|
CMP(4, ABSOLUTE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(CE) /* DEC $nnnn */
|
|
DEC(6, ABSOLUTE, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(CF) /* DCP $nnnn */
|
|
DCP(6, ABSOLUTE, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(D0) /* BNE $nnnn */
|
|
BNE();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(D1) /* CMP ($nn),Y */
|
|
CMP(5, INDIR_Y_BYTE_READ);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(D3) /* DCP ($nn),Y */
|
|
DCP(8, INDIR_Y, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(D5) /* CMP $nn,X */
|
|
CMP(4, ZP_IND_X_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(D6) /* DEC $nn,X */
|
|
DEC(6, ZP_IND_X, ZP_WRITEBYTE, baddr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(D7) /* DCP $nn,X */
|
|
DCP(6, ZP_IND_X, ZP_WRITEBYTE, baddr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(D8) /* CLD */
|
|
CLD();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(D9) /* CMP $nnnn,Y */
|
|
CMP(4, ABS_IND_Y_BYTE_READ);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(DB) /* DCP $nnnn,Y */
|
|
DCP(7, ABS_IND_Y, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(DD) /* CMP $nnnn,X */
|
|
CMP(4, ABS_IND_X_BYTE_READ);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(DE) /* DEC $nnnn,X */
|
|
DEC(7, ABS_IND_X, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(DF) /* DCP $nnnn,X */
|
|
DCP(7, ABS_IND_X, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(E0) /* CPX #$nn */
|
|
CPX(2, IMMEDIATE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(E1) /* SBC ($nn,X) */
|
|
SBC(6, INDIR_X_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(E3) /* ISB ($nn,X) */
|
|
ISB(8, INDIR_X, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(E4) /* CPX $nn */
|
|
CPX(3, ZERO_PAGE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(E5) /* SBC $nn */
|
|
SBC(3, ZERO_PAGE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(E6) /* INC $nn */
|
|
INC(5, ZERO_PAGE, ZP_WRITEBYTE, baddr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(E7) /* ISB $nn */
|
|
ISB(5, ZERO_PAGE, ZP_WRITEBYTE, baddr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(E8) /* INX */
|
|
INX();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(E9) /* SBC #$nn */
|
|
OPCODE_BEGIN(EB) /* USBC #$nn */
|
|
SBC(2, IMMEDIATE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(EA) /* NOP */
|
|
NOP();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(EC) /* CPX $nnnn */
|
|
CPX(4, ABSOLUTE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(ED) /* SBC $nnnn */
|
|
SBC(4, ABSOLUTE_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(EE) /* INC $nnnn */
|
|
INC(6, ABSOLUTE, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(EF) /* ISB $nnnn */
|
|
ISB(6, ABSOLUTE, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(F0) /* BEQ $nnnn */
|
|
BEQ();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(F1) /* SBC ($nn),Y */
|
|
SBC(5, INDIR_Y_BYTE_READ);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(F3) /* ISB ($nn),Y */
|
|
ISB(8, INDIR_Y, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(F5) /* SBC $nn,X */
|
|
SBC(4, ZP_IND_X_BYTE);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(F6) /* INC $nn,X */
|
|
INC(6, ZP_IND_X, ZP_WRITEBYTE, baddr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(F7) /* ISB $nn,X */
|
|
ISB(6, ZP_IND_X, ZP_WRITEBYTE, baddr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(F8) /* SED */
|
|
SED();
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(F9) /* SBC $nnnn,Y */
|
|
SBC(4, ABS_IND_Y_BYTE_READ);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(FB) /* ISB $nnnn,Y */
|
|
ISB(7, ABS_IND_Y, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(FD) /* SBC $nnnn,X */
|
|
SBC(4, ABS_IND_X_BYTE_READ);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(FE) /* INC $nnnn,X */
|
|
INC(7, ABS_IND_X, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
OPCODE_BEGIN(FF) /* ISB $nnnn,X */
|
|
ISB(7, ABS_IND_X, mem_writebyte, addr);
|
|
OPCODE_END
|
|
|
|
#ifdef NES6502_JUMPTABLE
|
|
end_execute:
|
|
|
|
#else /* !NES6502_JUMPTABLE */
|
|
}
|
|
}
|
|
#endif /* !NES6502_JUMPTABLE */
|
|
|
|
/* store local copy of regs */
|
|
STORE_LOCAL_REGS();
|
|
|
|
/* Return our actual amount of executed cycles */
|
|
return (cpu.total_cycles - old_cycles);
|
|
}
|
|
|
|
/* Issue a CPU Reset */
|
|
void nes6502_reset(void)
|
|
{
|
|
cpu.p_reg = Z_FLAG | R_FLAG | I_FLAG; /* Reserved bit always 1 */
|
|
cpu.int_pending = 0; /* No pending interrupts */
|
|
cpu.int_latency = 0; /* No latent interrupts */
|
|
cpu.pc_reg = bank_readword(RESET_VECTOR); /* Fetch reset vector */
|
|
cpu.burn_cycles = RESET_CYCLES;
|
|
cpu.jammed = false;
|
|
}
|
|
|
|
/* following macro is used for below 2 functions */
|
|
#define DECLARE_LOCAL_REGS \
|
|
uint32 PC; \
|
|
uint8 A, X, Y, S; \
|
|
uint8 n_flag, v_flag, b_flag; \
|
|
uint8 d_flag, i_flag, z_flag, c_flag;
|
|
|
|
/* Non-maskable interrupt */
|
|
void nes6502_nmi(void)
|
|
{
|
|
DECLARE_LOCAL_REGS
|
|
|
|
if (false == cpu.jammed)
|
|
{
|
|
GET_GLOBAL_REGS();
|
|
NMI_PROC();
|
|
cpu.burn_cycles += INT_CYCLES;
|
|
STORE_LOCAL_REGS();
|
|
}
|
|
}
|
|
|
|
/* Interrupt request */
|
|
void nes6502_irq(void)
|
|
{
|
|
DECLARE_LOCAL_REGS
|
|
|
|
if (false == cpu.jammed)
|
|
{
|
|
GET_GLOBAL_REGS();
|
|
if (0 == i_flag)
|
|
{
|
|
IRQ_PROC();
|
|
cpu.burn_cycles += INT_CYCLES;
|
|
}
|
|
else
|
|
{
|
|
cpu.int_pending = 1;
|
|
}
|
|
STORE_LOCAL_REGS();
|
|
}
|
|
}
|
|
|
|
/* Set dead cycle period */
|
|
void nes6502_burn(int cycles)
|
|
{
|
|
cpu.burn_cycles += cycles;
|
|
}
|
|
|
|
/* Release our timeslice */
|
|
void nes6502_release(void)
|
|
{
|
|
remaining_cycles = 0;
|
|
}
|
|
|
|
/*
|
|
** $Log: nes6502.c,v $
|
|
** Revision 1.2 2001/04/27 14:37:11 neil
|
|
** wheeee
|
|
**
|
|
** Revision 1.1 2001/04/27 12:54:39 neil
|
|
** blah
|
|
**
|
|
** Revision 1.1.1.1 2001/04/27 07:03:54 neil
|
|
** initial
|
|
**
|
|
** Revision 1.34 2000/11/27 19:33:07 matt
|
|
** concise interrupts
|
|
**
|
|
** Revision 1.33 2000/11/26 15:39:54 matt
|
|
** timing fixes
|
|
**
|
|
** Revision 1.32 2000/11/20 13:22:51 matt
|
|
** added note about word fetches across page boundaries
|
|
**
|
|
** Revision 1.31 2000/11/13 00:57:39 matt
|
|
** trying to add 1-instruction interrupt latency... and failing.
|
|
**
|
|
** Revision 1.30 2000/10/10 13:58:14 matt
|
|
** stroustrup squeezing his way in the door
|
|
**
|
|
** Revision 1.29 2000/10/10 13:05:05 matt
|
|
** Mr. Clean makes a guest appearance
|
|
**
|
|
** Revision 1.28 2000/10/08 17:55:41 matt
|
|
** check burn cycles before ints
|
|
**
|
|
** Revision 1.27 2000/09/15 03:42:32 matt
|
|
** nes6502_release to release current timeslice
|
|
**
|
|
** Revision 1.26 2000/09/15 03:16:17 matt
|
|
** optimized C flag handling, and ADC/SBC/ROL/ROR macros
|
|
**
|
|
** Revision 1.25 2000/09/14 02:12:03 matt
|
|
** disassembling now works with goto table, and removed memcpy from context get/set
|
|
**
|
|
** Revision 1.24 2000/09/11 03:55:57 matt
|
|
** cosmetics
|
|
**
|
|
** Revision 1.23 2000/09/11 01:45:45 matt
|
|
** flag optimizations. this thing is fast!
|
|
**
|
|
** Revision 1.22 2000/09/08 13:29:25 matt
|
|
** added switch()-less execution for gcc
|
|
**
|
|
** Revision 1.21 2000/09/08 11:54:48 matt
|
|
** optimize
|
|
**
|
|
** Revision 1.20 2000/09/07 21:58:18 matt
|
|
** api change for nes6502_burn, optimized core
|
|
**
|
|
** Revision 1.19 2000/09/07 13:39:01 matt
|
|
** resolved a few conflicts
|
|
**
|
|
** Revision 1.18 2000/09/07 01:34:55 matt
|
|
** nes6502_init deprecated, moved flag regs to separate vars
|
|
**
|
|
** Revision 1.17 2000/08/31 13:26:35 matt
|
|
** added DISASM flag, to sync with asm version
|
|
**
|
|
** Revision 1.16 2000/08/29 05:38:00 matt
|
|
** removed faulty failure note
|
|
**
|
|
** Revision 1.15 2000/08/28 12:53:44 matt
|
|
** fixes for disassembler
|
|
**
|
|
** Revision 1.14 2000/08/28 04:32:28 matt
|
|
** naming convention changes
|
|
**
|
|
** Revision 1.13 2000/08/28 01:46:15 matt
|
|
** moved some of them defines around, cleaned up jamming code
|
|
**
|
|
** Revision 1.12 2000/08/16 04:56:37 matt
|
|
** accurate CPU jamming, added dead page emulation
|
|
**
|
|
** Revision 1.11 2000/07/30 04:32:00 matt
|
|
** now emulates the NES frame IRQ
|
|
**
|
|
** Revision 1.10 2000/07/17 01:52:28 matt
|
|
** made sure last line of all source files is a newline
|
|
**
|
|
** Revision 1.9 2000/07/11 04:27:18 matt
|
|
** new disassembler calling convention
|
|
**
|
|
** Revision 1.8 2000/07/10 05:26:38 matt
|
|
** cosmetic
|
|
**
|
|
** Revision 1.7 2000/07/06 17:10:51 matt
|
|
** minor (er, spelling) error fixed
|
|
**
|
|
** 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
|
|
**
|
|
*/
|