cc65/src/sim65/6502.c

4140 lines
85 KiB
C

/*****************************************************************************/
/* */
/* 6502.c */
/* */
/* CPU core for the 6502 */
/* */
/* */
/* */
/* (C) 2003-2012, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* */
/* Mar-2017, Christian Krueger, added support for 65SC02 */
/* Dec-2023, Carlo Bramini, rewritten for better maintenance and added */
/* support for undocumented opcodes for 6502 */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
/* Known bugs and limitations of the 65C02 simulation:
* support currently only on the level of 65SC02:
BBRx, BBSx, RMBx, SMBx, WAI, and STP are unsupported
* BCD flag handling equals 6502 (unchecked if bug is simulated or wrong for
6502)
*/
#include "memory.h"
#include "error.h"
#include "6502.h"
#include "paravirt.h"
/*
6502 opcode map:
x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF
0x BRK ORA --- SLO NOP ORA ASL SLO PHP ORA ASL ANC NOP ORA ASL SLO
inx inx zp zp zp zp imm acc imm abs abs abs abs
1x BPL ORA --- SLO NOP ORA ASL SLO CLC ORA NOP SLO NOP ORA ASL SLO
rel iny iny zpx zpx zpx zpy aby aby abx abx abx abx
2x JSR AND --- RLA BIT AND ROL RLA PLP AND ROL ANC BIT AND ROL RLA
abs inx inx zp zp zp zp imm acc imm abs abs abs abs
3x BMI AND --- RLA NOP AND ROL RLA SEC AND NOP RLA NOP AND ROL RLA
rel iny iny zpx zpx zpx zpy aby aby abx abx abx abx
4x RTI EOR --- SRE NOP EOR LSR SRE PHA EOR LSR ASR JMP EOR LSR SRE
inx inx zp zp zp zp imm acc imm abs abs abs abs
5x BVC EOR --- SRE NOP EOR LSR SRE CLI EOR NOP SRE NOP EOR LSR SRE
rel iny iny zpx zpx zpx zpx aby aby abx abx abx abx
6x RTS ADC --- RRA NOP ADC ROR RRA PLA ADC ROR ARR JMP ADC ROR RRA
inx inx zp zp zp zp imm acc imm ind abs abs abs
7x BVS ADC --- RRA NOP ADC ROR RRA SEI ADC NOP RRA NOP ADC ROR RRA
rel iny iny zpx zpx zpx zpx aby aby abx abx abx abx
8x NOP STA NOP SAX STY STA STX SAX DEY NOP TXA ANE STY STA STX SAX
imm inx imm inx zp zp zp zp imm imm abs abs abs abs
9x BCC STA --- SHA STY STA STX SAX TYA STA TXS TAS SHY STA SHX SHA
rel iny iny zpx zpx zpy zpy aby aby abx abx aby aby
Ax LDY LDA LDX LAX LDY LDA LDX LAX TAY LDA TAX LXA LDY LDA LDX LAX
imm inx imm inx zp zp zp zp imm imm abs abs abs abs
Bx BCS LDA --- LAX LDY LDA LDX LAX CLV LDA TSX LAS LDY LDA LDX LAX
rel iny iny zpx zpx zpy zpy aby aby abx abx aby aby
Cx CPY CMP NOP DCP CPY CMP DEC DCP INY CMP DEX SBX CPY CMP DEC DCP
imm inx imm inx zp zp zp zp imm imm abs abs abs abs
Dx BNE CMP --- DCP NOP CMP DEC DCP CLD CMP NOP DCP NOP CMP DEC DCP
rel iny iny zpx zpx zpx zpx aby zpx aby abx abx abx abx
Ex CPX SBC NOP ISC CPX SBC INC ISC INX SBC NOP SBC CPX SBC INC ISC
imm inx imm inx zp zp zp zp imm imm abs abs abs abs
Fx BEQ SBC --- ISC NOP SBC INC ISC SED SBC NOP ISC NOP SBC INC ISC
rel iny iny zpx zpx zpx zpx aby zpx aby abx abx abx abx
--- = CPU JAM/HALT
*/
/*
65xx ILLEGAL INSTRUCTIONS
* SLO: shift left the contents of a memory location and then OR the result with
the accumulator.
Address mode | opcode | cycles | N V B D I Z C
-------------+--------+--------+ FLAGS: X . . . . X X
SLO abs | 0Fh | 6 |
SLO abs,X | 1Fh | 7 |
SLO abs,Y | 1Bh | 7 |
SLO zp | 07h | 5 |
SLO zp,X | 17h | 6 |
SLO (zp,X) | 03h | 8 |
SLO (zp),Y | 13h | 8 |
-------------+--------+--------+
* RLA: rotate left the contents of a memory location and then AND the result with
the accumulator.
Address mode | opcode | cycles | N V B D I Z C
-------------+--------+--------+ FLAGS: X . . . . X X
RLA abs | 2Fh | 6 |
RLA abs,X | 3Fh | 7 |
RLA abs,Y | 3Bh | 7 |
RLA zp | 27h | 5 |
RLA zp,X | 37h | 6 |
RLA (zp,X) | 23h | 8 |
RLA (zp),Y | 33h | 8 |
-------------+--------+--------+
* SRE: shift right the contents of a memory location and then X-OR the result
with the accumulator.
Address mode | opcode | cycles | N V B D I Z C
-------------+--------+--------+ FLAGS: X . . . . X X
SRE abs | 4Fh | 6 |
SRE abs,X | 5Fh | 7 |
SRE abs,Y | 5Bh | 7 |
SRE zp | 47h | 5 |
SRE zp,X | 57h | 6 |
SRE (zp,X) | 43h | 8 |
SRE (zp),Y | 53h | 8 |
-------------+--------+--------+
* RRA: rotate right the contents of a memory location and then adds with carry
the result with the accumulator.
Address mode | opcode | cycles | N V B D I Z C
-------------+--------+--------+ FLAGS: X X . . . X X
RRA abs | 6Fh | 6 |
RRA abs,X | 7Fh | 7 |
RRA abs,Y | 7Bh | 7 |
RRA zp | 67h | 5 |
RRA zp,X | 77h | 6 |
RRA (zp,X) | 63h | 8 |
RRA (zp),Y | 73h | 8 |
-------------+--------+--------+
* SAX: calculate AND between the A and X registers (without changing the
contents of the registers) and stores the result in memory.
Flags into P register are not modified.
Address mode | opcode | cycles | N V B D I Z C
-------------+--------+--------+ FLAGS: . . . . . . .
SAX abs | 8Fh | 4 |
SAX zp | 87h | 3 |
SAX zp,Y | 97h | 4 |
SAX (zp,X) | 83h | 6 |
-------------+--------+--------+
* LAX: loads both the accumulator and the X register with the content of a memory
location.
Address mode | opcode | cycles | N V B D I Z C
-------------+--------+--------+ FLAGS: X . . . . X .
LAX abs | AFh | 4 |
LAX abs,Y | BFh | 4* | * = adds +1 if page cross is detected.
LAX zp | A7h | 3 |
LAX zp,Y | B7h | 4 |
LAX (zp,X) | A3h | 6 |
LAX (zp),Y | B3h | 5* |
-------------+--------+--------+
* DCP: decrements the contents of a memory location and then compares the result
with the accumulator.
Address mode | opcode | cycles | N V B D I Z C
-------------+--------+--------+ FLAGS: X . . . . X X
DCP abs | CFh | 6 |
DCP abs,X | DFh | 7 |
DCP abs,Y | DBh | 7 |
DCP zp | C7h | 5 |
DCP zp,X | D7h | 6 |
DCP (zp,X) | C3h | 8 |
DCP (zp),Y | D3h | 8 |
-------------+--------+--------+
* ISC: increments the contents of a memory location and then subtract with carry
the result from the accumulator.
Address mode | opcode | cycles | N V B D I Z C
-------------+--------+--------+ FLAGS: X X . . . X X
ISC abs | EFh | 6 |
ISC abs,X | FFh | 7 |
ISC abs,Y | FBh | 7 |
ISC zp | E7h | 5 |
ISC zp,X | F7h | 6 |
ISC (zp,X) | E3h | 8 |
ISC (zp),Y | F3h | 8 |
-------------+--------+--------+
* ASR: calculates the AND between the accumulator and an immediate value and then
shift right the result.
Address mode | opcode | cycles | N V B D I Z C
-------------+--------+--------+ FLAGS: X . . . . X X
ASR #imm | 4Bh | 2 |
-------------+--------+--------+
* ARR: calculates the AND between the accumulator and an immediate value and then
rotate right the result.
Address mode | opcode | cycles | N V B D I Z C
-------------+--------+--------+ FLAGS: X . . . . X X
ARR #imm | 6Bh | 2 |
-------------+--------+--------+
* ANE: calculates the OR of the accumulator with an unstable constant, then it does
an AND with the X register and an immediate value.
The unstable constant varies with temperature, the production batch and
maybe other factors. Experimental measures assume its value to 0xEF.
Address mode | opcode | cycles | N V B D I Z C
-------------+--------+--------+ FLAGS: X . . . . X .
ANE #imm | 8Bh | 2 |
-------------+--------+--------+
* LXA: calculates the OR of the accumulator with an unstable constant, then it does
an AND with an immediate value. The result is copied into the X register and
the accumulator.
The unstable constant varies with temperature, the production batch and
maybe other factors. Experimental measures assume its value to 0xEE.
Address mode | opcode | cycles | N V B D I Z C
-------------+--------+--------+ FLAGS: X . . . . X .
LXA #imm | ABh | 2 |
-------------+--------+--------+
* SBX: calculates the AND of the accumulator with the X register and the subtracts
an immediate value.
Address mode | opcode | cycles | N V B D I Z C
-------------+--------+--------+ FLAGS: X . . . . X X
SBX #imm | CBh | 2 |
-------------+--------+--------+
* NOP: No-Operation.
Address mode | opcode | cycles | N V B D I Z C
-------------+--------+--------+ FLAGS: . . . . . . .
NOP | 1Ah | 2 |
NOP | 3Ah | 2 | * = adds +1 if page cross is detected.
NOP | 5Ah | 2 |
NOP | 7Ah | 2 |
NOP | DAh | 2 |
NOP | FAh | 2 |
NOP #imm | 80h | 2 |
NOP #imm | 82h | 2 |
NOP #imm | 89h | 2 |
NOP #imm | C2h | 2 |
NOP #imm | E2h | 2 |
NOP zp | 04h | 3 |
NOP zp,x | 14h | 4 |
NOP zp,x | 34h | 4 |
NOP zp | 44h | 3 |
NOP zp,x | 54h | 4 |
NOP zp | 64h | 3 |
NOP zp,x | 74h | 4 |
NOP zp,x | D4h | 4 |
NOP zp,x | F4h | 4 |
NOP abs | 0Ch | 4 |
NOP abs,x | 1Ch | 4* |
NOP abs,x | 3Ch | 4* |
NOP abs,x | 5Ch | 4* |
NOP abs,x | 7Ch | 4* |
NOP abs,x | DCh | 4* |
NOP abs,x | FCh | 4* |
-------------+--------+--------+
* TAS: calculates the AND of the accumulator with the X register and stores the result
into the stack pointer. Then, it calculates the AND of the result with the
high byte of the memory pointer plus 1 and it stores the final result in memory.
Address mode | opcode | cycles | N V B D I Z C
-------------+--------+--------+ FLAGS: . . . . . . .
TAS abs,y | 9Bh | 5 |
-------------+--------+--------+
* SHY: calculates the AND of the Y register with the high byte of the memory pointer
plus 1 and it stores the final result in memory.
Address mode | opcode | cycles | N V B D I Z C
-------------+--------+--------+ FLAGS: . . . . . . .
SHY abs,x | 9Ch | 5 |
-------------+--------+--------+
* SHX: calculates the AND of the X register with the high byte of the memory pointer
plus 1 and it stores the final result in memory.
Address mode | opcode | cycles | N V B D I Z C
-------------+--------+--------+ FLAGS: . . . . . . .
SHX abs,y | 9Eh | 5 |
-------------+--------+--------+
* SHA: calculates the AND of the accumulator with the X register with the high byte
of the memory pointer plus 1 and it stores the final result in memory.
Address mode | opcode | cycles | N V B D I Z C
-------------+--------+--------+ FLAGS: . . . . . . .
SHX abs,y | 9Fh | 5 |
SHX (zp),y | 93h | 6 |
-------------+--------+--------+
* ANC: calculates the AND of the accumulator with an immediate value and then
updates the status of N and Z bits of the status register.
The N flag is also copied into the Carry flag.
Address mode | opcode | cycles | N V B D I Z C
-------------+--------+--------+ FLAGS: X . . . . X X
ANC #imm | 0Bh | 2 |
ANC #imm | 2Bh | 2 |
-------------+--------+--------+
* LAS: calculates the contents of a memory location with the contents of the
stack pointer register and it stores the result in the accumulator, the X
register, and the stack pointer.
Address mode | opcode | cycles | N V B D I Z C
-------------+--------+--------+ FLAGS: X . . . . X .
LAS abs,y | BBh | 4* |
-------------+--------+--------+ * = adds +1 if page cross is detected.
* SBC: alias of the official SBC opcode.
Address mode | opcode | cycles | N V B D I Z C
-------------+--------+--------+ FLAGS: X X . . . X X
SBC #imm | EBh | 2 |
-------------+--------+--------+
*/
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Current CPU */
CPUType CPU;
/* Type of an opcode handler function */
typedef void (*OPFunc) (void);
/* The CPU registers */
static CPURegs Regs;
/* Cycles for the current insn */
static unsigned Cycles;
/* NMI request active */
static unsigned HaveNMIRequest;
/* IRQ request active */
static unsigned HaveIRQRequest;
/*****************************************************************************/
/* Helper functions and macros */
/*****************************************************************************/
/* Return the flags as boolean values (0/1) */
#define GET_CF() ((Regs.SR & CF) != 0)
#define GET_ZF() ((Regs.SR & ZF) != 0)
#define GET_IF() ((Regs.SR & IF) != 0)
#define GET_DF() ((Regs.SR & DF) != 0)
#define GET_OF() ((Regs.SR & OF) != 0)
#define GET_SF() ((Regs.SR & SF) != 0)
/* Set the flags. The parameter is a boolean flag that says if the flag should be
** set or reset.
*/
#define SET_CF(f) do { if (f) { Regs.SR |= CF; } else { Regs.SR &= ~CF; } } while (0)
#define SET_ZF(f) do { if (f) { Regs.SR |= ZF; } else { Regs.SR &= ~ZF; } } while (0)
#define SET_IF(f) do { if (f) { Regs.SR |= IF; } else { Regs.SR &= ~IF; } } while (0)
#define SET_DF(f) do { if (f) { Regs.SR |= DF; } else { Regs.SR &= ~DF; } } while (0)
#define SET_OF(f) do { if (f) { Regs.SR |= OF; } else { Regs.SR &= ~OF; } } while (0)
#define SET_SF(f) do { if (f) { Regs.SR |= SF; } else { Regs.SR &= ~SF; } } while (0)
/* Special test and set macros. The meaning of the parameter depends on the
** actual flag that should be set or reset.
*/
#define TEST_ZF(v) SET_ZF (((v) & 0xFF) == 0)
#define TEST_SF(v) SET_SF (((v) & 0x80) != 0)
#define TEST_CF(v) SET_CF (((v) & 0xFF00) != 0)
/* Program counter halves */
#define PCL (Regs.PC & 0xFF)
#define PCH ((Regs.PC >> 8) & 0xFF)
/* Stack operations */
#define PUSH(Val) MemWriteByte (0x0100 | (Regs.SP-- & 0xFF), Val)
#define POP() MemReadByte (0x0100 | (++Regs.SP & 0xFF))
/* Test for page cross */
#define PAGE_CROSS(addr,offs) ((((addr) & 0xFF) + offs) >= 0x100)
/* Address operators */
/* zp */
#define ADR_ZP(ad) \
ad = MemReadByte (Regs.PC+1); \
Regs.PC += 2
/* zp,x */
#define ADR_ZPX(ad) \
ad = (MemReadByte (Regs.PC+1) + Regs.XR) & 0xFF; \
Regs.PC += 2
/* zp,y */
#define ADR_ZPY(ad) \
ad = (MemReadByte (Regs.PC+1) + Regs.YR) & 0xFF; \
Regs.PC += 2
/* abs */
#define ADR_ABS(ad) \
ad = MemReadWord (Regs.PC+1); \
Regs.PC += 3
/* abs,x */
#define ADR_ABSX(ad) \
ad = MemReadWord (Regs.PC+1); \
if (PAGE_CROSS (ad, Regs.XR)) { \
++Cycles; \
} \
ad += Regs.XR; \
Regs.PC += 3
/* abs,y */
#define ADR_ABSY(ad) \
ad = MemReadWord (Regs.PC+1); \
if (PAGE_CROSS (ad, Regs.YR)) { \
++Cycles; \
} \
ad += Regs.YR; \
Regs.PC += 3
/* (zp,x) */
#define ADR_ZPXIND(ad) \
ad = (MemReadByte (Regs.PC+1) + Regs.XR) & 0xFF; \
ad = MemReadZPWord (ad); \
Regs.PC += 2
/* (zp),y */
#define ADR_ZPINDY(ad) \
ad = MemReadZPWord (MemReadByte (Regs.PC+1)); \
if (PAGE_CROSS (ad, Regs.YR)) { \
++Cycles; \
} \
ad += Regs.YR; \
Regs.PC += 2
/* (zp) */
#define ADR_ZPIND(ad) \
ad = MemReadZPWord (MemReadByte (Regs.PC+1)); \
Regs.PC += 2
/* Address operators (no penalty on page cross) */
/* abs,x - no penalty */
#define ADR_ABSX_NP(ad) \
ad = MemReadWord (Regs.PC+1); \
ad += Regs.XR; \
Regs.PC += 3
/* abs,y - no penalty */
#define ADR_ABSY_NP(ad) \
ad = MemReadWord (Regs.PC+1); \
ad += Regs.YR; \
Regs.PC += 3
/* (zp),y - no penalty */
#define ADR_ZPINDY_NP(ad) \
ad = MemReadZPWord (MemReadByte (Regs.PC+1)); \
ad += Regs.YR; \
Regs.PC += 2
/* Memory operators */
/* #imm */
#define MEM_AD_OP_IMM(op) \
op = MemReadByte (Regs.PC+1); \
Regs.PC += 2
/* zp / zp,x / zp,y / abs / abs,x / abs,y / (zp,x) / (zp),y / (zp) */
#define MEM_AD_OP(mode, ad, op) \
ADR_##mode(ad); \
op = MemReadByte (ad)
/* ALU opcode helpers */
/* Execution cycles for ALU opcodes */
#define ALU_CY_ZP 3
#define ALU_CY_ZPX 4
#define ALU_CY_ZPY 4
#define ALU_CY_ABS 4
#define ALU_CY_ABSX 4
#define ALU_CY_ABSY 4
#define ALU_CY_ZPXIND 6
#define ALU_CY_ZPINDY 5
#define ALU_CY_ZPIND 5
/* #imm */
#define ALU_OP_IMM(op) \
unsigned char immediate; \
MEM_AD_OP_IMM(immediate); \
Cycles = 2; \
op (immediate)
/* zp / zp,x / zp,y / abs / abs,x / abs,y / (zp,x) / (zp),y / (zp) */
#define ALU_OP(mode, op) \
unsigned address, operand; \
Cycles = ALU_CY_##mode; \
MEM_AD_OP (mode, address, operand); \
op (operand)
/* Store opcode helpers */
/* Execution cycles for store opcodes */
#define STO_CY_ZP 3
#define STO_CY_ZPX 4
#define STO_CY_ZPY 4
#define STO_CY_ABS 4
#define STO_CY_ABSX 5
#define STO_CY_ABSY 5
#define STO_CY_ZPXIND 6
#define STO_CY_ZPINDY 6
#define STO_CY_ZPIND 5
/* zp / zp,x / zp,y / abs / abs,x / abs,y / (zp,x) / (zp),y / (zp) */
#define STO_OP(mode, op) \
unsigned address; \
Cycles = STO_CY_##mode; \
ADR_##mode (address); \
MemWriteByte(address, op)
/* zp / zp,x / zp,y / abs / abs,x / abs,y / (zp,x) / (zp),y / (zp) */
#define STO_CB(mode, cb) \
unsigned address, operand; \
Cycles = STO_CY_##mode; \
ADR_##mode (address); \
cb (operand); \
MemWriteByte(address, operand)
/* Read-Modify-Write opcode helpers */
/* Execution cycles for R-M-W opcodes */
#define RMW_CY_ZP 5
#define RMW_CY_ZPX 6
#define RMW_CY_ZPY 6
#define RMW_CY_ABS 6
#define RMW_CY_ABSX 7
#define RMW_CY_ABSY 7
#define RMW_CY_ZPXIND 6
#define RMW_CY_ZPINDY 5
#define RMW_CY_ZPIND 5
#define RMW_CY_ABSX_NP RMW_CY_ABSX
#define RMW_CY_ABSY_NP RMW_CY_ABSY
#define RMW_CY_ZPINDY_NP RMW_CY_ZPINDY
/* zp / zp,x / zp,y / abs / abs,x / abs,y / (zp,x) / (zp),y / (zp) */
#define MEM_OP(mode, op) \
unsigned address, operand; \
Cycles = RMW_CY_##mode; \
MEM_AD_OP (mode, address, operand); \
op (operand); \
MemWriteByte (address, (unsigned char)operand)
/* 2 x Read-Modify-Write opcode helpers (illegal opcodes) */
/* Execution cycles for 2 x R-M-W opcodes */
#define RMW2_CY_ZP 5
#define RMW2_CY_ZPX 6
#define RMW2_CY_ZPY 6
#define RMW2_CY_ABS 6
#define RMW2_CY_ABSX 7
#define RMW2_CY_ABSY 7
#define RMW2_CY_ZPXIND 8
#define RMW2_CY_ZPINDY 8
/* zp / zp,x / zp,y / abs / abs,x / abs,y / (zp,x) / (zp),y */
#define ILLx2_OP(mode, op) \
unsigned address; \
unsigned operand; \
Cycles = RMW2_CY_##mode; \
MEM_AD_OP (mode, address, operand); \
op (operand); \
MemWriteByte (address, (unsigned char)operand)
/* AC opcode helpers */
/* #imm */
#define AC_OP_IMM(op) \
unsigned char immediate; \
MEM_AD_OP_IMM(immediate); \
Cycles = 2; \
Regs.AC = Regs.AC op immediate; \
TEST_ZF (Regs.AC); \
TEST_SF (Regs.AC)
/* zp / zp,x / zp,y / abs / abs,x / abs,y / (zp,x) / (zp),y / (zp) */
#define AC_OP(mode, op) \
unsigned address; \
unsigned operand; \
Cycles = ALU_CY_##mode; \
MEM_AD_OP(mode, address, operand); \
Regs.AC = Regs.AC op operand; \
TEST_ZF (Regs.AC); \
TEST_SF (Regs.AC)
/* ADC */
#define ADC(v) \
do { \
unsigned old = Regs.AC; \
unsigned rhs = (v & 0xFF); \
if (GET_DF ()) { \
unsigned lo; \
int res; \
lo = (old & 0x0F) + (rhs & 0x0F) + GET_CF (); \
if (lo >= 0x0A) { \
lo = ((lo + 0x06) & 0x0F) + 0x10; \
} \
Regs.AC = (old & 0xF0) + (rhs & 0xF0) + lo; \
res = (signed char)(old & 0xF0) + \
(signed char)(rhs & 0xF0) + \
(signed char)lo; \
TEST_ZF (old + rhs + GET_CF ()); \
TEST_SF (Regs.AC); \
if (Regs.AC >= 0xA0) { \
Regs.AC += 0x60; \
} \
TEST_CF (Regs.AC); \
SET_OF ((res < -128) || (res > 127)); \
if (CPU == CPU_65C02) { \
++Cycles; \
} \
} else { \
Regs.AC += rhs + GET_CF (); \
TEST_ZF (Regs.AC); \
TEST_SF (Regs.AC); \
TEST_CF (Regs.AC); \
SET_OF (!((old ^ rhs) & 0x80) && \
((old ^ Regs.AC) & 0x80)); \
Regs.AC &= 0xFF; \
} \
} while (0)
/* branches */
#define BRANCH(cond) \
Cycles = 2; \
if (cond) { \
signed char Offs; \
unsigned char OldPCH; \
++Cycles; \
Offs = (signed char) MemReadByte (Regs.PC+1); \
OldPCH = PCH; \
Regs.PC = (Regs.PC + 2 + (int) Offs) & 0xFFFF; \
if (PCH != OldPCH) { \
++Cycles; \
} \
} else { \
Regs.PC += 2; \
}
/* compares */
#define COMPARE(v1, v2) \
do { \
unsigned Result = v1 - v2; \
TEST_ZF (Result); \
TEST_SF (Result); \
SET_CF (Result <= 0xFF); \
} while (0)
#define CPX(operand) \
COMPARE (Regs.XR, operand)
#define CPY(operand) \
COMPARE (Regs.YR, operand)
#define CMP(operand) \
COMPARE (Regs.AC, operand)
/* ROL */
#define ROL(Val) \
Val <<= 1; \
if (GET_CF ()) { \
Val |= 0x01; \
} \
TEST_ZF (Val); \
TEST_SF (Val); \
TEST_CF (Val)
/* ROR */
#define ROR(Val) \
if (GET_CF ()) { \
Val |= 0x100; \
} \
SET_CF (Val & 0x01); \
Val >>= 1; \
TEST_ZF (Val); \
TEST_SF (Val)
/* ASL */
#define ASL(Val) \
SET_CF (Val & 0x80); \
Val = (Val << 1) & 0xFF; \
TEST_ZF (Val); \
TEST_SF (Val)
/* LSR */
#define LSR(Val) \
SET_CF (Val & 0x01); \
Val >>= 1; \
TEST_ZF (Val); \
TEST_SF (Val)
/* INC */
#define INC(Val) \
Val = (Val + 1) & 0xFF; \
TEST_ZF (Val); \
TEST_SF (Val)
/* DEC */
#define DEC(Val) \
Val = (Val - 1) & 0xFF; \
TEST_ZF (Val); \
TEST_SF (Val)
/* SLO */
#define SLO(Val) \
Val <<= 1; \
SET_CF (Val & 0x100); \
Regs.AC |= Val; \
Regs.AC &= 0xFF; \
TEST_ZF (Regs.AC); \
TEST_SF (Regs.AC)
/* RLA */
#define RLA(Val) \
Val <<= 1; \
if (GET_CF ()) { \
Val |= 0x01; \
} \
SET_CF (Val & 0x100); \
Regs.AC &= Val; \
TEST_ZF (Regs.AC); \
TEST_SF (Regs.AC)
/* SRE */
#define SRE(Val) \
SET_CF (Val & 0x01); \
Val >>= 1; \
Regs.AC ^= Val; \
TEST_ZF (Regs.AC); \
TEST_SF (Regs.AC)
/* RRA */
#define RRA(Val) \
if (GET_CF ()) { \
Val |= 0x100; \
} \
SET_CF (Val & 0x01); \
Val >>= 1; \
ADC (Val)
/* BIT */
#define BIT(Val) \
SET_SF (Val & 0x80); \
SET_OF (Val & 0x40); \
SET_ZF ((Val & Regs.AC) == 0)
/* LDA */
#define LDA(Val) \
Regs.AC = Val; \
TEST_SF (Val); \
TEST_ZF (Val)
/* LDX */
#define LDX(Val) \
Regs.XR = Val; \
TEST_SF (Val); \
TEST_ZF (Val)
/* LDY */
#define LDY(Val) \
Regs.YR = Val; \
TEST_SF (Val); \
TEST_ZF (Val)
/* LAX */
#define LAX(Val) \
Regs.AC = Val; \
Regs.XR = Val; \
TEST_SF (Val); \
TEST_ZF (Val)
/* TSB */
#define TSB(Val) \
SET_ZF ((Val & Regs.AC) == 0); \
Val |= Regs.AC
/* TRB */
#define TRB(Val) \
SET_ZF ((Val & Regs.AC) == 0); \
Val &= ~Regs.AC
/* DCP */
#define DCP(Val) \
Val = (Val - 1) & 0xFF; \
COMPARE (Regs.AC, Val)
/* ISC */
#define ISC(Val) \
Val = (Val + 1) & 0xFF; \
SBC(Val)
/* ASR */
#define ASR(Val) \
Regs.AC &= Val; \
LSR(Regs.AC)
/* ARR */
#define ARR(Val) \
do { \
unsigned tmp = Regs.AC & Val; \
Val = tmp >> 1; \
if (GET_CF ()) { \
Val |= 0x80; \
} \
if (GET_DF ()) { \
SET_SF (GET_CF ()); \
TEST_ZF (Val); \
SET_OF ((Val ^ tmp) & 0x40); \
if (((tmp & 0x0f) + (tmp & 0x01)) > 0x05) { \
Val = (Val & 0xf0) | ((Val + 0x06) & 0x0f); \
} \
if (((tmp & 0xf0) + (tmp & 0x10)) > 0x50) { \
Val = (Val & 0x0f) | ((Val + 0x60) & 0xf0); \
SET_CF(1); \
} else { \
SET_CF(0); \
} \
if (CPU == CPU_65C02) { \
++Cycles; \
} \
} else { \
TEST_SF (Val); \
TEST_ZF (Val); \
SET_CF (Val & 0x40); \
SET_OF ((Val & 0x40) ^ ((Val & 0x20) << 1)); \
} \
Regs.AC = Val; \
} while (0);
/* ANE */
#define ANE(Val) \
Val = (Regs.AC | 0xEF) & Regs.XR & Val; \
Regs.AC = Val; \
TEST_SF (Val); \
TEST_ZF (Val)
/* LXA */
#define LXA(Val) \
Val = (Regs.AC | 0xEE) & Val; \
Regs.AC = Val; \
Regs.XR = Val; \
TEST_SF (Val); \
TEST_ZF (Val)
/* SBX */
#define SBX(Val) \
do { \
unsigned tmp = (Regs.AC & Regs.XR) - (Val); \
SET_CF (tmp < 0x100); \
tmp &= 0xFF; \
Regs.XR = tmp; \
TEST_SF (tmp); \
TEST_ZF (tmp); \
} while (0);
/* NOP */
#define NOP(Val) \
(void)Val
/* TAS */
#define TAS(Val) \
Val = Regs.AC & Regs.XR; \
Regs.SP = Val; \
Val &= (address >> 8) + 1
/* SHA */
#define SHA(Val) \
Val = Regs.AC & Regs.XR & ((address >> 8) + 1)
/* ANC */
#define ANC(Val) \
Val = Regs.AC & Val; \
Regs.AC = Val; \
SET_CF (Val & 0x80); \
TEST_SF (Val); \
TEST_ZF (Val)
/* LAS */
#define LAS(Val) \
Val = Regs.SP & Val; \
Regs.AC = Val; \
Regs.XR = Val; \
Regs.SP = Val; \
TEST_SF (Val); \
TEST_ZF (Val)
/* SBC */
#define SBC(v) \
do { \
unsigned r_a = Regs.AC; \
unsigned src = (v) & 0xFF; \
unsigned ccc = (Regs.SR & CF) ^ CF; \
unsigned tmp = r_a - src - ccc; \
\
SET_CF(tmp < 0x100); \
TEST_SF(tmp); \
TEST_ZF(tmp); \
SET_OF((r_a ^ tmp) & (r_a ^ src) & 0x80); \
\
if (GET_DF ()) { \
unsigned low = (r_a & 0x0f) - (src & 0x0f) - ccc; \
tmp = (r_a & 0xf0) - (src & 0xf0); \
if (low & 0x10) { \
low -= 6; \
tmp -= 0x10; \
} \
tmp = (low & 0xf) | tmp; \
if (tmp & 0x100) { \
tmp -= 0x60; \
} \
} \
Regs.AC = tmp & 0xFF; \
} while (0)
/*****************************************************************************/
/* Opcode handling functions */
/*****************************************************************************/
static void OPC_Illegal (void)
{
Error ("Illegal opcode $%02X at address $%04X",
MemReadByte (Regs.PC), Regs.PC);
}
static void OPC_6502_00 (void)
/* Opcode $00: BRK */
{
Cycles = 7;
Regs.PC += 2;
PUSH (PCH);
PUSH (PCL);
PUSH (Regs.SR);
SET_IF (1);
if (CPU == CPU_65C02)
{
SET_DF (0);
}
Regs.PC = MemReadWord (0xFFFE);
}
static void OPC_6502_01 (void)
/* Opcode $01: ORA (ind,x) */
{
AC_OP (ZPXIND, |);
}
static void OPC_6502_03 (void)
/* Opcode $03: SLO (zp,x) */
{
ILLx2_OP (ZPXIND, SLO);
}
/* Aliases of opcode $04 */
#define OPC_6502_44 OPC_6502_04
#define OPC_6502_64 OPC_6502_04
static void OPC_6502_04 (void)
/* Opcode $04: NOP zp */
{
ALU_OP (ZP, NOP);
}
static void OPC_65SC02_04 (void)
/* Opcode $04: TSB zp */
{
MEM_OP (ZP, TSB);
}
static void OPC_6502_05 (void)
/* Opcode $05: ORA zp */
{
AC_OP (ZP, |);
}
static void OPC_6502_06 (void)
/* Opcode $06: ASL zp */
{
MEM_OP (ZP, ASL);
}
static void OPC_6502_07 (void)
/* Opcode $07: SLO zp */
{
ILLx2_OP (ZP, SLO);
}
static void OPC_6502_08 (void)
/* Opcode $08: PHP */
{
Cycles = 3;
PUSH (Regs.SR);
Regs.PC += 1;
}
static void OPC_6502_09 (void)
/* Opcode $09: ORA #imm */
{
AC_OP_IMM (|);
}
static void OPC_6502_0A (void)
/* Opcode $0A: ASL a */
{
Cycles = 2;
ASL(Regs.AC);
Regs.PC += 1;
}
/* Aliases of opcode $0B */
#define OPC_6502_2B OPC_6502_0B
static void OPC_6502_0B (void)
/* Opcode $0B: ANC #imm */
{
ALU_OP_IMM (ANC);
}
static void OPC_6502_0C (void)
/* Opcode $0C: NOP abs */
{
ALU_OP (ABS, NOP);
}
static void OPC_65SC02_0C (void)
/* Opcode $0C: TSB abs */
{
MEM_OP (ABS, TSB);
}
static void OPC_6502_0D (void)
/* Opcode $0D: ORA abs */
{
AC_OP (ABS, |);
}
static void OPC_6502_0E (void)
/* Opcode $0E: ASL abs */
{
MEM_OP (ABS, ASL);
}
static void OPC_6502_0F (void)
/* Opcode $0F: SLO abs */
{
ILLx2_OP (ABS, SLO);
}
static void OPC_6502_10 (void)
/* Opcode $10: BPL */
{
BRANCH (!GET_SF ());
}
static void OPC_6502_11 (void)
/* Opcode $11: ORA (zp),y */
{
AC_OP (ZPINDY, |);
}
static void OPC_65SC02_12 (void)
/* Opcode $12: ORA (zp) */
{
AC_OP (ZPIND, |);
}
static void OPC_6502_13 (void)
/* Opcode $03: SLO (zp),y */
{
ILLx2_OP (ZPINDY, SLO);
}
/* Aliases of opcode $14 */
#define OPC_6502_34 OPC_6502_14
#define OPC_6502_54 OPC_6502_14
#define OPC_6502_74 OPC_6502_14
#define OPC_6502_D4 OPC_6502_14
#define OPC_6502_F4 OPC_6502_14
static void OPC_6502_14 (void)
/* Opcode $04: NOP zp,x */
{
ALU_OP (ZPX, NOP);
}
static void OPC_65SC02_14 (void)
/* Opcode $14: TRB zp */
{
MEM_OP (ZP, TRB);
}
static void OPC_6502_15 (void)
/* Opcode $15: ORA zp,x */
{
AC_OP (ZPX, |);
}
static void OPC_6502_16 (void)
/* Opcode $16: ASL zp,x */
{
MEM_OP (ZPX, ASL);
}
static void OPC_6502_17 (void)
/* Opcode $17: SLO zp,x */
{
ILLx2_OP (ZPX, SLO);
}
static void OPC_6502_18 (void)
/* Opcode $18: CLC */
{
Cycles = 2;
SET_CF (0);
Regs.PC += 1;
}
static void OPC_6502_19 (void)
/* Opcode $19: ORA abs,y */
{
AC_OP (ABSY, |);
}
static void OPC_65SC02_1A (void)
/* Opcode $1A: INC a */
{
Cycles = 2;
INC(Regs.AC);
Regs.PC += 1;
}
static void OPC_6502_1B (void)
/* Opcode $1B: SLO abs,y */
{
ILLx2_OP (ABSY, SLO);
}
/* Aliases of opcode $1C */
#define OPC_6502_3C OPC_6502_1C
#define OPC_6502_5C OPC_6502_1C
#define OPC_6502_7C OPC_6502_1C
#define OPC_6502_DC OPC_6502_1C
#define OPC_6502_FC OPC_6502_1C
static void OPC_6502_1C (void)
/* Opcode $1C: NOP abs,x */
{
ALU_OP (ABSX, NOP);
}
static void OPC_65SC02_1C (void)
/* Opcode $1C: TRB abs */
{
MEM_OP (ABS, TRB);
}
static void OPC_6502_1D (void)
/* Opcode $1D: ORA abs,x */
{
AC_OP (ABSX, |);
}
static void OPC_6502_1E (void)
/* Opcode $1E: ASL abs,x */
{
MEM_OP (ABSX, ASL);
}
static void OPC_65C02_1E (void)
/* Opcode $1E: ASL abs,x */
{
MEM_OP (ABSX_NP, ASL);
}
static void OPC_6502_1F (void)
/* Opcode $1F: SLO abs,x */
{
ILLx2_OP (ABSX, SLO);
}
static void OPC_6502_20 (void)
/* Opcode $20: JSR */
{
unsigned Addr;
Cycles = 6;
Addr = MemReadWord (Regs.PC+1);
Regs.PC += 2;
PUSH (PCH);
PUSH (PCL);
Regs.PC = Addr;
ParaVirtHooks (&Regs);
}
static void OPC_6502_21 (void)
/* Opcode $21: AND (zp,x) */
{
AC_OP (ZPXIND, &);
}
static void OPC_6502_23 (void)
/* Opcode $23: RLA (zp,x) */
{
ILLx2_OP (ZPXIND, RLA);
}
static void OPC_6502_24 (void)
{
/* Opcode $24: BIT zp */
ALU_OP (ZP, BIT);
}
static void OPC_6502_25 (void)
/* Opcode $25: AND zp */
{
AC_OP (ZP, &);
}
static void OPC_6502_26 (void)
/* Opcode $26: ROL zp */
{
MEM_OP (ZP, ROL);
}
static void OPC_6502_27 (void)
/* Opcode $27: RLA zp */
{
ILLx2_OP (ZP, RLA);
}
static void OPC_6502_28 (void)
/* Opcode $28: PLP */
{
Cycles = 4;
/* Bits 5 and 4 aren't used, and always are 1! */
Regs.SR = (POP () | 0x30);
Regs.PC += 1;
}
static void OPC_6502_29 (void)
/* Opcode $29: AND #imm */
{
AC_OP_IMM (&);
}
static void OPC_6502_2A (void)
/* Opcode $2A: ROL a */
{
Cycles = 2;
ROL (Regs.AC);
Regs.AC &= 0xFF;
Regs.PC += 1;
}
static void OPC_6502_2C (void)
/* Opcode $2C: BIT abs */
{
ALU_OP (ABS, BIT);
}
static void OPC_6502_2D (void)
/* Opcode $2D: AND abs */
{
AC_OP (ABS, &);
}
static void OPC_6502_2E (void)
/* Opcode $2E: ROL abs */
{
MEM_OP (ABS, ROL);
}
static void OPC_6502_2F (void)
/* Opcode $2F: RLA abs */
{
ILLx2_OP (ABS, RLA);
}
static void OPC_6502_30 (void)
/* Opcode $30: BMI */
{
BRANCH (GET_SF ());
}
static void OPC_6502_31 (void)
/* Opcode $31: AND (zp),y */
{
AC_OP (ZPINDY, &);
}
static void OPC_65SC02_32 (void)
/* Opcode $32: AND (zp) */
{
AC_OP (ZPIND, &);
}
static void OPC_6502_33 (void)
/* Opcode $33: RLA (zp),y */
{
ILLx2_OP (ZPINDY, RLA);
}
static void OPC_65SC02_34 (void)
/* Opcode $34: BIT zp,x */
{
ALU_OP (ZPX, BIT);
}
static void OPC_6502_35 (void)
/* Opcode $35: AND zp,x */
{
AC_OP (ZPX, &);
}
static void OPC_6502_36 (void)
/* Opcode $36: ROL zp,x */
{
MEM_OP (ZPX, ROL);
}
static void OPC_6502_37 (void)
/* Opcode $37: RLA zp,x */
{
ILLx2_OP (ZPX, RLA);
}
static void OPC_6502_38 (void)
/* Opcode $38: SEC */
{
Cycles = 2;
SET_CF (1);
Regs.PC += 1;
}
static void OPC_6502_39 (void)
/* Opcode $39: AND abs,y */
{
AC_OP (ABSY, &);
}
static void OPC_65SC02_3A (void)
/* Opcode $3A: DEC a */
{
Cycles = 2;
DEC (Regs.AC);
Regs.PC += 1;
}
static void OPC_6502_3B (void)
/* Opcode $3B: RLA abs,y */
{
ILLx2_OP (ABSY, RLA);
}
static void OPC_65SC02_3C (void)
/* Opcode $3C: BIT abs,x */
{
ALU_OP (ABSX, BIT);
}
static void OPC_6502_3D (void)
/* Opcode $3D: AND abs,x */
{
AC_OP (ABSX, &);
}
static void OPC_6502_3E (void)
/* Opcode $3E: ROL abs,x */
{
MEM_OP (ABSX, ROL);
}
static void OPC_65C02_3E (void)
/* Opcode $3E: ROL abs,x */
{
MEM_OP (ABSX_NP, ROL);
}
static void OPC_6502_3F (void)
/* Opcode $3B: RLA abs,x */
{
ILLx2_OP (ABSX, RLA);
}
static void OPC_6502_40 (void)
/* Opcode $40: RTI */
{
Cycles = 6;
/* Bits 5 and 4 aren't used, and always are 1! */
Regs.SR = POP () | 0x30;
Regs.PC = POP (); /* PCL */
Regs.PC |= (POP () << 8); /* PCH */
}
static void OPC_6502_41 (void)
/* Opcode $41: EOR (zp,x) */
{
AC_OP (ZPXIND, ^);
}
static void OPC_6502_43 (void)
/* Opcode $43: SRE (zp,x) */
{
ILLx2_OP (ZPXIND, SRE);
}
static void OPC_6502_45 (void)
/* Opcode $45: EOR zp */
{
AC_OP (ZP, ^);
}
static void OPC_6502_46 (void)
/* Opcode $46: LSR zp */
{
MEM_OP (ZP, LSR);
}
static void OPC_6502_47 (void)
/* Opcode $47: SRE zp */
{
ILLx2_OP (ZP, SRE);
}
static void OPC_6502_48 (void)
/* Opcode $48: PHA */
{
Cycles = 3;
PUSH (Regs.AC);
Regs.PC += 1;
}
static void OPC_6502_49 (void)
/* Opcode $49: EOR #imm */
{
AC_OP_IMM (^);
}
static void OPC_6502_4A (void)
/* Opcode $4A: LSR a */
{
Cycles = 2;
LSR (Regs.AC);
Regs.PC += 1;
}
static void OPC_6502_4B (void)
/* Opcode $4B: ASR imm */
{
ALU_OP_IMM (ASR);
}
static void OPC_6502_4C (void)
/* Opcode $4C: JMP abs */
{
Cycles = 3;
Regs.PC = MemReadWord (Regs.PC+1);
ParaVirtHooks (&Regs);
}
static void OPC_6502_4D (void)
/* Opcode $4D: EOR abs */
{
AC_OP (ABS, ^);
}
static void OPC_6502_4E (void)
/* Opcode $4E: LSR abs */
{
MEM_OP (ABS, LSR);
}
static void OPC_6502_4F (void)
/* Opcode $4F: SRE abs */
{
ILLx2_OP (ABS, SRE);
}
static void OPC_6502_50 (void)
/* Opcode $50: BVC */
{
BRANCH (!GET_OF ());
}
static void OPC_6502_51 (void)
/* Opcode $51: EOR (zp),y */
{
AC_OP (ZPINDY, ^);
}
static void OPC_65SC02_52 (void)
/* Opcode $52: EOR (zp) */
{
AC_OP (ZPIND, ^);
}
static void OPC_6502_53 (void)
/* Opcode $43: SRE (zp),y */
{
ILLx2_OP (ZPINDY, SRE);
}
static void OPC_6502_55 (void)
/* Opcode $55: EOR zp,x */
{
AC_OP (ZPX, ^);
}
static void OPC_6502_56 (void)
/* Opcode $56: LSR zp,x */
{
MEM_OP (ZPX, LSR);
}
static void OPC_6502_57 (void)
/* Opcode $57: SRE zp,x */
{
ILLx2_OP (ZPX, SRE);
}
static void OPC_6502_58 (void)
/* Opcode $58: CLI */
{
Cycles = 2;
SET_IF (0);
Regs.PC += 1;
}
static void OPC_6502_59 (void)
/* Opcode $59: EOR abs,y */
{
AC_OP (ABSY, ^);
}
static void OPC_65SC02_5A (void)
/* Opcode $5A: PHY */
{
Cycles = 3;
PUSH (Regs.YR);
Regs.PC += 1;
}
static void OPC_6502_5B (void)
/* Opcode $5B: SRE abs,y */
{
ILLx2_OP (ABSY, SRE);
}
static void OPC_65C02_5C (void)
/* Opcode $5C: 'Absolute' 8 cycle NOP */
{
Cycles = 8;
Regs.PC += 3;
}
static void OPC_6502_5D (void)
/* Opcode $5D: EOR abs,x */
{
AC_OP (ABSX, ^);
}
static void OPC_6502_5E (void)
/* Opcode $5E: LSR abs,x */
{
MEM_OP (ABSX, LSR);
}
static void OPC_65C02_5E (void)
/* Opcode $5E: LSR abs,x */
{
MEM_OP (ABSX_NP, LSR);
}
static void OPC_6502_5F (void)
/* Opcode $5F: SRE abs,x */
{
ILLx2_OP (ABSX, SRE);
}
static void OPC_6502_60 (void)
/* Opcode $60: RTS */
{
Cycles = 6;
Regs.PC = POP (); /* PCL */
Regs.PC |= (POP () << 8); /* PCH */
Regs.PC += 1;
}
static void OPC_6502_61 (void)
/* Opcode $61: ADC (zp,x) */
{
ALU_OP (ZPXIND, ADC);
}
static void OPC_6502_63 (void)
/* Opcode $63: RRA (zp,x) */
{
ILLx2_OP (ZPXIND, RRA);
}
static void OPC_65SC02_64 (void)
/* Opcode $64: STZ zp */
{
STO_OP (ZP, 0);
}
static void OPC_6502_65 (void)
/* Opcode $65: ADC zp */
{
ALU_OP (ZP, ADC);
}
static void OPC_6502_66 (void)
/* Opcode $66: ROR zp */
{
MEM_OP (ZP, ROR);
}
static void OPC_6502_67 (void)
/* Opcode $67: RRA zp */
{
ILLx2_OP (ZP, RRA);
}
static void OPC_6502_68 (void)
/* Opcode $68: PLA */
{
Cycles = 4;
Regs.AC = POP ();
TEST_ZF (Regs.AC);
TEST_SF (Regs.AC);
Regs.PC += 1;
}
static void OPC_6502_69 (void)
/* Opcode $69: ADC #imm */
{
ALU_OP_IMM (ADC);
}
static void OPC_6502_6A (void)
/* Opcode $6A: ROR a */
{
Cycles = 2;
ROR (Regs.AC);
Regs.PC += 1;
}
static void OPC_6502_6B (void)
/* Opcode $6B: ARR imm */
{
ALU_OP_IMM (ARR);
}
static void OPC_6502_6C (void)
/* Opcode $6C: JMP (ind) */
{
unsigned PC, Lo, Hi;
PC = Regs.PC;
Lo = MemReadWord (PC+1);
if (CPU == CPU_6502)
{
/* Emulate the 6502 bug */
Cycles = 5;
Regs.PC = MemReadByte (Lo);
Hi = (Lo & 0xFF00) | ((Lo + 1) & 0xFF);
Regs.PC |= (MemReadByte (Hi) << 8);
/* Output a warning if the bug is triggered */
if (Hi != Lo + 1)
{
Warning ("6502 indirect jump bug triggered at $%04X, ind addr = $%04X",
PC, Lo);
}
}
else
{
Cycles = 6;
Regs.PC = MemReadWord(Lo);
}
ParaVirtHooks (&Regs);
}
static void OPC_65C02_6C (void)
/* Opcode $6C: JMP (ind) */
{
/* 6502 bug fixed here */
Cycles = 5;
Regs.PC = MemReadWord (MemReadWord (Regs.PC+1));
ParaVirtHooks (&Regs);
}
static void OPC_6502_6D (void)
/* Opcode $6D: ADC abs */
{
ALU_OP (ABS, ADC);
}
static void OPC_6502_6E (void)
/* Opcode $6E: ROR abs */
{
MEM_OP (ABS, ROR);
}
static void OPC_6502_6F (void)
/* Opcode $6F: RRA abs */
{
ILLx2_OP (ABS, RRA);
}
static void OPC_6502_70 (void)
/* Opcode $70: BVS */
{
BRANCH (GET_OF ());
}
static void OPC_6502_71 (void)
/* Opcode $71: ADC (zp),y */
{
ALU_OP (ZPINDY, ADC);
}
static void OPC_65SC02_72 (void)
/* Opcode $72: ADC (zp) */
{
ALU_OP (ZPIND, ADC);
}
static void OPC_6502_73 (void)
/* Opcode $73: RRA (zp),y */
{
ILLx2_OP (ZPINDY, RRA);
}
static void OPC_65SC02_74 (void)
/* Opcode $74: STZ zp,x */
{
STO_OP (ZPX, 0);
}
static void OPC_6502_75 (void)
/* Opcode $75: ADC zp,x */
{
ALU_OP (ZPX, ADC);
}
static void OPC_6502_76 (void)
/* Opcode $76: ROR zp,x */
{
MEM_OP (ZPX, ROR);
}
static void OPC_6502_77 (void)
/* Opcode $77: RRA zp,x */
{
ILLx2_OP (ZPX, RRA);
}
static void OPC_6502_78 (void)
/* Opcode $78: SEI */
{
Cycles = 2;
SET_IF (1);
Regs.PC += 1;
}
static void OPC_6502_79 (void)
/* Opcode $79: ADC abs,y */
{
ALU_OP (ABSY, ADC);
}
static void OPC_65SC02_7A (void)
/* Opcode $7A: PLY */
{
Cycles = 4;
Regs.YR = POP ();
TEST_ZF (Regs.YR);
TEST_SF (Regs.YR);
Regs.PC += 1;
}
static void OPC_6502_7B (void)
/* Opcode $7B: RRA abs,y */
{
ILLx2_OP (ABSY, RRA);
}
static void OPC_65SC02_7C (void)
/* Opcode $7C: JMP (ind,X) */
{
unsigned PC, Adr;
Cycles = 6;
PC = Regs.PC;
Adr = MemReadWord (PC+1);
Regs.PC = MemReadWord(Adr+Regs.XR);
ParaVirtHooks (&Regs);
}
static void OPC_6502_7D (void)
/* Opcode $7D: ADC abs,x */
{
ALU_OP (ABSX, ADC);
}
static void OPC_6502_7E (void)
/* Opcode $7E: ROR abs,x */
{
MEM_OP (ABSX, ROR);
}
static void OPC_65C02_7E (void)
/* Opcode $7E: ROR abs,x */
{
MEM_OP (ABSX_NP, ROR);
}
static void OPC_6502_7F (void)
/* Opcode $7F: RRA abs,x */
{
ILLx2_OP (ABSX, RRA);
}
/* Aliases of opcode $80 */
#define OPC_6502_82 OPC_6502_80
#define OPC_6502_C2 OPC_6502_80
#define OPC_6502_E2 OPC_6502_80
#define OPC_6502_89 OPC_6502_80
static void OPC_6502_80 (void)
/* Opcode $80: NOP imm */
{
ALU_OP_IMM (NOP);
}
static void OPC_65SC02_80 (void)
/* Opcode $80: BRA */
{
BRANCH (1);
}
static void OPC_6502_81 (void)
/* Opcode $81: STA (zp,x) */
{
STO_OP (ZPXIND, Regs.AC);
}
static void OPC_6502_83 (void)
/* Opcode $83: SAX (zp,x) */
{
STO_OP (ZPXIND, Regs.AC & Regs.XR);
}
static void OPC_6502_84 (void)
/* Opcode $84: STY zp */
{
STO_OP (ZP, Regs.YR);
}
static void OPC_6502_85 (void)
/* Opcode $85: STA zp */
{
STO_OP (ZP, Regs.AC);
}
static void OPC_6502_86 (void)
/* Opcode $86: STX zp */
{
STO_OP (ZP, Regs.XR);
}
static void OPC_6502_87 (void)
/* Opcode $87: SAX zp */
{
STO_OP (ZP, Regs.AC & Regs.XR);
}
static void OPC_6502_88 (void)
/* Opcode $88: DEY */
{
Cycles = 2;
DEC (Regs.YR);
Regs.PC += 1;
}
static void OPC_65SC02_89 (void)
/* Opcode $89: BIT #imm */
{
ALU_OP_IMM (BIT);
}
static void OPC_6502_8A (void)
/* Opcode $8A: TXA */
{
Cycles = 2;
Regs.AC = Regs.XR;
TEST_ZF (Regs.AC);
TEST_SF (Regs.AC);
Regs.PC += 1;
}
static void OPC_6502_8B (void)
/* Opcode $8B: ANE imm */
{
ALU_OP_IMM (ANE);
}
static void OPC_6502_8C (void)
/* Opcode $8C: STY abs */
{
STO_OP (ABS, Regs.YR);
}
static void OPC_6502_8D (void)
/* Opcode $8D: STA abs */
{
STO_OP (ABS, Regs.AC);
}
static void OPC_6502_8E (void)
/* Opcode $8E: STX abs */
{
STO_OP (ABS, Regs.XR);
}
static void OPC_6502_8F (void)
/* Opcode $8F: SAX abs */
{
STO_OP (ABS, Regs.AC & Regs.XR);
}
static void OPC_6502_90 (void)
/* Opcode $90: BCC */
{
BRANCH (!GET_CF ());
}
static void OPC_6502_91 (void)
/* Opcode $91: sta (zp),y */
{
STO_OP (ZPINDY, Regs.AC);
}
static void OPC_65SC02_92 (void)
/* Opcode $92: sta (zp) */
{
STO_OP (ZPIND, Regs.AC);
}
static void OPC_6502_93 (void)
/* Opcode $93: SHA (zp),y */
{
STO_CB (ZPINDY, SHA);
}
static void OPC_6502_94 (void)
/* Opcode $94: STY zp,x */
{
STO_OP (ZPX, Regs.YR);
}
static void OPC_6502_95 (void)
/* Opcode $95: STA zp,x */
{
STO_OP (ZPX, Regs.AC);
}
static void OPC_6502_96 (void)
/* Opcode $96: stx zp,y */
{
STO_OP (ZPY, Regs.XR);
}
static void OPC_6502_97 (void)
/* Opcode $97: SAX zp,y */
{
STO_OP (ZPY, Regs.AC & Regs.XR);
}
static void OPC_6502_98 (void)
/* Opcode $98: TYA */
{
Cycles = 2;
Regs.AC = Regs.YR;
TEST_ZF (Regs.AC);
TEST_SF (Regs.AC);
Regs.PC += 1;
}
static void OPC_6502_99 (void)
/* Opcode $99: STA abs,y */
{
STO_OP (ABSY, Regs.AC);
}
static void OPC_6502_9A (void)
/* Opcode $9A: TXS */
{
Cycles = 2;
Regs.SP = Regs.XR;
Regs.PC += 1;
}
static void OPC_6502_9B (void)
/* Opcode $9B: TAS abs,y */
{
STO_CB (ABSY, TAS);
}
static void OPC_6502_9C (void)
/* Opcode $9D: SHY abs,x */
{
STO_OP (ABSX, Regs.YR & ((address >> 8) + 1));
}
static void OPC_65SC02_9C (void)
/* Opcode $9C: STZ abs */
{
STO_OP (ABS, 0);
}
static void OPC_6502_9D (void)
/* Opcode $9D: STA abs,x */
{
STO_OP (ABSX, Regs.AC);
}
static void OPC_6502_9E (void)
/* Opcode $9E: SHX abs,x */
{
STO_OP (ABSY, Regs.XR & ((address >> 8) + 1));
}
static void OPC_6502_9F (void)
/* Opcode $9F: SHA abs,y */
{
STO_CB (ABSY, SHA);
}
static void OPC_65SC02_9E (void)
/* Opcode $9E: STZ abs,x */
{
STO_OP (ABSX, 0);
}
static void OPC_6502_A0 (void)
/* Opcode $A0: LDY #imm */
{
ALU_OP_IMM (LDY);
}
static void OPC_6502_A1 (void)
/* Opcode $A1: LDA (zp,x) */
{
ALU_OP (ZPXIND, LDA);
}
static void OPC_6502_A2 (void)
/* Opcode $A2: LDX #imm */
{
ALU_OP_IMM (LDX);
}
static void OPC_6502_A3 (void)
/* Opcode $A3: LAX (zp,x) */
{
ALU_OP (ZPXIND, LAX);
}
static void OPC_6502_A4 (void)
/* Opcode $A4: LDY zp */
{
ALU_OP (ZP, LDY);
}
static void OPC_6502_A5 (void)
/* Opcode $A5: LDA zp */
{
ALU_OP (ZP, LDA);
}
static void OPC_6502_A6 (void)
/* Opcode $A6: LDX zp */
{
ALU_OP (ZP, LDX);
}
static void OPC_6502_A7 (void)
/* Opcode $A7: LAX zp */
{
ALU_OP (ZP, LAX);
}
static void OPC_6502_A8 (void)
/* Opcode $A8: TAY */
{
Cycles = 2;
Regs.YR = Regs.AC;
TEST_ZF (Regs.YR);
TEST_SF (Regs.YR);
Regs.PC += 1;
}
static void OPC_6502_A9 (void)
/* Opcode $A9: LDA #imm */
{
ALU_OP_IMM (LDA);
}
static void OPC_6502_AA (void)
/* Opcode $AA: TAX */
{
Cycles = 2;
Regs.XR = Regs.AC;
TEST_ZF (Regs.XR);
TEST_SF (Regs.XR);
Regs.PC += 1;
}
static void OPC_6502_AB (void)
/* Opcode $AB: LXA imm */
{
ALU_OP_IMM (LXA);
}
static void OPC_6502_AC (void)
/* Opcode $Regs.AC: LDY abs */
{
ALU_OP (ABS, LDY);
}
static void OPC_6502_AD (void)
/* Opcode $AD: LDA abs */
{
ALU_OP (ABS, LDA);
}
static void OPC_6502_AE (void)
/* Opcode $AE: LDX abs */
{
ALU_OP (ABS, LDX);
}
static void OPC_6502_AF (void)
/* Opcode $AF: LAX abs */
{
ALU_OP (ABS, LAX);
}
static void OPC_6502_B0 (void)
/* Opcode $B0: BCS */
{
BRANCH (GET_CF ());
}
static void OPC_6502_B1 (void)
/* Opcode $B1: LDA (zp),y */
{
ALU_OP (ZPINDY, LDA);
}
static void OPC_65SC02_B2 (void)
/* Opcode $B2: LDA (zp) */
{
ALU_OP (ZPIND, LDA);
}
static void OPC_6502_B3 (void)
/* Opcode $B3: LAX (zp),y */
{
ALU_OP (ZPINDY, LAX);
}
static void OPC_6502_B4 (void)
/* Opcode $B4: LDY zp,x */
{
ALU_OP (ZPX, LDY);
}
static void OPC_6502_B5 (void)
/* Opcode $B5: LDA zp,x */
{
ALU_OP (ZPX, LDA);
}
static void OPC_6502_B6 (void)
/* Opcode $B6: LDX zp,y */
{
ALU_OP (ZPY, LDX);
}
static void OPC_6502_B7 (void)
/* Opcode $B7: LAX zp,y */
{
ALU_OP (ZPY, LAX);
}
static void OPC_6502_B8 (void)
/* Opcode $B8: CLV */
{
Cycles = 2;
SET_OF (0);
Regs.PC += 1;
}
static void OPC_6502_B9 (void)
/* Opcode $B9: LDA abs,y */
{
ALU_OP (ABSY, LDA);
}
static void OPC_6502_BA (void)
/* Opcode $BA: TSX */
{
Cycles = 2;
Regs.XR = Regs.SP & 0xFF;
TEST_ZF (Regs.XR);
TEST_SF (Regs.XR);
Regs.PC += 1;
}
static void OPC_6502_BB (void)
/* Opcode $BB: LAS abs,y */
{
ALU_OP (ABSY, LAS);
}
static void OPC_6502_BC (void)
/* Opcode $BC: LDY abs,x */
{
ALU_OP (ABSX, LDY);
}
static void OPC_6502_BD (void)
/* Opcode $BD: LDA abs,x */
{
ALU_OP (ABSX, LDA);
}
static void OPC_6502_BE (void)
/* Opcode $BE: LDX abs,y */
{
ALU_OP (ABSY, LDX);
}
static void OPC_6502_BF (void)
/* Opcode $BF: LAX abs,y */
{
ALU_OP (ABSY, LAX);
}
static void OPC_6502_C0 (void)
/* Opcode $C0: CPY #imm */
{
ALU_OP_IMM (CPY);
}
static void OPC_6502_C1 (void)
/* Opcode $C1: CMP (zp,x) */
{
ALU_OP (ZPXIND, CMP);
}
static void OPC_6502_C3 (void)
/* Opcode $C3: DCP (zp,x) */
{
MEM_OP (ZPXIND, DCP);
}
static void OPC_6502_C4 (void)
/* Opcode $C4: CPY zp */
{
ALU_OP (ZP, CPY);
}
static void OPC_6502_C5 (void)
/* Opcode $C5: CMP zp */
{
ALU_OP (ZP, CMP);
}
static void OPC_6502_C6 (void)
/* Opcode $C6: DEC zp */
{
MEM_OP (ZP, DEC);
}
static void OPC_6502_C7 (void)
/* Opcode $C7: DCP zp */
{
MEM_OP (ZP, DCP);
}
static void OPC_6502_C8 (void)
/* Opcode $C8: INY */
{
Cycles = 2;
INC(Regs.YR);
Regs.PC += 1;
}
static void OPC_6502_C9 (void)
/* Opcode $C9: CMP #imm */
{
ALU_OP_IMM (CMP);
}
static void OPC_6502_CA (void)
/* Opcode $CA: DEX */
{
Cycles = 2;
DEC (Regs.XR);
Regs.PC += 1;
}
static void OPC_6502_CB (void)
/* Opcode $CB: SBX imm */
{
ALU_OP_IMM (SBX);
}
static void OPC_6502_CC (void)
/* Opcode $CC: CPY abs */
{
ALU_OP (ABS, CPY);
}
static void OPC_6502_CD (void)
/* Opcode $CD: CMP abs */
{
ALU_OP (ABS, CMP);
}
static void OPC_6502_CE (void)
/* Opcode $CE: DEC abs */
{
MEM_OP (ABS, DEC);
}
static void OPC_6502_CF (void)
/* Opcode $CF: DCP abs */
{
MEM_OP (ABS, DCP);
}
static void OPC_6502_D0 (void)
/* Opcode $D0: BNE */
{
BRANCH (!GET_ZF ());
}
static void OPC_6502_D1 (void)
/* Opcode $D1: CMP (zp),y */
{
ALU_OP (ZPINDY, CMP);
}
static void OPC_65SC02_D2 (void)
/* Opcode $D2: CMP (zp) */
{
ALU_OP (ZPIND, CMP);
}
static void OPC_6502_D3 (void)
/* Opcode $D3: DCP (zp),y */
{
MEM_OP (ZPINDY, DCP);
}
static void OPC_6502_D5 (void)
/* Opcode $D5: CMP zp,x */
{
ALU_OP (ZPX, CMP);
}
static void OPC_6502_D6 (void)
/* Opcode $D6: DEC zp,x */
{
MEM_OP (ZPX, DEC);
}
static void OPC_6502_D7 (void)
/* Opcode $D7: DCP zp,x */
{
MEM_OP (ZPX, DCP);
}
static void OPC_6502_D8 (void)
/* Opcode $D8: CLD */
{
Cycles = 2;
SET_DF (0);
Regs.PC += 1;
}
static void OPC_6502_D9 (void)
/* Opcode $D9: CMP abs,y */
{
ALU_OP (ABSY, CMP);
}
static void OPC_65SC02_DA (void)
/* Opcode $DA: PHX */
{
Cycles = 3;
PUSH (Regs.XR);
Regs.PC += 1;
}
static void OPC_6502_DB (void)
/* Opcode $DB: DCP abs,y */
{
MEM_OP (ABSY, DCP);
}
static void OPC_6502_DD (void)
/* Opcode $DD: CMP abs,x */
{
ALU_OP (ABSX, CMP);
}
static void OPC_6502_DE (void)
/* Opcode $DE: DEC abs,x */
{
MEM_OP (ABSX, DEC);
}
static void OPC_6502_DF (void)
/* Opcode $DF: DCP abs,x */
{
MEM_OP (ABSX, DCP);
}
static void OPC_6502_E0 (void)
/* Opcode $E0: CPX #imm */
{
ALU_OP_IMM (CPX);
}
static void OPC_6502_E1 (void)
/* Opcode $E1: SBC (zp,x) */
{
ALU_OP (ZPXIND, SBC);
}
static void OPC_6502_E3 (void)
/* Opcode $E3: ISC (zp,x) */
{
MEM_OP (ZPXIND, ISC);
}
static void OPC_6502_E4 (void)
/* Opcode $E4: CPX zp */
{
ALU_OP (ZP, CPX);
}
static void OPC_6502_E5 (void)
/* Opcode $E5: SBC zp */
{
ALU_OP (ZP, SBC);
}
static void OPC_6502_E6 (void)
/* Opcode $E6: INC zp */
{
MEM_OP (ZP, INC);
}
static void OPC_6502_E7 (void)
/* Opcode $E7: ISC zp */
{
MEM_OP (ZP, ISC);
}
static void OPC_6502_E8 (void)
/* Opcode $E8: INX */
{
Cycles = 2;
INC (Regs.XR);
Regs.PC += 1;
}
/* Aliases of opcode $EA */
#define OPC_6502_EB OPC_6502_E9
static void OPC_6502_E9 (void)
/* Opcode $E9: SBC #imm */
{
ALU_OP_IMM (SBC);
}
/* Aliases of opcode $EA */
#define OPC_6502_1A OPC_6502_EA
#define OPC_6502_3A OPC_6502_EA
#define OPC_6502_5A OPC_6502_EA
#define OPC_6502_7A OPC_6502_EA
#define OPC_6502_DA OPC_6502_EA
#define OPC_6502_FA OPC_6502_EA
static void OPC_6502_EA (void)
/* Opcode $EA: NOP */
{
/* This one is easy... */
Cycles = 2;
Regs.PC += 1;
}
static void OPC_65C02_NOP11(void)
/* Opcode 'Illegal' 1 cycle NOP */
{
Cycles = 1;
Regs.PC += 1;
}
static void OPC_65C02_NOP22 (void)
/* Opcode 'Illegal' 2 byte 2 cycle NOP */
{
Cycles = 2;
Regs.PC += 2;
}
static void OPC_65C02_NOP24 (void)
/* Opcode 'Illegal' 2 byte 4 cycle NOP */
{
Cycles = 4;
Regs.PC += 2;
}
static void OPC_65C02_NOP34 (void)
/* Opcode 'Illegal' 3 byte 4 cycle NOP */
{
Cycles = 4;
Regs.PC += 3;
}
static void OPC_6502_EC (void)
/* Opcode $EC: CPX abs */
{
ALU_OP (ABS, CPX);
}
static void OPC_6502_ED (void)
/* Opcode $ED: SBC abs */
{
ALU_OP (ABS, SBC);
}
static void OPC_6502_EE (void)
/* Opcode $EE: INC abs */
{
MEM_OP (ABS, INC);
}
static void OPC_6502_EF (void)
/* Opcode $EF: ISC abs */
{
MEM_OP (ABS, ISC);
}
static void OPC_6502_F0 (void)
/* Opcode $F0: BEQ */
{
BRANCH (GET_ZF ());
}
static void OPC_6502_F1 (void)
/* Opcode $F1: SBC (zp),y */
{
ALU_OP (ZPINDY, SBC);
}
static void OPC_65SC02_F2 (void)
/* Opcode $F2: SBC (zp) */
{
ALU_OP (ZPIND, SBC);
}
static void OPC_6502_F3 (void)
/* Opcode $F3: ISC (zp),y */
{
MEM_OP (ZPINDY, ISC);
}
static void OPC_6502_F5 (void)
/* Opcode $F5: SBC zp,x */
{
ALU_OP (ZPX, SBC);
}
static void OPC_6502_F6 (void)
/* Opcode $F6: INC zp,x */
{
MEM_OP (ZPX, INC);
}
static void OPC_6502_F7 (void)
/* Opcode $F7: ISC zp,x */
{
MEM_OP (ZPX, ISC);
}
static void OPC_6502_F8 (void)
/* Opcode $F8: SED */
{
Cycles = 2;
SET_DF (1);
Regs.PC += 1;
}
static void OPC_6502_F9 (void)
/* Opcode $F9: SBC abs,y */
{
ALU_OP (ABSY, SBC);
}
static void OPC_65SC02_FA (void)
/* Opcode $7A: PLX */
{
Cycles = 4;
Regs.XR = POP ();
TEST_ZF (Regs.XR);
TEST_SF (Regs.XR);
Regs.PC += 1;
}
static void OPC_6502_FB (void)
/* Opcode $FB: ISC abs,y */
{
MEM_OP (ABSY, ISC);
}
static void OPC_6502_FD (void)
/* Opcode $FD: SBC abs,x */
{
ALU_OP (ABSX, SBC);
}
static void OPC_6502_FE (void)
/* Opcode $FE: INC abs,x */
{
MEM_OP (ABSX, INC);
}
static void OPC_6502_FF (void)
/* Opcode $FF: ISC abs,x */
{
MEM_OP (ABSX, ISC);
}
/*****************************************************************************/
/* Opcode handler tables */
/*****************************************************************************/
/* Opcode handler table for the 6502 */
static const OPFunc OP6502Table[256] = {
OPC_6502_00,
OPC_6502_01,
OPC_Illegal,
OPC_Illegal,
OPC_Illegal,
OPC_6502_05,
OPC_6502_06,
OPC_Illegal,
OPC_6502_08,
OPC_6502_09,
OPC_6502_0A,
OPC_Illegal,
OPC_Illegal,
OPC_6502_0D,
OPC_6502_0E,
OPC_Illegal,
OPC_6502_10,
OPC_6502_11,
OPC_Illegal,
OPC_Illegal,
OPC_Illegal,
OPC_6502_15,
OPC_6502_16,
OPC_Illegal,
OPC_6502_18,
OPC_6502_19,
OPC_Illegal,
OPC_Illegal,
OPC_Illegal,
OPC_6502_1D,
OPC_6502_1E,
OPC_Illegal,
OPC_6502_20,
OPC_6502_21,
OPC_Illegal,
OPC_Illegal,
OPC_6502_24,
OPC_6502_25,
OPC_6502_26,
OPC_Illegal,
OPC_6502_28,
OPC_6502_29,
OPC_6502_2A,
OPC_Illegal,
OPC_6502_2C,
OPC_6502_2D,
OPC_6502_2E,
OPC_Illegal,
OPC_6502_30,
OPC_6502_31,
OPC_Illegal,
OPC_Illegal,
OPC_Illegal,
OPC_6502_35,
OPC_6502_36,
OPC_Illegal,
OPC_6502_38,
OPC_6502_39,
OPC_Illegal,
OPC_Illegal,
OPC_Illegal,
OPC_6502_3D,
OPC_6502_3E,
OPC_Illegal,
OPC_6502_40,
OPC_6502_41,
OPC_Illegal,
OPC_Illegal,
OPC_Illegal,
OPC_6502_45,
OPC_6502_46,
OPC_Illegal,
OPC_6502_48,
OPC_6502_49,
OPC_6502_4A,
OPC_Illegal,
OPC_6502_4C,
OPC_6502_4D,
OPC_6502_4E,
OPC_Illegal,
OPC_6502_50,
OPC_6502_51,
OPC_Illegal,
OPC_Illegal,
OPC_Illegal,
OPC_6502_55,
OPC_6502_56,
OPC_Illegal,
OPC_6502_58,
OPC_6502_59,
OPC_Illegal,
OPC_Illegal,
OPC_Illegal,
OPC_6502_5D,
OPC_6502_5E,
OPC_Illegal,
OPC_6502_60,
OPC_6502_61,
OPC_Illegal,
OPC_Illegal,
OPC_Illegal,
OPC_6502_65,
OPC_6502_66,
OPC_Illegal,
OPC_6502_68,
OPC_6502_69,
OPC_6502_6A,
OPC_Illegal,
OPC_6502_6C,
OPC_6502_6D,
OPC_6502_6E,
OPC_Illegal,
OPC_6502_70,
OPC_6502_71,
OPC_Illegal,
OPC_Illegal,
OPC_Illegal,
OPC_6502_75,
OPC_6502_76,
OPC_Illegal,
OPC_6502_78,
OPC_6502_79,
OPC_Illegal,
OPC_Illegal,
OPC_Illegal,
OPC_6502_7D,
OPC_6502_7E,
OPC_Illegal,
OPC_Illegal,
OPC_6502_81,
OPC_Illegal,
OPC_Illegal,
OPC_6502_84,
OPC_6502_85,
OPC_6502_86,
OPC_Illegal,
OPC_6502_88,
OPC_Illegal,
OPC_6502_8A,
OPC_Illegal,
OPC_6502_8C,
OPC_6502_8D,
OPC_6502_8E,
OPC_Illegal,
OPC_6502_90,
OPC_6502_91,
OPC_Illegal,
OPC_Illegal,
OPC_6502_94,
OPC_6502_95,
OPC_6502_96,
OPC_Illegal,
OPC_6502_98,
OPC_6502_99,
OPC_6502_9A,
OPC_Illegal,
OPC_Illegal,
OPC_6502_9D,
OPC_Illegal,
OPC_Illegal,
OPC_6502_A0,
OPC_6502_A1,
OPC_6502_A2,
OPC_Illegal,
OPC_6502_A4,
OPC_6502_A5,
OPC_6502_A6,
OPC_Illegal,
OPC_6502_A8,
OPC_6502_A9,
OPC_6502_AA,
OPC_Illegal,
OPC_6502_AC,
OPC_6502_AD,
OPC_6502_AE,
OPC_Illegal,
OPC_6502_B0,
OPC_6502_B1,
OPC_Illegal,
OPC_Illegal,
OPC_6502_B4,
OPC_6502_B5,
OPC_6502_B6,
OPC_Illegal,
OPC_6502_B8,
OPC_6502_B9,
OPC_6502_BA,
OPC_Illegal,
OPC_6502_BC,
OPC_6502_BD,
OPC_6502_BE,
OPC_Illegal,
OPC_6502_C0,
OPC_6502_C1,
OPC_Illegal,
OPC_Illegal,
OPC_6502_C4,
OPC_6502_C5,
OPC_6502_C6,
OPC_Illegal,
OPC_6502_C8,
OPC_6502_C9,
OPC_6502_CA,
OPC_Illegal,
OPC_6502_CC,
OPC_6502_CD,
OPC_6502_CE,
OPC_Illegal,
OPC_6502_D0,
OPC_6502_D1,
OPC_Illegal,
OPC_Illegal,
OPC_Illegal,
OPC_6502_D5,
OPC_6502_D6,
OPC_Illegal,
OPC_6502_D8,
OPC_6502_D9,
OPC_Illegal,
OPC_Illegal,
OPC_Illegal,
OPC_6502_DD,
OPC_6502_DE,
OPC_Illegal,
OPC_6502_E0,
OPC_6502_E1,
OPC_Illegal,
OPC_Illegal,
OPC_6502_E4,
OPC_6502_E5,
OPC_6502_E6,
OPC_Illegal,
OPC_6502_E8,
OPC_6502_E9,
OPC_6502_EA,
OPC_Illegal,
OPC_6502_EC,
OPC_6502_ED,
OPC_6502_EE,
OPC_Illegal,
OPC_6502_F0,
OPC_6502_F1,
OPC_Illegal,
OPC_Illegal,
OPC_Illegal,
OPC_6502_F5,
OPC_6502_F6,
OPC_Illegal,
OPC_6502_F8,
OPC_6502_F9,
OPC_Illegal,
OPC_Illegal,
OPC_Illegal,
OPC_6502_FD,
OPC_6502_FE,
OPC_Illegal,
};
/* Opcode handler table for the 6502X */
static const OPFunc OP6502XTable[256] = {
OPC_6502_00,
OPC_6502_01,
OPC_Illegal,
OPC_6502_03,
OPC_6502_04,
OPC_6502_05,
OPC_6502_06,
OPC_6502_07,
OPC_6502_08,
OPC_6502_09,
OPC_6502_0A,
OPC_6502_0B,
OPC_6502_0C,
OPC_6502_0D,
OPC_6502_0E,
OPC_6502_0F,
OPC_6502_10,
OPC_6502_11,
OPC_Illegal,
OPC_6502_13,
OPC_6502_14,
OPC_6502_15,
OPC_6502_16,
OPC_6502_17,
OPC_6502_18,
OPC_6502_19,
OPC_6502_1A,
OPC_6502_1B,
OPC_6502_1C,
OPC_6502_1D,
OPC_6502_1E,
OPC_6502_1F,
OPC_6502_20,
OPC_6502_21,
OPC_Illegal,
OPC_6502_23,
OPC_6502_24,
OPC_6502_25,
OPC_6502_26,
OPC_6502_27,
OPC_6502_28,
OPC_6502_29,
OPC_6502_2A,
OPC_6502_2B,
OPC_6502_2C,
OPC_6502_2D,
OPC_6502_2E,
OPC_6502_2F,
OPC_6502_30,
OPC_6502_31,
OPC_Illegal,
OPC_6502_33,
OPC_6502_34,
OPC_6502_35,
OPC_6502_36,
OPC_6502_37,
OPC_6502_38,
OPC_6502_39,
OPC_6502_3A,
OPC_6502_3B,
OPC_6502_3C,
OPC_6502_3D,
OPC_6502_3E,
OPC_6502_3F,
OPC_6502_40,
OPC_6502_41,
OPC_Illegal,
OPC_6502_43,
OPC_6502_44,
OPC_6502_45,
OPC_6502_46,
OPC_6502_47,
OPC_6502_48,
OPC_6502_49,
OPC_6502_4A,
OPC_6502_4B,
OPC_6502_4C,
OPC_6502_4D,
OPC_6502_4E,
OPC_6502_4F,
OPC_6502_50,
OPC_6502_51,
OPC_Illegal,
OPC_6502_53,
OPC_6502_54,
OPC_6502_55,
OPC_6502_56,
OPC_6502_57,
OPC_6502_58,
OPC_6502_59,
OPC_6502_5A,
OPC_6502_5B,
OPC_6502_5C,
OPC_6502_5D,
OPC_6502_5E,
OPC_6502_5F,
OPC_6502_60,
OPC_6502_61,
OPC_Illegal,
OPC_6502_63,
OPC_6502_64,
OPC_6502_65,
OPC_6502_66,
OPC_6502_67,
OPC_6502_68,
OPC_6502_69,
OPC_6502_6A,
OPC_6502_6B,
OPC_6502_6C,
OPC_6502_6D,
OPC_6502_6E,
OPC_6502_6F,
OPC_6502_70,
OPC_6502_71,
OPC_Illegal,
OPC_6502_73,
OPC_6502_74,
OPC_6502_75,
OPC_6502_76,
OPC_6502_77,
OPC_6502_78,
OPC_6502_79,
OPC_6502_7A,
OPC_6502_7B,
OPC_6502_7C,
OPC_6502_7D,
OPC_6502_7E,
OPC_6502_7F,
OPC_6502_80,
OPC_6502_81,
OPC_6502_82,
OPC_6502_83,
OPC_6502_84,
OPC_6502_85,
OPC_6502_86,
OPC_6502_87,
OPC_6502_88,
OPC_6502_89,
OPC_6502_8A,
OPC_6502_8B,
OPC_6502_8C,
OPC_6502_8D,
OPC_6502_8E,
OPC_6502_8F,
OPC_6502_90,
OPC_6502_91,
OPC_Illegal,
OPC_6502_93,
OPC_6502_94,
OPC_6502_95,
OPC_6502_96,
OPC_6502_97,
OPC_6502_98,
OPC_6502_99,
OPC_6502_9A,
OPC_6502_9B,
OPC_6502_9C,
OPC_6502_9D,
OPC_6502_9E,
OPC_6502_9F,
OPC_6502_A0,
OPC_6502_A1,
OPC_6502_A2,
OPC_6502_A3,
OPC_6502_A4,
OPC_6502_A5,
OPC_6502_A6,
OPC_6502_A7,
OPC_6502_A8,
OPC_6502_A9,
OPC_6502_AA,
OPC_6502_AB,
OPC_6502_AC,
OPC_6502_AD,
OPC_6502_AE,
OPC_6502_AF,
OPC_6502_B0,
OPC_6502_B1,
OPC_Illegal,
OPC_6502_B3,
OPC_6502_B4,
OPC_6502_B5,
OPC_6502_B6,
OPC_6502_B7,
OPC_6502_B8,
OPC_6502_B9,
OPC_6502_BA,
OPC_6502_BB,
OPC_6502_BC,
OPC_6502_BD,
OPC_6502_BE,
OPC_6502_BF,
OPC_6502_C0,
OPC_6502_C1,
OPC_6502_C2,
OPC_6502_C3,
OPC_6502_C4,
OPC_6502_C5,
OPC_6502_C6,
OPC_6502_C7,
OPC_6502_C8,
OPC_6502_C9,
OPC_6502_CA,
OPC_6502_CB,
OPC_6502_CC,
OPC_6502_CD,
OPC_6502_CE,
OPC_6502_CF,
OPC_6502_D0,
OPC_6502_D1,
OPC_Illegal,
OPC_6502_D3,
OPC_6502_D4,
OPC_6502_D5,
OPC_6502_D6,
OPC_6502_D7,
OPC_6502_D8,
OPC_6502_D9,
OPC_6502_DA,
OPC_6502_DB,
OPC_6502_DC,
OPC_6502_DD,
OPC_6502_DE,
OPC_6502_DF,
OPC_6502_E0,
OPC_6502_E1,
OPC_6502_E2,
OPC_6502_E3,
OPC_6502_E4,
OPC_6502_E5,
OPC_6502_E6,
OPC_6502_E7,
OPC_6502_E8,
OPC_6502_E9,
OPC_6502_EA,
OPC_6502_EB,
OPC_6502_EC,
OPC_6502_ED,
OPC_6502_EE,
OPC_6502_EF,
OPC_6502_F0,
OPC_6502_F1,
OPC_Illegal,
OPC_6502_F3,
OPC_6502_F4,
OPC_6502_F5,
OPC_6502_F6,
OPC_6502_F7,
OPC_6502_F8,
OPC_6502_F9,
OPC_6502_FA,
OPC_6502_FB,
OPC_6502_FC,
OPC_6502_FD,
OPC_6502_FE,
OPC_6502_FF
};
/* Opcode handler table for the 65C02 */
static const OPFunc OP65C02Table[256] = {
OPC_6502_00,
OPC_6502_01,
OPC_65C02_NOP22, // $02
OPC_65C02_NOP11, // $03
OPC_65SC02_04,
OPC_6502_05,
OPC_6502_06,
OPC_Illegal, // $07: RMB0 currently unsupported
OPC_6502_08,
OPC_6502_09,
OPC_6502_0A,
OPC_65C02_NOP11, // $0B
OPC_65SC02_0C,
OPC_6502_0D,
OPC_6502_0E,
OPC_Illegal, // $0F: BBR0 currently unsupported
OPC_6502_10,
OPC_6502_11,
OPC_65SC02_12,
OPC_65C02_NOP11, // $13
OPC_65SC02_14,
OPC_6502_15,
OPC_6502_16,
OPC_Illegal, // $17: RMB1 currently unsupported
OPC_6502_18,
OPC_6502_19,
OPC_65SC02_1A,
OPC_65C02_NOP11, // $1B
OPC_65SC02_1C,
OPC_6502_1D,
OPC_65C02_1E,
OPC_Illegal, // $1F: BBR1 currently unsupported
OPC_6502_20,
OPC_6502_21,
OPC_65C02_NOP22, // $22
OPC_65C02_NOP11, // $23
OPC_6502_24,
OPC_6502_25,
OPC_6502_26,
OPC_Illegal, // $27: RMB2 currently unsupported
OPC_6502_28,
OPC_6502_29,
OPC_6502_2A,
OPC_65C02_NOP11, // $2B
OPC_6502_2C,
OPC_6502_2D,
OPC_6502_2E,
OPC_Illegal, // $2F: BBR2 currently unsupported
OPC_6502_30,
OPC_6502_31,
OPC_65SC02_32,
OPC_65C02_NOP11, // $33
OPC_65SC02_34,
OPC_6502_35,
OPC_6502_36,
OPC_Illegal, // $37: RMB3 currently unsupported
OPC_6502_38,
OPC_6502_39,
OPC_65SC02_3A,
OPC_65C02_NOP11, // $3B
OPC_65SC02_3C,
OPC_6502_3D,
OPC_65C02_3E,
OPC_Illegal, // $3F: BBR3 currently unsupported
OPC_6502_40,
OPC_6502_41,
OPC_65C02_NOP22, // $42
OPC_65C02_NOP11, // $43
OPC_6502_44, // $44
OPC_6502_45,
OPC_6502_46,
OPC_Illegal, // $47: RMB4 currently unsupported
OPC_6502_48,
OPC_6502_49,
OPC_6502_4A,
OPC_65C02_NOP11, // $4B
OPC_6502_4C,
OPC_6502_4D,
OPC_6502_4E,
OPC_Illegal, // $4F: BBR4 currently unsupported
OPC_6502_50,
OPC_6502_51,
OPC_65SC02_52,
OPC_65C02_NOP11, // $53
OPC_65C02_NOP24, // $54
OPC_6502_55,
OPC_6502_56,
OPC_Illegal, // $57: RMB5 currently unsupported
OPC_6502_58,
OPC_6502_59,
OPC_65SC02_5A,
OPC_65C02_NOP11, // $5B
OPC_65C02_5C,
OPC_6502_5D,
OPC_65C02_5E,
OPC_Illegal, // $5F: BBR5 currently unsupported
OPC_6502_60,
OPC_6502_61,
OPC_65C02_NOP22, // $62
OPC_65C02_NOP11, // $63
OPC_65SC02_64,
OPC_6502_65,
OPC_6502_66,
OPC_Illegal, // $67: RMB6 currently unsupported
OPC_6502_68,
OPC_6502_69,
OPC_6502_6A,
OPC_65C02_NOP11, // $6B
OPC_65C02_6C,
OPC_6502_6D,
OPC_6502_6E,
OPC_Illegal, // $6F: BBR6 currently unsupported
OPC_6502_70,
OPC_6502_71,
OPC_65SC02_72,
OPC_65C02_NOP11, // $73
OPC_65SC02_74,
OPC_6502_75,
OPC_6502_76,
OPC_Illegal, // $77: RMB7 currently unsupported
OPC_6502_78,
OPC_6502_79,
OPC_65SC02_7A,
OPC_65C02_NOP11, // $7B
OPC_65SC02_7C,
OPC_6502_7D,
OPC_65C02_7E,
OPC_Illegal, // $7F: BBR7 currently unsupported
OPC_65SC02_80,
OPC_6502_81,
OPC_65C02_NOP22, // $82
OPC_65C02_NOP11, // $83
OPC_6502_84,
OPC_6502_85,
OPC_6502_86,
OPC_Illegal, // $87: SMB0 currently unsupported
OPC_6502_88,
OPC_65SC02_89,
OPC_6502_8A,
OPC_65C02_NOP11, // $8B
OPC_6502_8C,
OPC_6502_8D,
OPC_6502_8E,
OPC_Illegal, // $8F: BBS0 currently unsupported
OPC_6502_90,
OPC_6502_91,
OPC_65SC02_92,
OPC_65C02_NOP11, // $93
OPC_6502_94,
OPC_6502_95,
OPC_6502_96,
OPC_Illegal, // $97: SMB1 currently unsupported
OPC_6502_98,
OPC_6502_99,
OPC_6502_9A,
OPC_65C02_NOP11, // $9B
OPC_65SC02_9C,
OPC_6502_9D,
OPC_65SC02_9E,
OPC_Illegal, // $9F: BBS1 currently unsupported
OPC_6502_A0,
OPC_6502_A1,
OPC_6502_A2,
OPC_65C02_NOP11, // $A3
OPC_6502_A4,
OPC_6502_A5,
OPC_6502_A6,
OPC_Illegal, // $A7: SMB2 currently unsupported
OPC_6502_A8,
OPC_6502_A9,
OPC_6502_AA,
OPC_65C02_NOP11, // $AB
OPC_6502_AC,
OPC_6502_AD,
OPC_6502_AE,
OPC_Illegal, // $AF: BBS2 currently unsupported
OPC_6502_B0,
OPC_6502_B1,
OPC_65SC02_B2,
OPC_65C02_NOP11, // $B3
OPC_6502_B4,
OPC_6502_B5,
OPC_6502_B6,
OPC_Illegal, // $B7: SMB3 currently unsupported
OPC_6502_B8,
OPC_6502_B9,
OPC_6502_BA,
OPC_65C02_NOP11, // $BB
OPC_6502_BC,
OPC_6502_BD,
OPC_6502_BE,
OPC_Illegal, // $BF: BBS3 currently unsupported
OPC_6502_C0,
OPC_6502_C1,
OPC_65C02_NOP22, // $C2
OPC_65C02_NOP11, // $C3
OPC_6502_C4,
OPC_6502_C5,
OPC_6502_C6,
OPC_Illegal, // $C7: SMB4 currently unsupported
OPC_6502_C8,
OPC_6502_C9,
OPC_6502_CA,
OPC_Illegal, // $CB: WAI currently unsupported
OPC_6502_CC,
OPC_6502_CD,
OPC_6502_CE,
OPC_Illegal, // $CF: BBS4 currently unsupported
OPC_6502_D0,
OPC_6502_D1,
OPC_65SC02_D2,
OPC_65C02_NOP11, // $D3
OPC_65C02_NOP24, // $D4
OPC_6502_D5,
OPC_6502_D6,
OPC_Illegal, // $D7: SMB5 currently unsupported
OPC_6502_D8,
OPC_6502_D9,
OPC_65SC02_DA,
OPC_Illegal, // $DB: STP currently unsupported
OPC_65C02_NOP34, // $DC
OPC_6502_DD,
OPC_6502_DE,
OPC_Illegal, // $DF: BBS5 currently unsupported
OPC_6502_E0,
OPC_6502_E1,
OPC_65C02_NOP22, // $E2
OPC_65C02_NOP11, // $E3
OPC_6502_E4,
OPC_6502_E5,
OPC_6502_E6,
OPC_Illegal, // $E7: SMB6 currently unsupported
OPC_6502_E8,
OPC_6502_E9,
OPC_6502_EA,
OPC_65C02_NOP11, // $EB
OPC_6502_EC,
OPC_6502_ED,
OPC_6502_EE,
OPC_Illegal, // $EF: BBS6 currently unsupported
OPC_6502_F0,
OPC_6502_F1,
OPC_65SC02_F2,
OPC_65C02_NOP11, // $F3
OPC_65C02_NOP24, // $F4
OPC_6502_F5,
OPC_6502_F6,
OPC_Illegal, // $F7: SMB7 currently unsupported
OPC_6502_F8,
OPC_6502_F9,
OPC_65SC02_FA,
OPC_65C02_NOP11, // $FB
OPC_65C02_NOP34, // $FC
OPC_6502_FD,
OPC_6502_FE,
OPC_Illegal, // $FF: BBS7 currently unsupported
};
/* Tables with opcode handlers */
static const OPFunc* Handlers[3] = {
OP6502Table,
OP65C02Table,
OP6502XTable
};
/*****************************************************************************/
/* Code */
/*****************************************************************************/
void IRQRequest (void)
/* Generate an IRQ */
{
/* Remember the request */
HaveIRQRequest = 1;
}
void NMIRequest (void)
/* Generate an NMI */
{
/* Remember the request */
HaveNMIRequest = 1;
}
void Reset (void)
/* Generate a CPU RESET */
{
/* Reset the CPU */
HaveIRQRequest = 0;
HaveNMIRequest = 0;
/* Bits 5 and 4 aren't used, and always are 1! */
Regs.SR = 0x30;
Regs.PC = MemReadWord (0xFFFC);
}
unsigned ExecuteInsn (void)
/* Execute one CPU instruction */
{
/* If we have an NMI request, handle it */
if (HaveNMIRequest) {
HaveNMIRequest = 0;
PUSH (PCH);
PUSH (PCL);
PUSH (Regs.SR & ~BF);
SET_IF (1);
if (CPU != CPU_6502)
{
SET_DF (0);
}
Regs.PC = MemReadWord (0xFFFA);
Cycles = 7;
} else if (HaveIRQRequest && GET_IF () == 0) {
HaveIRQRequest = 0;
PUSH (PCH);
PUSH (PCL);
PUSH (Regs.SR & ~BF);
SET_IF (1);
if (CPU != CPU_6502)
{
SET_DF (0);
}
Regs.PC = MemReadWord (0xFFFE);
Cycles = 7;
} else {
/* Normal instruction - read the next opcode */
unsigned char OPC = MemReadByte (Regs.PC);
/* Execute it */
Handlers[CPU][OPC] ();
}
/* Return the number of clock cycles needed by this insn */
return Cycles;
}