Files
2026-02-02 04:50:13 +01:00

1350 lines
36 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Copyright (c) 2002 - 2023 Magnus Lind.
*
*
* This software is provided 'as-is', without any express 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.
*
*/
#include "glk/scott/globals.h"
#include "glk/scott/unp64/6502_emu.h"
namespace Glk {
namespace Scott {
#define FLAG_N 128
#define FLAG_V 64
#define FLAG_D 8
#define FLAG_I 4
#define FLAG_Z 2
#define FLAG_C 1
struct ArgEa {
uint16_t _value;
};
struct ArgRelative {
int8_t _value;
};
struct ArgImmediate {
uint8_t _value;
};
union InstArg {
ArgEa _ea;
ArgRelative _rel;
ArgImmediate _imm;
};
typedef void op_f(CpuCtx *r, int mode, InstArg *arg);
typedef int mode_f(CpuCtx *r, InstArg *arg);
struct OpInfo {
op_f *_f;
const char *_fmt;
};
struct ModeInfo {
mode_f *_f;
const char *_fmt;
};
struct InstInfo {
OpInfo *_op;
ModeInfo *_mode;
uint8_t _cycles;
};
#define MODE_IMMEDIATE 0
#define MODE_ZERO_PAGE 1
#define MODE_ZERO_PAGE_X 2
#define MODE_ZERO_PAGE_Y 3
#define MODE_ABSOLUTE 4
#define MODE_ABSOLUTE_X 5
#define MODE_ABSOLUTE_Y 6
#define MODE_INDIRECT 7
#define MODE_INDIRECT_X 8
#define MODE_INDIRECT_Y 9
#define MODE_RELATIVE 10
#define MODE_ACCUMULATOR 11
#define MODE_IMPLIED 12
static int mode_imm(CpuCtx *r, InstArg *arg) {
arg->_imm._value = r->_mem[r->_pc + 1];
r->_pc += 2;
return MODE_IMMEDIATE;
}
static int mode_zp(CpuCtx *r, InstArg *arg) {
arg->_ea._value = r->_mem[r->_pc + 1];
r->_pc += 2;
return MODE_ZERO_PAGE;
}
static int mode_zpx(CpuCtx *r, InstArg *arg) { /* iAN: ldx #1 lda $ff,x should fetch from $00 and not $100 */
uint8_t lsbLo = (r->_mem[r->_pc + 1] + r->_x) & 0xff;
arg->_ea._value = lsbLo;
r->_pc += 2;
return MODE_ZERO_PAGE_X;
}
static int mode_zpy(CpuCtx *r, InstArg *arg) { /* iAN: ldy #1 ldx $ff,y should fetch from $00 and not $100 */
uint8_t lsbLo = (r->_mem[r->_pc + 1] + r->_y) & 0xff;
arg->_ea._value = lsbLo;
r->_pc += 2;
return MODE_ZERO_PAGE_Y;
}
static int mode_abs(CpuCtx *r, InstArg *arg) {
uint16_t offset = r->_mem[r->_pc + 1];
uint16_t base = r->_mem[r->_pc + 2] << 8;
arg->_ea._value = base + offset;
r->_pc += 3;
return MODE_ABSOLUTE;
}
static int mode_absx(CpuCtx *r, InstArg *arg) {
uint16_t offset = r->_mem[r->_pc + 1] + r->_x;
uint16_t base = r->_mem[r->_pc + 2] << 8;
arg->_ea._value = base + offset;
r->_pc += 3;
r->_cycles += (offset > 255);
return MODE_ABSOLUTE_X;
}
static int mode_absy(CpuCtx *r, InstArg *arg) {
uint16_t offset = r->_mem[r->_pc + 1] + r->_y;
uint16_t base = r->_mem[r->_pc + 2] << 8;
arg->_ea._value = base + offset;
r->_pc += 3;
r->_cycles += (offset > 255);
return MODE_ABSOLUTE_Y;
}
static int mode_ind(CpuCtx *r, InstArg *arg) {
int lsbLo = r->_mem[r->_pc + 1];
int msbLo = r->_mem[r->_pc + 2];
int offsetlo = lsbLo | msbLo << 8;
int offsethi = ((lsbLo + 1) & 0xff) | msbLo << 8;
arg->_ea._value = r->_mem[offsetlo] | r->_mem[offsethi] << 8;
r->_pc += 3;
return MODE_INDIRECT;
}
static int mode_indx(CpuCtx *r, InstArg *arg) {
uint8_t lsbLo = r->_mem[r->_pc + 1] + r->_x;
uint8_t msbLo = lsbLo + 1;
uint16_t base = r->_mem[msbLo] << 8;
uint16_t offset = r->_mem[lsbLo];
arg->_ea._value = base + offset;
r->_pc += 2;
return MODE_INDIRECT_X;
}
static int mode_indy(CpuCtx *r, InstArg *arg) {
uint8_t lsbLo = r->_mem[r->_pc + 1];
uint8_t msbLo = lsbLo + 1;
uint16_t base = r->_mem[msbLo] << 8;
uint16_t offset = r->_mem[lsbLo] + r->_y;
arg->_ea._value = base + offset;
r->_pc += 2;
r->_cycles += (offset > 255);
return MODE_INDIRECT_Y;
}
static int mode_rel(CpuCtx *r, InstArg *arg) {
arg->_rel._value = (int8_t)r->_mem[r->_pc + 1];
r->_pc += 2;
return MODE_RELATIVE;
}
static int mode_acc(CpuCtx *r, InstArg *arg) {
r->_pc++;
return MODE_ACCUMULATOR;
}
static int mode_imp(CpuCtx *r, InstArg *arg) {
r->_pc++;
return MODE_IMPLIED;
}
static ModeInfo mode_imm_o = { &mode_imm, "#$%02x" };
static ModeInfo mode_zp_o = { &mode_zp, "$%02x" };
static ModeInfo mode_zpx_o = { &mode_zpx, "$%02x,x" };
static ModeInfo mode_zpy_o = { &mode_zpy, "$%02x,y" };
static ModeInfo mode_abs_o = { &mode_abs, "$%04x" };
static ModeInfo mode_absx_o = { &mode_absx, "$%04x,x" };
static ModeInfo mode_absy_o = { &mode_absy, "$%04x,y" };
static ModeInfo mode_ind_o = { &mode_ind, "($%04x)" };
static ModeInfo mode_indx_o = { &mode_indx, "($%02x,x)" };
static ModeInfo mode_indy_o = { &mode_indy, "($%02x),y" };
static ModeInfo mode_rel_o = { &mode_rel, "$%02x" };
static ModeInfo mode_acc_o = { &mode_acc, "a" };
static ModeInfo mode_imp_o = { &mode_imp, nullptr };
static void updateFlagsNz(CpuCtx *r, uint8_t value) {
r->_flags &= ~(FLAG_Z | FLAG_N);
r->_flags |= (value == 0 ? FLAG_Z : 0) | (value & FLAG_N);
}
static void updateCarry(CpuCtx *r, int boolean) {
r->_flags = (r->_flags & ~FLAG_C) | (boolean != 0 ? FLAG_C : 0);
}
static uint16_t subtract(CpuCtx *r, int carry, uint8_t val1, uint8_t value) {
uint16_t target = val1 - value - (1 - !!carry);
updateCarry(r, !(target & 256));
updateFlagsNz(r, target & 255);
return target;
}
static void update_overflow(CpuCtx *r, int boolean) {
r->_flags = (r->_flags & ~FLAG_V) | (boolean != 0 ? FLAG_V : 0);
}
static void op_adc(CpuCtx *r, int mode, InstArg *arg) {
uint8_t value;
uint16_t result;
switch (mode) {
case MODE_IMMEDIATE:
value = arg->_imm._value;
break;
default:
value = r->_mem[arg->_ea._value];
break;
}
result = r->_a + value + (r->_flags & FLAG_C);
updateCarry(r, result & 256);
update_overflow(r, !((r->_a & 0x80) ^ (value & 0x80)) && ((r->_a & 0x80) ^ (result & 0x80)));
r->_a = result & 0xff;
updateFlagsNz(r, r->_a);
}
static void op_and(CpuCtx *r, int mode, InstArg *arg) {
uint8_t value;
switch (mode) {
case MODE_IMMEDIATE:
value = arg->_imm._value;
break;
default:
value = r->_mem[arg->_ea._value];
break;
}
r->_a &= value;
updateFlagsNz(r, r->_a);
}
static void op_asl(CpuCtx *r, int mode, InstArg *arg) {
uint8_t *valuep;
switch (mode) {
case MODE_ACCUMULATOR:
valuep = &r->_a;
break;
default:
valuep = &r->_mem[arg->_ea._value];
break;
}
updateCarry(r, *valuep & 128);
*valuep <<= 1;
updateFlagsNz(r, *valuep);
}
static void branch(CpuCtx *r, InstArg *arg) {
uint16_t target = r->_pc + arg->_rel._value;
r->_cycles += 1 + ((target & ~255) != (r->_pc & ~255));
r->_pc = target;
}
static void op_bcc(CpuCtx *r, int mode, InstArg *arg) {
if (!(r->_flags & FLAG_C)) {
branch(r, arg);
}
}
static void op_bcs(CpuCtx *r, int mode, InstArg *arg) {
if (r->_flags & FLAG_C) {
branch(r, arg);
}
}
static void op_beq(CpuCtx *r, int mode, InstArg *arg) {
if (r->_flags & FLAG_Z) {
branch(r, arg);
}
}
static void op_bit(CpuCtx *r, int mode, InstArg *arg) {
r->_flags &= ~(FLAG_N | FLAG_V | FLAG_Z);
r->_flags |= (r->_mem[arg->_ea._value] & FLAG_N) != 0 ? FLAG_N : 0;
r->_flags |= (r->_mem[arg->_ea._value] & FLAG_V) != 0 ? FLAG_V : 0;
r->_flags |= (r->_mem[arg->_ea._value] & r->_a) == 0 ? FLAG_Z : 0;
}
static void op_bmi(CpuCtx *r, int mode, InstArg *arg) {
if (r->_flags & FLAG_N) {
branch(r, arg);
}
}
static void op_bne(CpuCtx *r, int mode, InstArg *arg) {
if (!(r->_flags & FLAG_Z)) {
branch(r, arg);
}
}
static void op_bpl(CpuCtx *r, int mode, InstArg *arg) {
if (!(r->_flags & FLAG_N)) {
branch(r, arg);
}
}
static void op_brk(CpuCtx *r, int mode, InstArg *arg) {
r->_mem[0x100 + r->_sp--] = (r->_pc + 1) >> 8;
r->_mem[0x100 + r->_sp--] = r->_pc + 1;
r->_mem[0x100 + r->_sp--] = r->_flags | 0x10;
}
static void op_bvc(CpuCtx *r, int mode, InstArg *arg) {
if (!(r->_flags & FLAG_V)) {
branch(r, arg);
}
}
static void op_bvs(CpuCtx *r, int mode, InstArg *arg) {
if ((r->_flags & FLAG_V)) {
branch(r, arg);
}
}
static void op_clc(CpuCtx *r, int mode, InstArg *arg) {
r->_flags &= ~FLAG_C;
}
static void op_cld(CpuCtx *r, int mode, InstArg *arg) {
r->_flags &= ~FLAG_D;
}
static void op_cli(CpuCtx *r, int mode, InstArg *arg) {
r->_flags &= ~FLAG_I;
}
static void op_clv(CpuCtx *r, int mode, InstArg *arg) {
r->_flags &= ~FLAG_V;
}
static void op_cmp(CpuCtx *r, int mode, InstArg *arg) {
uint8_t value;
switch (mode) {
case MODE_IMMEDIATE:
value = arg->_imm._value;
break;
default:
value = r->_mem[arg->_ea._value];
break;
}
subtract(r, 1, r->_a, value);
}
static void op_cpx(CpuCtx *r, int mode, InstArg *arg) {
uint8_t value;
switch (mode) {
case MODE_IMMEDIATE:
value = arg->_imm._value;
break;
default:
value = r->_mem[arg->_ea._value];
break;
}
subtract(r, 1, r->_x, value);
}
static void op_cpy(CpuCtx *r, int mode, InstArg *arg) {
uint8_t value;
switch (mode) {
case MODE_IMMEDIATE:
value = arg->_imm._value;
break;
default:
value = r->_mem[arg->_ea._value];
break;
}
subtract(r, 1, r->_y, value);
}
static void op_dec(CpuCtx *r, int mode, InstArg *arg) {
r->_mem[arg->_ea._value]--;
updateFlagsNz(r, r->_mem[arg->_ea._value]);
}
static void op_dex(CpuCtx *r, int mode, InstArg *arg) {
r->_x--;
updateFlagsNz(r, r->_x);
}
static void op_dey(CpuCtx *r, int mode, InstArg *arg) {
r->_y--;
updateFlagsNz(r, r->_y);
}
static void op_eor(CpuCtx *r, int mode, InstArg *arg) {
uint8_t value;
switch (mode) {
case MODE_IMMEDIATE:
value = arg->_imm._value;
break;
default:
value = r->_mem[arg->_ea._value];
break;
}
r->_a ^= value;
updateFlagsNz(r, r->_a);
}
static void op_inc(CpuCtx *r, int mode, InstArg *arg) {
r->_mem[arg->_ea._value]++;
updateFlagsNz(r, r->_mem[arg->_ea._value]);
}
static void op_inx(CpuCtx *r, int mode, InstArg *arg) {
r->_x++;
updateFlagsNz(r, r->_x);
}
static void op_iny(CpuCtx *r, int mode, InstArg *arg) {
r->_y++;
updateFlagsNz(r, r->_y);
}
static void op_jmp(CpuCtx *r, int mode, InstArg *arg) {
r->_pc = arg->_ea._value;
}
static void op_jsr(CpuCtx *r, int mode, InstArg *arg) {
r->_pc--;
r->_mem[0x100 + r->_sp--] = r->_pc >> 8;
r->_mem[0x100 + r->_sp--] = r->_pc & 0xff;
r->_pc = arg->_ea._value;
}
static void op_lda(CpuCtx *r, int mode, InstArg *arg) {
uint8_t value;
switch (mode) {
case MODE_IMMEDIATE:
value = arg->_imm._value;
break;
default:
value = r->_mem[arg->_ea._value];
break;
}
r->_a = value;
updateFlagsNz(r, r->_a);
}
static void op_ldx(CpuCtx *r, int mode, InstArg *arg) {
uint8_t value;
switch (mode) {
case MODE_IMMEDIATE:
value = arg->_imm._value;
break;
default:
value = r->_mem[arg->_ea._value];
break;
}
r->_x = value;
updateFlagsNz(r, r->_x);
}
static void op_ldy(CpuCtx *r, int mode, InstArg *arg) {
uint8_t value;
switch (mode) {
case MODE_IMMEDIATE:
value = arg->_imm._value;
break;
default:
value = r->_mem[arg->_ea._value];
break;
}
r->_y = value;
updateFlagsNz(r, r->_y);
}
static void op_lsr(CpuCtx *r, int mode, InstArg *arg) {
uint8_t *valuep;
switch (mode) {
case MODE_ACCUMULATOR:
valuep = &r->_a;
break;
default:
valuep = &r->_mem[arg->_ea._value];
break;
}
updateCarry(r, *valuep & 1);
*valuep >>= 1;
updateFlagsNz(r, *valuep);
}
static void op_nop(CpuCtx *r, int mode, InstArg *arg) {}
static void op_ora(CpuCtx *r, int mode, InstArg *arg) {
uint8_t value;
switch (mode) {
case MODE_IMMEDIATE:
value = arg->_imm._value;
break;
default:
value = r->_mem[arg->_ea._value];
break;
}
r->_a |= value;
updateFlagsNz(r, r->_a);
}
static void op_pha(CpuCtx *r, int mode, InstArg *arg) {
r->_mem[0x100 + r->_sp--] = r->_a;
}
static void op_php(CpuCtx *r, int mode, InstArg *arg) {
r->_mem[0x100 + r->_sp--] = r->_flags & ~0x10;
}
static void op_pla(CpuCtx *r, int mode, InstArg *arg) {
r->_a = r->_mem[0x100 + ++r->_sp];
updateFlagsNz(r, r->_a);
}
static void op_plp(CpuCtx *r, int mode, InstArg *arg) {
r->_flags = r->_mem[0x100 + ++r->_sp];
}
static void op_rol(CpuCtx *r, int mode, InstArg *arg) {
uint8_t *valuep;
uint8_t old_flags;
switch (mode) {
case MODE_ACCUMULATOR:
valuep = &r->_a;
break;
default:
valuep = &r->_mem[arg->_ea._value];
break;
}
old_flags = r->_flags;
updateCarry(r, *valuep & 128);
*valuep <<= 1;
*valuep |= (old_flags & FLAG_C) != 0 ? 1 : 0;
updateFlagsNz(r, *valuep);
}
static void op_ror(CpuCtx *r, int mode, InstArg *arg) {
uint8_t *valuep;
uint8_t old_flags;
switch (mode) {
case MODE_ACCUMULATOR:
valuep = &r->_a;
break;
default:
valuep = &r->_mem[arg->_ea._value];
break;
}
old_flags = r->_flags;
updateCarry(r, *valuep & 1);
*valuep >>= 1;
*valuep |= (old_flags & FLAG_C) != 0 ? 128 : 0;
updateFlagsNz(r, *valuep);
}
static void op_rti(CpuCtx *r, int mode, InstArg *arg) {
r->_flags = r->_mem[0x100 + ++r->_sp];
r->_pc = r->_mem[0x100 + ++r->_sp];
r->_pc |= r->_mem[0x100 + ++r->_sp] << 8;
}
static void op_rts(CpuCtx *r, int mode, InstArg *arg) {
r->_pc = r->_mem[0x100 + ++r->_sp];
r->_pc |= r->_mem[0x100 + ++r->_sp] << 8;
r->_pc++;
}
static void op_sbc(CpuCtx *r, int mode, InstArg *arg) {
uint8_t value;
uint16_t result;
switch (mode) {
case MODE_IMMEDIATE:
value = arg->_imm._value;
break;
default:
value = r->_mem[arg->_ea._value];
break;
}
result = subtract(r, r->_flags & FLAG_C, r->_a, value);
update_overflow(r, !((r->_a & 0x80) ^ (value & 0x80)) && ((r->_a & 0x80) ^ (result & 0x80)));
r->_a = result & 0xff;
updateFlagsNz(r, r->_a);
}
static void op_sec(CpuCtx *r, int mode, InstArg *arg) {
r->_flags |= FLAG_C;
}
static void op_sed(CpuCtx *r, int mode, InstArg *arg) {
r->_flags |= FLAG_D;
}
static void op_sei(CpuCtx *r, int mode, InstArg *arg) {
r->_flags |= FLAG_I;
}
static void op_sta(CpuCtx *r, int mode, InstArg *arg) {
r->_mem[arg->_ea._value] = r->_a;
}
static void op_stx(CpuCtx *r, int mode, InstArg *arg) {
r->_mem[arg->_ea._value] = r->_x;
}
static void op_sty(CpuCtx *r, int mode, InstArg *arg) {
r->_mem[arg->_ea._value] = r->_y;
}
static void op_tax(CpuCtx *r, int mode, InstArg *arg) {
r->_x = r->_a;
updateFlagsNz(r, r->_x);
}
static void op_tay(CpuCtx *r, int mode, InstArg *arg) {
r->_y = r->_a;
updateFlagsNz(r, r->_y);
}
static void op_tsx(CpuCtx *r, int mode, InstArg *arg) {
r->_x = r->_sp;
updateFlagsNz(r, r->_x);
}
static void op_txa(CpuCtx *r, int mode, InstArg *arg) {
r->_a = r->_x;
updateFlagsNz(r, r->_a);
}
static void op_txs(CpuCtx *r, int mode, InstArg *arg) {
r->_sp = r->_x;
}
static void op_tya(CpuCtx *r, int mode, InstArg *arg) {
r->_a = r->_y;
updateFlagsNz(r, r->_a);
}
/* iAN */
static void op_anc(CpuCtx *r, int mode, InstArg *arg) {
uint8_t value;
switch (mode) {
case MODE_IMMEDIATE:
value = arg->_imm._value;
break;
default:
value = r->_mem[arg->_ea._value];
break;
}
r->_a &= value;
if (r->_a & 0x80)
r->_flags |= FLAG_C;
updateFlagsNz(r, r->_a);
}
/* iAN */
static void op_lax(CpuCtx *r, int mode, InstArg *arg) {
op_lda(r, mode, arg);
r->_x = r->_a;
updateFlagsNz(r, r->_x);
}
/* iAN */
static void op_lae(CpuCtx *r, int mode, InstArg *arg) {
op_lda(r, mode, arg);
r->_x = r->_a;
r->_sp = r->_a;
updateFlagsNz(r, r->_a);
}
/* iAN */
static void op_dcp(CpuCtx *r, int mode, InstArg *arg) {
op_dec(r, mode, arg);
op_cmp(r, mode, arg);
}
/* iAN */
static void op_sax(CpuCtx *r, int mode, InstArg *arg) {
r->_a &= r->_x;
op_sta(r, mode, arg);
}
/* iAN */
static void op_rla(CpuCtx *r, int mode, InstArg *arg) {
op_rol(r, mode, arg);
op_and(r, mode, arg);
}
/* iAN */
static void op_rra(CpuCtx *r, int mode, InstArg *arg) {
op_rol(r, mode, arg);
op_adc(r, mode, arg);
}
/* iAN */
static void op_isb(CpuCtx *r, int mode, InstArg *arg) {
op_inc(r, mode, arg);
op_sbc(r, mode, arg);
}
/* iAN */
static void op_slo(CpuCtx *r, int mode, InstArg *arg) {
op_asl(r, mode, arg);
op_ora(r, mode, arg);
}
/* iAN */
static void op_sbx(CpuCtx *r, int mode, InstArg *arg) {
/* immediate mode only: sbx #$ff */
r->_x &= r->_a;
r->_flags = (r->_flags & 0xfe) | (r->_x >= arg->_imm._value ? 1 : 0); /* fixed: Carry IS set by SBX but
not used during subtraction */
r->_x -= arg->_imm._value;
updateFlagsNz(r, r->_x);
}
/* iAN */
static void op_sre(CpuCtx *r, int mode, InstArg *arg) {
op_lsr(r, mode, arg);
op_eor(r, mode, arg);
}
/* iAN */
static void
op_asr(CpuCtx *r, int mode,
InstArg *arg) { /* first A AND #immediate, then LSR A */
op_and(r, MODE_IMMEDIATE, arg);
op_lsr(r, MODE_ACCUMULATOR, arg);
}
/* iAN */
static void op_ane(CpuCtx *r, int mode, InstArg *arg) {
r->_a |= 0xee;
r->_a &= r->_x;
op_and(r, MODE_IMMEDIATE, arg);
}
/* iAN */
static void op_lxa(CpuCtx *r, int mode, InstArg *arg) {
r->_a |= 0xee;
op_and(r, MODE_IMMEDIATE, arg);
r->_x = r->_a;
}
static OpInfo op_adc_o = {&op_adc, "adc"};
static OpInfo op_anc_o = {&op_anc, "anc"};
static OpInfo op_and_o = {&op_and, "and"};
static OpInfo op_ane_o = {&op_ane, "ane"};
static OpInfo op_asl_o = {&op_asl, "asl"};
static OpInfo op_asr_o = {&op_asr, "asr"};
static OpInfo op_bcc_o = {&op_bcc, "bcc"};
static OpInfo op_bcs_o = {&op_bcs, "bcs"};
static OpInfo op_beq_o = {&op_beq, "beq"};
static OpInfo op_bit_o = {&op_bit, "bit"};
static OpInfo op_bmi_o = {&op_bmi, "bmi"};
static OpInfo op_bne_o = {&op_bne, "bne"};
static OpInfo op_bpl_o = {&op_bpl, "bpl"};
static OpInfo op_brk_o = {&op_brk, "brk"};
static OpInfo op_bvc_o = {&op_bvc, "bvc"};
static OpInfo op_bvs_o = {&op_bvs, "bvs"};
static OpInfo op_clc_o = {&op_clc, "clc"};
static OpInfo op_cld_o = {&op_cld, "cld"};
static OpInfo op_cli_o = {&op_cli, "cli"};
static OpInfo op_clv_o = {&op_clv, "clv"};
static OpInfo op_cmp_o = {&op_cmp, "cmp"};
static OpInfo op_cpx_o = {&op_cpx, "cpx"};
static OpInfo op_cpy_o = {&op_cpy, "cpy"};
static OpInfo op_dcp_o = {&op_dcp, "dcp"};
static OpInfo op_dec_o = {&op_dec, "dec"};
static OpInfo op_dex_o = {&op_dex, "dex"};
static OpInfo op_dey_o = {&op_dey, "dey"};
static OpInfo op_eor_o = {&op_eor, "eor"};
static OpInfo op_inc_o = {&op_inc, "inc"};
static OpInfo op_isb_o = {&op_isb, "isb"};
static OpInfo op_inx_o = {&op_inx, "inx"};
static OpInfo op_iny_o = {&op_iny, "iny"};
static OpInfo op_jmp_o = {&op_jmp, "jmp"};
static OpInfo op_jsr_o = {&op_jsr, "jsr"};
static OpInfo op_lda_o = {&op_lda, "lda"};
static OpInfo op_ldx_o = {&op_ldx, "ldx"};
static OpInfo op_ldy_o = {&op_ldy, "ldy"};
static OpInfo op_lsr_o = {&op_lsr, "lsr"};
static OpInfo op_nop_o = {&op_nop, "nop"};
static OpInfo op_ora_o = {&op_ora, "ora"};
static OpInfo op_pha_o = {&op_pha, "pha"};
static OpInfo op_php_o = {&op_php, "php"};
static OpInfo op_pla_o = {&op_pla, "pla"};
static OpInfo op_plp_o = {&op_plp, "plp"};
static OpInfo op_rol_o = {&op_rol, "rol"};
static OpInfo op_rla_o = {&op_rla, "rla"};
static OpInfo op_ror_o = {&op_ror, "ror"};
static OpInfo op_rti_o = {&op_rti, "rti"};
static OpInfo op_rra_o = {&op_rra, "rra"};
static OpInfo op_rts_o = {&op_rts, "rts"};
static OpInfo op_sbc_o = {&op_sbc, "sbc"};
static OpInfo op_sbx_o = {&op_sbx, "sbx"};
static OpInfo op_sec_o = {&op_sec, "sec"};
static OpInfo op_sed_o = {&op_sed, "sed"};
static OpInfo op_sei_o = {&op_sei, "sei"};
static OpInfo op_slo_o = {&op_slo, "slo"};
static OpInfo op_sta_o = {&op_sta, "sta"};
static OpInfo op_stx_o = {&op_stx, "stx"};
static OpInfo op_sty_o = {&op_sty, "sty"};
static OpInfo op_lax_o = {&op_lax, "lax"};
static OpInfo op_lae_o = {&op_lae, "lae"};
static OpInfo op_lxa_o = {&op_lxa, "lxa"};
static OpInfo op_tax_o = {&op_tax, "tax"};
static OpInfo op_sax_o = {&op_sax, "sax"};
static OpInfo op_sre_o = {&op_sre, "sre"};
static OpInfo op_tay_o = {&op_tay, "tay"};
static OpInfo op_tsx_o = {&op_tsx, "tsx"};
static OpInfo op_txa_o = {&op_txa, "txa"};
static OpInfo op_txs_o = {&op_txs, "txs"};
static OpInfo op_tya_o = {&op_tya, "tya"};
#define NULL_OP { nullptr, nullptr, 0 }
static InstInfo g_ops[256] = {
/* 0x00 */
{ &op_brk_o, &mode_imp_o, 7 },
{ &op_ora_o, &mode_indx_o, 6 },
NULL_OP,
NULL_OP,
{ &op_nop_o, &mode_zp_o, 3 }, /* $04 nop $ff */
{ &op_ora_o, &mode_zp_o, 3 },
{ &op_asl_o, &mode_zp_o, 5 },
{ &op_slo_o, &mode_zp_o, 5 }, /* $07 slo $ff */
{ &op_php_o, &mode_imp_o, 3 },
{ &op_ora_o, &mode_imm_o, 2 },
{ &op_asl_o, &mode_acc_o, 2 },
{ &op_anc_o, &mode_imm_o, 2 }, /* $0b anc #$ff */
{ &op_nop_o, &mode_abs_o, 4 }, /* $0c nop $ffff */
{ &op_ora_o, &mode_abs_o, 4 },
{ &op_asl_o, &mode_abs_o, 6 },
{ &op_slo_o, &mode_abs_o, 6 }, /* $0f slo $ffff */
/* 0x10 */
{ &op_bpl_o, &mode_rel_o, 2 },
{ &op_ora_o, &mode_indy_o, 5 },
NULL_OP,
NULL_OP,
{ &op_nop_o, &mode_zpx_o, 4 }, /* $14 nop $ff,x */
{ &op_ora_o, &mode_zpx_o, 4 },
{ &op_asl_o, &mode_zpx_o, 6 },
NULL_OP,
{ &op_clc_o, &mode_imp_o, 2 },
{ &op_ora_o, &mode_absy_o, 4 },
{ &op_nop_o, &mode_imp_o, 2 }, /* $1a nop */
{ &op_slo_o, &mode_absy_o, 4 }, /* $1b slo $ffff,y */
{ &op_nop_o, &mode_absx_o, 4 }, /* $1c nop $ffff,x */
{ &op_ora_o, &mode_absx_o, 4 },
{ &op_asl_o, &mode_absx_o, 7 },
{ &op_slo_o, &mode_absx_o, 7 }, /* $1f slo $ffff,x */
/* 0x20 */
{ &op_jsr_o, &mode_abs_o, 6 },
{ &op_and_o, &mode_indx_o, 6 },
NULL_OP,
{ &op_rla_o, &mode_indx_o, 8 }, /* $23 rla ($ff,x) */
{ &op_bit_o, &mode_zp_o, 3 },
{ &op_and_o, &mode_zp_o, 3 },
{ &op_rol_o, &mode_zp_o, 5 },
{ &op_rla_o, &mode_zp_o, 5 }, /* $27 rla $ff */
{ &op_plp_o, &mode_imp_o, 4 },
{ &op_and_o, &mode_imm_o, 2 },
{ &op_rol_o, &mode_acc_o, 2 },
{ &op_anc_o, &mode_imm_o, 2 }, /* $2b anc #$ff */
{ &op_bit_o, &mode_abs_o, 4 },
{ &op_and_o, &mode_abs_o, 4 },
{ &op_rol_o, &mode_abs_o, 6 },
{ &op_rla_o, &mode_abs_o, 6 }, /* $2f rla $ffff */
/* 0x30 */
{ &op_bmi_o, &mode_rel_o, 2 },
{ &op_and_o, &mode_indy_o, 5 },
NULL_OP,
{ &op_rla_o, &mode_indy_o, 8 }, /* $33 rla ($ff),y */
{ &op_nop_o, &mode_zpx_o, 4 }, /* $34 nop $ff,x */
{ &op_and_o, &mode_zpx_o, 4 },
{ &op_rol_o, &mode_zpx_o, 6 },
{ &op_rla_o, &mode_zpx_o, 6 }, /* $37 rla $ff,x */
{ &op_sec_o, &mode_imp_o, 2 },
{ &op_and_o, &mode_absy_o, 4 },
{ &op_nop_o, &mode_imp_o, 2 }, /* $3a nop */
{ &op_rla_o, &mode_absy_o, 7 }, /* $3b rla $ffff,y */
{ &op_nop_o, &mode_absx_o, 7 }, /* $3c nop $ffff,x */
{ &op_and_o, &mode_absx_o, 4 },
{ &op_rol_o, &mode_absx_o, 7 },
{ &op_rla_o, &mode_absx_o, 7 }, /* $3f rla $ffff,x */
/* 0x40 */
{ &op_rti_o, &mode_imp_o, 6 },
{ &op_eor_o, &mode_indx_o, 6 },
NULL_OP,
{ &op_sre_o, &mode_indx_o, 6 }, /* $43 sre ($ff,x) */
{ &op_nop_o, &mode_zp_o, 3 }, /* $44 nop $ff */
{ &op_eor_o, &mode_zp_o, 3 },
{ &op_lsr_o, &mode_zp_o, 5 },
{ &op_sre_o, &mode_zp_o, 5 }, /* $47 sre $ff */
{ &op_pha_o, &mode_imp_o, 3 },
{ &op_eor_o, &mode_imm_o, 2 },
{ &op_lsr_o, &mode_acc_o, 2 },
{ &op_asr_o, &mode_imm_o, 2 }, /* $4b asr #$ff */
{ &op_jmp_o, &mode_abs_o, 3 },
{ &op_eor_o, &mode_abs_o, 4 },
{ &op_lsr_o, &mode_abs_o, 6 },
{ &op_sre_o, &mode_abs_o, 6 }, /* $4f sre $ffff */
/* 0x50 */
{ &op_bvc_o, &mode_rel_o, 2 },
{ &op_eor_o, &mode_indy_o, 5 },
NULL_OP,
NULL_OP,
{ &op_nop_o, &mode_zpx_o, 4 }, /* $54 nop $ff,x */
{ &op_eor_o, &mode_zpx_o, 4 }, /* fix: eor $ff,x takes 4 cycles*/
{ &op_lsr_o, &mode_zpx_o, 6 },
{ &op_sre_o, &mode_zpx_o, 6 }, /* $57 sre $ff,x */
{ &op_cli_o, &mode_imp_o, 2 },
{ &op_eor_o, &mode_absy_o, 4 },
{ &op_nop_o, &mode_imp_o, 2 }, /* $5a nop */
{ &op_sre_o, &mode_absy_o, 7 }, /* $5b sre $ffff,y */
{ &op_nop_o, &mode_absx_o, 4 }, /* $5c nop $ffff,x */
{ &op_eor_o, &mode_absx_o, 4 },
{ &op_lsr_o, &mode_absx_o, 7 },
{ &op_sre_o, &mode_absx_o, 7 }, /* $5f sre $ffff,x */
/* 0x60 */
{ &op_rts_o, &mode_imp_o, 6 },
{ &op_adc_o, &mode_indx_o, 6 },
NULL_OP,
{ &op_rra_o, &mode_indx_o, 8 }, /* $63 rra ($ff,x) */
{ &op_nop_o, &mode_zp_o, 3 }, /* $64 nop $ff */
{ &op_adc_o, &mode_zp_o, 3 },
{ &op_ror_o, &mode_zp_o, 5 },
{ &op_rra_o, &mode_zp_o, 5 }, /* $67 rra $ff */
{ &op_pla_o, &mode_imp_o, 4 },
{ &op_adc_o, &mode_imm_o, 2 },
{ &op_ror_o, &mode_acc_o, 2 },
NULL_OP, /* fix: $6b ARR (todo?) */
{ &op_jmp_o, &mode_ind_o, 5 }, /* fix: $6c JMP ($FFFF) */
{ &op_adc_o, &mode_abs_o, 4 },
{ &op_ror_o, &mode_abs_o, 6 },
{ &op_rra_o, &mode_abs_o, 6 }, /* $6f rra $ffff */
/* 0x70 */
{ &op_bvs_o, &mode_rel_o, 2 },
{ &op_adc_o, &mode_indy_o, 5 },
NULL_OP,
{ &op_rra_o, &mode_indy_o, 8 }, /* $73 rra ($ff),y */
{ &op_nop_o, &mode_zpx_o, 4 }, /* $74 nop $ff,x */
{ &op_adc_o, &mode_zpx_o, 4 },
{ &op_ror_o, &mode_zpx_o, 6 },
{ &op_rra_o, &mode_zpx_o, 6 }, /* $77 rra $ff,x */
{ &op_sei_o, &mode_imp_o, 2 },
{ &op_adc_o, &mode_absy_o, 4 },
{ &op_nop_o, &mode_imp_o, 2 }, /* $7a nop */
{ &op_rra_o, &mode_absy_o, 7 }, /* $7b rra $ffff,y */
{ &op_nop_o, &mode_absx_o, 4 }, /* $7c nop $ffff,x */
{ &op_adc_o, &mode_absx_o, 4 },
{ &op_ror_o, &mode_absx_o, 7 },
{ &op_rra_o, &mode_absx_o, 7 }, /* $7f rra $ffff,x */
/* 0x80 */
{ &op_nop_o, &mode_imm_o, 2 }, /* $80 nop #$ff */
{ &op_sta_o, &mode_indx_o, 6 },
{ &op_nop_o, &mode_imm_o, 2 }, /* $82 nop #$ff */
{ &op_sax_o, &mode_indx_o, 6 }, /* $83 sax ($ff,x) */
{ &op_sty_o, &mode_zp_o, 3 },
{ &op_sta_o, &mode_zp_o, 3 },
{ &op_stx_o, &mode_zp_o, 3 },
{ &op_sax_o, &mode_zp_o, 3 }, /* $87 sax $ff */
{ &op_dey_o, &mode_imp_o, 2 },
{ &op_nop_o, &mode_imm_o, 2 }, /* $89 nop #$ff */
{ &op_txa_o, &mode_imp_o, 2 },
{ &op_ane_o, &mode_imm_o, 2 }, /* $8b ane #$ff */
{ &op_sty_o, &mode_abs_o, 4 },
{ &op_sta_o, &mode_abs_o, 4 },
{ &op_stx_o, &mode_abs_o, 4 },
{ &op_sax_o, &mode_abs_o, 4 }, /* $8f sax $ffff */
/* 0x90 */
{ &op_bcc_o, &mode_rel_o, 2 },
{ &op_sta_o, &mode_indy_o, 6 },
NULL_OP,
NULL_OP,
{ &op_sty_o, &mode_zpx_o, 4 },
{ &op_sta_o, &mode_zpx_o, 4 },
{ &op_stx_o, &mode_zpy_o, 4 },
{ &op_sax_o, &mode_zpy_o, 4 }, /* $97 sax $ff,y */
{ &op_tya_o, &mode_imp_o, 2 },
{ &op_sta_o, &mode_absy_o, 5 },
{ &op_txs_o, &mode_imp_o, 2 },
NULL_OP,
NULL_OP,
{ &op_sta_o, &mode_absx_o, 5 },
NULL_OP,
NULL_OP,
/* 0xa0 */
{ &op_ldy_o, &mode_imm_o, 2 },
{ &op_lda_o, &mode_indx_o, 6 },
{ &op_ldx_o, &mode_imm_o, 2 },
{ &op_lax_o, &mode_indx_o, 6 }, /* $a3 lax ($ff,x) */
{ &op_ldy_o, &mode_zp_o, 3 },
{ &op_lda_o, &mode_zp_o, 3 },
{ &op_ldx_o, &mode_zp_o, 3 },
{ &op_lax_o, &mode_zp_o, 3 }, /* $a7 lax $ff */
{ &op_tay_o, &mode_imp_o, 2 },
{ &op_lda_o, &mode_imm_o, 2 },
{ &op_tax_o, &mode_imp_o, 2 },
{ &op_lxa_o, &mode_imm_o, 2 }, /* $ab lxa #$ff */
{ &op_ldy_o, &mode_abs_o, 4 },
{ &op_lda_o, &mode_abs_o, 4 },
{ &op_ldx_o, &mode_abs_o, 4 },
{ &op_lax_o, &mode_abs_o, 4 }, /* $af lax $ffff */
/* 0xb0 */
{ &op_bcs_o, &mode_rel_o, 2 },
{ &op_lda_o, &mode_indy_o, 5 },
NULL_OP,
{ &op_lax_o, &mode_indy_o, 5 }, /* $b3 lax ($ff),y */
{ &op_ldy_o, &mode_zpx_o, 4 },
{ &op_lda_o, &mode_zpx_o, 4 },
{ &op_ldx_o, &mode_zpy_o, 4 },
{ &op_lax_o, &mode_zpy_o, 4 }, /* $b7 lax $ff,y */
{ &op_clv_o, &mode_imp_o, 2 },
{ &op_lda_o, &mode_absy_o, 4 },
{ &op_tsx_o, &mode_imp_o, 2 },
{ &op_lae_o, &mode_absy_o, 4 }, /* $bb lae $ffff,y */
{ &op_ldy_o, &mode_absx_o, 4 },
{ &op_lda_o, &mode_absx_o, 4 },
{ &op_ldx_o, &mode_absy_o, 4 },
{ &op_lax_o, &mode_absy_o, 4 }, /* $bf lax $ffff,y */
/* 0xc0 */
{ &op_cpy_o, &mode_imm_o, 2 },
{ &op_cmp_o, &mode_indx_o, 6 },
{ &op_nop_o, &mode_imm_o, 2 }, /* $c2 nop #$ff */
{ &op_dcp_o, &mode_indx_o, 8 }, /* $c3 dcp ($ff,x) */
{ &op_cpy_o, &mode_zp_o, 3 },
{ &op_cmp_o, &mode_zp_o, 3 },
{ &op_dec_o, &mode_zp_o, 5 },
{ &op_dcp_o, &mode_zp_o, 5 }, /* $c7 dcp $FF */
{ &op_iny_o, &mode_imp_o, 2 },
{ &op_cmp_o, &mode_imm_o, 2 },
{ &op_dex_o, &mode_imp_o, 2 },
{ &op_sbx_o, &mode_imm_o, 2 }, /* $cb sbx #$ff */
{ &op_cpy_o, &mode_abs_o, 4 },
{ &op_cmp_o, &mode_abs_o, 4 },
{ &op_dec_o, &mode_abs_o, 6 },
{ &op_dcp_o, &mode_abs_o, 6 }, /* $cf dcp $ffff */
/* 0xd0 */
{ &op_bne_o, &mode_rel_o, 2 },
{ &op_cmp_o, &mode_indy_o, 5 },
NULL_OP,
{ &op_dcp_o, &mode_indy_o, 8 }, /* $d3 dcp ($ff),y */
{ &op_nop_o, &mode_zpx_o, 4 }, /* $d4 nop $ff,x */
{ &op_cmp_o, &mode_zpx_o, 4 },
{ &op_dec_o, &mode_zpx_o, 6 },
{ &op_dcp_o, &mode_zpx_o, 6 }, /* $d7 dcp $ff,x */
{ &op_cld_o, &mode_imp_o, 2 },
{ &op_cmp_o, &mode_absy_o, 4 },
{ &op_nop_o, &mode_imp_o, 2 }, /* $da nop */
{ &op_dcp_o, &mode_absy_o, 7 }, /* $db dcp $ffff,y */
{ &op_nop_o, &mode_absx_o, 4 }, /* $dc nop $ffff,x */
{ &op_cmp_o, &mode_absx_o, 4 },
{ &op_dec_o, &mode_absx_o, 7 },
{ &op_dcp_o, &mode_absx_o, 7 }, /* $df dcp $ffff,x */
/* 0xe0 */
{ &op_cpx_o, &mode_imm_o, 2 },
{ &op_sbc_o, &mode_indx_o, 6 },
{ &op_nop_o, &mode_imm_o, 2 }, /* $e2 nop #$ff */
{ &op_isb_o, &mode_indx_o, 8 }, /* $e3 isb ($ff,x) */
{ &op_cpx_o, &mode_zp_o, 3 },
{ &op_sbc_o, &mode_zp_o, 3 },
{ &op_inc_o, &mode_zp_o, 5 },
{ &op_isb_o, &mode_zp_o, 5 }, /* $e7 isb $ff */
{ &op_inx_o, &mode_imp_o, 2 },
{ &op_sbc_o, &mode_imm_o, 2 },
{ &op_nop_o, &mode_imp_o, 2 },
{ &op_sbc_o, &mode_imm_o, 2 }, /* $eb sbc #$ff */
{ &op_cpx_o, &mode_abs_o, 4 },
{ &op_sbc_o, &mode_abs_o, 4 },
{ &op_inc_o, &mode_abs_o, 6 },
{ &op_isb_o, &mode_abs_o, 6 }, /* $ef isb $ffff */
/* 0xf0 */
{ &op_beq_o, &mode_rel_o, 2 },
{ &op_sbc_o, &mode_indy_o, 5 },
NULL_OP,
{ &op_isb_o, &mode_indy_o, 8 }, /* $f3 isb ($ff),y */
{ &op_nop_o, &mode_zpx_o, 4 }, /* $f4 nop $ff,x */
{ &op_sbc_o, &mode_zpx_o, 4 },
{ &op_inc_o, &mode_zpx_o, 6 },
{ &op_isb_o, &mode_zpx_o, 6 }, /* $f7 isb $ff,x */
{ &op_sed_o, &mode_imp_o, 2 },
{ &op_sbc_o, &mode_absy_o, 4 },
{ &op_nop_o, &mode_imp_o, 2 }, /* $fa nop */
{ &op_isb_o, &mode_absy_o, 7 }, /* $fb isb $ffff,y */
{ &op_nop_o, &mode_absx_o, 7 }, /* $fc nop $ffff,x */
{ &op_sbc_o, &mode_absx_o, 4 },
{ &op_inc_o, &mode_absx_o, 7 },
{ &op_isb_o, &mode_absx_o, 7 }, /* $ff isb $ffff,x */
};
int flipfire(void) {
_G(_retfire) ^= 0x90;
return _G(_retfire);
}
int flipspace(void) {
_G(_retspace) ^= 0x10;
return _G(_retspace);
}
int nextInst(CpuCtx* r) {
InstArg arg[1];
int opCode = r->_mem[r->_pc];
InstInfo *info = g_ops + opCode;
int mode, WriteToIO = 0;
int bt = 0, br;
if (info->_op == nullptr) {
return 1;
}
mode = info->_mode->_f(r, arg);
/* iAN: only if RAM is not visible there! */
if (((r->_mem[1] & 0x7) >= 0x5) && ((r->_mem[1] & 0x07) <= 0x7)) {
if (arg->_ea._value >= 0xd000 && arg->_ea._value < 0xe000) {
/* is this an absolute sta, stx or sty to the IO-area? */
/* iAN: added all possible writing opcodes */
if (opCode == 0x0E || /*ASL $ffff */
opCode == 0x1E || /*ASL $ffff,X*/
opCode == 0xCE || /*DEC $ffff */
opCode == 0xDE || /*DEC $ffff,X*/
opCode == 0xEE || /*INC $ffff */
opCode == 0xFE || /*INC $ffff,X*/
opCode == 0x4E || /*LSR $ffff */
opCode == 0x5E || /*LSR $ffff,X*/
opCode == 0x2E || /*ROL $ffff */
opCode == 0x3E || /*ROL $ffff,X*/
opCode == 0x6E || /*ROR $ffff */
opCode == 0x7E || /*ROR $ffff,X*/
opCode == 0x8D || /*STA $ffff */
opCode == 0x9D || /*STA $ffff,X*/
opCode == 0x99 || /*STA $ffff,Y*/
opCode == 0x91 || /*STA ($ff),Y*/
opCode == 0x8E || /*STX $ffff */
opCode == 0x8C /*STY $ffff */
) {
r->_cycles += g_ops[opCode]._cycles;
/* ignore it, its probably an effect */
/* try to keep updated at least a copy of $d011 */
if (arg->_ea._value == 0xd011) {
switch (opCode) {
case 0x8D:
_G(_byted011)[0] = r->_a & 0x7f;
break;
case 0x8E:
_G(_byted011)[0] = r->_x & 0x7f;
break;
case 0x8C:
_G(_byted011)[0] = r->_y & 0x7f;
break;
default:
break;
}
}
WriteToIO = 1;
} else {
_G(_byted011)[1] = (r->_cycles / 0x3f) % 0x157;
_G(_byted011)[0] = (_G(_byted011)[0] & 0x7f) | ((_G(_byted011)[1] & 0x100) >> 1);
_G(_byted011)[1] &= 0xff;
switch (opCode) {
case 0xad:
case 0xaf: /* lda $ffff / lax $ffff */
if ((arg->_ea._value == 0xd011) || (arg->_ea._value == 0xd012)) {
r->_cycles += g_ops[opCode]._cycles;
r->_a = _G(_byted011)[arg->_ea._value - 0xd011];
if (opCode == 0xaf)
r->_x = r->_a;
updateFlagsNz(r, r->_a);
WriteToIO = 5;
break;
}
/* intros: simulate space */
if (arg->_ea._value == 0xdc00 || arg->_ea._value == 0xdc01) {
r->_cycles += g_ops[opCode]._cycles;
if (arg->_ea._value == 0xdc00)
r->_a = flipfire();
else
r->_a = flipspace();
if (opCode == 0xaf)
r->_x = r->_a;
updateFlagsNz(r, r->_a);
WriteToIO = 6;
break;
}
if (arg->_ea._value >= 0xdd01 && arg->_ea._value <= 0xdd0f) {
r->_cycles += g_ops[opCode]._cycles;
r->_a = 0xff;
if (opCode == 0xaf)
r->_x = r->_a;
updateFlagsNz(r, r->_a);
WriteToIO = 2;
break;
}
break;
case 0x2d: /* and $ffff */
/* intros: simulate space */
if (arg->_ea._value == 0xdc00 || arg->_ea._value == 0xdc01) {
r->_cycles += g_ops[opCode]._cycles;
if (arg->_ea._value == 0xdc00)
r->_a &= flipfire();
else
r->_a &= flipspace();
updateFlagsNz(r, r->_a);
WriteToIO = 6;
break;
}
break;
case 0xae: /* ldx $ffff */
if ((arg->_ea._value == 0xd011) || (arg->_ea._value == 0xd012)) {
r->_cycles += g_ops[opCode]._cycles;
r->_x = _G(_byted011)[arg->_ea._value - 0xd011];
updateFlagsNz(r, r->_x);
WriteToIO = 5;
break;
}
if (arg->_ea._value == 0xdc00 || arg->_ea._value == 0xdc01) {
r->_cycles += g_ops[opCode]._cycles;
if (arg->_ea._value == 0xdc00)
r->_x = flipfire();
else
r->_x = flipspace();
updateFlagsNz(r, r->_x);
WriteToIO = 6;
break;
}
break;
case 0xac: /* ldy $ffff */
if ((arg->_ea._value == 0xd011) || (arg->_ea._value == 0xd012)) {
r->_cycles += g_ops[opCode]._cycles;
r->_y = _G(_byted011)[arg->_ea._value - 0xd011];
updateFlagsNz(r, r->_y);
WriteToIO = 5;
break;
}
if (arg->_ea._value == 0xdc00 || arg->_ea._value == 0xdc01) {
r->_cycles += g_ops[opCode]._cycles;
if (arg->_ea._value == 0xdc00)
r->_y = flipfire();
else
r->_y = flipspace();
updateFlagsNz(r, r->_y);
WriteToIO = 6;
break;
}
break;
case 0x2c: /* bit $d011 */
if ((arg->_ea._value == 0xd011) || (arg->_ea._value == 0xd012)) {
r->_cycles += g_ops[opCode]._cycles;
bt = _G(_byted011)[arg->_ea._value - 0xd011];
r->_flags &= ~(FLAG_N | FLAG_V | FLAG_Z);
r->_flags |= (bt & FLAG_N) != 0 ? FLAG_N : 0;
r->_flags |= (bt & FLAG_V) != 0 ? FLAG_V : 0;
r->_flags |= (bt & r->_a) == 0 ? FLAG_Z : 0;
WriteToIO = 3;
}
break;
case 0xcd: /* cmp $ffff */
case 0xec: /* cpx $ffff */
case 0xcc: /* cpy $ffff */
if ((arg->_ea._value == 0xd011) || (arg->_ea._value == 0xd012)) {
r->_cycles += g_ops[opCode]._cycles;
bt = _G(_byted011)[arg->_ea._value - 0xd011];
br = r->_a;
if (opCode == 0xec)
br = r->_x;
if (opCode == 0xcc)
br = r->_y;
subtract(r, 1, br, bt);
WriteToIO = 4;
break;
}
/* intros: simulate space */
if (arg->_ea._value == 0xdc00 || arg->_ea._value == 0xdc01) {
r->_cycles += g_ops[opCode]._cycles;
br = r->_a;
if (opCode == 0xec)
br = r->_x;
if (opCode == 0xcc)
br = r->_y;
if (arg->_ea._value == 0xdc00)
bt = flipfire();
else
bt = flipspace();
subtract(r, 1, br, bt);
WriteToIO = 6;
break;
}
break;
}
}
}
}
if (WriteToIO) {
return 0;
}
info->_op->_f(r, mode, arg);
r->_cycles += info->_cycles;
if (opCode == 0) {
return 1;
}
return 0;
}
} // End of namespace Scott
} // End of namespace Glk