apple2ix/src/x86/cpu.S

2227 lines
57 KiB
ArmAsm

/*
* Apple // emulator for *ix
*
* This software package is subject to the GNU General Public License
* version 3 or later (your choice) as published by the Free Software
* Foundation.
*
* Copyright 1994 Alexander Jean-Claude Bottema
* Copyright 1995 Stephen Lee
* Copyright 1997, 1998 Aaron Culliney
* Copyright 1998, 1999, 2000 Michael Deutschmann
* Copyright 2013-2015 Aaron Culliney
*
*/
#include "cpu-regs.h"
#include "vm.h"
#define SAVE_Y_REG() \
movb Y_Reg, CPU65_Y(reg_args)
#define CommonSaveCPUState \
movw EffectiveAddr, CPU65_EA(reg_args); \
movb A_Reg, CPU65_A(reg_args); \
xorw %ax, %ax; \
movb F_Reg, %al; \
MOVB_IND(CPU65_FLAGS_ENCODE,_XAX,%al); \
movb %al, CPU65_F(reg_args); \
movb X_Reg, CPU65_X(reg_args); \
SAVE_Y_REG();
#if CPU_TRACING
# define TRACE_PROLOGUE \
movw PC_Reg, CPU65_PC(reg_args); \
callLQ *CPU65_TRACE_PROLOGUE(reg_args);
# define TRACE_ARG \
callLQ *CPU65_TRACE_ARG(reg_args);
# define TRACE_EPILOGUE \
pushLQ _XAX; \
CommonSaveCPUState; \
popLQ _XAX; \
callLQ *CPU65_TRACE_EPILOGUE(reg_args);
# define TRACE_IRQ \
callLQ *CPU65_TRACE_IRQ(reg_args);
#else
# define TRACE_PROLOGUE
# define TRACE_ARG
# define TRACE_EPILOGUE
# define TRACE_IRQ
#endif
/* -------------------------------------------------------------------------
CPU (6502) Helper Routines
------------------------------------------------------------------------- */
#define GetFromPC_B \
movLQ PC_Reg_X, EffectiveAddr_X; \
incw PC_Reg; \
CALL_IND(CPU65_VMEM_R,EffectiveAddr_X); \
TRACE_ARG;
#define GetFromPC_W \
movLQ PC_Reg_X, EffectiveAddr_X; \
addw $2, PC_Reg; \
CALL_IND(CPU65_VMEM_R,EffectiveAddr_X); \
TRACE_ARG; \
movb %al, %ah; \
incw EffectiveAddr; \
CALL_IND(CPU65_VMEM_R,EffectiveAddr_X); \
TRACE_ARG; \
xchgb %al, %ah;
#define CPUStatsReset \
movb $0, CPU65_OPCYCLES(reg_args); \
movb $0, CPU65_RW(reg_args);
#define JumpNextInstruction \
TRACE_PROLOGUE; \
GetFromPC_B \
movb %al, CPU65_OPCODE(reg_args); \
JUMP_IND(CPU65__OPCODES,_XAX)
#define GetFromEA_B \
orb $1, CPU65_RW(reg_args); \
CALL_IND(CPU65_VMEM_R,EffectiveAddr_X);
#define GetFromEA_W \
incw EffectiveAddr; \
CALL_IND(CPU65_VMEM_R,EffectiveAddr_X); \
decw EffectiveAddr; \
movb %al, %ah; \
CALL_IND(CPU65_VMEM_R,EffectiveAddr_X);
#define PutToEA_B \
orb $2, CPU65_RW(reg_args); \
movb %al, CPU65_D(reg_args); \
CALL_IND(CPU65_VMEM_W,EffectiveAddr_X);
#define GetFromMem_B(x) \
movLQ x, EffectiveAddr_X; \
CALL_IND(CPU65_VMEM_R,EffectiveAddr_X);
#define GetFromMem_W(x) \
movLQ x, EffectiveAddr_X; \
GetFromEA_W
#define Continue \
jmp continue;
#define BranchXCycles \
incb CPU65_OPCYCLES(reg_args); /* +1 branch taken */ \
shlLQ $16, _XBX; \
movw PC_Reg, %bx; \
cbw; \
addw %bx, %ax; \
movw %ax, PC_Reg; \
cmpb %ah, %bh; \
je 9f; \
incb CPU65_OPCYCLES(reg_args); /* +1 branch new page */ \
9: shrLQ $16, _XBX;
#define FlagC \
lahf; \
andb $C_Flag, %ah; \
andb $~C_Flag, F_Reg; \
orb %ah, F_Reg;
#define FlagZ \
lahf; \
andb $Z_Flag, %ah; \
andb $~Z_Flag, F_Reg; \
orb %ah, F_Reg;
#define FlagN \
lahf; \
andb $N_Flag, %ah; \
andb $~N_Flag, F_Reg; \
orb %ah, F_Reg;
#define FlagNZ \
lahf; \
andb $(N_Flag|Z_Flag), %ah; \
andb $~(N_Flag|Z_Flag), F_Reg; \
orb %ah, F_Reg;
#define FlagNZC \
lahf; \
andb $(N_Flag|Z_Flag|C_Flag), %ah; \
andb $~(N_Flag|Z_Flag|C_Flag), F_Reg; \
orb %ah, F_Reg;
/* Have to do things a little differently since
* overflow is not read by the LAHF instruction
*
* Use of long operands wastes two bytes on the AND
* constant, but saves three instruction prefixes.
* This doesn't affect the cycle count.
*/
#define FlagNVZC \
pushfLQ; \
popLQ _XAX; \
andLQ $(N_Flag|(V_Flag<<8)|Z_Flag|C_Flag),_XAX; \
andb $~(N_Flag|V_Flag|Z_Flag|C_Flag), F_Reg; \
orb %ah, F_Reg; \
orb %al, F_Reg;
#ifdef APPLE2_VM
# define _GetStkOff \
movzbLQ CPU65_SP(reg_args), _XBP; \
addLQ BASE_STACKZP(reg_args), _XBP; \
addLQ $0x0100, _XBP;
#else
# error FIXME TODO ...
#endif
#define Push(x) \
_GetStkOff \
movb x, (_XBP); \
decb CPU65_SP(reg_args);
#define Pop(x) \
incb CPU65_SP(reg_args); \
_GetStkOff \
movb (_XBP), x;
/* Immediate Addressing - the operand is contained in the second byte of the
instruction. */
#define _GetImm \
movLQ PC_Reg_X, EffectiveAddr_X; \
incw PC_Reg;
#if CPU_TRACING
#define GetImm \
_GetImm \
CALL_IND(CPU65_VMEM_R,EffectiveAddr_X); \
TRACE_ARG;
#else
#define GetImm \
_GetImm
#endif
/* Absolute Addressing - the second byte of the instruction is the low
order address, and the third byte is the high order byte. */
#define GetAbs \
GetFromPC_W; \
movLQ _XAX, EffectiveAddr_X;
/* Zero Page Addressing - the second byte of the instruction is an
address on the zero page */
#define GetZPage \
GetFromPC_B; \
movLQ _XAX, EffectiveAddr_X;
/* Zero Page Indexed Addressing - The effective address is calculated by
adding the second byte to the contents of the index register. Due
to the zero page addressing nature of this mode, no carry is added
to the high address byte, and the crossing of page boundaries does
not occur. */
#define GetZPage_X \
GetFromPC_B; \
addb X_Reg, %al; \
movLQ _XAX, EffectiveAddr_X;
#define GetZPage_Y \
GetFromPC_B; \
addb Y_Reg, %al; \
movLQ _XAX, EffectiveAddr_X;
/* Absolute Indexed Addressing - The effective address is formed by
adding the contents of X or Y to the address contained in the
second and third bytes of the instruction. */
#define _GetAbs_X \
GetFromPC_W; \
addb X_Reg, %al; \
jnc 9f; \
adcb $0, %ah;
#define GetAbs_X \
_GetAbs_X \
incb CPU65_OPCYCLES(reg_args); /* +1 cycle on page boundary */ \
9: movLQ _XAX, EffectiveAddr_X;
#define GetAbs_X_STx \
_GetAbs_X \
9: movLQ _XAX, EffectiveAddr_X;
#define _GetAbs_Y \
GetFromPC_W; \
addb Y_Reg, %al; \
jnc 9f; \
adcb $0, %ah;
#define GetAbs_Y \
_GetAbs_Y \
incb CPU65_OPCYCLES(reg_args); /* +1 cycle on page boundary */ \
9: movLQ _XAX, EffectiveAddr_X;
#define GetAbs_Y_STA \
_GetAbs_Y \
9: movLQ _XAX, EffectiveAddr_X;
/* Zero Page Indirect Addressing (65c02) - The second byte of the
instruction points to a memory location on page zero containing the
low order byte of the effective address. The next location on page
zero contains the high order byte of the address. */
#define GetIndZPage \
GetFromPC_B; \
incb %al; \
movLQ _XAX, EffectiveAddr_X; \
GetFromEA_B; \
movb %al, %ah; \
decLQ EffectiveAddr_X; \
andLQ $0xFF, EffectiveAddr_X; \
GetFromEA_B; \
movLQ _XAX, EffectiveAddr_X;
/* Zero Page Indexed Indirect Addressing - The second byte is added to
the contents of the X index register; the carry is discarded. The
result of this addition points to a memory location on page zero
whose contents is the low order byte of the effective address. The
next memory location in page zero contains the high-order byte of
the effective address. Both memory locations specifying the high
and low-order bytes must be in page zero. */
#define GetIndZPage_X \
GetFromPC_B; \
addb X_Reg, %al; \
incb %al; \
movLQ _XAX, EffectiveAddr_X; \
GetFromEA_B; \
movb %al, %ah; \
decLQ EffectiveAddr_X; \
andLQ $0xFF, EffectiveAddr_X; \
GetFromEA_B; \
movLQ _XAX, EffectiveAddr_X;
/* Indirect Indexed Addressing - The second byte of the instruction
points to a memory location in page zero. The contents of this
memory location are added to the contents of the Y index register,
the result being the low order byte of the effective address. The
carry from this addition is added to the contents of the next page
zero memory location, the result being the high order byte of the
effective address. */
#define _GetIndZPage_Y \
GetFromPC_B; \
incb %al; \
movLQ _XAX, EffectiveAddr_X; \
GetFromEA_B; \
movb %al, %ah; \
decLQ EffectiveAddr_X; \
andLQ $0xFF, EffectiveAddr_X; \
GetFromEA_B; \
addb Y_Reg, %al; \
jnc 9f;
#define GetIndZPage_Y \
_GetIndZPage_Y \
adcb $0, %ah; \
incb CPU65_OPCYCLES(reg_args); /* +1 cycle on page boundary */ \
9: movLQ _XAX, EffectiveAddr_X;
#define GetIndZPage_Y_STA \
_GetIndZPage_Y \
adcb $0, %ah; \
9: movLQ _XAX, EffectiveAddr_X;
#define DoADC_b GetFromEA_B \
bt $C_Flag_Bit, AF_Reg_X; \
adcb %al, A_Reg; \
FlagNVZC
#ifndef NDEBUG
#define DebugBCDCheck \
testb $0x80, A_Reg; \
jz 6f; \
testb $0x60, A_Reg; \
jz 6f; \
callLQ *DEBUG_ILLEGAL_BCD(reg_args); \
6: testb $0x08, A_Reg; \
jz 7f; \
testb $0x06, A_Reg; \
jz 7f; \
callLQ *DEBUG_ILLEGAL_BCD(reg_args); \
7: testb $0x80, %al; \
jz 8f; \
testb $0x60, %al; \
jz 8f; \
callLQ *DEBUG_ILLEGAL_BCD(reg_args); \
8: testb $0x08, %al; \
jz 9f; \
testb $0x06, %al; \
jz 9f; \
callLQ *DEBUG_ILLEGAL_BCD(reg_args); \
9:
#else
#define DebugBCDCheck
#endif
#define DoAND \
GetFromEA_B \
andb %al, A_Reg; \
FlagNZ
#define _DoASL(x) \
addb x, x; \
FlagNZC
#define DoASL \
GetFromEA_B \
_DoASL(%al) \
PutToEA_B
#define _DoBIT \
GetFromEA_B \
testb %al, A_Reg;
/* SAR (and the following AND) effectively moves
* bit 6 to Bit 3 while leaving Bit 7 unchanged */
#define DoBIT \
_DoBIT \
lahf; \
sarb $3, %al; \
andw $0x4088, %ax; \
andb $~(N_Flag|V_Flag|Z_Flag), F_Reg; \
orb %al, F_Reg; \
orb %ah, F_Reg;
#define DoCMP \
GetFromEA_B \
cmpb %al, A_Reg; \
cmc; \
FlagNZC
#define DoCPX \
GetFromEA_B \
cmpb %al, X_Reg; \
cmc; \
FlagNZC
#define DoCPY \
GetFromEA_B \
cmpb %al, Y_Reg; \
cmc; \
FlagNZC
#define _DoDEC(x) \
decb x; \
FlagNZ
#define DoDEC \
GetFromEA_B \
_DoDEC(%al) \
PutToEA_B
#define DoEOR \
GetFromEA_B \
xorb %al, A_Reg; \
FlagNZ
#define _DoINC(x) \
incb x; \
FlagNZ
#define DoINC \
GetFromEA_B \
_DoINC(%al) \
PutToEA_B
#define DoLDA \
GetFromEA_B \
movb %al, A_Reg; \
orb A_Reg, A_Reg; \
FlagNZ
#define DoLDX \
GetFromEA_B \
movb %al, X_Reg; \
orb X_Reg, X_Reg; \
FlagNZ
#define DoLDY \
GetFromEA_B \
movb %al, Y_Reg; \
orb Y_Reg, Y_Reg; \
FlagNZ
#define _DoLSR(x) \
shrb $1, x; \
FlagNZC
#define DoLSR \
GetFromEA_B \
_DoLSR(%al) \
PutToEA_B
#define DoORA \
GetFromEA_B \
orb %al, A_Reg; \
FlagNZ
#define _DoROL(x) \
bt $C_Flag_Bit, AF_Reg_X; \
adcb x, x; \
FlagNZC
#define DoROL \
GetFromEA_B \
_DoROL(%al) \
PutToEA_B
#define DoROR \
GetFromEA_B \
movb F_Reg, %ah; \
rorLQ $1, _XAX; \
orb %al, %al; \
btr $ROR_BIT, _XAX; \
FlagNZC \
PutToEA_B
#define DoSBC_b \
GetFromEA_B \
notb %al; \
bt $C_Flag_Bit, AF_Reg_X; \
adcb %al, A_Reg; \
FlagNVZC
#define DoSTA \
movb A_Reg, %al; \
PutToEA_B
#define DoSTX \
movb X_Reg, %al; \
PutToEA_B
#define DoSTY \
movb Y_Reg, %al; \
PutToEA_B
#define DoSTZ \
movb $0x0, %al; \
PutToEA_B
#define DoTRB \
GetFromEA_B \
testb A_Reg, %al; \
FlagZ \
notb A_Reg; \
andb A_Reg, %al; \
notb A_Reg; \
PutToEA_B
#define DoTSB \
GetFromEA_B \
testb A_Reg, %al; \
FlagZ \
orb A_Reg, %al; \
PutToEA_B
/* ----------------------------------------------------------------------
6502 routines and instructions
---------------------------------------------------------------------- */
/* ----------------------------------
ADC instructions
ADd memory to accumulator with Carry
---------------------------------- */
// Decimal mode
ENTRY(op_ADC_dec)
incb CPU65_OPCYCLES(reg_args) // +1 cycle
GetFromEA_B
DebugBCDCheck
bt $C_Flag_Bit, AF_Reg_X
adcb A_Reg, %al
#if !__LP64__
daa
movb %al, A_Reg
FlagNVZC
#else
// DAA algorithm : http://www.ray.masmcode.com/BCDdaa.html
// CF_old = CF
// IF (al AND 0Fh > 9) or (the Auxiliary Flag is set)
// al = al + 6
// CF = CF (automagically) or CF_old
// AF set (automagically)
// ENDIF
// IF (al > 99h) or (Carry Flag is set)
// al = al + 60h
// CF set
// ENDIF
pushfq
popq _XBP
andb $~(N_Flag|V_Flag|Z_Flag|C_Flag), F_Reg
movb %al, %ah
andb $0x0f, %ah
cmpb $9, %ah
jg _daa_lo_nyb
btq $X86_AF_Bit, _XBP
jnc _daa_next0
_daa_lo_nyb: addb $6, %al // adjust lo nybble
jc _daa_hi_nyb
_daa_next0: btq $X86_CF_Bit, _XBP
jc _daa_hi_nyb
xorb %ah, %ah
cmpw $0x99, %ax
jle _daa_next1
_daa_hi_nyb: addb $0x60, %al // adjust hi nybble
orb $C_Flag, F_Reg // FlagC
_daa_next1: testq $0x80, %rax
jz _daa_next2
orb $N_Flag, F_Reg // FlagN
_daa_next2: testq $0xFF, %rax
jnz _daa_finish
orb $Z_Flag, F_Reg // FlagZ
_daa_finish: movb %al, A_Reg
#endif
Continue
#define maybe_DoADC_d \
testb $D_Flag, F_Reg; /* Decimal mode? */ \
jnz CALL(op_ADC_dec) /* Yes, jump to decimal version */
ENTRY(op_ADC_imm) // 0x69
GetImm
maybe_DoADC_d
DoADC_b
Continue
ENTRY(op_ADC_zpage) // 0x65
GetZPage
maybe_DoADC_d
DoADC_b
Continue
ENTRY(op_ADC_zpage_x) // 0x75
GetZPage_X
maybe_DoADC_d
DoADC_b
Continue
// UNIMPLEMENTED : W65C02S datasheet
ENTRY(op_ADC_zpage_y)
jmp CALL(op_NOP)
ENTRY(op_ADC_abs) // 0x6d
GetAbs
maybe_DoADC_d
DoADC_b
Continue
ENTRY(op_ADC_abs_x) // 0x7d
GetAbs_X
maybe_DoADC_d
DoADC_b
Continue
ENTRY(op_ADC_abs_y) // 0x79
GetAbs_Y
maybe_DoADC_d
DoADC_b
Continue
ENTRY(op_ADC_ind_x) // 0x61
GetIndZPage_X
maybe_DoADC_d
DoADC_b
Continue
ENTRY(op_ADC_ind_y) // 0x71
GetIndZPage_Y
maybe_DoADC_d
DoADC_b
Continue
// 65c02 : 0x72
ENTRY(op_ADC_ind_zpage)
GetIndZPage
maybe_DoADC_d
DoADC_b
Continue
/* ----------------------------------
AND instructions
logical AND memory with accumulator
---------------------------------- */
ENTRY(op_AND_imm) // 0x29
GetImm
DoAND
Continue
ENTRY(op_AND_zpage) // 0x25
GetZPage
DoAND
Continue
ENTRY(op_AND_zpage_x) // 0x35
GetZPage_X
DoAND
Continue
// UNIMPLEMENTED : W65C02S datasheet
ENTRY(op_AND_zpage_y)
jmp CALL(op_NOP)
ENTRY(op_AND_abs) // 0x2d
GetAbs
DoAND
Continue
ENTRY(op_AND_abs_x) // 0x3d
GetAbs_X
DoAND
Continue
ENTRY(op_AND_abs_y) // 0x39
GetAbs_Y
DoAND
Continue
ENTRY(op_AND_ind_x) // 0x21
GetIndZPage_X
DoAND
Continue
ENTRY(op_AND_ind_y) // 0x31
GetIndZPage_Y
DoAND
Continue
// 65c02 : 0x32
ENTRY(op_AND_ind_zpage)
GetIndZPage
DoAND
Continue
/* ----------------------------------
ASL instructions
Arithmetic Shift one bit Left, memory or accumulator
---------------------------------- */
ENTRY(op_ASL_acc) // 0x0a
_DoASL(A_Reg)
Continue
ENTRY(op_ASL_zpage) // 0x06
GetZPage
DoASL
Continue
ENTRY(op_ASL_zpage_x) // 0x16
GetZPage_X
DoASL
Continue
ENTRY(op_ASL_abs) // 0x0e
GetAbs
DoASL
Continue
ENTRY(op_ASL_abs_x) // 0x1e
GetAbs_X
DoASL
Continue
/* ----------------------------------
BBRx instructions
UNIMPLEMENTED : These are documented in the W65C02S datasheet ...
+ 1 cycle if branch within page
+ 2 cycles if branch across page boundary
---------------------------------- */
ENTRY(op_BBR0_65c02)
Continue
ENTRY(op_BBR1_65c02)
Continue
ENTRY(op_BBR2_65c02)
Continue
ENTRY(op_BBR3_65c02)
Continue
ENTRY(op_BBR4_65c02)
Continue
ENTRY(op_BBR5_65c02)
Continue
ENTRY(op_BBR6_65c02)
Continue
ENTRY(op_BBR7_65c02)
Continue
/* ----------------------------------
BBSx instructions
UNIMPLEMENTED : These are documented in the W65C02S datasheet ...
+ 1 cycle if branch within page
+ 2 cycles if branch across page boundary
---------------------------------- */
ENTRY(op_BBS0_65c02)
Continue
ENTRY(op_BBS1_65c02)
Continue
ENTRY(op_BBS2_65c02)
Continue
ENTRY(op_BBS3_65c02)
Continue
ENTRY(op_BBS4_65c02)
Continue
ENTRY(op_BBS5_65c02)
Continue
ENTRY(op_BBS6_65c02)
Continue
ENTRY(op_BBS7_65c02)
Continue
/* ----------------------------------
BCC instruction
Branch on Carry Clear
---------------------------------- */
ENTRY(op_BCC) // 0x90
GetFromPC_B
testb $C_Flag, F_Reg
jnz op_BCC_not // branch not taken
BranchXCycles
op_BCC_not:
Continue
/* ----------------------------------
BCS instruction
Branch on Carry Set
---------------------------------- */
ENTRY(op_BCS) // 0xB0
GetFromPC_B
testb $C_Flag, F_Reg
jz op_BCS_not // branch not taken
BranchXCycles
op_BCS_not:
Continue
/* ----------------------------------
BEQ instruction
Branch if EQual
---------------------------------- */
ENTRY(op_BEQ) // 0xF0
GetFromPC_B
testb $Z_Flag, F_Reg
jz op_BEQ_not // branch not taken
BranchXCycles
op_BEQ_not:
Continue
/* ----------------------------------
BIT instructions
BIt Test
---------------------------------- */
ENTRY(op_BIT_zpage) // 0x24
GetZPage
DoBIT
Continue
ENTRY(op_BIT_abs) // 0x2c
GetAbs
DoBIT
Continue
// 65c02 : 0x34
ENTRY(op_BIT_zpage_x)
GetZPage_X
DoBIT
Continue
// 65c02 : 0x3C
ENTRY(op_BIT_abs_x)
GetAbs_X
DoBIT
Continue
/* BIT immediate is anomalous in that it does not affect the
* N and V flags, unlike in other addressing modes.
*/
// 65c02 : 0x89
ENTRY(op_BIT_imm)
GetImm
_DoBIT
FlagZ
Continue
/* ----------------------------------
BMI instruction
Branch on result MInus
---------------------------------- */
ENTRY(op_BMI) // 0x30
GetFromPC_B
testb F_Reg, F_Reg // check N flag, (which happens to be sign bit)
jns op_BMI_not
BranchXCycles
op_BMI_not:
Continue
/* ----------------------------------
BNE instruction
Branch on result Not Equal
---------------------------------- */
ENTRY(op_BNE) // 0xD0
GetFromPC_B
testb $Z_Flag, F_Reg
jnz op_BNE_not
BranchXCycles
op_BNE_not:
Continue
/* ----------------------------------
BPL instruction
Branch on result PLus
---------------------------------- */
ENTRY(op_BPL) // 0x10
GetFromPC_B
testb F_Reg, F_Reg // check N flag, (which happens to be sign bit)
js op_BPL_not
BranchXCycles
op_BPL_not:
Continue
/* ----------------------------------
BRA instruction
BRanch Always
---------------------------------- */
// 65c02 : 0x80
ENTRY(op_BRA)
GetFromPC_B
BranchXCycles
Continue
/* ----------------------------------
BRK instruction
---------------------------------- */
ENTRY(op_UNK) /* make undefined opcodes fault */
ENTRY(op_BRK)
incw PC_Reg
movw PC_Reg, %ax
Push(%ah)
Push(%al)
orb $(B_Flag|X_Flag), F_Reg
xorw %ax, %ax
movb F_Reg, %al
MOVB_IND(CPU65_FLAGS_ENCODE,_XAX,%al)
Push(%al)
orb $I_Flag, F_Reg
movw $0xFFFE, EffectiveAddr // ROM interrupt vector
GetFromEA_W
movw %ax, PC_Reg
Continue
/* ----------------------------------
BVC instruction
Branch on oVerflow Clear
---------------------------------- */
ENTRY(op_BVC) // 0x50
GetFromPC_B
testb $V_Flag, F_Reg
jnz op_BVC_not
BranchXCycles
op_BVC_not:
Continue
/* ----------------------------------
BVS instruction
Branch on oVerflow Set
---------------------------------- */
ENTRY(op_BVS) // 0x70
GetFromPC_B
testb $V_Flag, F_Reg
jz op_BVS_not
BranchXCycles
op_BVS_not:
Continue
/* ----------------------------------
CLC instruction
---------------------------------- */
ENTRY(op_CLC) // 0x18
andb $~C_Flag, F_Reg
Continue
/* ----------------------------------
CLD instruction
---------------------------------- */
ENTRY(op_CLD) // 0xd8
andb $~D_Flag, F_Reg
Continue
/* ----------------------------------
CLI instruction
---------------------------------- */
ENTRY(op_CLI) // 0x58
andb $~I_Flag, F_Reg
Continue
/* ----------------------------------
CLV instruction
---------------------------------- */
ENTRY(op_CLV) // 0xB8
andb $~V_Flag, F_Reg
Continue
/* ----------------------------------
CMP instructions
CoMPare memory and accumulator
---------------------------------- */
ENTRY(op_CMP_imm) // 0xc9
GetImm
DoCMP
Continue
ENTRY(op_CMP_zpage) // 0xc5
GetZPage
DoCMP
Continue
ENTRY(op_CMP_zpage_x) // 0xd5
GetZPage_X
DoCMP
Continue
// UNIMPLEMENTED : W65C02S datasheet
ENTRY(op_CMP_zpage_y)
jmp CALL(op_NOP)
ENTRY(op_CMP_abs) // 0xcd
GetAbs
DoCMP
Continue
ENTRY(op_CMP_abs_x) // 0xdd
GetAbs_X
DoCMP
Continue
ENTRY(op_CMP_abs_y) // 0xd9
GetAbs_Y
DoCMP
Continue
ENTRY(op_CMP_ind_x) // 0xc1
GetIndZPage_X
DoCMP
Continue
ENTRY(op_CMP_ind_y) // 0xd1
GetIndZPage_Y
DoCMP
Continue
// 65c02 : 0xD2
ENTRY(op_CMP_ind_zpage)
GetIndZPage
DoCMP
Continue
/* ----------------------------------
CPX instructions
ComPare memory and X register
---------------------------------- */
ENTRY(op_CPX_imm) // 0xe0
GetImm
DoCPX
Continue
ENTRY(op_CPX_zpage) // 0xe4
GetZPage
DoCPX
Continue
ENTRY(op_CPX_abs) // 0xec
GetAbs
DoCPX
Continue
/* ----------------------------------
CPY instructions
ComPare memory and Y register
---------------------------------- */
ENTRY(op_CPY_imm) // 0xc0
GetImm
DoCPY
Continue
ENTRY(op_CPY_zpage) // 0xc4
GetZPage
DoCPY
Continue
ENTRY(op_CPY_abs) // 0xcc
GetAbs
DoCPY
Continue
/* ----------------------------------
DEA: DEcrement Accumulator
---------------------------------- */
ENTRY(op_DEC_acc)
ENTRY(op_DEA) // 0x3A
_DoDEC(A_Reg)
Continue
/* ----------------------------------
DEC instructions
DECrement memory or accumulator by one
---------------------------------- */
ENTRY(op_DEC_zpage) // 0xc6
GetZPage
DoDEC
Continue
ENTRY(op_DEC_zpage_x) // 0xd6
GetZPage_X
DoDEC
Continue
ENTRY(op_DEC_abs) // 0xce
GetAbs
DoDEC
Continue
ENTRY(op_DEC_abs_x) // 0xde
GetAbs_X_STx
DoDEC
Continue
/* ----------------------------------
DEX instruction
---------------------------------- */
ENTRY(op_DEX) // 0xca
_DoDEC(X_Reg)
Continue
/* ----------------------------------
DEY instruction
---------------------------------- */
ENTRY(op_DEY) // 0x88
_DoDEC(Y_Reg)
Continue
/* ----------------------------------
EOR instructions
Exclusive OR memory with accumulator
---------------------------------- */
ENTRY(op_EOR_imm) // 0x49
GetImm
DoEOR
Continue
ENTRY(op_EOR_zpage) // 0x45
GetZPage
DoEOR
Continue
ENTRY(op_EOR_zpage_x) // 0x55
GetZPage_X
DoEOR
Continue
// UNIMPLEMENTED : W65C02S datasheet
ENTRY(op_EOR_zpage_y)
jmp CALL(op_NOP)
ENTRY(op_EOR_abs) // 0x4d
GetAbs
DoEOR
Continue
ENTRY(op_EOR_abs_x) // 0x5d
GetAbs_X
DoEOR
Continue
ENTRY(op_EOR_abs_y) // 0x59
GetAbs_Y
DoEOR
Continue
ENTRY(op_EOR_ind_x) // 0x41
GetIndZPage_X
DoEOR
Continue
ENTRY(op_EOR_ind_y) // 0x51
GetIndZPage_Y
DoEOR
Continue
// 65c02 : 0x52
ENTRY(op_EOR_ind_zpage)
GetIndZPage
DoEOR
Continue
/* ----------------------------------
INA : INcrement Accumulator
---------------------------------- */
ENTRY(op_INC_acc)
ENTRY(op_INA) // 0x1A
_DoINC(A_Reg)
Continue
/* ----------------------------------
INC instructions
INCrement memory
---------------------------------- */
ENTRY(op_INC_zpage) // 0xe6
GetZPage
DoINC
Continue
ENTRY(op_INC_zpage_x) // 0xf6
GetZPage_X
DoINC
Continue
ENTRY(op_INC_abs) // 0xee
GetAbs
DoINC
Continue
ENTRY(op_INC_abs_x) // 0xfe
GetAbs_X_STx
DoINC
Continue
/* ----------------------------------
INX instruction
---------------------------------- */
ENTRY(op_INX) // 0xe8
_DoINC(X_Reg)
Continue
/* ----------------------------------
INY instruction
---------------------------------- */
ENTRY(op_INY) // 0xc8
_DoINC(Y_Reg)
Continue
/* ----------------------------------
JMP instructions
JuMP to new location
---------------------------------- */
ENTRY(op_JMP_abs)
GetAbs
movw EffectiveAddr, PC_Reg;
Continue
ENTRY(op_JMP_ind) // 0x6c
GetFromPC_W
cmpb $0xFF, %al
je jmp_special
GetFromMem_W(_XAX)
movw %ax, PC_Reg
Continue
jmp_special: // see JMP indirect note in _Understanding the Apple IIe_ 4-25
movw %ax, PC_Reg
subw $0xFF, PC_Reg
GetFromMem_B(PC_Reg_X)
xchgb %al, %ah
addw $0xFF, PC_Reg
GetFromMem_B(PC_Reg_X)
movw %ax, PC_Reg
Continue
// 65c02 : 0x7C
ENTRY(op_JMP_abs_ind_x)
GetFromPC_W
movw %ax, EffectiveAddr
movzbLQ X_Reg, _XAX
#warning HACK FIXME TODO : need to check the Bible here ... is this a signed addition (in which case we need to cbw)
//cbw
addw %ax, EffectiveAddr
GetFromMem_W(EffectiveAddr_X)
movw %ax, PC_Reg
Continue
/* ----------------------------------
JSR instruction
---------------------------------- */
ENTRY(op_JSR) // 0x20
GetAbs
movw PC_Reg, %ax
decw %ax
Push(%ah)
Push(%al)
movw EffectiveAddr, PC_Reg
Continue
/* ----------------------------------
LDA instructions
LoaD Accumulator with memory
---------------------------------- */
ENTRY(op_LDA_imm) // 0xa9
GetImm
DoLDA
Continue
ENTRY(op_LDA_zpage) // 0xa5
GetZPage
DoLDA
Continue
ENTRY(op_LDA_zpage_x) // 0xb5
GetZPage_X
DoLDA
Continue
// UNIMPLEMENTED : W65C02S datasheet
ENTRY(op_LDA_zpage_y)
jmp CALL(op_NOP)
ENTRY(op_LDA_abs) // 0xad
GetAbs
DoLDA
Continue
ENTRY(op_LDA_abs_x) // 0xbd
GetAbs_X
DoLDA
Continue
ENTRY(op_LDA_abs_y) // 0xb9
GetAbs_Y
DoLDA
Continue
ENTRY(op_LDA_ind_x) // 0xa1
GetIndZPage_X
DoLDA
Continue
ENTRY(op_LDA_ind_y) // 0xb1
GetIndZPage_Y
DoLDA
Continue
// 65c02 : 0xB2
ENTRY(op_LDA_ind_zpage)
GetIndZPage
DoLDA
Continue
/* ----------------------------------
LDX instructions
---------------------------------- */
ENTRY(op_LDX_imm) // 0xa2
GetImm
DoLDX
Continue
ENTRY(op_LDX_zpage) // 0xa6
GetZPage
DoLDX
Continue
ENTRY(op_LDX_zpage_y) // 0xb6
GetZPage_Y
DoLDX
Continue
ENTRY(op_LDX_abs) // 0xae
GetAbs
DoLDX
Continue
ENTRY(op_LDX_abs_y) // 0xbe
GetAbs_Y
DoLDX
Continue
/* ----------------------------------
LDY instructions
---------------------------------- */
ENTRY(op_LDY_imm) // 0xa0
GetImm
DoLDY
Continue
ENTRY(op_LDY_zpage) // 0xa4
GetZPage
DoLDY
Continue
ENTRY(op_LDY_zpage_x) // 0xb4
GetZPage_X
DoLDY
Continue
ENTRY(op_LDY_abs) // 0xac
GetAbs
DoLDY
Continue
ENTRY(op_LDY_abs_x) // 0xbc
GetAbs_X
DoLDY
Continue
/* ----------------------------------
LSR instructions
---------------------------------- */
ENTRY(op_LSR_acc) // 0x4a
_DoLSR(A_Reg)
Continue
ENTRY(op_LSR_zpage) // 0x46
GetZPage
DoLSR
Continue
ENTRY(op_LSR_zpage_x) // 0x56
GetZPage_X
DoLSR
Continue
ENTRY(op_LSR_abs) // 0x4e
GetAbs
DoLSR
Continue
ENTRY(op_LSR_abs_x) // 0x5e
GetAbs_X
DoLSR
Continue
/* ----------------------------------
NOP instruction
---------------------------------- */
ENTRY(op_NOP) // 0xea
Continue
/* ----------------------------------
ORA instructions
---------------------------------- */
ENTRY(op_ORA_imm) // 0x09
GetImm
DoORA
Continue
ENTRY(op_ORA_zpage) // 0x05
GetZPage
DoORA
Continue
ENTRY(op_ORA_zpage_x) // 0x15
GetZPage_X
DoORA
Continue
// UNIMPLEMENTED : W65C02S datasheet
ENTRY(op_ORA_zpage_y)
jmp CALL(op_NOP)
ENTRY(op_ORA_abs) // 0x0d
GetAbs
DoORA
Continue
ENTRY(op_ORA_abs_x) // 0x1d
GetAbs_X
DoORA
Continue
ENTRY(op_ORA_abs_y) // 0x19
GetAbs_Y
DoORA
Continue
ENTRY(op_ORA_ind_x) // 0x01
GetIndZPage_X
DoORA
Continue
ENTRY(op_ORA_ind_y) // 0x11
GetIndZPage_Y
DoORA
Continue
// 65c02 : 0x12
ENTRY(op_ORA_ind_zpage)
GetIndZPage
DoORA
Continue
/* ----------------------------------
PHA instruction
---------------------------------- */
ENTRY(op_PHA) // 0x48
Push(A_Reg)
Continue
/* ----------------------------------
PHP instruction
---------------------------------- */
ENTRY(op_PHP) // 0x08
movb F_Reg, %al
MOVB_IND(CPU65_FLAGS_ENCODE,_XAX,%al)
Push(%al)
Continue
/* ----------------------------------
PHX instruction
65c02 : 0xDA
---------------------------------- */
ENTRY(op_PHX)
Push(X_Reg)
Continue
/* ----------------------------------
PHY instruction
65c02 : 0x5A
---------------------------------- */
ENTRY(op_PHY)
Push(Y_Reg)
Continue
/* ----------------------------------
PLA instruction
---------------------------------- */
ENTRY(op_PLA) // 0x68
Pop(A_Reg)
orb A_Reg, A_Reg
FlagNZ
Continue
/* ----------------------------------
PLP instruction
---------------------------------- */
ENTRY(op_PLP) // 0x28
Pop(%al)
MOVB_IND(CPU65_FLAGS_DECODE,_XAX,F_Reg)
orb $(B_Flag|X_Flag), F_Reg
Continue
/* ----------------------------------
PLX instruction
65c02 : 0xFA
---------------------------------- */
ENTRY(op_PLX)
Pop(X_Reg)
orb X_Reg, X_Reg
FlagNZ
Continue
/* ----------------------------------
PLY instruction
65c02 : 0x7A
---------------------------------- */
ENTRY(op_PLY)
Pop(Y_Reg)
orb Y_Reg, Y_Reg
FlagNZ
Continue
/* ----------------------------------
ROL instructions
---------------------------------- */
ENTRY(op_ROL_acc) // 0x2a
_DoROL(A_Reg)
Continue
ENTRY(op_ROL_zpage) // 0x26
GetZPage
DoROL
Continue
ENTRY(op_ROL_zpage_x) // 0x36
GetZPage_X
DoROL
Continue
ENTRY(op_ROL_abs) // 0x2e
GetAbs
DoROL
Continue
ENTRY(op_ROL_abs_x) // 0x3e
GetAbs_X
DoROL
Continue
/* ----------------------------------
ROR instructions
---------------------------------- */
ENTRY(op_ROR_acc) // 0x6a
// NB: assumes A_Reg = %cl, F_Reg = %ch
rorw $1, %cx // Roll flags into accum
adcb F_Reg, F_Reg // Roll carry into flags
orb A_Reg, A_Reg
FlagNZ // implied C
Continue
ENTRY(op_ROR_zpage) // 0x66
GetZPage
DoROR
Continue
ENTRY(op_ROR_zpage_x) // 0x76
GetZPage_X
DoROR
Continue
ENTRY(op_ROR_abs) // 0x6e
GetAbs
DoROR
Continue
ENTRY(op_ROR_abs_x) // 0x7e
GetAbs_X
DoROR
Continue
/* ----------------------------------
RTI instruction
---------------------------------- */
ENTRY(op_RTI) // 0x40
Pop(%al)
MOVB_IND(CPU65_FLAGS_DECODE,_XAX,F_Reg)
orb $(B_Flag|X_Flag), F_Reg
Pop(%al)
Pop(%ah)
movw %ax, PC_Reg
Continue
/* ----------------------------------
RTS instruction
---------------------------------- */
ENTRY(op_RTS) // 0x60
Pop(%al)
Pop(%ah)
incw %ax
movw %ax, PC_Reg
Continue
/* ----------------------------------
SBC instructions
SuBtract memory from accumulator with Borrow
---------------------------------- */
ENTRY(op_SBC_dec)
incb CPU65_OPCYCLES(reg_args) // +1 cycle
GetFromEA_B
DebugBCDCheck
bt $C_Flag_Bit, AF_Reg_X
cmc
xchgb A_Reg, %al
#if !__LP64__
sbbb A_Reg, %al
das
movb %al, A_Reg
cmc
FlagNVZC
#else
sbbb A_Reg, %al
// DAS algorithm : http://www.ray.masmcode.com/BCDdas.html
// CF_old = CF
// IF (al AND 0Fh > 9) or (the Auxiliary Flag is set)
// al = al - 6
// CF = CF (automagically) or CF_old
// AF set (automagically)
// ENDIF
// IF (al > 99h) or (Carry Flag is set)
// al = al - 60h
// ^CF set
// ENDIF
pushfq
popq _XBP
andb $~(N_Flag|V_Flag|Z_Flag), F_Reg
orb $C_Flag, F_Reg
movb %al, %ah
andb $0x0f, %ah
cmpb $9, %ah
jg _das_lo_nyb
btq $X86_AF_Bit, _XBP
jnc _das_next0
_das_lo_nyb: subb $6, %al // adjust lo nybble
jc _das_hi_nyb
_das_next0: btq $X86_CF_Bit, _XBP
jc _das_hi_nyb
xorb %ah, %ah
cmpw $0x99, %ax
jle _das_next1
_das_hi_nyb: subb $0x60, %al // adjust hi nybble
andb $~C_Flag, F_Reg // !FlagC
_das_next1: testq $0x80, %rax
jz _das_next2
orb $N_Flag, F_Reg // FlagN
_das_next2: testq $0xFF, %rax
jnz _das_finish
orb $Z_Flag, F_Reg // FlagZ
_das_finish: movb %al, A_Reg
#endif
Continue
#define maybe_DoSBC_d \
testb $D_Flag, F_Reg; /* Decimal mode? */ \
jnz CALL(op_SBC_dec) /* Yes, jump to decimal version */
ENTRY(op_SBC_imm) // 0xe9
GetImm
maybe_DoSBC_d
DoSBC_b
Continue
ENTRY(op_SBC_zpage) // 0xe5
GetZPage
maybe_DoSBC_d
DoSBC_b
Continue
ENTRY(op_SBC_zpage_x) // 0xf5
GetZPage_X
maybe_DoSBC_d
DoSBC_b
Continue
// UNIMPLEMENTED : W65C02S datasheet
ENTRY(op_SBC_zpage_y)
jmp CALL(op_NOP)
ENTRY(op_SBC_abs) // 0xed
GetAbs
maybe_DoSBC_d
DoSBC_b
Continue
ENTRY(op_SBC_abs_x) // 0xfd
GetAbs_X
maybe_DoSBC_d
DoSBC_b
Continue
ENTRY(op_SBC_abs_y) // 0xf9
GetAbs_Y
maybe_DoSBC_d
DoSBC_b
Continue
ENTRY(op_SBC_ind_x) // 0xe1
GetIndZPage_X
maybe_DoSBC_d
DoSBC_b
Continue
ENTRY(op_SBC_ind_y) // 0xf1
GetIndZPage_Y
maybe_DoSBC_d
DoSBC_b
Continue
// 65c02 : 0xF2
ENTRY(op_SBC_ind_zpage)
GetIndZPage
maybe_DoSBC_d
DoSBC_b
Continue
/* ----------------------------------
SEC instruction
---------------------------------- */
ENTRY(op_SEC) // 0x38
orb $C_Flag, F_Reg
Continue
/* ----------------------------------
SED instruction
---------------------------------- */
ENTRY(op_SED) // 0xf8
orb $D_Flag, F_Reg
Continue
/* ----------------------------------
SEI instruction
---------------------------------- */
ENTRY(op_SEI) // 0x78
orb $I_Flag, F_Reg
Continue
/* ----------------------------------
SMBx instructions -- Available in Rockwell 65C02 but not NCR 65C02
UNIMPLEMENTED : These are documented in the W65C02S datasheet ...
---------------------------------- */
ENTRY(op_SMB0_65c02)
Continue
ENTRY(op_SMB1_65c02)
Continue
ENTRY(op_SMB2_65c02)
Continue
ENTRY(op_SMB3_65c02)
Continue
ENTRY(op_SMB4_65c02)
Continue
ENTRY(op_SMB5_65c02)
Continue
ENTRY(op_SMB6_65c02)
Continue
ENTRY(op_SMB7_65c02)
Continue
/* ----------------------------------
STA instructions
---------------------------------- */
ENTRY(op_STA_zpage) // 0x85
GetZPage
DoSTA
Continue
ENTRY(op_STA_zpage_x) // 0x95
GetZPage_X
DoSTA
Continue
// UNIMPLEMENTED : W65C02S datasheet
ENTRY(op_STA_zpage_y)
jmp CALL(op_NOP)
ENTRY(op_STA_abs) // 0x8d
GetAbs
DoSTA
Continue
ENTRY(op_STA_abs_x) // 0x9d
GetAbs_X_STx
DoSTA
Continue
ENTRY(op_STA_abs_y) // 0x99
GetAbs_Y_STA
DoSTA
Continue
ENTRY(op_STA_ind_x) // 0x81
GetIndZPage_X
DoSTA
Continue
ENTRY(op_STA_ind_y) // 0x91
GetIndZPage_Y_STA
DoSTA
Continue
// 65c02 : 0x92
ENTRY(op_STA_ind_zpage)
GetIndZPage
DoSTA
Continue
/* ----------------------------------
STP instruction
UNIMPLEMENTED : This is documented in the W65C02S datasheet ...
---------------------------------- */
ENTRY(op_STP_65c02)
Continue
/* ----------------------------------
RMBx instructions -- Available in Rockwell 65C02 but not NCR 65C02
UNIMPLEMENTED : These are documented in the W65C02S datasheet ...
---------------------------------- */
ENTRY(op_RMB0_65c02)
Continue
ENTRY(op_RMB1_65c02)
Continue
ENTRY(op_RMB2_65c02)
Continue
ENTRY(op_RMB3_65c02)
Continue
ENTRY(op_RMB4_65c02)
Continue
ENTRY(op_RMB5_65c02)
Continue
ENTRY(op_RMB6_65c02)
Continue
ENTRY(op_RMB7_65c02)
Continue
/* ----------------------------------
STX instructions
---------------------------------- */
ENTRY(op_STX_zpage) // 0x86
GetZPage
DoSTX
Continue
ENTRY(op_STX_zpage_y) // 0x96
GetZPage_Y
DoSTX
Continue
ENTRY(op_STX_abs) // 0x8e
GetAbs
DoSTX
Continue
/* ----------------------------------
STY instructions
---------------------------------- */
ENTRY(op_STY_zpage) // 0x84
GetZPage
DoSTY
Continue
ENTRY(op_STY_zpage_x) // 0x94
GetZPage_X
DoSTY
Continue
ENTRY(op_STY_abs) // 0x8c
GetAbs
DoSTY
Continue
/* ----------------------------------
STZ instructions
65c02 only
---------------------------------- */
// 65c02 : 0x64
ENTRY(op_STZ_zpage)
GetZPage
DoSTZ
Continue
// 65c02 : 0x74
ENTRY(op_STZ_zpage_x)
GetZPage_X
DoSTZ
Continue
// 65c02 : 0x9C
ENTRY(op_STZ_abs)
GetAbs
DoSTZ
Continue
// 65c02 : 0x9E
ENTRY(op_STZ_abs_x)
GetAbs_X_STx
DoSTZ
Continue
/* ----------------------------------
TAX instruction
---------------------------------- */
ENTRY(op_TAX) // 0xaa
movb A_Reg, X_Reg
orb X_Reg, X_Reg
FlagNZ
Continue
/* ----------------------------------
TAY instruction
---------------------------------- */
ENTRY(op_TAY) // 0xa8
movb A_Reg, Y_Reg
orb Y_Reg, Y_Reg
FlagNZ
Continue
/* ----------------------------------
TRB instructions
65c02 only
---------------------------------- */
// 65c02 : 0x1C
ENTRY(op_TRB_abs)
GetAbs
DoTRB
Continue
// 65c02 : 0x14
ENTRY(op_TRB_zpage)
GetZPage
DoTRB
Continue
/* ----------------------------------
TSB instructions
65c02 only
---------------------------------- */
// 65c02 : 0x0C
ENTRY(op_TSB_abs)
GetAbs
DoTSB
Continue
// 65c02 : 0x04
ENTRY(op_TSB_zpage)
GetZPage
DoTSB
Continue
/* ----------------------------------
TSX instruction
---------------------------------- */
ENTRY(op_TSX) // 0xba
movb CPU65_SP(reg_args), X_Reg
orb X_Reg, X_Reg
FlagNZ
Continue
/* ----------------------------------
TXA instruction
---------------------------------- */
ENTRY(op_TXA) // 0x8a
movb X_Reg, A_Reg
orb A_Reg, A_Reg
FlagNZ
Continue
/* ----------------------------------
TXS instruction
---------------------------------- */
ENTRY(op_TXS) // 0x9a
movb X_Reg, CPU65_SP(reg_args)
Continue
/* ----------------------------------
TYA instruction
---------------------------------- */
ENTRY(op_TYA) // 0x98
movb Y_Reg, A_Reg
orb A_Reg, A_Reg
FlagNZ
Continue
/* ----------------------------------
??? instruction - 65c02
Defined as NOPs by spec
---------------------------------- */
ENTRY(op_UNK_65c02)
Continue
/* ----------------------------------
WAI instruction - 65c02
UNIMPLEMENTED : This is documented in the W65C02S datasheet ...
---------------------------------- */
ENTRY(op_WAI_65c02)
Continue
#pragma mark -
#pragma mark cpu main entry
/* -------------------------------------------------------------------------
CPU continue
Keep executing until we've executed >= cpu65_cycles_to_execute
------------------------------------------------------------------------- */
continue:
movzbLQ CPU65_OPCODE(reg_args), _XAX
MOVB_IND(CPU65__OPCYCLES,_XAX,%al)
addb CPU65_OPCYCLES(reg_args), %al
movb %al, CPU65_OPCYCLES(reg_args)
TRACE_EPILOGUE
addl %eax, CPU65_CYCLE_COUNT(reg_args)
subl %eax, GC_CYCLES_TIMER_0(reg_args)
subl %eax, GC_CYCLES_TIMER_1(reg_args)
continue1: subl %eax, CPU65_CYCLES_TO_EXECUTE(reg_args)
jle exit_cpu65_run
continue2: xorLQ _XAX, _XAX
orb CPU65__SIGNAL(reg_args), %al
jnz exception
CPUStatsReset
JumpNextInstruction
/* -------------------------------------------------------------------------
Exception handlers
------------------------------------------------------------------------- */
exception: testb $ResetSig, %al
jz ex_irq
testb $0xff, JOY_BUTTON0(reg_args) // OpenApple
jnz exit_reinit
testb $0xff, JOY_BUTTON1(reg_args) // ClosedApple
jnz exit_reinit
ex_reset: movb $0, CPU65__SIGNAL(reg_args)
movw $0xFFFC, EffectiveAddr // ROM reset vector
GetFromEA_W
movw %ax, PC_Reg
xorb %ah, %ah
CPUStatsReset
JumpNextInstruction
ex_irq: testb $I_Flag, F_Reg // Already interrupted?
jz 1f
CPUStatsReset
JumpNextInstruction // Yes (ignored) ...
1: TRACE_IRQ // No (handle IRQ) ...
movw PC_Reg, %ax
Push(%ah)
Push(%al)
orb $X_Flag, F_Reg
xorw %ax, %ax
movb F_Reg, %al
MOVB_IND(CPU65_FLAGS_ENCODE,_XAX,%al)
Push(%al)
orb $(B_Flag | I_Flag), F_Reg
//andb $~D_Flag, F_Reg // AppleWin clears Decimal bit?
movLQ $0xFFFE, EffectiveAddr_X
GetFromEA_W
movw %ax, PC_Reg
xorb %ah, %ah
CPUStatsReset
addb $7, CPU65_OPCYCLES(reg_args); // IRQ handling will take additional 7 cycles
JumpNextInstruction
/* -------------------------------------------------------------------------
65c02 CPU processing loop entry point
------------------------------------------------------------------------- */
ENTRY(cpu65_run)
#if __LP64__
movLQ %rdi, reg_args
#else
movLQ 4(%esp), reg_args
#endif
pushLQ _XBP
pushLQ _XDI
pushLQ _XSI
pushLQ _XBX
// Restore CPU state when being called from C.
movzwLQ CPU65_EA(reg_args), EffectiveAddr_X
movzwLQ CPU65_PC(reg_args), PC_Reg_X
movzbLQ CPU65_A(reg_args), AF_Reg_X
movzbLQ CPU65_X(reg_args), XY_Reg_X
movb CPU65_Y(reg_args), Y_Reg
movzbLQ CPU65_F(reg_args), _XAX
MOVB_IND(CPU65_FLAGS_DECODE,_XAX,F_Reg)
cmpb $0, EMUL_REINITIALIZE(reg_args)
jnz enter_reinit
jmp continue2
enter_reinit: movb $0, EMUL_REINITIALIZE(reg_args)
jmp ex_reset
/* -------------------------------------------------------------------------
65c02 CPU processing loop exit point
------------------------------------------------------------------------- */
exit_cpu65_run:
// Save CPU state when returning from being called from C
movw PC_Reg, CPU65_PC(reg_args)
CommonSaveCPUState
popLQ _XBX
popLQ _XSI
popLQ _XDI
popLQ _XBP
ret
exit_reinit: movb $0, CPU65__SIGNAL(reg_args)
movb $1, EMUL_REINITIALIZE(reg_args)
popLQ _XBX
popLQ _XSI
popLQ _XDI
popLQ _XBP
ret
/* -------------------------------------------------------------------------
Debugger hooks
------------------------------------------------------------------------- */
ENTRY(cpu65_direct_write)
pushLQ EffectiveAddr_X
movLQ 8(_XSP),EffectiveAddr_X
movLQ 12(_XSP),_XAX
movLQ CPU65_VMEM_W(reg_args), _XBP;
callLQ *(_XBP,EffectiveAddr_X,SZ_PTR)
popLQ EffectiveAddr_X
ret