/* 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 . * */ /* * 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