From a5f17c7727836a62742feab8f840c43beee49440 Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Wed, 12 Aug 2015 20:21:24 +0300 Subject: [PATCH] 3200b7 --- 65c02core.cpp | 2493 ++++++++++++++++++++++++++++++++++ cdtvcr.cpp | 484 +++++++ cia.cpp | 2 +- disk.cpp | 4 +- gfxboard.cpp | 6 +- include/gui.h | 2 +- memory.cpp | 54 +- od-win32/rp.cpp | 8 +- od-win32/rp.h | 2 +- od-win32/win32.cpp | 2 +- od-win32/win32.h | 4 +- od-win32/win32gfx.cpp | 6 +- od-win32/win32gui.cpp | 55 +- od-win32/winuaechangelog.txt | 32 + qemuvga/esp.cpp | 4 + specialmonitors.cpp | 204 ++- x86.cpp | 2 +- 17 files changed, 3276 insertions(+), 88 deletions(-) create mode 100644 65c02core.cpp diff --git a/65c02core.cpp b/65c02core.cpp new file mode 100644 index 00000000..d162fdce --- /dev/null +++ b/65c02core.cpp @@ -0,0 +1,2493 @@ +/* + * 65C02core.c - 65C02/65SC02 emulation core. + * + * Written by + * Marco van den Heuvel + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +/* This file is included by the following CPU definition files: + - drivecpu65c02.c + */ + +/* any CPU definition file that includes this file needs to do the following: + * + * - define reg_a as 8bit. + * - define reg_x as 8bit. + * - define reg_y as 8bit. + * - define reg_pc as 16bit. + * - define reg_sp as 8bit. + * - define reg_p as 8bit + * - define the cpu being emulated in a var 'cpu_type' (CPU_WDC65C02, CPU_R65C02, CPU_65SC02). + * - define a function to handle the WDC65C02 STP opcode (WDC_STP(void)). + * - define a function to handle the WDC65C02 WAI opcode (WDC_WAI(void)). + * + */ + +/* still to check and possibly fix: + * + * - BRK does get interrupted by an IRQ/NMI on the 65(S)C02? + */ + +#ifndef CPU_STR +#define CPU_STR "65(S)C02 CPU" +#endif + +//#include "traps.h" + +/* To avoid 'magic' numbers, we will use the following defines. */ +#define CYCLES_0 0 +#define CYCLES_1 1 +#define CYCLES_2 2 +#define CYCLES_3 3 +#define CYCLES_4 4 +#define CYCLES_5 5 + +#define SIZE_1 1 +#define SIZE_2 2 +#define SIZE_3 3 + +#define BIT_0 0 +#define BIT_1 1 +#define BIT_2 2 +#define BIT_3 3 +#define BIT_4 4 +#define BIT_5 5 +#define BIT_6 6 +#define BIT_7 7 + +#define IRQ_CYCLES 7 +#define NMI_CYCLES 7 +#define RESET_CYCLES 6 + +/* ------------------------------------------------------------------------- */ +/* Backup for non-6509 CPUs. */ + +#ifndef LOAD_IND +#define LOAD_IND(a) LOAD(a) +#endif +#ifndef STORE_IND +#define STORE_IND(a, b) STORE(a, b) +#endif + +/* ------------------------------------------------------------------------- */ +/* Backup for non-variable cycle CPUs. */ + +#ifndef CLK_ADD +#define CLK_ADD(clock, amount) clock += amount +#endif + +#ifndef REWIND_FETCH_OPCODE +#define REWIND_FETCH_OPCODE(clock, amount) clock -= amount +#endif + +/* ------------------------------------------------------------------------- */ +/* Hook for additional delay. */ + +#ifndef CPU_DELAY_CLK +#define CPU_DELAY_CLK +#endif + +#ifndef CPU_REFRESH_CLK +#define CPU_REFRESH_CLK +#endif + +/* ------------------------------------------------------------------------- */ + +#ifndef CYCLE_EXACT_ALARM +#define PROCESS_ALARMS \ + while (CLK >= alarm_context_next_pending_clk(ALARM_CONTEXT)) { \ + alarm_context_dispatch(ALARM_CONTEXT, CLK); \ + CPU_DELAY_CLK \ + } +#else +#define PROCESS_ALARMS +#endif + +/* ------------------------------------------------------------------------- */ + +#define LOCAL_SET_NZ(val) (flag_z = flag_n = (val)) + +#define LOCAL_SET_OVERFLOW(val) \ + do { \ + if (val) { \ + reg_p |= P_OVERFLOW; \ + } else { \ + reg_p &= ~P_OVERFLOW; \ + } \ + } while (0) + +#define LOCAL_SET_BREAK(val) \ + do { \ + if (val) { \ + reg_p |= P_BREAK; \ + } else { \ + reg_p &= ~P_BREAK; \ + } \ + } while (0) + +#define LOCAL_SET_DECIMAL(val) \ + do { \ + if (val) { \ + reg_p |= P_DECIMAL; \ + } else { \ + reg_p &= ~P_DECIMAL; \ + } \ + } while (0) + +#define LOCAL_SET_INTERRUPT(val) \ + do { \ + if (val) { \ + reg_p |= P_INTERRUPT; \ + } else { \ + reg_p &= ~P_INTERRUPT; \ + } \ + } while (0) + +#define LOCAL_SET_CARRY(val) \ + do { \ + if (val) { \ + reg_p |= P_CARRY; \ + } else { \ + reg_p &= ~P_CARRY; \ + } \ + } while (0) + +#define LOCAL_SET_SIGN(val) (flag_n = (val) ? 0x80 : 0) +#define LOCAL_SET_ZERO(val) (flag_z = !(val)) +#define LOCAL_SET_STATUS(val) (reg_p = ((val) & ~(P_ZERO | P_SIGN)), \ + LOCAL_SET_ZERO((val) & P_ZERO), \ + flag_n = (val)) + +#define LOCAL_OVERFLOW() (reg_p & P_OVERFLOW) +#define LOCAL_BREAK() (reg_p & P_BREAK) +#define LOCAL_DECIMAL() (reg_p & P_DECIMAL) +#define LOCAL_INTERRUPT() (reg_p & P_INTERRUPT) +#define LOCAL_CARRY() (reg_p & P_CARRY) +#define LOCAL_SIGN() (flag_n & 0x80) +#define LOCAL_ZERO() (!flag_z) +#define LOCAL_STATUS() (reg_p | (flag_n & 0x80) | P_UNUSED \ + | (LOCAL_ZERO() ? P_ZERO : 0)) + +#ifdef LAST_OPCODE_INFO + +/* If requested, gather some info about the last executed opcode for timing + purposes. */ + +/* Remember the number of the last opcode. By default, the opcode does not + delay interrupt and does not change the I flag. */ +#define SET_LAST_OPCODE(x) OPINFO_SET(LAST_OPCODE_INFO, (x), 0, 0, 0) + +/* Remember that the last opcode delayed a pending IRQ or NMI by one cycle. */ +#define OPCODE_DELAYS_INTERRUPT() OPINFO_SET_DELAYS_INTERRUPT(LAST_OPCODE_INFO, 1) + +/* Remember that the last opcode changed the I flag from 0 to 1, so we have + to dispatch an IRQ even if the I flag is 0 when we check it. */ +#define OPCODE_DISABLES_IRQ() OPINFO_SET_DISABLES_IRQ(LAST_OPCODE_INFO, 1) + +/* Remember that the last opcode changed the I flag from 1 to 0, so we must + not dispatch an IRQ even if the I flag is 1 when we check it. */ +#define OPCODE_ENABLES_IRQ() OPINFO_SET_ENABLES_IRQ(LAST_OPCODE_INFO, 1) + +#else + +/* Info about the last opcode is not needed. */ +#define SET_LAST_OPCODE(x) +#define OPCODE_DELAYS_INTERRUPT() +#define OPCODE_DISABLES_IRQ() +#define OPCODE_ENABLES_IRQ() + +#endif + +#ifdef LAST_OPCODE_ADDR +#define SET_LAST_ADDR(x) LAST_OPCODE_ADDR = (x) +#else +#error "please define LAST_OPCODE_ADDR" +#endif + +#ifndef DRIVE_CPU +/* Export the local version of the registers. */ +#define EXPORT_REGISTERS() \ + do { \ + GLOBAL_REGS.pc = reg_pc; \ + GLOBAL_REGS.a = reg_a; \ + GLOBAL_REGS.x = reg_x; \ + GLOBAL_REGS.y = reg_y; \ + GLOBAL_REGS.sp = reg_sp; \ + GLOBAL_REGS.p = reg_p; \ + GLOBAL_REGS.n = flag_n; \ + GLOBAL_REGS.z = flag_z; \ + } while (0) + +/* Import the public version of the registers. */ +#define IMPORT_REGISTERS() \ + do { \ + reg_a = GLOBAL_REGS.a; \ + reg_x = GLOBAL_REGS.x; \ + reg_y = GLOBAL_REGS.y; \ + reg_sp = GLOBAL_REGS.sp; \ + reg_p = GLOBAL_REGS.p; \ + flag_n = GLOBAL_REGS.n; \ + flag_z = GLOBAL_REGS.z; \ + bank_start = bank_limit = 0; /* prevent caching */ \ + JUMP(GLOBAL_REGS.pc); \ + } while (0) +#else /* DRIVE_CPU */ +#define IMPORT_REGISTERS() +#define EXPORT_REGISTERS() +#endif /* !DRIVE_CPU */ + +/* Stack operations. */ + +#ifndef PUSH +#define PUSH(val) ((PAGE_ONE)[(reg_sp--)] = ((BYTE)(val))) +#endif +#ifndef PULL +#define PULL() ((PAGE_ONE)[(++reg_sp)]) +#endif + +#ifdef DEBUG +#define TRACE_NMI(clk) \ + do { \ + if (TRACEFLG) { \ + debug_nmi(CPU_INT_STATUS, (clk)); \ + } \ + } while (0) +#define TRACE_IRQ(clk) \ + do { \ + if (TRACEFLG) { \ + debug_irq(CPU_INT_STATUS, (clk)); \ + } \ + } while (0) +#define TRACE_BRK() \ + do { \ + if (TRACEFLG) { \ + debug_text("*** BRK"); \ + } \ + } while (0) +#else +#define TRACE_NMI(clk) +#define TRACE_IRQ(clk) +#define TRACE_BRK() +#endif + +/* Perform the interrupts in `int_kind'. If we have both NMI and IRQ, + execute NMI. NMI can _not_ take over an in progress IRQ. */ +/* FIXME: LOCAL_STATUS() should check byte ready first. */ +#define DO_INTERRUPT(int_kind) \ + do { \ + BYTE ik = (int_kind); \ + \ + if (ik & (IK_IRQ | IK_IRQPEND | IK_NMI)) { \ + if ((ik & IK_NMI) \ + && interrupt_check_nmi_delay(CPU_INT_STATUS, CLK)) { \ + TRACE_NMI(CLK); \ + if (monitor_mask[CALLER] & (MI_STEP)) { \ + monitor_check_icount_interrupt(); \ + } \ + interrupt_ack_nmi(CPU_INT_STATUS); \ + if (NMI_CYCLES == 7) { \ + LOAD(reg_pc); /* dummy reads */ \ + CLK_ADD(CLK, 1); \ + LOAD(reg_pc); \ + CLK_ADD(CLK, 1); \ + } \ + LOCAL_SET_BREAK(0); \ + PUSH(reg_pc >> 8); \ + PUSH(reg_pc & 0xff); \ + CLK_ADD(CLK, 2); \ + PUSH(LOCAL_STATUS()); \ + CLK_ADD(CLK, 1); \ + LOCAL_SET_DECIMAL(0); \ + LOCAL_SET_INTERRUPT(1); \ + JUMP(LOAD_ADDR(0xfffa)); \ + SET_LAST_OPCODE(0); \ + CLK_ADD(CLK, 2); \ + } \ + if ((ik & (IK_IRQ | IK_IRQPEND)) && (!LOCAL_INTERRUPT() || OPINFO_DISABLES_IRQ(LAST_OPCODE_INFO)) \ + && interrupt_check_irq_delay(CPU_INT_STATUS, CLK)) { \ + TRACE_IRQ(CLK); \ + if (monitor_mask[CALLER] & (MI_STEP)) { \ + monitor_check_icount_interrupt(); \ + } \ + interrupt_ack_irq(CPU_INT_STATUS); \ + if (NMI_CYCLES == 7) { \ + LOAD(reg_pc); /* dummy reads */ \ + CLK_ADD(CLK, 1); \ + LOAD(reg_pc); \ + CLK_ADD(CLK, 1); \ + } \ + LOCAL_SET_BREAK(0); \ + PUSH(reg_pc >> 8); \ + PUSH(reg_pc & 0xff); \ + CLK_ADD(CLK, 2); \ + PUSH(LOCAL_STATUS()); \ + CLK_ADD(CLK, 1); \ + LOCAL_SET_DECIMAL(0); \ + LOCAL_SET_INTERRUPT(1); \ + JUMP(LOAD_ADDR(0xfffe)); \ + SET_LAST_OPCODE(0); \ + CLK_ADD(CLK, 2); \ + } \ + } \ + if (ik & (IK_TRAP | IK_RESET)) { \ + if (ik & IK_TRAP) { \ + EXPORT_REGISTERS(); \ + interrupt_do_trap(CPU_INT_STATUS, (WORD)reg_pc); \ + IMPORT_REGISTERS(); \ + if (CPU_INT_STATUS->global_pending_int & IK_RESET) { \ + ik |= IK_RESET; \ + } \ + } \ + if (ik & IK_RESET) { \ + interrupt_ack_reset(CPU_INT_STATUS); \ + cpu65c02_reset(); \ + bank_start = bank_limit = 0; /* prevent caching */ \ + JUMP(LOAD_ADDR(0xfffc)); \ + DMA_ON_RESET; \ + } \ + } \ + if (ik & (IK_MONITOR | IK_DMA)) { \ + if (ik & IK_MONITOR) { \ + if (monitor_force_import(CALLER)) { \ + IMPORT_REGISTERS(); \ + } \ + if (monitor_mask[CALLER]) { \ + EXPORT_REGISTERS(); \ + } \ + if (monitor_mask[CALLER] & (MI_STEP)) { \ + monitor_check_icount((WORD)reg_pc); \ + IMPORT_REGISTERS(); \ + } \ + if (monitor_mask[CALLER] & (MI_BREAK)) { \ + if (monitor_check_breakpoints(CALLER, (WORD)reg_pc)) { \ + monitor_startup(CALLER); \ + IMPORT_REGISTERS(); \ + } \ + } \ + if (monitor_mask[CALLER] & (MI_WATCH)) { \ + monitor_check_watchpoints(LAST_OPCODE_ADDR, (WORD)reg_pc); \ + IMPORT_REGISTERS(); \ + } \ + } \ + if (ik & IK_DMA) { \ + EXPORT_REGISTERS(); \ + DMA_FUNC; \ + interrupt_ack_dma(CPU_INT_STATUS); \ + IMPORT_REGISTERS(); \ + } \ + } \ + } while (0) + +/* ------------------------------------------------------------------------- */ + +/* Addressing modes. For convenience, page boundary crossing cycles and + ``idle'' memory reads are handled here as well. */ + +#define LOAD_ABS(addr) LOAD(addr) + +#define LOAD_ABS_X(addr) \ + ((((addr) & 0xff) + reg_x) > 0xff \ + ? (LOAD(reg_pc + 2), \ + CLK_ADD(CLK, CYCLES_1), \ + LOAD((addr) + reg_x)) \ + : LOAD((addr) + reg_x)) + +#define LOAD_ABS_X_RMW(addr) \ + (LOAD(reg_pc + 2), \ + CLK_ADD(CLK, CYCLES_1), \ + LOAD((addr) + reg_x)) + +#define LOAD_ABS_Y(addr) \ + ((((addr) & 0xff) + reg_y) > 0xff \ + ? (LOAD(reg_pc + 2), \ + CLK_ADD(CLK, CYCLES_1), \ + LOAD((addr) + reg_y)) \ + : LOAD((addr) + reg_y)) + +#define LOAD_INDIRECT(addr) (CLK_ADD(CLK, CYCLES_2), LOAD(LOAD_ZERO_ADDR((addr)))) + +#define LOAD_IND_X(addr) (CLK_ADD(CLK, CYCLES_3), LOAD(LOAD_ZERO_ADDR((addr) + reg_x))) + +#define LOAD_IND_Y(addr) \ + (CLK_ADD(CLK, CYCLES_2), ((LOAD_ZERO_ADDR((addr)) & 0xff) + reg_y) > 0xff \ + ? (LOAD(reg_pc + 1), \ + CLK_ADD(CLK, CYCLES_1), \ + LOAD(LOAD_ZERO_ADDR((addr)) + reg_y)) \ + : LOAD(LOAD_ZERO_ADDR((addr)) + reg_y)) + +#define LOAD_ZERO_X(addr) (LOAD_ZERO((addr) + reg_x)) + +#define LOAD_ZERO_Y(addr) (LOAD_ZERO((addr) + reg_y)) + +#define LOAD_IND_Y_BANK(addr) \ + (CLK_ADD(CLK, CYCLES_2), ((LOAD_ZERO_ADDR((addr)) & 0xff) + reg_y) > 0xff \ + ? (LOAD(reg_pc + 1), \ + CLK_ADD(CLK, CYCLES_1), \ + LOAD_IND(LOAD_ZERO_ADDR((addr)) + reg_y)) \ + : LOAD_IND(LOAD_ZERO_ADDR((addr)) + reg_y)) + +#define STORE_ABS(addr, value) \ + do { \ + STORE((addr), (value)); \ + } while (0) + +#define STORE_ABS_RRW(addr, value) \ + do { \ + LOAD(addr); \ + CLK_ADD(CLK, CYCLES_1); \ + STORE(addr, value); \ + CLK_ADD(CLK, CYCLES_1); \ + } while (0) + +#define STORE_ABS_X(addr, value) \ + do { \ + LOAD(reg_pc - 1); \ + CLK_ADD(CLK, CYCLES_1); \ + STORE((addr) + reg_x, (value)); \ + CLK_ADD(CLK, CYCLES_1); \ + } while (0) + +#define STORE_ABS_X_RRW(addr, value) \ + do { \ + LOAD((addr) + reg_x); \ + CLK_ADD(CLK, CYCLES_1); \ + STORE((addr) + reg_x, (value)); \ + CLK_ADD(CLK, CYCLES_1); \ + } while (0) + +#define STORE_ABS_Y(addr, value) \ + do { \ + LOAD(reg_pc - 1); \ + CLK_ADD(CLK, CYCLES_1); \ + STORE((addr) + reg_y, (value)); \ + CLK_ADD(CLK, CYCLES_1); \ + } while (0) + +#define INC_PC(value) (reg_pc += (value)) + +/* ------------------------------------------------------------------------- */ + +/* Opcodes. */ + +/* + A couple of caveats about PC: + + - the VIC-II emulation requires PC to be incremented before the first + write access (this is not (very) important when writing to the zero + page); + + - `p0', `p1' and `p2' can only be used *before* incrementing PC: some + machines (eg. the C128) might depend on this. +*/ + +#define ADC(value, clk_inc, pc_inc) \ + do { \ + unsigned int tmp_value; \ + unsigned int tmp, tmp2; \ + \ + tmp_value = (value); \ + CLK_ADD(CLK, (clk_inc)); \ + \ + if (LOCAL_DECIMAL()) { \ + tmp = (reg_a & 0xf) + (tmp_value & 0xf) + LOCAL_CARRY(); \ + tmp2 = (reg_a & 0xf0) + (tmp_value & 0xf0); \ + if (tmp > 9) { \ + tmp2 += 0x10; \ + tmp += 6; \ + } \ + LOCAL_SET_OVERFLOW(~(reg_a ^ tmp_value) & (reg_a ^ tmp) & 0x80); \ + if (tmp2 > 0x90) { \ + tmp2 += 0x60; \ + } \ + LOCAL_SET_CARRY(tmp2 & 0xff00); \ + tmp = (tmp & 0xf) + (tmp2 & 0xf0); \ + LOCAL_SET_NZ(tmp); \ + LOAD(reg_pc + pc_inc - 1); \ + CLK_ADD(CLK, CYCLES_1); \ + } else { \ + tmp = tmp_value + reg_a + LOCAL_CARRY(); \ + LOCAL_SET_NZ(tmp & 0xff); \ + LOCAL_SET_OVERFLOW(!((reg_a ^ tmp_value) & 0x80) && ((reg_a ^ tmp) & 0x80)); \ + LOCAL_SET_CARRY(tmp > 0xff); \ + } \ + reg_a = tmp; \ + INC_PC(pc_inc); \ + } while (0) + +#define AND(value, clk_inc, pc_inc) \ + do { \ + reg_a = (BYTE)(reg_a & (value)); \ + LOCAL_SET_NZ(reg_a); \ + CLK_ADD(CLK, (clk_inc)); \ + INC_PC(pc_inc); \ + } while (0) + +#define ASL(addr, clk_inc, pc_inc, load_func, store_func) \ + do { \ + unsigned int tmp_value, tmp_addr; \ + \ + tmp_addr = (addr); \ + tmp_value = load_func(tmp_addr); \ + LOCAL_SET_CARRY(tmp_value & 0x80); \ + tmp_value = (tmp_value << 1) & 0xff; \ + LOCAL_SET_NZ(tmp_value); \ + INC_PC(pc_inc); \ + CLK_ADD(CLK, clk_inc); \ + store_func(tmp_addr, tmp_value); \ + } while (0) + +#define ASL_A() \ + do { \ + LOCAL_SET_CARRY(reg_a & 0x80); \ + reg_a = reg_a << 1; \ + LOCAL_SET_NZ(reg_a); \ + INC_PC(SIZE_1); \ + } while (0) + +#define BBR(bit) \ + do { \ + unsigned int tmp, tmp_addr; \ + unsigned int dest_addr; \ + BYTE value; \ + \ + if (cpu_type == CPU_65SC02) { \ + NOOP_IMM(SIZE_1); \ + } else { \ + tmp_addr = LOAD(reg_pc + 1); \ + CLK_ADD(CLK, CYCLES_1); \ + value = LOAD(reg_pc + 2); \ + CLK_ADD(CLK, CYCLES_1); \ + tmp = LOAD_ZERO(tmp_addr) & (1 << bit); \ + CLK_ADD(CLK, CYCLES_1); \ + INC_PC(SIZE_3); \ + LOAD(reg_pc); \ + CLK_ADD(CLK, CYCLES_1); \ + if (!tmp) { \ + dest_addr = reg_pc + (signed char)(value); \ + OPCODE_DELAYS_INTERRUPT(); \ + JUMP(dest_addr & 0xffff); \ + } \ + } \ + } while (0) + +#define BBS(bit) \ + do { \ + unsigned int tmp, tmp_addr; \ + unsigned int dest_addr; \ + BYTE value; \ + \ + if (cpu_type == CPU_65SC02) { \ + NOOP_IMM(SIZE_1); \ + } else { \ + tmp_addr = LOAD(reg_pc + 1); \ + CLK_ADD(CLK, CYCLES_1); \ + value = LOAD(reg_pc + 2); \ + CLK_ADD(CLK, CYCLES_1); \ + tmp = LOAD_ZERO(tmp_addr) & (1 << bit); \ + CLK_ADD(CLK, CYCLES_1); \ + INC_PC(SIZE_3); \ + LOAD(reg_pc); \ + CLK_ADD(CLK, CYCLES_1); \ + \ + if (tmp) { \ + dest_addr = reg_pc + (signed char)(value); \ + OPCODE_DELAYS_INTERRUPT(); \ + JUMP(dest_addr & 0xffff); \ + } \ + } \ + } while (0) + +#define BIT(value, clk_inc, pc_inc) \ + do { \ + unsigned int tmp; \ + \ + tmp = (value); \ + CLK_ADD(CLK, clk_inc); \ + LOCAL_SET_SIGN(tmp & 0x80); \ + LOCAL_SET_OVERFLOW(tmp & 0x40); \ + LOCAL_SET_ZERO(!(tmp & reg_a)); \ + INC_PC(pc_inc); \ + } while (0) + +#define BIT_IMM(value) \ + do { \ + unsigned int tmp; \ + \ + tmp = (value); \ + LOCAL_SET_ZERO(!(tmp & reg_a)); \ + INC_PC(SIZE_2); \ + } while (0) + +#define BRANCH(cond, value) \ + do { \ + unsigned int dest_addr = 0; \ + INC_PC(SIZE_2); \ + \ + if (cond) { \ + dest_addr = reg_pc + (signed char)(value); \ + \ + LOAD(reg_pc); \ + CLK_ADD(CLK, CYCLES_1); \ + if ((reg_pc ^ dest_addr) & 0xff00) { \ + LOAD(reg_pc); \ + CLK_ADD(CLK, CYCLES_1); \ + } else { \ + OPCODE_DELAYS_INTERRUPT(); \ + } \ + JUMP(dest_addr & 0xffff); \ + } \ + } while (0) + +#define BRK() \ + do { \ + EXPORT_REGISTERS(); \ + TRACE_BRK(); \ + INC_PC(SIZE_2); \ + LOCAL_SET_BREAK(1); \ + PUSH(reg_pc >> 8); \ + PUSH(reg_pc & 0xff); \ + CLK_ADD(CLK, CYCLES_2); \ + PUSH(LOCAL_STATUS()); \ + CLK_ADD(CLK, CYCLES_1); \ + LOCAL_SET_DECIMAL(0); \ + LOCAL_SET_INTERRUPT(1); \ + JUMP(LOAD_ADDR(0xfffe)); \ + CLK_ADD(CLK, CYCLES_2); \ + } while (0) + +#define CLC() \ + do { \ + INC_PC(SIZE_1); \ + LOCAL_SET_CARRY(0); \ + } while (0) + +#define CLD() \ + do { \ + INC_PC(SIZE_1); \ + LOCAL_SET_DECIMAL(0); \ + } while (0) + +#define CLI() \ + do { \ + INC_PC(SIZE_1); \ + if (LOCAL_INTERRUPT()) { \ + OPCODE_ENABLES_IRQ(); \ + } \ + LOCAL_SET_INTERRUPT(0); \ + } while (0) + +#define CLV() \ + do { \ + INC_PC(SIZE_1); \ + LOCAL_SET_OVERFLOW(0); \ + } while (0) + +#define CMP(value, clk_inc, pc_inc) \ + do { \ + unsigned int tmp; \ + \ + tmp = reg_a - (value); \ + LOCAL_SET_CARRY(tmp < 0x100); \ + LOCAL_SET_NZ(tmp & 0xff); \ + CLK_ADD(CLK, (clk_inc)); \ + INC_PC(pc_inc); \ + } while (0) + +#define CPX(value, clk_inc, pc_inc) \ + do { \ + unsigned int tmp; \ + \ + tmp = reg_x - (value); \ + LOCAL_SET_CARRY(tmp < 0x100); \ + LOCAL_SET_NZ(tmp & 0xff); \ + CLK_ADD(CLK, (clk_inc)); \ + INC_PC(pc_inc); \ + } while (0) + +#define CPY(value, clk_inc, pc_inc) \ + do { \ + unsigned int tmp; \ + \ + tmp = reg_y - (value); \ + LOCAL_SET_CARRY(tmp < 0x100); \ + LOCAL_SET_NZ(tmp & 0xff); \ + CLK_ADD(CLK, (clk_inc)); \ + INC_PC(pc_inc); \ + } while (0) + +#define DEA() \ + do { \ + reg_a--; \ + LOCAL_SET_NZ(reg_a); \ + INC_PC(SIZE_1); \ + } while (0) + +#define DEC(addr, clk_inc, pc_inc, load_func, store_func) \ + do { \ + unsigned int tmp, tmp_addr; \ + \ + tmp_addr = (addr); \ + tmp = load_func(tmp_addr); \ + tmp = (tmp - 1) & 0xff; \ + LOCAL_SET_NZ(tmp); \ + INC_PC(pc_inc); \ + CLK_ADD(CLK, (clk_inc)); \ + store_func(tmp_addr, tmp); \ + } while (0) + +#define DEX() \ + do { \ + reg_x--; \ + LOCAL_SET_NZ(reg_x); \ + INC_PC(SIZE_1); \ + } while (0) + +#define DEY() \ + do { \ + reg_y--; \ + LOCAL_SET_NZ(reg_y); \ + INC_PC(SIZE_1); \ + } while (0) + +#define EOR(value, clk_inc, pc_inc) \ + do { \ + reg_a = (BYTE)(reg_a ^ (value)); \ + LOCAL_SET_NZ(reg_a); \ + CLK_ADD(CLK, (clk_inc)); \ + INC_PC(pc_inc); \ + } while (0) + +#define INA() \ + do { \ + reg_a++; \ + LOCAL_SET_NZ(reg_a); \ + INC_PC(SIZE_1); \ + } while (0) + +#define INC(addr, clk_inc, pc_inc, load_func, store_func) \ + do { \ + unsigned int tmp, tmp_addr; \ + \ + tmp_addr = (addr); \ + tmp = (load_func(tmp_addr) + 1) & 0xff; \ + LOCAL_SET_NZ(tmp); \ + INC_PC(pc_inc); \ + CLK_ADD(CLK, (clk_inc)); \ + store_func(tmp_addr, tmp); \ + } while (0) + +#define INX() \ + do { \ + reg_x++; \ + LOCAL_SET_NZ(reg_x); \ + INC_PC(SIZE_1); \ + } while (0) + +#define INY() \ + do { \ + reg_y++; \ + LOCAL_SET_NZ(reg_y); \ + INC_PC(SIZE_1); \ + } while (0) + +/* The 0x02 NOP opcode is also used to patch the ROM. The function trap_handler() + returns nonzero if this is not a patch, but a `real' NOP instruction. */ + +#define NOP_02() \ + do { \ + DWORD trap_result; \ + EXPORT_REGISTERS(); \ + if (!ROM_TRAP_ALLOWED() \ + || (trap_result = ROM_TRAP_HANDLER()) == (DWORD)-1) { \ + NOOP_IMM(SIZE_2); \ + } else { \ + if (trap_result) { \ + REWIND_FETCH_OPCODE(CLK, CYCLES_2); \ + SET_OPCODE(trap_result); \ + IMPORT_REGISTERS(); \ + goto trap_skipped; \ + } else { \ + IMPORT_REGISTERS(); \ + } \ + } \ + } while (0) + +#define JMP(addr) \ + do { \ + JUMP(addr); \ + } while (0) + +#define JMP_IND() \ + do { \ + WORD dest_addr; \ + dest_addr = LOAD(p2); \ + CLK_ADD(CLK, CYCLES_1); \ + LOAD(reg_pc + 2); \ + CLK_ADD(CLK, CYCLES_1); \ + dest_addr |= (LOAD((p2 + 1) & 0xffff) << 8); \ + CLK_ADD(CLK, CYCLES_1); \ + JUMP(dest_addr); \ + } while (0) + +#define JMP_IND_X() \ + do { \ + WORD dest_addr; \ + dest_addr = LOAD((p2 + reg_x) & 0xffff); \ + CLK_ADD(CLK, CYCLES_1); \ + LOAD(reg_pc + 2); \ + CLK_ADD(CLK, CYCLES_1); \ + dest_addr |= (LOAD((p2 + reg_x + 1) & 0xffff) << 8); \ + CLK_ADD(CLK, CYCLES_1); \ + JUMP(dest_addr); \ + } while (0) + +#define JSR() \ + do { \ + unsigned int tmp_addr; \ + \ + CLK_ADD(CLK, CYCLES_1); \ + INC_PC(SIZE_2); \ + CLK_ADD(CLK, CYCLES_2); \ + PUSH(((reg_pc) >> 8) & 0xff); \ + PUSH((reg_pc) & 0xff); \ + tmp_addr = (p1 | (LOAD(reg_pc) << 8)); \ + CLK_ADD(CLK, CYCLES_1); \ + JUMP(tmp_addr); \ + } while (0) + +#define LDA(value, clk_inc, pc_inc) \ + do { \ + reg_a = (BYTE)(value); \ + CLK_ADD(CLK, (clk_inc)); \ + LOCAL_SET_NZ(reg_a); \ + INC_PC(pc_inc); \ + } while (0) + +#define LDX(value, clk_inc, pc_inc) \ + do { \ + reg_x = (BYTE)(value); \ + LOCAL_SET_NZ(reg_x); \ + CLK_ADD(CLK, (clk_inc)); \ + INC_PC(pc_inc); \ + } while (0) + +#define LDY(value, clk_inc, pc_inc) \ + do { \ + reg_y = (BYTE)(value); \ + LOCAL_SET_NZ(reg_y); \ + CLK_ADD(CLK, (clk_inc)); \ + INC_PC(pc_inc); \ + } while (0) + +#define LSR(addr, clk_inc, pc_inc, load_func, store_func) \ + do { \ + unsigned int tmp, tmp_addr; \ + \ + tmp_addr = (addr); \ + tmp = load_func(tmp_addr); \ + LOCAL_SET_CARRY(tmp & 0x01); \ + tmp >>= 1; \ + LOCAL_SET_NZ(tmp); \ + INC_PC(pc_inc); \ + CLK_ADD(CLK, clk_inc); \ + store_func(tmp_addr, tmp); \ + } while (0) + +#define LSR_A() \ + do { \ + LOCAL_SET_CARRY(reg_a & 0x01); \ + reg_a = reg_a >> 1; \ + LOCAL_SET_NZ(reg_a); \ + INC_PC(SIZE_1); \ + } while (0) + +#define ORA(value, clk_inc, pc_inc) \ + do { \ + reg_a = (BYTE)(reg_a | (value)); \ + LOCAL_SET_NZ(reg_a); \ + CLK_ADD(CLK, (clk_inc)); \ + INC_PC(pc_inc); \ + } while (0) + +#define NOOP(clk_inc, pc_inc) (CLK_ADD(CLK, (clk_inc)), INC_PC(pc_inc)) + +#define NOOP_IMM(pc_inc) INC_PC(pc_inc) + +#define NOOP_ZP() \ + do { \ + LOAD_ZERO(p1); \ + CLK_ADD(CLK, CYCLES_1); \ + INC_PC(SIZE_2); \ + } while (0) + +#define NOOP_ZP_X() \ + do { \ + LOAD_ZERO(p1); \ + CLK_ADD(CLK, CYCLES_1); \ + LOAD_ZERO(p1 + reg_x); \ + CLK_ADD(CLK, CYCLES_1); \ + INC_PC(SIZE_2); \ + } while (0) + +#define NOOP_ABS() \ + do { \ + LOAD(p2); \ + CLK_ADD(CLK, CYCLES_1); \ + INC_PC(SIZE_3); \ + } while (0) + +#define NOOP_5C() \ + do { \ + LOAD(p2); \ + CLK_ADD(CLK, CYCLES_1); \ + LOAD(reg_pc + 2); \ + CLK_ADD(CLK, CYCLES_1); \ + LOAD(reg_pc + 2); \ + CLK_ADD(CLK, CYCLES_1); \ + LOAD(reg_pc + 2); \ + CLK_ADD(CLK, CYCLES_1); \ + LOAD(reg_pc + 2); \ + CLK_ADD(CLK, CYCLES_1); \ + INC_PC(SIZE_3); \ + } while (0) + +#define NOP() NOOP_IMM(SIZE_1) + +#define PHA() \ + do { \ + CLK_ADD(CLK, CYCLES_1); \ + PUSH(reg_a); \ + INC_PC(SIZE_1); \ + } while (0) + +#define PHP() \ + do { \ + CLK_ADD(CLK, CYCLES_1); \ + PUSH(LOCAL_STATUS() | P_BREAK); \ + INC_PC(SIZE_1); \ + } while (0) + +#define PHX() \ + do { \ + CLK_ADD(CLK, CYCLES_1); \ + PUSH(reg_x); \ + INC_PC(SIZE_1); \ + } while (0) + +#define PHY() \ + do { \ + CLK_ADD(CLK, CYCLES_1); \ + PUSH(reg_y); \ + INC_PC(SIZE_1); \ + } while (0) + +#define PLA() \ + do { \ + CLK_ADD(CLK, CYCLES_2); \ + reg_a = PULL(); \ + LOCAL_SET_NZ(reg_a); \ + INC_PC(SIZE_1); \ + } while (0) + +#define PLP() \ + do { \ + BYTE s = PULL(); \ + \ + if (!(s & P_INTERRUPT) && LOCAL_INTERRUPT()) { \ + OPCODE_ENABLES_IRQ(); \ + } else if ((s & P_INTERRUPT) && !LOCAL_INTERRUPT()) { \ + OPCODE_DISABLES_IRQ(); \ + } \ + CLK_ADD(CLK, CYCLES_2); \ + LOCAL_SET_STATUS(s); \ + INC_PC(SIZE_1); \ + } while (0) + +#define PLX() \ + do { \ + CLK_ADD(CLK, CYCLES_2); \ + reg_x = PULL(); \ + LOCAL_SET_NZ(reg_x); \ + INC_PC(SIZE_1); \ + } while (0) + +#define PLY() \ + do { \ + CLK_ADD(CLK, CYCLES_2); \ + reg_y = PULL(); \ + LOCAL_SET_NZ(reg_y); \ + INC_PC(SIZE_1); \ + } while (0) + +#define RMB(bit) \ + do { \ + unsigned int tmp, tmp_addr; \ + \ + if (cpu_type == CPU_65SC02) { \ + NOOP_IMM(SIZE_1); \ + } else { \ + tmp_addr = LOAD(reg_pc + 1); \ + CLK_ADD(CLK, CYCLES_1); \ + LOAD_ZERO(tmp_addr); \ + CLK_ADD(CLK, CYCLES_1); \ + tmp = LOAD_ZERO(tmp_addr) & ~(1 << bit); \ + CLK_ADD(CLK, CYCLES_1); \ + INC_PC(SIZE_2); \ + STORE_ZERO(tmp_addr, tmp); \ + CLK_ADD(CLK, 1); \ + } \ + } while (0) + +#define ROL(addr, clk_inc, pc_inc, load_func, store_func) \ + do { \ + unsigned int tmp, tmp_addr; \ + \ + tmp_addr = (addr); \ + tmp = load_func(tmp_addr); \ + tmp = (tmp << 1) | LOCAL_CARRY(); \ + LOCAL_SET_CARRY(tmp & 0x100); \ + LOCAL_SET_NZ(tmp & 0xff); \ + INC_PC(pc_inc); \ + CLK_ADD(CLK, clk_inc); \ + store_func(tmp_addr, tmp); \ + } while (0) + +#define ROL_A() \ + do { \ + unsigned int tmp = reg_a << 1; \ + \ + reg_a = tmp | LOCAL_CARRY(); \ + LOCAL_SET_CARRY(tmp & 0x100); \ + LOCAL_SET_NZ(reg_a); \ + INC_PC(SIZE_1); \ + } while (0) + +#define ROR(addr, clk_inc, pc_inc, load_func, store_func) \ + do { \ + unsigned int src, tmp_addr; \ + \ + tmp_addr = (addr); \ + src = load_func(tmp_addr); \ + if (LOCAL_CARRY()) { \ + src |= 0x100; \ + } \ + LOCAL_SET_CARRY(src & 0x01); \ + src >>= 1; \ + LOCAL_SET_NZ(src); \ + INC_PC(pc_inc); \ + CLK_ADD(CLK, (clk_inc)); \ + store_func(tmp_addr, src); \ + } while (0) + +#define ROR_A() \ + do { \ + BYTE tmp = reg_a; \ + \ + reg_a = (reg_a >> 1) | (reg_p << 7); \ + LOCAL_SET_CARRY(tmp & 0x01); \ + LOCAL_SET_NZ(reg_a); \ + INC_PC(SIZE_1); \ + } while (0) + +/* RTI does must not use `OPCODE_ENABLES_IRQ()' even if the I flag changes + from 1 to 0 because the value of I is set 3 cycles before the end of the + opcode, and thus the 6510 has enough time to call the interrupt routine as + soon as the opcode ends, if necessary. */ +#define RTI() \ + do { \ + WORD tmp; \ + \ + CLK_ADD(CLK, CYCLES_4); \ + tmp = (WORD)PULL(); \ + LOCAL_SET_STATUS((BYTE)tmp); \ + tmp = (WORD)PULL(); \ + tmp |= (WORD)PULL() << 8; \ + JUMP(tmp); \ + } while (0) + +#define RTS() \ + do { \ + WORD tmp; \ + \ + CLK_ADD(CLK, CYCLES_3); \ + tmp = PULL(); \ + tmp = tmp | (PULL() << 8); \ + LOAD(tmp); \ + CLK_ADD(CLK, CYCLES_1); \ + tmp++; \ + JUMP(tmp); \ + } while (0) + +#define SBC(value, clk_inc, pc_inc) \ + do { \ + WORD src, tmp; \ + \ + src = (WORD)(value); \ + CLK_ADD(CLK, (clk_inc)); \ + if (LOCAL_DECIMAL()) { \ + tmp = reg_a - (src & 0xf) + LOCAL_CARRY() - 1; \ + if ((tmp & 0xf) > (reg_a & 0xf)) { \ + tmp -= 6; \ + } \ + tmp -= (src & 0xf0); \ + if ((tmp & 0xf0) > (reg_a & 0xf0)) { \ + tmp -= 0x60; \ + } \ + LOCAL_SET_OVERFLOW(!(tmp > reg_a)); \ + LOCAL_SET_CARRY(!(tmp > reg_a)); \ + LOCAL_SET_NZ(tmp & 0xff); \ + LOAD(reg_pc + pc_inc - 1); \ + CLK_ADD(CLK, CYCLES_1); \ + } else { \ + tmp = reg_a - src - ((LOCAL_CARRY()) ? 0 : 1); \ + LOCAL_SET_NZ(tmp & 0xff); \ + LOCAL_SET_CARRY(tmp < 0x100); \ + LOCAL_SET_OVERFLOW(((reg_a ^ tmp) & 0x80) && ((reg_a ^ src) & 0x80)); \ + } \ + reg_a = (BYTE)tmp; \ + INC_PC(pc_inc); \ + } while (0) + +#undef SEC /* defined in time.h on SunOS. */ +#define SEC() \ + do { \ + LOCAL_SET_CARRY(1); \ + INC_PC(SIZE_1); \ + } while (0) + +#define SED() \ + do { \ + LOCAL_SET_DECIMAL(1); \ + INC_PC(SIZE_1); \ + } while (0) + +#define SEI() \ + do { \ + if (!LOCAL_INTERRUPT()) { \ + OPCODE_DISABLES_IRQ(); \ + } \ + LOCAL_SET_INTERRUPT(1); \ + INC_PC(SIZE_1); \ + } while (0) + +#define SMB(bit) \ + do { \ + unsigned tmp, tmp_addr; \ + \ + if (cpu_type == CPU_65SC02) { \ + NOOP_IMM(SIZE_1); \ + } else { \ + tmp_addr = LOAD(reg_pc + 1); \ + CLK_ADD(CLK, CYCLES_1); \ + LOAD(tmp_addr); \ + CLK_ADD(CLK, CYCLES_1); \ + tmp = LOAD_ZERO(tmp_addr) | (1 << bit); \ + CLK_ADD(CLK, CYCLES_1); \ + INC_PC(SIZE_2); \ + STORE_ZERO(tmp_addr, tmp); \ + CLK_ADD(CLK, CYCLES_1); \ + } \ + } while (0) + +#define STA(addr, clk_inc1, clk_inc2, pc_inc, store_func) \ + do { \ + unsigned int tmp; \ + \ + CLK_ADD(CLK, (clk_inc1)); \ + tmp = (addr); \ + INC_PC(pc_inc); \ + CLK_ADD(CLK, clk_inc2 - 1); \ + store_func(tmp, reg_a); \ + CLK_ADD(CLK, CYCLES_1); \ + } while (0) + +#define STA_ZERO(addr, clk_inc, pc_inc) \ + do { \ + CLK_ADD(CLK, (clk_inc)); \ + STORE_ZERO((addr), reg_a); \ + INC_PC(pc_inc); \ + } while (0) + +#define STA_IND_Y(addr) \ + do { \ + unsigned int tmp; \ + \ + CLK_ADD(CLK, CYCLES_2); \ + tmp = LOAD_ZERO_ADDR(addr); \ + LOAD(reg_pc + 1); \ + CLK_ADD(CLK, CYCLES_1); \ + INC_PC(SIZE_2); \ + STORE_IND(tmp + reg_y, reg_a); \ + CLK_ADD(CLK, CYCLES_1); \ + } while (0) + +#define STP() \ + do { \ + if (cpu_type == CPU_WDC65C02) { \ + WDC_STP(); \ + } else { \ + REWIND_FETCH_OPCODE(CLK, 2); \ + NOOP_IMM(SIZE_1); \ + } \ + } while (0) + +#define STX(addr) \ + do { \ + unsigned int tmp; \ + \ + tmp = (addr); \ + INC_PC(SIZE_3); \ + STORE(tmp, reg_x); \ + CLK_ADD(CLK, CYCLES_1); \ + } while (0) + +#define STX_ZERO(addr, clk_inc, pc_inc) \ + do { \ + CLK_ADD(CLK, (clk_inc)); \ + STORE_ZERO((addr), reg_x); \ + INC_PC(pc_inc); \ + } while (0) + +#define STY(addr) \ + do { \ + unsigned int tmp; \ + \ + tmp = (addr); \ + INC_PC(SIZE_3); \ + STORE(tmp, reg_y); \ + CLK_ADD(CLK, CYCLES_1); \ + } while (0) + +#define STY_ZERO(addr, clk_inc, pc_inc) \ + do { \ + CLK_ADD(CLK, (clk_inc)); \ + STORE_ZERO((addr), reg_y); \ + INC_PC(pc_inc); \ + } while (0) + +#define STZ(addr, clk_inc, pc_inc, store_func) \ + do { \ + unsigned int tmp; \ + \ + tmp = (addr); \ + INC_PC(pc_inc); \ + CLK_ADD(CLK, clk_inc); \ + store_func(tmp, 0); \ + } while (0) + +#define STZ_ZERO(addr, clk_inc, pc_inc) \ + do { \ + CLK_ADD(CLK, (clk_inc)); \ + STORE_ZERO((addr), 0); \ + INC_PC(pc_inc); \ + } while (0) + +#define TAX() \ + do { \ + reg_x = reg_a; \ + LOCAL_SET_NZ(reg_a); \ + INC_PC(SIZE_1); \ + } while (0) + +#define TAY() \ + do { \ + reg_y = reg_a; \ + LOCAL_SET_NZ(reg_a); \ + INC_PC(SIZE_1); \ + } while (0) + +#define TRB(addr, clk_inc, pc_inc, load_func, store_func) \ + do { \ + unsigned int tmp_value, tmp_addr; \ + \ + tmp_addr = (addr); \ + tmp_value = load_func(tmp_addr); \ + LOCAL_SET_ZERO(!(tmp_value & reg_a)); \ + tmp_value &= (~reg_a); \ + INC_PC(pc_inc); \ + CLK_ADD(CLK, clk_inc); \ + store_func(tmp_addr, tmp_value); \ + } while (0) + +#define TSB(addr, clk_inc, pc_inc, load_func, store_func) \ + do { \ + unsigned int tmp_value, tmp_addr; \ + \ + tmp_addr = (addr); \ + tmp_value = load_func(tmp_addr); \ + LOCAL_SET_ZERO(!(tmp_value & reg_a)); \ + tmp_value |= reg_a; \ + INC_PC(pc_inc); \ + CLK_ADD(CLK, clk_inc); \ + store_func(tmp_addr, tmp_value); \ + } while (0) + +#define TSX() \ + do { \ + reg_x = reg_sp; \ + LOCAL_SET_NZ(reg_sp); \ + INC_PC(SIZE_1); \ + } while (0) + +#define TXA() \ + do { \ + reg_a = reg_x; \ + LOCAL_SET_NZ(reg_a); \ + INC_PC(SIZE_1); \ + } while (0) + +#define TXS() \ + do { \ + reg_sp = reg_x; \ + INC_PC(SIZE_1); \ + } while (0) + +#define TYA() \ + do { \ + reg_a = reg_y; \ + LOCAL_SET_NZ(reg_a); \ + INC_PC(SIZE_1); \ + } while (0) + +#define WAI() \ + do { \ + if (cpu_type == CPU_WDC65C02) { \ + WDC_WAI(); \ + } else { \ + REWIND_FETCH_OPCODE(CLK, 2); \ + NOOP_IMM(SIZE_1); \ + } \ + } while (0) + +/* ------------------------------------------------------------------------- */ + +/* These tables have a different meaning than for the 6502, it represents + the amount of extra fetches to the opcode fetch. + */ + static const BYTE fetch_tab[] = { + /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + /* $00 */ 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, /* $00 */ + /* $10 */ 1, 1, 1, 0, 1, 1, 1, 0, 1, 2, 1, 0, 2, 2, 2, 0, /* $10 */ + /* $20 */ 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, /* $20 */ + /* $30 */ 1, 1, 1, 0, 1, 1, 1, 0, 1, 2, 1, 0, 2, 2, 2, 0, /* $30 */ + /* $40 */ 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, /* $40 */ + /* $50 */ 1, 1, 1, 0, 1, 1, 1, 0, 1, 2, 1, 0, 2, 2, 2, 0, /* $50 */ + /* $60 */ 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, /* $60 */ + /* $70 */ 1, 1, 1, 0, 1, 1, 1, 0, 1, 2, 1, 0, 2, 2, 2, 0, /* $70 */ + /* $80 */ 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, /* $80 */ + /* $90 */ 1, 1, 1, 0, 1, 1, 1, 0, 1, 2, 1, 0, 2, 2, 2, 0, /* $90 */ + /* $A0 */ 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, /* $A0 */ + /* $B0 */ 1, 1, 1, 0, 1, 1, 1, 0, 1, 2, 1, 0, 2, 2, 2, 0, /* $B0 */ + /* $C0 */ 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 2, 2, 2, 2, 0, /* $C0 */ + /* $D0 */ 1, 1, 1, 0, 1, 1, 1, 0, 1, 2, 1, 2, 2, 2, 2, 0, /* $D0 */ + /* $E0 */ 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, /* $E0 */ + /* $F0 */ 1, 1, 1, 0, 1, 1, 1, 0, 1, 2, 1, 0, 2, 2, 2, 0 /* $F0 */ +}; + +#if !defined WORDS_BIGENDIAN && defined ALLOW_UNALIGNED_ACCESS + +#define opcode_t DWORD + +#define FETCH_OPCODE(o) \ + do { \ + if (((int)reg_pc) < bank_limit) { \ + o = (*((DWORD *)(bank_base + reg_pc)) & 0xffffff); \ + CLK_ADD(CLK, CYCLES_1); \ + if (fetch_tab[o & 0xff]) { \ + CLK_ADD(CLK, fetch_tab[o & 0xff]); \ + } \ + } else { \ + o = LOAD(reg_pc); \ + CLK_ADD(CLK, CYCLES_1); \ + if (fetch_tab[o & 0xff]) { \ + o |= LOAD(reg_pc + 1) << 8; \ + CLK_ADD(CLK, CYCLES_1); \ + if (fetch_tab[o & 0xff] - 1) { \ + o |= (LOAD(reg_pc + 2) << 16); \ + CLK_ADD(CLK, CYCLES_1); \ + } \ + } \ + } \ + } while (0) + +#define p0 (opcode & 0xff) +#define p1 ((opcode >> 8) & 0xff) +#define p2 (opcode >> 8) + +#else /* WORDS_BIGENDIAN || !ALLOW_UNALIGNED_ACCESS */ + +#define opcode_t \ + struct { \ + BYTE ins; \ + union { \ + BYTE op8[2]; \ + WORD op16; \ + } op; \ + } + +#define FETCH_OPCODE(o) \ + do { \ + if (((int)reg_pc) < bank_limit) { \ + (o).ins = *(bank_base + reg_pc); \ + (o).op.op16 = (*(bank_base + reg_pc + 1) | (*(bank_base + reg_pc + 2) << 8)); \ + CLK_ADD(CLK, CYCLES_1); \ + if (fetch_tab[(o).ins]) { \ + CLK_ADD(CLK, fetch_tab[(o).ins]); \ + } \ + } else { \ + (o).ins = LOAD(reg_pc); \ + CLK_ADD(CLK, CYCLES_1); \ + if (fetch_tab[(o).ins]) { \ + (o).op.op16 = LOAD(reg_pc + 1); \ + CLK_ADD(CLK, CYCLES_1); \ + if (fetch_tab[(o).ins - 1]) { \ + (o).op.op16 |= (LOAD(reg_pc + 2) << 8); \ + CLK_ADD(CLK, CYCLES_1); \ + } \ + } \ + } \ + } while (0) + +#define p0 (opcode.ins) +#define p2 (opcode.op.op16) + +#ifdef WORDS_BIGENDIAN +# define p1 (opcode.op.op8[1]) +#else +# define p1 (opcode.op.op8[0]) +#endif + +#endif /* !WORDS_BIGENDIAN */ + +/* SET_OPCODE for traps */ +#if !defined WORDS_BIGENDIAN && defined ALLOW_UNALIGNED_ACCESS +#define SET_OPCODE(o) (opcode) = o; +#else +#if !defined WORDS_BIGENDIAN +#define SET_OPCODE(o) \ + do { \ + opcode.ins = (o) & 0xff; \ + opcode.op.op8[0] = ((o) >> 8) & 0xff; \ + opcode.op.op8[1] = ((o) >> 16) & 0xff; \ + } while (0) +#else +#define SET_OPCODE(o) \ + do { \ + opcode.ins = (o) & 0xff; \ + opcode.op.op8[1] = ((o) >> 8) & 0xff; \ + opcode.op.op8[0] = ((o) >> 16) & 0xff; \ + } while (0) +#endif +#endif + +/* ------------------------------------------------------------------------ */ + +/* Here, the CPU is emulated. */ + +{ + CPU_DELAY_CLK; + + PROCESS_ALARMS; + + { + enum cpu_int pending_interrupt; + + if (!(CPU_INT_STATUS->global_pending_int & IK_IRQ) + && (CPU_INT_STATUS->global_pending_int & IK_IRQPEND) + && CPU_INT_STATUS->irq_pending_clk <= CLK) { + interrupt_ack_irq(CPU_INT_STATUS); + } + + pending_interrupt = (cpu_int)CPU_INT_STATUS->global_pending_int; + if (pending_interrupt != IK_NONE) { + DO_INTERRUPT(pending_interrupt); + if (!(CPU_INT_STATUS->global_pending_int & IK_IRQ) + && CPU_INT_STATUS->global_pending_int & IK_IRQPEND) { + CPU_INT_STATUS->global_pending_int &= ~IK_IRQPEND; + } + CPU_DELAY_CLK + + PROCESS_ALARMS \ + } + } + + { + opcode_t opcode; +#ifdef DEBUG + CLOCK debug_clk; +#ifdef DRIVE_CPU + debug_clk = CLK; +#else + debug_clk = maincpu_clk; +#endif +#endif + +#ifdef FEATURE_CPUMEMHISTORY +#ifndef DRIVE_CPU + memmap_state |= (MEMMAP_STATE_INSTR | MEMMAP_STATE_OPCODE); +#endif +#endif + SET_LAST_ADDR(reg_pc); + FETCH_OPCODE(opcode); + +#ifdef FEATURE_CPUMEMHISTORY +#ifndef DRIVE_CPU + /* HACK to cope with FETCH_OPCODE optimization in x64 */ + if (((int)reg_pc) < bank_limit) { + memmap_mem_read(reg_pc); + } +#endif + if (p0 == 0x20) { + monitor_cpuhistory_store(reg_pc, p0, p1, LOAD(reg_pc + 2), reg_a, reg_x, reg_y, reg_sp, LOCAL_STATUS()); + } else { + monitor_cpuhistory_store(reg_pc, p0, p1, p2 >> 8, reg_a, reg_x, reg_y, reg_sp, LOCAL_STATUS()); + } + memmap_state &= ~(MEMMAP_STATE_INSTR | MEMMAP_STATE_OPCODE); +#endif + +#ifdef DEBUG +#ifdef DRIVE_CPU + if (TRACEFLG) { + BYTE op = (BYTE)(p0); + BYTE lo = (BYTE)(p1); + BYTE hi = (BYTE)(p2 >> 8); + + debug_drive((DWORD)(reg_pc), debug_clk, + mon_disassemble_to_string(e_disk8_space, + reg_pc, op, + lo, hi, 0, 1, "R65(SC)02"), + reg_a, reg_x, reg_y, reg_sp, drv->mynumber + 8); + } +#else + if (TRACEFLG) { + BYTE op = (BYTE)(p0); + BYTE lo = (BYTE)(p1); + BYTE hi = (BYTE)(p2 >> 8); + + if (op == 0x20) { + hi = LOAD(reg_pc + 2); + } + + debug_maincpu((DWORD)(reg_pc), debug_clk, + mon_disassemble_to_string(e_comp_space, + reg_pc, op, + lo, hi, 0, 1, "65(SC)02"), + reg_a, reg_x, reg_y, reg_sp); + } + if (debug.perform_break_into_monitor) { + monitor_startup_trap(); + debug.perform_break_into_monitor = 0; + } +#endif +#endif + +trap_skipped: + SET_LAST_OPCODE(p0); + + switch (p0) { + default: /* 1 byte, 1 cycle NOP */ + NOOP_IMM(SIZE_1); + break; + + case 0x22: /* NOP #$nn */ + case 0x42: /* NOP #$nn */ + case 0x62: /* NOP #$nn */ + case 0x82: /* NOP #$nn */ + case 0xc2: /* NOP #$nn */ + case 0xe2: /* NOP #$nn */ + NOOP_IMM(SIZE_2); + break; + + case 0x44: /* NOP $nn */ + NOOP_ZP(); + break; + + case 0x54: /* NOP $nn,X */ + case 0xd4: /* NOP $nn,X */ + case 0xf4: /* NOP $nn,X */ + NOOP_ZP_X(); + break; + + case 0xdc: /* NOP $nnnn */ + case 0xfc: /* NOP $nnnn */ + NOOP_ABS(); + break; + + case 0x5c: /* NOP $nnnn + 4 (FIXME: correct ??) */ + NOOP_5C(); + break; + + case 0x00: /* BRK */ + BRK(); + break; + + case 0x01: /* ORA ($nn,X) */ + ORA(LOAD_IND_X(p1), CYCLES_1, SIZE_2); + break; + + case 0x02: /* NOP #$nn - also used for traps */ + STATIC_ASSERT(TRAP_OPCODE == 0x02); + NOP_02(); + break; + + case 0x04: /* TSB $nn */ + TSB(p1, CYCLES_3, SIZE_2, LOAD_ZERO, STORE_ZERO); + break; + + case 0x05: /* ORA $nn */ + ORA(LOAD_ZERO(p1), CYCLES_1, SIZE_2); + break; + + case 0x06: /* ASL $nn */ + ASL(p1, CYCLES_3, SIZE_2, LOAD_ZERO, STORE_ZERO); + break; + + case 0x07: /* RMB0 $nn (65C02) / single byte, single cycle NOP (65SC02) */ + RMB(BIT_0); + break; + + case 0x08: /* PHP */ + PHP(); + break; + + case 0x09: /* ORA #$nn */ + ORA(p1, CYCLES_0, SIZE_2); + break; + + case 0x0a: /* ASL A */ + ASL_A(); + break; + + case 0x0c: /* TSB $nnnn */ + TSB(p2, CYCLES_1, SIZE_3, LOAD_ABS, STORE_ABS_RRW); + break; + + case 0x0d: /* ORA $nnnn */ + ORA(LOAD(p2), CYCLES_1, SIZE_3); + break; + + case 0x0e: /* ASL $nnnn */ + ASL(p2, CYCLES_1, SIZE_3, LOAD_ABS, STORE_ABS_RRW); + break; + + case 0x0f: /* BBR0 $nn,$nnnn (65C02) / single byte, single cycle NOP (65SC02) */ + BBR(BIT_0); + break; + + case 0x10: /* BPL $nnnn */ + BRANCH(!LOCAL_SIGN(), p1); + break; + + case 0x11: /* ORA ($nn),Y */ + ORA(LOAD_IND_Y(p1), CYCLES_1, SIZE_2); + break; + + case 0x12: /* ORA ($nn) */ + ORA(LOAD_INDIRECT(p1), CYCLES_1, SIZE_2); + break; + + case 0x14: /* TRB $nn */ + TRB(p1, CYCLES_3, SIZE_2, LOAD_ZERO, STORE_ZERO); + break; + + case 0x15: /* ORA $nn,X */ + ORA(LOAD_ZERO_X(p1), CYCLES_2, SIZE_2); + break; + + case 0x16: /* ASL $nn,X */ + ASL((p1 + reg_x) & 0xff, CYCLES_4, SIZE_2, LOAD_ZERO, STORE_ZERO); + break; + + case 0x17: /* RMB1 $nn (65C02) / single byte, single cycle NOP (65SC02) */ + RMB(BIT_1); + break; + + case 0x18: /* CLC */ + CLC(); + break; + + case 0x19: /* ORA $nnnn,Y */ + ORA(LOAD_ABS_Y(p2), CYCLES_1, SIZE_3); + break; + + case 0x1a: /* INA */ + INA(); + break; + + case 0x1c: /* TRB $nnnn */ + TRB(p2, CYCLES_1, SIZE_3, LOAD_ABS, STORE_ABS_RRW); + break; + + case 0x1d: /* ORA $nnnn,X */ + ORA(LOAD_ABS_X(p2), CYCLES_1, SIZE_3); + break; + + case 0x1e: /* ASL $nnnn,X */ + ASL(p2, CYCLES_1, SIZE_3, LOAD_ABS_X, STORE_ABS_X_RRW); + break; + + case 0x1f: /* BBR1 $nn,$nnnn (65C02) / single byte, single cycle NOP (65SC02) */ + BBR(BIT_1); + break; + + case 0x20: /* JSR $nnnn */ + JSR(); + break; + + case 0x21: /* AND ($nn,X) */ + AND(LOAD_IND_X(p1), CYCLES_1, SIZE_2); + break; + + case 0x24: /* BIT $nn */ + BIT(LOAD_ZERO(p1), CYCLES_1, SIZE_2); + break; + + case 0x25: /* AND $nn */ + AND(LOAD_ZERO(p1), CYCLES_1, SIZE_2); + break; + + case 0x26: /* ROL $nn */ + ROL(p1, CYCLES_3, SIZE_2, LOAD_ZERO, STORE_ZERO); + break; + + case 0x27: /* RMB2 $nn (65C02) / single byte, single cycle NOP (65SC02) */ + RMB(BIT_2); + break; + + case 0x28: /* PLP */ + PLP(); + break; + + case 0x29: /* AND #$nn */ + AND(p1, CYCLES_0, SIZE_2); + break; + + case 0x2a: /* ROL A */ + ROL_A(); + break; + + case 0x2c: /* BIT $nnnn */ + BIT(LOAD(p2), CYCLES_1, SIZE_3); + break; + + case 0x2d: /* AND $nnnn */ + AND(LOAD(p2), CYCLES_1, SIZE_3); + break; + + case 0x2e: /* ROL $nnnn */ + ROL(p2, CYCLES_1, SIZE_3, LOAD_ABS, STORE_ABS_RRW); + break; + + case 0x2f: /* BBR2 $nn,$nnnn (65C02) / single byte, single cycle NOP (65SC02) */ + BBR(BIT_2); + break; + + case 0x30: /* BMI $nnnn */ + BRANCH(LOCAL_SIGN(), p1); + break; + + case 0x31: /* AND ($nn),Y */ + AND(LOAD_IND_Y(p1), CYCLES_1, SIZE_2); + break; + + case 0x32: /* AND ($nn) */ + AND(LOAD_INDIRECT(p1), CYCLES_1, SIZE_2); + break; + + case 0x34: /* BIT $nn,X */ + BIT(LOAD_ZERO_X(p1), CYCLES_2, SIZE_2); + break; + + case 0x35: /* AND $nn,X */ + AND(LOAD_ZERO_X(p1), CYCLES_2, SIZE_2); + break; + + case 0x36: /* ROL $nn,X */ + ROL((p1 + reg_x) & 0xff, CYCLES_4, SIZE_2, LOAD_ZERO, STORE_ZERO); + break; + + case 0x37: /* RMB3 $nn (65C02) / single byte, single cycle NOP (65SC02) */ + RMB(BIT_3); + break; + + case 0x38: /* SEC */ + SEC(); + break; + + case 0x39: /* AND $nnnn,Y */ + AND(LOAD_ABS_Y(p2), CYCLES_1, SIZE_3); + break; + + case 0x3a: /* DEA */ + DEA(); + break; + + case 0x3c: /* BIT $nnnn,X */ + BIT(LOAD_ABS_X(p2), CYCLES_1, SIZE_3); + break; + + case 0x3d: /* AND $nnnn,X */ + AND(LOAD_ABS_X(p2), CYCLES_1, SIZE_3); + break; + + case 0x3e: /* ROL $nnnn,X */ + ROL(p2, CYCLES_1, SIZE_3, LOAD_ABS_X, STORE_ABS_X_RRW); + break; + + case 0x3f: /* BBR3 $nn,$nnnn (65C02) / single byte, single cycle NOP (65SC02) */ + BBR(BIT_3); + break; + + case 0x40: /* RTI */ + RTI(); + break; + + case 0x41: /* EOR ($nn,X) */ + EOR(LOAD_IND_X(p1), CYCLES_1, SIZE_2); + break; + + case 0x45: /* EOR $nn */ + EOR(LOAD_ZERO(p1), CYCLES_1, SIZE_2); + break; + + case 0x46: /* LSR $nn */ + LSR(p1, CYCLES_3, SIZE_2, LOAD_ZERO, STORE_ZERO); + break; + + case 0x47: /* RMB4 $nn (65C02) / single byte, single cycle NOP (65SC02) */ + RMB(BIT_4); + break; + + case 0x48: /* PHA */ + PHA(); + break; + + case 0x49: /* EOR #$nn */ + EOR(p1, CYCLES_0, SIZE_2); + break; + + case 0x4a: /* LSR A */ + LSR_A(); + break; + + case 0x4c: /* JMP $nnnn */ + JMP(p2); + break; + + case 0x4d: /* EOR $nnnn */ + EOR(LOAD(p2), CYCLES_1, SIZE_3); + break; + + case 0x4e: /* LSR $nnnn */ + LSR(p2, CYCLES_1, SIZE_3, LOAD_ABS, STORE_ABS_RRW); + break; + + case 0x4f: /* BBR4 $nn,$nnnn (65C02) / single byte, single cycle NOP (65SC02) */ + BBR(BIT_4); + break; + + case 0x50: /* BVC $nnnn */ + BRANCH(!LOCAL_OVERFLOW(), p1); + break; + + case 0x51: /* EOR ($nn),Y */ + EOR(LOAD_IND_Y(p1), CYCLES_1, SIZE_2); + break; + + case 0x52: /* EOR ($nn) */ + EOR(LOAD_INDIRECT(p1), CYCLES_1, SIZE_2); + break; + + case 0x55: /* EOR $nn,X */ + EOR(LOAD_ZERO_X(p1), CYCLES_2, SIZE_2); + break; + + case 0x56: /* LSR $nn,X */ + LSR((p1 + reg_x) & 0xff, CYCLES_4, SIZE_2, LOAD_ZERO, STORE_ZERO); + break; + + case 0x57: /* RMB5 $nn (65C02) / single byte, single cycle NOP (65SC02) */ + RMB(BIT_5); + break; + + case 0x58: /* CLI */ + CLI(); + break; + + case 0x59: /* EOR $nnnn,Y */ + EOR(LOAD_ABS_Y(p2), CYCLES_1, SIZE_3); + break; + + case 0x5a: /* PHY */ + PHY(); + break; + + case 0x5d: /* EOR $nnnn,X */ + EOR(LOAD_ABS_X(p2), CYCLES_1, SIZE_3); + break; + + case 0x5e: /* LSR $nnnn,X */ + LSR(p2, CYCLES_1, SIZE_3, LOAD_ABS_X, STORE_ABS_X_RRW); + break; + + case 0x5f: /* BBR5 $nn,$nnnn (65C02) / single byte, single cycle NOP (65SC02) */ + BBR(BIT_5); + break; + + case 0x60: /* RTS */ + RTS(); + break; + + case 0x61: /* ADC ($nn,X) */ + ADC(LOAD_IND_X(p1), CYCLES_1, SIZE_2); + break; + + case 0x64: /* STZ $nn */ + STZ_ZERO(p1, CYCLES_1, SIZE_2); + break; + + case 0x65: /* ADC $nn */ + ADC(LOAD_ZERO(p1), CYCLES_1, SIZE_2); + break; + + case 0x66: /* ROR $nn */ + ROR(p1, CYCLES_3, SIZE_2, LOAD_ZERO, STORE_ZERO); + break; + + case 0x67: /* RMB6 $nn (65C02) / single byte, single cycle NOP (65SC02) */ + RMB(BIT_6); + break; + + case 0x68: /* PLA */ + PLA(); + break; + + case 0x69: /* ADC #$nn */ + ADC(p1, CYCLES_0, SIZE_2); + break; + + case 0x6a: /* ROR A */ + ROR_A(); + break; + + case 0x6c: /* JMP ($nnnn) */ + JMP_IND(); + break; + + case 0x6d: /* ADC $nnnn */ + ADC(LOAD(p2), CYCLES_1, SIZE_3); + break; + + case 0x6e: /* ROR $nnnn */ + ROR(p2, CYCLES_1, SIZE_3, LOAD_ABS, STORE_ABS_RRW); + break; + + case 0x6f: /* BBR6 $nn,$nnnn (65C02) / single byte, single cycle NOP (65SC02) */ + BBR(BIT_6); + break; + + case 0x70: /* BVS $nnnn */ + BRANCH(LOCAL_OVERFLOW(), p1); + break; + + case 0x71: /* ADC ($nn),Y */ + ADC(LOAD_IND_Y(p1), CYCLES_1, SIZE_2); + break; + + case 0x72: /* ADC ($nn) */ + ADC(LOAD_INDIRECT(p1), CYCLES_1, SIZE_2); + break; + + case 0x74: /* STZ $nn,X */ + STZ_ZERO(p1 + reg_x, CYCLES_2, SIZE_2); + break; + + case 0x75: /* ADC $nn,X */ + ADC(LOAD_ZERO_X(p1), CYCLES_2, SIZE_2); + break; + + case 0x76: /* ROR $nn,X */ + ROR((p1 + reg_x) & 0xff, CYCLES_4, SIZE_2, LOAD_ZERO, STORE_ZERO); + break; + + case 0x77: /* RMB7 $nn (65C02) / single byte, single cycle NOP (65SC02) */ + RMB(BIT_7); + break; + + case 0x78: /* SEI */ + SEI(); + break; + + case 0x79: /* ADC $nnnn,Y */ + ADC(LOAD_ABS_Y(p2), CYCLES_1, SIZE_3); + break; + + case 0x7a: /* PLY */ + PLY(); + break; + + case 0x7c: /* JMP ($nnnn,X) */ + JMP_IND_X(); + break; + + case 0x7d: /* ADC $nnnn,X */ + ADC(LOAD_ABS_X(p2), CYCLES_1, SIZE_3); + break; + + case 0x7e: /* ROR $nnnn,X */ + ROR(p2, CYCLES_1, SIZE_3, LOAD_ABS_X, STORE_ABS_X_RRW); + break; + + case 0x7f: /* BBR7 $nn,$nnnn (65C02) / single byte, single cycle NOP (65SC02) */ + BBR(BIT_7); + break; + + case 0x80: /* BRA $nnnn */ + BRANCH(1, p1); + break; + + case 0x81: /* STA ($nn,X) */ + STA(LOAD_ZERO_ADDR(p1 + reg_x), CYCLES_3, CYCLES_1, SIZE_2, STORE_ABS); + break; + + case 0x84: /* STY $nn */ + STY_ZERO(p1, CYCLES_1, SIZE_2); + break; + + case 0x85: /* STA $nn */ + STA_ZERO(p1, CYCLES_1, SIZE_2); + break; + + case 0x86: /* STX $nn */ + STX_ZERO(p1, CYCLES_1, SIZE_2); + break; + + case 0x87: /* SMB0 $nn (65C02) / single byte, single cycle NOP (65SC02) */ + SMB(BIT_0); + break; + + case 0x88: /* DEY */ + DEY(); + break; + + case 0x89: /* BIT #$nn */ + BIT_IMM(p1); + break; + + case 0x8a: /* TXA */ + TXA(); + break; + + case 0x8c: /* STY $nnnn */ + STY(p2); + break; + + case 0x8d: /* STA $nnnn */ + STA(p2, CYCLES_0, CYCLES_1, SIZE_3, STORE_ABS); + break; + + case 0x8e: /* STX $nnnn */ + STX(p2); + break; + + case 0x8f: /* BBS0 $nn,$nnnn (65C02) / single byte, single cycle NOP (65SC02) */ + BBS(BIT_0); + break; + + case 0x90: /* BCC $nnnn */ + BRANCH(!LOCAL_CARRY(), p1); + break; + + case 0x91: /* STA ($nn),Y */ + STA_IND_Y(p1); + break; + + case 0x92: /* STA ($nn) */ + STA(LOAD_ZERO_ADDR(p1), CYCLES_2, CYCLES_1, SIZE_2, STORE_ABS); + break; + + case 0x94: /* STY $nn,X */ + STY_ZERO(p1 + reg_x, CYCLES_2, SIZE_2); + break; + + case 0x95: /* STA $nn,X */ + STA_ZERO(p1 + reg_x, CYCLES_2, SIZE_2); + break; + + case 0x96: /* STX $nn,Y */ + STX_ZERO(p1 + reg_y, CYCLES_2, SIZE_2); + break; + + case 0x97: /* SMB1 $nn (65C02) / single byte, single cycle NOP (65SC02) */ + SMB(BIT_1); + break; + + case 0x98: /* TYA */ + TYA(); + break; + + case 0x99: /* STA $nnnn,Y */ + STA(p2, CYCLES_0, CYCLES_0, SIZE_3, STORE_ABS_Y); + break; + + case 0x9a: /* TXS */ + TXS(); + break; + + case 0x9c: /* STZ $nnnn */ + STZ(p2, CYCLES_1, SIZE_3, STORE_ABS); + break; + + case 0x9d: /* STA $nnnn,X */ + STA(p2, CYCLES_0, CYCLES_0, SIZE_3, STORE_ABS_X); + break; + + case 0x9e: /* STZ $nnnn,X */ + STZ(p2, CYCLES_0, SIZE_3, STORE_ABS_X); + break; + + case 0x9f: /* BBS1 $nn,$nnnn (65C02) / single byte, single cycle NOP (65SC02) */ + BBS(BIT_1); + break; + + case 0xa0: /* LDY #$nn */ + LDY(p1, CYCLES_0, SIZE_2); + break; + + case 0xa1: /* LDA ($nn,X) */ + LDA(LOAD_IND_X(p1), CYCLES_1, SIZE_2); + break; + + case 0xa2: /* LDX #$nn */ + LDX(p1, CYCLES_0, SIZE_2); + break; + + case 0xa4: /* LDY $nn */ + LDY(LOAD_ZERO(p1), CYCLES_1, SIZE_2); + break; + + case 0xa5: /* LDA $nn */ + LDA(LOAD_ZERO(p1), CYCLES_1, SIZE_2); + break; + + case 0xa6: /* LDX $nn */ + LDX(LOAD_ZERO(p1), CYCLES_1, SIZE_2); + break; + + case 0xa7: /* SMB2 $nn (65C02) / single byte, single cycle NOP (65SC02) */ + SMB(BIT_2); + break; + + case 0xa8: /* TAY */ + TAY(); + break; + + case 0xa9: /* LDA #$nn */ + LDA(p1, CYCLES_0, SIZE_2); + break; + + case 0xaa: /* TAX */ + TAX(); + break; + + case 0xac: /* LDY $nnnn */ + LDY(LOAD(p2), CYCLES_1, SIZE_3); + break; + + case 0xad: /* LDA $nnnn */ + LDA(LOAD(p2), CYCLES_1, SIZE_3); + break; + + case 0xae: /* LDX $nnnn */ + LDX(LOAD(p2), CYCLES_1, SIZE_3); + break; + + case 0xaf: /* BBS2 $nn,$nnnn (65C02) / single byte, single cycle NOP (65SC02) */ + BBS(BIT_2); + break; + + case 0xb0: /* BCS $nnnn */ + BRANCH(LOCAL_CARRY(), p1); + break; + + case 0xb1: /* LDA ($nn),Y */ + LDA(LOAD_IND_Y_BANK(p1), CYCLES_1, SIZE_2); + break; + + case 0xb2: /* LDA ($nn) */ + LDA(LOAD_INDIRECT(p1), CYCLES_1, SIZE_2); + break; + + case 0xb4: /* LDY $nn,X */ + LDY(LOAD_ZERO_X(p1), CYCLES_2, SIZE_2); + break; + + case 0xb5: /* LDA $nn,X */ + LDA(LOAD_ZERO_X(p1), CYCLES_2, SIZE_2); + break; + + case 0xb6: /* LDX $nn,Y */ + LDX(LOAD_ZERO_Y(p1), CYCLES_2, SIZE_2); + break; + + case 0xb7: /* SMB3 $nn (65C02) / single byte, single cycle NOP (65SC02) */ + SMB(BIT_3); + break; + + case 0xb8: /* CLV */ + CLV(); + break; + + case 0xb9: /* LDA $nnnn,Y */ + LDA(LOAD_ABS_Y(p2), CYCLES_1, SIZE_3); + break; + + case 0xba: /* TSX */ + TSX(); + break; + + case 0xbc: /* LDY $nnnn,X */ + LDY(LOAD_ABS_X(p2), CYCLES_1, SIZE_3); + break; + + case 0xbd: /* LDA $nnnn,X */ + LDA(LOAD_ABS_X(p2), CYCLES_1, SIZE_3); + break; + + case 0xbe: /* LDX $nnnn,Y */ + LDX(LOAD_ABS_Y(p2), CYCLES_1, SIZE_3); + break; + + case 0xbf: /* BBS3 $nn,$nnnn (65C02) / single byte, single cycle NOP (65SC02) */ + BBS(BIT_3); + break; + + case 0xc0: /* CPY #$nn */ + CPY(p1, CYCLES_0, SIZE_2); + break; + + case 0xc1: /* CMP ($nn,X) */ + CMP(LOAD_IND_X(p1), CYCLES_1, SIZE_2); + break; + + case 0xc4: /* CPY $nn */ + CPY(LOAD_ZERO(p1), CYCLES_1, SIZE_2); + break; + + case 0xc5: /* CMP $nn */ + CMP(LOAD_ZERO(p1), CYCLES_1, SIZE_2); + break; + + case 0xc6: /* DEC $nn */ + DEC(p1, CYCLES_3, SIZE_2, LOAD_ZERO, STORE_ZERO); + break; + + case 0xc7: /* SMB4 $nn (65C02) / single byte, single cycle NOP (65SC02) */ + SMB(BIT_4); + break; + + case 0xc8: /* INY */ + INY(); + break; + + case 0xc9: /* CMP #$nn */ + CMP(p1, CYCLES_0, SIZE_2); + break; + + case 0xca: /* DEX */ + DEX(); + break; + + case 0xcb: /* WAI (WDC65C02) / single byte, single cycle NOP (R65C02/65SC02) */ + WAI(); + break; + + case 0xcc: /* CPY $nnnn */ + CPY(LOAD(p2), CYCLES_1, SIZE_3); + break; + + case 0xcd: /* CMP $nnnn */ + CMP(LOAD(p2), CYCLES_1, SIZE_3); + break; + + case 0xce: /* DEC $nnnn */ + DEC(p2, CYCLES_1, SIZE_3, LOAD_ABS, STORE_ABS_RRW); + break; + + case 0xcf: /* BBS4 $nn,$nnnn (65C02) / single byte, single cycle NOP (65SC02) */ + BBS(BIT_4); + break; + + case 0xd0: /* BNE $nnnn */ + BRANCH(!LOCAL_ZERO(), p1); + break; + + case 0xd1: /* CMP ($nn),Y */ + CMP(LOAD_IND_Y(p1), CYCLES_1, SIZE_2); + break; + + case 0xd2: /* CMP ($nn) */ + CMP(LOAD_INDIRECT(p1), CYCLES_1, SIZE_2); + break; + + case 0xd5: /* CMP $nn,X */ + CMP(LOAD_ZERO_X(p1), CYCLES_2, SIZE_2); + break; + + case 0xd6: /* DEC $nn,X */ + DEC((p1 + reg_x) & 0xff, CYCLES_4, SIZE_2, LOAD_ZERO, STORE_ZERO); + break; + + case 0xd7: /* SMB5 $nn (65C02) / single byte, single cycle NOP (65SC02) */ + SMB(BIT_5); + break; + + case 0xd8: /* CLD */ + CLD(); + break; + + case 0xd9: /* CMP $nnnn,Y */ + CMP(LOAD_ABS_Y(p2), CYCLES_1, SIZE_3); + break; + + case 0xda: /* PHX */ + PHX(); + break; + + case 0xdb: /* STP (WDC65C02) / single byte, single cycle NOP (R65C02/65SC02) */ + STP(); + break; + + case 0xdd: /* CMP $nnnn,X */ + CMP(LOAD_ABS_X(p2), CYCLES_1, SIZE_3); + break; + + case 0xde: /* DEC $nnnn,X */ + DEC(p2, CYCLES_1, SIZE_3, LOAD_ABS_X_RMW, STORE_ABS_X_RRW); + break; + + case 0xdf: /* BBS5 $nn,$nnnn (65C02) / single byte, single cycle NOP (65SC02) */ + BBS(BIT_5); + break; + + case 0xe0: /* CPX #$nn */ + CPX(p1, CYCLES_0, SIZE_2); + break; + + case 0xe1: /* SBC ($nn,X) */ + SBC(LOAD_IND_X(p1), CYCLES_1, SIZE_2); + break; + + case 0xe4: /* CPX $nn */ + CPX(LOAD_ZERO(p1), CYCLES_1, SIZE_2); + break; + + case 0xe5: /* SBC $nn */ + SBC(LOAD_ZERO(p1), CYCLES_1, SIZE_2); + break; + + case 0xe6: /* INC $nn */ + INC(p1, CYCLES_3, SIZE_2, LOAD_ZERO, STORE_ZERO); + break; + + case 0xe7: /* SMB6 $nn (65C02) / single byte, single cycle NOP (65SC02) */ + SMB(BIT_6); + break; + + case 0xe8: /* INX */ + INX(); + break; + + case 0xe9: /* SBC #$nn */ + SBC(p1, CYCLES_0, SIZE_2); + break; + + case 0xea: /* NOP */ + NOP(); + break; + + case 0xec: /* CPX $nnnn */ + CPX(LOAD(p2), CYCLES_1, SIZE_3); + break; + + case 0xed: /* SBC $nnnn */ + SBC(LOAD(p2), CYCLES_1, SIZE_3); + break; + + case 0xee: /* INC $nnnn */ + INC(p2, CYCLES_1, SIZE_3, LOAD_ABS, STORE_ABS_RRW); + break; + + case 0xef: /* BBS6 $nn,$nnnn (65C02) / single byte, single cycle NOP (65SC02) */ + BBS(BIT_6); + break; + + case 0xf0: /* BEQ $nnnn */ + BRANCH(LOCAL_ZERO(), p1); + break; + + case 0xf1: /* SBC ($nn),Y */ + SBC(LOAD_IND_Y(p1), CYCLES_1, SIZE_2); + break; + + case 0xf2: /* SBC ($nn) */ + SBC(LOAD_INDIRECT(p1), CYCLES_1, SIZE_2); + break; + + case 0xf5: /* SBC $nn,X */ + SBC(LOAD_ZERO_X(p1), CYCLES_2, SIZE_2); + break; + + case 0xf6: /* INC $nn,X */ + INC((p1 + reg_x) & 0xff, CYCLES_4, SIZE_2, LOAD_ZERO, STORE_ZERO); + break; + + case 0xf7: /* SMB7 $nn (65C02) / single byte, single cycle NOP (65SC02) */ + SMB(BIT_7); + break; + + case 0xf8: /* SED */ + SED(); + break; + + case 0xf9: /* SBC $nnnn,Y */ + SBC(LOAD_ABS_Y(p2), CYCLES_1, SIZE_3); + break; + + case 0xfa: /* PLX */ + PLX(); + break; + + case 0xfd: /* SBC $nnnn,X */ + SBC(LOAD_ABS_X(p2), CYCLES_1, SIZE_3); + break; + + case 0xfe: /* INC $nnnn,X */ + INC(p2, CYCLES_1, SIZE_3, LOAD_ABS_X_RMW, STORE_ABS_X_RRW); + break; + + case 0xff: /* BBS7 $nn,$nnnn (65C02) / single byte, single cycle NOP (65SC02) */ + BBS(BIT_7); + break; + } + } +} diff --git a/cdtvcr.cpp b/cdtvcr.cpp index 693ffb65..a9bb9bfb 100644 --- a/cdtvcr.cpp +++ b/cdtvcr.cpp @@ -9,6 +9,8 @@ * */ +#define CDTVCR_4510_EMULATION 0 + #define CDTVCR_DEBUG 0 #include "sysconfig.h" @@ -1018,3 +1020,485 @@ void cdtvcr_free(void) thread_alive = 0; close_unit (); } + +#if CDTVCR_4510_EMULATION + +// VICE 65C02 emulator, waiting for future full CDTV-CR 4510 emulation. + +typedef unsigned char BYTE; +typedef unsigned short WORD; +typedef unsigned int CLOCK; + +static void cpu65c02_reset(void) +{ +} + +#define CLOCK_MAX (~((CLOCK)0)) +#define TRAP_OPCODE 0x02 +#define STATIC_ASSERT(_x) + +#define NUM_MEMSPACES e_invalid_space + +enum mon_int { + MI_NONE = 0, + MI_BREAK = 1 << 0, + MI_WATCH = 1 << 1, + MI_STEP = 1 << 2 +}; + +enum t_memspace { + e_default_space = 0, + e_comp_space, + e_disk8_space, + e_disk9_space, + e_disk10_space, + e_disk11_space, + e_invalid_space +}; +typedef enum t_memspace MEMSPACE; +static unsigned monitor_mask[NUM_MEMSPACES]; +static void monitor_check_icount_interrupt(void) +{ +} +static void monitor_check_icount(WORD a) +{ +} +static int monitor_force_import(int mem) +{ + return 0; +} +static int monitor_check_breakpoints(int mem, WORD addr) +{ + return 0; +} +static void monitor_check_watchpoints(unsigned int lastpc, unsigned int pc) +{ +} +static void monitor_startup(int mem) +{ +} + +#define INTERRUPT_DELAY 2 + +#define INTRRUPT_MAX_DMA_PER_OPCODE (7+10000) + +enum cpu_int { + IK_NONE = 0, + IK_NMI = 1 << 0, + IK_IRQ = 1 << 1, + IK_RESET = 1 << 2, + IK_TRAP = 1 << 3, + IK_MONITOR = 1 << 4, + IK_DMA = 1 << 5, + IK_IRQPEND = 1 << 6 +}; + +struct interrupt_cpu_status_s { + /* Number of interrupt lines. */ + unsigned int num_ints; + + /* Define, for each interrupt source, whether it has a pending interrupt + (IK_IRQ, IK_NMI, IK_RESET and IK_TRAP) or not (IK_NONE). */ + unsigned int *pending_int; + + /* Name for each interrupt source */ + char **int_name; + + /* Number of active IRQ lines. */ + int nirq; + + /* Tick when the IRQ was triggered. */ + CLOCK irq_clk; + + /* Number of active NMI lines. */ + int nnmi; + + /* Tick when the NMI was triggered. */ + CLOCK nmi_clk; + + /* If an opcode is intercepted by a DMA, save the number of cycles + left at the start of this particular DMA (needed by *_set_irq() to + calculate irq_clk). */ + unsigned int num_dma_per_opcode; + unsigned int num_cycles_left[INTRRUPT_MAX_DMA_PER_OPCODE]; + CLOCK dma_start_clk[INTRRUPT_MAX_DMA_PER_OPCODE]; + + /* counters for delay between interrupt request and handler */ + unsigned int irq_delay_cycles; + unsigned int nmi_delay_cycles; + + /* If 1, do a RESET. */ + int reset; + + /* If 1, call the trapping function. */ + int trap; + + /* Debugging function. */ + void(*trap_func)(WORD, void *data); + + /* Data to pass to the debugging function when called. */ + void *trap_data; + + /* Pointer to the last executed opcode information. */ + unsigned int *last_opcode_info_ptr; + + /* Number of cycles we have stolen to the processor last time. */ + int num_last_stolen_cycles; + + /* Clock tick at which these cycles have been stolen. */ + CLOCK last_stolen_cycles_clk; + + /* Clock tick where just ACK'd IRQs may still trigger an interrupt. + Set to CLOCK_MAX when irrelevant. */ + CLOCK irq_pending_clk; + + unsigned int global_pending_int; + + void(*nmi_trap_func)(void); + + void(*reset_trap_func)(void); +}; +typedef struct interrupt_cpu_status_s interrupt_cpu_status_t; + +/* Masks to extract information. */ +#define OPINFO_DELAYS_INTERRUPT_MSK (1 << 8) +#define OPINFO_DISABLES_IRQ_MSK (1 << 9) +#define OPINFO_ENABLES_IRQ_MSK (1 << 10) + +/* Return nonzero if `opinfo' causes a 1-cycle interrupt delay. */ +#define OPINFO_DELAYS_INTERRUPT(opinfo) \ + ((opinfo) & OPINFO_DELAYS_INTERRUPT_MSK) + +/* Return nonzero if `opinfo' has changed the I flag from 0 to 1, so that an +IRQ that happened 2 or more cycles before the end of the opcode should be +allowed. */ +#define OPINFO_DISABLES_IRQ(opinfo) \ + ((opinfo) & OPINFO_DISABLES_IRQ_MSK) + +/* Return nonzero if `opinfo' has changed the I flag from 1 to 0, so that an +IRQ that happened 2 or more cycles before the end of the opcode should not +be allowed. */ +#define OPINFO_ENABLES_IRQ(opinfo) \ + ((opinfo) & OPINFO_ENABLES_IRQ_MSK) + +/* Set the information for `opinfo'. `number' is the opcode number, +`delays_interrupt' must be non-zero if it causes a 1-cycle interrupt +delay, `disables_interrupts' must be non-zero if it disabled IRQs. */ +#define OPINFO_SET(opinfo, \ + number, delays_interrupt, disables_irq, enables_irq) \ + ((opinfo) = ((number) \ + | ((delays_interrupt) ? OPINFO_DELAYS_INTERRUPT_MSK : 0) \ + | ((disables_irq) ? OPINFO_DISABLES_IRQ_MSK : 0) \ + | ((enables_irq) ? OPINFO_ENABLES_IRQ_MSK : 0))) + +/* Set whether the opcode causes the 1-cycle interrupt delay according to +`delay'. */ +#define OPINFO_SET_DELAYS_INTERRUPT(opinfo, delay) \ + do { \ + if ((delay)) \ + (opinfo) |= OPINFO_DELAYS_INTERRUPT_MSK; \ + } while (0) + +/* Set whether the opcode disables previously enabled IRQs according to +`disable'. */ +#define OPINFO_SET_DISABLES_IRQ(opinfo, disable) \ + do { \ + if ((disable)) \ + (opinfo) |= OPINFO_DISABLES_IRQ_MSK; \ + } while (0) + +/* Set whether the opcode enables previously disabled IRQs according to +`enable'. */ +#define OPINFO_SET_ENABLES_IRQ(opinfo, enable) \ + do { \ + if ((enable)) \ + (opinfo) |= OPINFO_ENABLES_IRQ_MSK; \ + } while (0) + + + +typedef struct mos6510_regs_s { + unsigned int pc; /* `unsigned int' required by the drive code. */ + BYTE a; + BYTE x; + BYTE y; + BYTE sp; + BYTE p; + BYTE n; + BYTE z; +} mos6510_regs_t; + +typedef struct R65C02_regs_s +{ + unsigned int pc; + BYTE a; + BYTE x; + BYTE y; + BYTE sp; + BYTE p; + BYTE n; + BYTE z; +} R65C02_regs_t; + +#define DRIVE_RAM_SIZE 32768 + +typedef BYTE drive_read_func_t(struct drive_context_s *, WORD); +typedef void drive_store_func_t(struct drive_context_s *, WORD, + BYTE); + +typedef struct drivecpud_context_s { + /* Drive RAM */ + BYTE drive_ram[DRIVE_RAM_SIZE]; + + /* functions */ + drive_read_func_t *read_func[0x101]; + drive_store_func_t *store_func[0x101]; +// drive_read_func_t *read_func_watch[0x101]; +// drive_store_func_t *store_func_watch[0x101]; +// drive_read_func_t *read_func_nowatch[0x101]; +// drive_store_func_t *store_func_nowatch[0x101]; + + int sync_factor; +} drivecpud_context_t; + +typedef struct drive_context_s { + int mynumber; /* init to [0123] */ + CLOCK *clk_ptr; /* shortcut to drive_clk[mynumber] */ + + struct drivecpu_context_s *cpu; + struct drivecpud_context_s *cpud; + struct drivefunc_context_s *func; +} drive_context_t; + +static int drive_trap_handler(drive_context_t *d) +{ + return -1; +} + +typedef struct drivecpu_context_s +{ + int traceflg; + /* This is non-zero each time a Read-Modify-Write instructions that accesses + memory is executed. We can emulate the RMW bug of the 6502 this way. */ + int rmw_flag; /* init to 0 */ + + /* Interrupt/alarm status. */ + struct interrupt_cpu_status_s *int_status; + + struct alarm_context_s *alarm_context; + + /* Clk guard. */ + struct clk_guard_s *clk_guard; + + struct monitor_interface_s *monitor_interface; + + /* Value of clk for the last time mydrive_cpu_execute() was called. */ + CLOCK last_clk; + + /* Number of cycles in excess we executed last time mydrive_cpu_execute() + was called. */ + CLOCK last_exc_cycles; + + CLOCK stop_clk; + + CLOCK cycle_accum; + BYTE *d_bank_base; + unsigned int d_bank_start; + unsigned int d_bank_limit; + + /* Information about the last executed opcode. */ + unsigned int last_opcode_info; + + /* Address of the last executed opcode. This is used by watchpoints. */ + unsigned int last_opcode_addr; + + /* Public copy of the registers. */ + mos6510_regs_t cpu_regs; +// R65C02_regs_t cpu_R65C02_regs; + + BYTE *pageone; /* init to NULL */ + + int monspace; /* init to e_disk[89]_space */ + + char *snap_module_name; + + char *identification_string; +} drivecpu_context_t; + +#define LOAD(a) (drv->cpud->read_func[(a) >> 8](drv, (WORD)(a))) +#define LOAD_ZERO(a) (drv->cpud->read_func[0](drv, (WORD)(a))) +#define LOAD_ADDR(a) (LOAD(a) | (LOAD((a) + 1) << 8)) +#define LOAD_ZERO_ADDR(a) (LOAD_ZERO(a) | (LOAD_ZERO((a) + 1) << 8)) +#define STORE(a, b) (drv->cpud->store_func[(a) >> 8](drv, (WORD)(a), \ + (BYTE)(b))) +#define STORE_ZERO(a, b) (drv->cpud->store_func[0](drv, (WORD)(a), \ + (BYTE)(b))) + +#define JUMP(addr) \ + +#define P_SIGN 0x80 +#define P_OVERFLOW 0x40 +#define P_UNUSED 0x20 +#define P_BREAK 0x10 +#define P_DECIMAL 0x08 +#define P_INTERRUPT 0x04 +#define P_ZERO 0x02 +#define P_CARRY 0x01 + +#define CPU_WDC65C02 0 +#define CPU_R65C02 1 +#define CPU_65SC02 2 + +#define CLK (*(drv->clk_ptr)) +#define RMW_FLAG (cpu->rmw_flag) +#define PAGE_ONE (cpu->pageone) +#define LAST_OPCODE_INFO (cpu->last_opcode_info) +#define LAST_OPCODE_ADDR (cpu->last_opcode_addr) +#define TRACEFLG (debug.drivecpu_traceflg[drv->mynumber]) + +#define CPU_INT_STATUS (cpu->int_status) + +#define ALARM_CONTEXT (cpu->alarm_context) + +#define ROM_TRAP_ALLOWED() 1 + +#define ROM_TRAP_HANDLER() drive_trap_handler(drv) + +#define CALLER (cpu->monspace) + +#define DMA_FUNC drive_generic_dma() + +#define DMA_ON_RESET + +#define cpu_reset() (cpu_reset)(drv) +#define bank_limit (cpu->d_bank_limit) +#define bank_start (cpu->d_bank_start) +#define bank_base (cpu->d_bank_base) + +/* WDC_STP() and WDC_WAI() are not used on the R65C02. */ +#define WDC_STP() +#define WDC_WAI() + +#define GLOBAL_REGS cpu->cpu_R65C02_regs + +#define DRIVE_CPU + +static void drive_generic_dma(void) +{ +} +static void interrupt_trigger_dma(interrupt_cpu_status_t *cs, CLOCK cpu_clk) +{ + cs->global_pending_int = (enum cpu_int) + (cs->global_pending_int | IK_DMA); +} +static void interrupt_ack_dma(interrupt_cpu_status_t *cs) +{ + cs->global_pending_int = (enum cpu_int) + (cs->global_pending_int & ~IK_DMA); +} +static void interrupt_do_trap(interrupt_cpu_status_t *cs, WORD address) +{ + cs->global_pending_int &= ~IK_TRAP; + cs->trap_func(address, cs->trap_data); +} +static void interrupt_ack_reset(interrupt_cpu_status_t *cs) +{ + cs->global_pending_int &= ~IK_RESET; + + if (cs->reset_trap_func) + cs->reset_trap_func(); +} +static void interrupt_ack_nmi(interrupt_cpu_status_t *cs) +{ + cs->global_pending_int = + (cs->global_pending_int & ~IK_NMI); + + if (cs->nmi_trap_func) { + cs->nmi_trap_func(); + } +} +static void interrupt_ack_irq(interrupt_cpu_status_t *cs) +{ + cs->global_pending_int = + (cs->global_pending_int & ~IK_IRQPEND); + cs->irq_pending_clk = CLOCK_MAX; +} +static int interrupt_check_nmi_delay(interrupt_cpu_status_t *cs, + CLOCK cpu_clk) +{ + CLOCK nmi_clk = cs->nmi_clk + INTERRUPT_DELAY; + + /* Branch instructions delay IRQs and NMI by one cycle if branch + is taken with no page boundary crossing. */ + if (OPINFO_DELAYS_INTERRUPT(*cs->last_opcode_info_ptr)) + nmi_clk++; + + if (cpu_clk >= nmi_clk) + return 1; + + return 0; +} +static int interrupt_check_irq_delay(interrupt_cpu_status_t *cs, + CLOCK cpu_clk) +{ + CLOCK irq_clk = cs->irq_clk + INTERRUPT_DELAY; + + /* Branch instructions delay IRQs and NMI by one cycle if branch + is taken with no page boundary crossing. */ + if (OPINFO_DELAYS_INTERRUPT(*cs->last_opcode_info_ptr)) + irq_clk++; + + /* If an opcode changes the I flag from 1 to 0, the 6510 needs + one more opcode before it triggers the IRQ routine. */ + if (cpu_clk >= irq_clk) { + if (!OPINFO_ENABLES_IRQ(*cs->last_opcode_info_ptr)) { + return 1; + } else { + cs->global_pending_int |= IK_IRQPEND; + } + } + return 0; +} + +struct alarm_context_s { + CLOCK next_pending_alarm_clk; +}; +typedef struct alarm_context_s alarm_context_t; + +static void alarm_context_dispatch(alarm_context_t *context, CLOCK cpu_clk) +{ +} +static CLOCK alarm_context_next_pending_clk(alarm_context_t *context) +{ + return context->next_pending_alarm_clk; +} + +static void cpu_4510(void) +{ + int cpu_type = CPU_R65C02; + drivecpu_context_t *cpu = NULL; + drive_context_t *drv = NULL; + +#define reg_a (cpu->cpu_regs.a) +#define reg_x (cpu->cpu_regs.x) +#define reg_y (cpu->cpu_regs.y) +#define reg_pc (cpu->cpu_regs.pc) +#define reg_sp (cpu->cpu_regs.sp) +#define reg_p (cpu->cpu_regs.p) +#define flag_z (cpu->cpu_regs.z) +#define flag_n (cpu->cpu_regs.n) + +#include "65c02core.cpp" +} + +static void init_65c02(struct drive_context_s *drv) +{ + drivecpu_context_t *cpu = drv->cpu; + + cpu->rmw_flag = 0; + cpu->d_bank_limit = 0; + cpu->d_bank_start = 0; + cpu->pageone = NULL; +} + +#endif diff --git a/cia.cpp b/cia.cpp index 91eeb3f2..ef15c962 100644 --- a/cia.cpp +++ b/cia.cpp @@ -868,7 +868,7 @@ static void led_vsync (void) led_cycles_off = 0; if (led_old_brightness != gui_data.powerled_brightness) { gui_data.powerled = gui_data.powerled_brightness > 127; - gui_led (LED_POWER, gui_data.powerled); + gui_led (LED_POWER, gui_data.powerled, gui_data.powerled_brightness); led_filter_audio (); } led_old_brightness = gui_data.powerled_brightness; diff --git a/disk.cpp b/disk.cpp index 360f8111..e22d74e3 100644 --- a/disk.cpp +++ b/disk.cpp @@ -711,7 +711,7 @@ static void reset_drive (int num) drv->dskready_up_time = 0; drv->buffered_cyl = -1; drv->buffered_side = -1; - gui_led (num + LED_DF0, 0); + gui_led (num + LED_DF0, 0, -1); drive_settype_id (drv); _tcscpy (currprefs.floppyslots[num].df, changed_prefs.floppyslots[num].df); drv->newname[0] = 0; @@ -742,7 +742,7 @@ static void update_drive_gui (int num, bool force) else gui_data.drive_side = side; gui_data.drive_writing[num] = writ; - gui_led (num + LED_DF0, (gui_data.drive_motor[num] ? 1 : 0) | (gui_data.drive_writing[num] ? 2 : 0)); + gui_led (num + LED_DF0, (gui_data.drive_motor[num] ? 1 : 0) | (gui_data.drive_writing[num] ? 2 : 0), -1); } static void drive_fill_bigbuf (drive * drv,int); diff --git a/gfxboard.cpp b/gfxboard.cpp index a411d733..95a3133e 100644 --- a/gfxboard.cpp +++ b/gfxboard.cpp @@ -431,7 +431,7 @@ void gfxboard_vsync_handler (void) monswitch_delay = 0; } - if (monswitch_current && picasso_on) { + if (!monswitch_delay && monswitch_current && picasso_on && picasso_requested_on) { picasso_getwritewatch (vram_start_offset); if (fullrefresh) vga.vga.graphic_mode = -1; @@ -2308,6 +2308,7 @@ addrbank *gfxboard_init_memory (int devnum) if (ISP4()) { int roms[] = { 91, -1 }; + struct romlist *rl = getromlistbyids(roms, NULL); TCHAR path[MAX_DPATH]; fetch_rompath (path, sizeof path / sizeof (TCHAR)); @@ -2316,6 +2317,9 @@ addrbank *gfxboard_init_memory (int devnum) if (!p4rom && currprefs.picassoivromfile[0]) p4rom = read_rom_name(currprefs.picassoivromfile); + if (!p4rom && rl) + p4rom = read_rom(rl->rd); + if (!p4rom) { _tcscat (path, _T("picasso_iv_flash.rom")); p4rom = read_rom_name (path); diff --git a/include/gui.h b/include/gui.h index b509e80f..890e1584 100644 --- a/include/gui.h +++ b/include/gui.h @@ -9,7 +9,7 @@ extern int gui_init (void); extern int gui_update (void); extern void gui_exit (void); -extern void gui_led (int, int); +extern void gui_led (int, int, int); extern void gui_handle_events (void); extern void gui_filename (int, const TCHAR *); extern void gui_fps (int fps, int idle, int color); diff --git a/memory.cpp b/memory.cpp index 56c22a4c..7084ad9e 100644 --- a/memory.cpp +++ b/memory.cpp @@ -1979,14 +1979,14 @@ static void allocate_memory (void) } } if (mem25bit_bank.allocated != currprefs.mem25bit_size) { - mapped_free (&mem25bit_bank); + mapped_free(&mem25bit_bank); mem25bit_bank.allocated = currprefs.mem25bit_size; mem25bit_bank.mask = mem25bit_bank.allocated - 1; mem25bit_bank.start = 0x01000000; if (mem25bit_bank.allocated) { - if (!mapped_malloc (&mem25bit_bank)) { - write_log (_T("Out of memory for 25 bit memory.\n")); + if (!mapped_malloc(&mem25bit_bank)) { + write_log(_T("Out of memory for 25 bit memory.\n")); mem25bit_bank.allocated = 0; } } @@ -2069,7 +2069,7 @@ static void allocate_memory (void) if (bogomem_bank.allocated > 0) restore_ram (bogo_filepos, bogomem_bank.baseaddr); if (mem25bit_bank.allocated > 0) - restore_ram (mem25bit_filepos, mem25bit_bank.baseaddr); + restore_ram(mem25bit_filepos, mem25bit_bank.baseaddr); if (a3000lmem_bank.allocated > 0) restore_ram (a3000lmem_filepos, a3000lmem_bank.baseaddr); if (a3000hmem_bank.allocated > 0) @@ -2096,14 +2096,14 @@ static void fill_ce_banks (void) memset (ce_banktype, CE_MEMBANK_FAST32, sizeof ce_banktype); } // data cachable regions (2 = burst supported) - memset (ce_cachable, 0, sizeof ce_cachable); - memset (ce_cachable + (0x00200000 >> 16), 1 | 2, currprefs.fastmem_size >> 16); - memset (ce_cachable + (0x00c00000 >> 16), 1, currprefs.bogomem_size >> 16); - memset (ce_cachable + (z3fastmem_bank.start >> 16), 1 | 2, currprefs.z3fastmem_size >> 16); - memset (ce_cachable + (z3fastmem2_bank.start >> 16), 1 | 2, currprefs.z3fastmem2_size >> 16); - memset (ce_cachable + (a3000hmem_bank.start >> 16), 1 | 2, currprefs.mbresmem_high_size >> 16); - memset (ce_cachable + (a3000lmem_bank.start >> 16), 1 | 2, currprefs.mbresmem_low_size >> 16); - memset (ce_cachable + (mem25bit_bank.start >> 16), 1 | 2, currprefs.mem25bit_size >> 16); + memset(ce_cachable, 0, sizeof ce_cachable); + memset(ce_cachable + (0x00200000 >> 16), 1 | 2, currprefs.fastmem_size >> 16); + memset(ce_cachable + (0x00c00000 >> 16), 1, currprefs.bogomem_size >> 16); + memset(ce_cachable + (z3fastmem_bank.start >> 16), 1 | 2, currprefs.z3fastmem_size >> 16); + memset(ce_cachable + (z3fastmem2_bank.start >> 16), 1 | 2, currprefs.z3fastmem2_size >> 16); + memset(ce_cachable + (a3000hmem_bank.start >> 16), 1 | 2, currprefs.mbresmem_high_size >> 16); + memset(ce_cachable + (a3000lmem_bank.start >> 16), 1 | 2, currprefs.mbresmem_low_size >> 16); + memset(ce_cachable + (mem25bit_bank.start >> 16), 1 | 2, currprefs.mem25bit_size >> 16); if (&get_mem_bank (0) == &chipmem_bank) { for (i = 0; i < (0x200000 >> 16); i++) { @@ -2242,15 +2242,15 @@ void memory_clear (void) if (savestate_state == STATE_RESTORE) return; if (chipmem_bank.baseaddr) - memset (chipmem_bank.baseaddr, 0, chipmem_bank.allocated); + memset(chipmem_bank.baseaddr, 0, chipmem_bank.allocated); if (bogomem_bank.baseaddr) - memset (bogomem_bank.baseaddr, 0, bogomem_bank.allocated); + memset(bogomem_bank.baseaddr, 0, bogomem_bank.allocated); if (mem25bit_bank.baseaddr) - memset (mem25bit_bank.baseaddr, 0, mem25bit_bank.allocated); + memset(mem25bit_bank.baseaddr, 0, mem25bit_bank.allocated); if (a3000lmem_bank.baseaddr) - memset (a3000lmem_bank.baseaddr, 0, a3000lmem_bank.allocated); + memset(a3000lmem_bank.baseaddr, 0, a3000lmem_bank.allocated); if (a3000hmem_bank.baseaddr) - memset (a3000hmem_bank.baseaddr, 0, a3000hmem_bank.allocated); + memset(a3000hmem_bank.baseaddr, 0, a3000hmem_bank.allocated); expansion_clear (); cpuboard_clear(); } @@ -2449,11 +2449,11 @@ void memory_reset (void) #endif if (mem25bit_bank.baseaddr) - map_banks (&mem25bit_bank, mem25bit_bank.start >> 16, mem25bit_bank.allocated >> 16, 0); + map_banks(&mem25bit_bank, mem25bit_bank.start >> 16, mem25bit_bank.allocated >> 16, 0); if (a3000lmem_bank.baseaddr) - map_banks (&a3000lmem_bank, a3000lmem_bank.start >> 16, a3000lmem_bank.allocated >> 16, 0); + map_banks(&a3000lmem_bank, a3000lmem_bank.start >> 16, a3000lmem_bank.allocated >> 16, 0); if (a3000hmem_bank.baseaddr) - map_banks (&a3000hmem_bank, a3000hmem_bank.start >> 16, a3000hmem_bank.allocated >> 16, 0); + map_banks(&a3000hmem_bank, a3000hmem_bank.start >> 16, a3000hmem_bank.allocated >> 16, 0); #ifdef CDTV if (cardmem_bank.baseaddr) map_banks (&cardmem_bank, cardmem_bank.start >> 16, cardmem_bank.allocated >> 16, 0); @@ -2610,13 +2610,13 @@ void memory_init (void) void memory_cleanup (void) { - mapped_free (&mem25bit_bank); - mapped_free (&a3000lmem_bank); - mapped_free (&a3000hmem_bank); - mapped_free (&bogomem_bank); - mapped_free (&kickmem_bank); - xfree (a1000_bootrom); - mapped_free (&chipmem_bank); + mapped_free(&mem25bit_bank); + mapped_free(&a3000lmem_bank); + mapped_free(&a3000hmem_bank); + mapped_free(&bogomem_bank); + mapped_free(&kickmem_bank); + xfree(a1000_bootrom); + mapped_free(&chipmem_bank); #ifdef CDTV if (cardmem_bank.baseaddr) { cdtv_savecardmem (cardmem_bank.baseaddr, cardmem_bank.allocated); diff --git a/od-win32/rp.cpp b/od-win32/rp.cpp index 9fb16704..00e0ff34 100644 --- a/od-win32/rp.cpp +++ b/od-win32/rp.cpp @@ -1420,7 +1420,7 @@ void rp_fixup_options (struct uae_prefs *p) rp_turbo_cpu (currprefs.turbo_emulation); rp_turbo_floppy (currprefs.floppy_speed == 0); for (i = 0; i <= 4; i++) - rp_update_leds (i, 0, 0); + rp_update_leds (i, 0, -1, 0); set_config_changed (); } @@ -1543,7 +1543,7 @@ void rp_floppy_track (int floppy, int track) RPPostMessagex (RP_IPC_TO_HOST_DEVICESEEK, MAKEWORD (RP_DEVICECATEGORY_FLOPPY, floppy), track, &guestinfo); } -void rp_update_leds (int led, int onoff, int write) +void rp_update_leds (int led, int onoff, int brightness, int write) { static int oldled[5]; int ledstate; @@ -1554,10 +1554,12 @@ void rp_update_leds (int led, int onoff, int write) return; if (onoff < 0) return; + if (brightness < 0) + brightness = onoff ? 250 : 0; switch (led) { case LED_POWER: - ledstate = onoff >= 250 ? 100 : onoff * 5 / 26 + 49; + ledstate = brightness >= 250 ? 100 : brightness * 5 / 26 + 49; if (ledstate == oldled[led]) return; oldled[led] = ledstate; diff --git a/od-win32/rp.h b/od-win32/rp.h index 2a3c495a..385a3d43 100644 --- a/od-win32/rp.h +++ b/od-win32/rp.h @@ -33,7 +33,7 @@ extern void rp_cd_image_change (int num, const TCHAR *name); extern void rp_update_gameport (int port, int mask, int onoff); extern void rp_update_volume (struct uae_prefs*); -extern void rp_update_leds (int, int, int); +extern void rp_update_leds (int, int, int, int); extern void rp_floppy_track (int floppy, int track); extern void rp_hd_activity (int, int, int); extern void rp_cd_activity (int, int); diff --git a/od-win32/win32.cpp b/od-win32/win32.cpp index 7860fd4e..09141055 100644 --- a/od-win32/win32.cpp +++ b/od-win32/win32.cpp @@ -2305,7 +2305,7 @@ bool handle_events (void) was_paused = pause_emulation; manual_painting_needed++; gui_fps (0, 0, 0); - gui_led (LED_SND, 0); + gui_led (LED_SND, 0, -1); } MsgWaitForMultipleObjects (0, NULL, FALSE, 100, QS_ALLINPUT); while (PeekMessage (&msg, 0, 0, 0, PM_REMOVE)) { diff --git a/od-win32/win32.h b/od-win32/win32.h index bb9a00da..bffb2ccb 100644 --- a/od-win32/win32.h +++ b/od-win32/win32.h @@ -20,12 +20,12 @@ #define LANG_DLL_FULL_VERSION_MATCH 1 #if WINUAEPUBLICBETA -#define WINUAEBETA _T("6") +#define WINUAEBETA _T("7") #else #define WINUAEBETA _T("") #endif -#define WINUAEDATE MAKEBD(2015, 8, 1) +#define WINUAEDATE MAKEBD(2015, 8, 12) //#define WINUAEEXTRA _T("AmiKit Preview") //#define WINUAEEXTRA _T("Amiga Forever Edition") diff --git a/od-win32/win32gfx.cpp b/od-win32/win32gfx.cpp index d2578846..d888ec8e 100644 --- a/od-win32/win32gfx.cpp +++ b/od-win32/win32gfx.cpp @@ -1744,13 +1744,13 @@ static int open_windows (bool mousecapture) if (upd > 1) { for (i = 0; i < NUM_LEDS; i++) gui_flicker_led (i, -1, -1); - gui_led (LED_POWER, gui_data.powerled); + gui_led (LED_POWER, gui_data.powerled, gui_data.powerled_brightness); gui_fps (0, 0, 0); if (gui_data.md >= 0) - gui_led (LED_MD, 0); + gui_led (LED_MD, 0, -1); for (i = 0; i < 4; i++) { if (currprefs.floppyslots[i].dfxtype >= 0) - gui_led (LED_DF0 + i, 0); + gui_led (LED_DF0 + i, 0, -1); } } if (upd > 0) { diff --git a/od-win32/win32gui.cpp b/od-win32/win32gui.cpp index 59207ab9..10c4ded1 100644 --- a/od-win32/win32gui.cpp +++ b/od-win32/win32gui.cpp @@ -1707,6 +1707,7 @@ static void show_rom_list (void) 110, -1, -1, // GVP G-Force 030 114, -1, -1, // A3001 126, -1, -1, // Golem 030 + 144, -1, -1, // E-Matrix 530 89, -1, -1, // 1230-IV 89, -1, 94, -1, -1, // 1230-IV SCSI 90, -1, -1, // 1260 @@ -1759,6 +1760,7 @@ static void show_rom_list (void) _T("GVP G-FORCE 030\0") _T("GVP A3001 Series I\0") _T("Kupke Golem 030\0") + _T("M-Tec E-Matrix 530\0") _T("Blizzard 1230-IV\0Blizzard 1260\0") _T("Blizzard 1230-IV/SCSI\0Blizzard 1260/SCSI\0") _T("Blizzard 2060\0Warp Engine\0TekMagic 2040/2060\0") @@ -7738,8 +7740,9 @@ static void setcpuboardmemsize(HWND hDlg) if (cpuboard_memorytype(&workprefs) == BOARD_MEMORY_25BITMEM) { workprefs.mem25bit_size = workprefs.cpuboardmem1_size; } - if (workprefs.cpuboard_type == 0) + if (workprefs.cpuboard_type == 0) { workprefs.mem25bit_size = 0; + } if (cpuboard_memorytype(&workprefs) == BOARD_MEMORY_HIGHMEM) workprefs.mbresmem_high_size = workprefs.cpuboardmem1_size; @@ -8827,6 +8830,8 @@ static INT_PTR CALLBACK Expansion2DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LP case IDC_A2065: if (ischecked(hDlg, IDC_A2065)) { _tcscpy(workprefs.a2065name, _T("none")); + workprefs.ne2000pciname[0] = 0; + setchecked(hDlg, IDC_NE2000, false); expansion_net(hDlg); enable_for_expansion2dlg(hDlg); } else { @@ -8839,6 +8844,8 @@ static INT_PTR CALLBACK Expansion2DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LP case IDC_NE2000: if (ischecked(hDlg, IDC_NE2000)) { _tcscpy(workprefs.ne2000pciname, _T("none")); + workprefs.a2065name[0] = 0; + setchecked(hDlg, IDC_A2065, false); expansion_net(hDlg); enable_for_expansion2dlg(hDlg); } else { @@ -8859,15 +8866,33 @@ static INT_PTR CALLBACK Expansion2DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LP if (!workprefs.sound_toccata) workprefs.sound_toccata_mixer = false; enable_for_expansion2dlg(hDlg); + if (workprefs.sound_toccata && (workprefs.sound_fm801 || workprefs.sound_es1370)) { + workprefs.sound_fm801 = 0; + workprefs.sound_es1370 = 0; + } break; case IDC_CS_TOCCATAMIXER: workprefs.sound_toccata_mixer = ischecked(hDlg, IDC_CS_TOCCATAMIXER) ? 1 : 0; break; case IDC_CS_ES1370: workprefs.sound_es1370 = ischecked(hDlg, IDC_CS_ES1370) ? 1 : 0; + if (workprefs.sound_es1370 && (workprefs.sound_fm801 || workprefs.sound_toccata)) { + workprefs.sound_fm801 = 0; + workprefs.sound_toccata = 0; + workprefs.sound_toccata_mixer = false; + values_to_expansion2dlg(hDlg); + enable_for_expansion2dlg(hDlg); + } break; case IDC_CS_FM801: workprefs.sound_fm801 = ischecked(hDlg, IDC_CS_FM801) ? 1 : 0; + if (workprefs.sound_fm801 && (workprefs.sound_es1370 || workprefs.sound_toccata)) { + workprefs.sound_es1370 = 0; + workprefs.sound_toccata = 0; + workprefs.sound_toccata_mixer = false; + values_to_expansion2dlg(hDlg); + enable_for_expansion2dlg(hDlg); + } break; case IDC_SCSIROMSELECTED: values_from_expansion2dlg(hDlg); @@ -8968,10 +8993,16 @@ static INT_PTR CALLBACK Expansion2DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LP v--; s = ndd[v]->name; } - if (ischecked(hDlg, IDC_A2065)) + if (ischecked(hDlg, IDC_A2065)) { _tcscpy(workprefs.a2065name, s); - if (ischecked(hDlg, IDC_NE2000)) + workprefs.ne2000pciname[0] = 0; + setchecked(hDlg, IDC_NE2000, false); + } + if (ischecked(hDlg, IDC_NE2000)) { _tcscpy(workprefs.ne2000pciname, s); + workprefs.a2065name[0] = 0; + setchecked(hDlg, IDC_A2065, false); + } } break; } @@ -18903,16 +18934,16 @@ static void gui_flicker_led2 (int led, int unitnum, int status) old = *p; if (status < 0) { if (old < 0) { - gui_led (led, -1); + gui_led (led, -1, -1); } else { - gui_led (led, 0); + gui_led (led, 0, -1); } return; } if (status == 0 && old < 0) { *p = 0; resetcounter[led] = 0; - gui_led (led, 0); + gui_led (led, 0, -1); return; } if (status == 0) { @@ -18931,7 +18962,7 @@ static void gui_flicker_led2 (int led, int unitnum, int status) *p = status; resetcounter[led] = 6; if (old != *p) - gui_led (led, *p); + gui_led (led, *p, -1); } void gui_flicker_led (int led, int unitnum, int status) @@ -18951,13 +18982,13 @@ void gui_fps (int fps, int idle, int color) gui_data.fps = fps; gui_data.idle = idle; gui_data.fps_color = color; - gui_led (LED_FPS, 0); - gui_led (LED_CPU, 0); - gui_led (LED_SND, (gui_data.sndbuf_status > 1 || gui_data.sndbuf_status < 0) ? 0 : 1); + gui_led (LED_FPS, 0, -1); + gui_led (LED_CPU, 0, -1); + gui_led (LED_SND, (gui_data.sndbuf_status > 1 || gui_data.sndbuf_status < 0) ? 0 : 1, -1); } #define LED_STRING_WIDTH 40 -void gui_led (int led, int on) +void gui_led (int led, int on, int brightness) { WORD type; static TCHAR drive_text[NUM_LEDS * LED_STRING_WIDTH]; @@ -18976,7 +19007,7 @@ void gui_led (int led, int on) rp_floppy_track (led - LED_DF0, gui_data.drive_track[led - LED_DF0]); writing = gui_data.drive_writing[led - LED_DF0]; } - rp_update_leds (led, on, writing); + rp_update_leds (led, on, brightness, writing); #endif if (!hStatusWnd) return; diff --git a/od-win32/winuaechangelog.txt b/od-win32/winuaechangelog.txt index 9be49bd6..35b1e6f0 100644 --- a/od-win32/winuaechangelog.txt +++ b/od-win32/winuaechangelog.txt @@ -1,4 +1,36 @@ +Beta 7: + +- 68030 prefetch/ce mode now also uses improved prefetch pipeline emulation. +- b4 prefetch RTS (and others) special case does not exist, my original test must have been broken. +- GUI won't anymore allow multiple sound or network cards enabled at the same. (It has never been + supported configuration) +- Cirrus Logic out of bounds VRAM access check improved. +- Picasso IV ROM loader update didn't support all old ROM paths (b6) +- SCSI Unit Attention (bus reset/media change) status handling should be now exactly as described in + SCSI spec. (Roctec Rochard v2 boot ROM*) +- A1060 Diagnostics and 8087 jumper was inverted. +- Continuing WD SCSI transfer with another Select and Transfer when previous SaT had already transferred + all buffered data: new SaT restarted from beginning. (A590/A2091 omniscsi.device + cdfs) +- Config file loaded with non-existing *_rom_file_id: rom key file ("rom" with ID=0) was selected. +- M-Tec E-Matrix 530 accelerator board added (Thanks to Jozsef Vamosi) + +Rochard RH800C with v2 boot ROM: +- Supports both SCSI and IDE. v1 is IDE only. +- Has crazy "Is drive ready?" polling routine, driver executes 300 (!) TEST UNIT READY commands in + CPU loop per LUN (timer.device exists for a reason..), with single SCSI drive, driver executes total + 6*300=1800 TUR commands during drive detection! (I recommend not to enable scsi logging..) +- ROM not yet added. + +M-Tec E-Matrix 530: +- ROM image is software dumped (chip is not socketed), ROM layout (single chip contains two logical + autoconfig boot ROMs) may not match real ROM dump. +- 53C94 based SCSI. Fake DMA, 2*long word wide data port. Whole transfer loop runs in level 2 + interrupt routine.. +- Boot ROM requires KS2.0+ only because it calls CacheControl() without checking ROM version. + +Beta 6: + - Bridgeboard floppy drive motor and click sound supported. - x86 CPU status string was visible even when bridgeboard was not active. - Added software readable A4091 DIP switches and Warp Engine SCSI jumpers to GUI. Note that default diff --git a/qemuvga/esp.cpp b/qemuvga/esp.cpp index ce65243f..8f32ffb2 100644 --- a/qemuvga/esp.cpp +++ b/qemuvga/esp.cpp @@ -513,6 +513,10 @@ void esp_reg_write(void *opaque, uint32_t saddr, uint64_t val) break; case CMD_RESET: esp_soft_reset(s); + // E-Matrix 530 detects existence of SCSI chip by + // writing CMD_RESET and then immediately checking + // if it reads back. + s->rregs[saddr] = CMD_RESET; break; case CMD_BUSRESET: s->rregs[ESP_RINTR] = INTR_RST; diff --git a/specialmonitors.cpp b/specialmonitors.cpp index ae460b0d..9abc785a 100755 --- a/specialmonitors.cpp +++ b/specialmonitors.cpp @@ -102,6 +102,20 @@ STATIC_INLINE uae_u8 FIRGB(struct vidbuffer *src, uae_u8 *dataline) return v; } +STATIC_INLINE uae_u8 DCTV_FIRBG(struct vidbuffer *src, uae_u8 *dataline) +{ + uae_u8 v = 0; + if (FI(src, dataline)) + v |= 0x40; + if (FR(src, dataline)) + v |= 0x10; + if (FB(src, dataline)) + v |= 0x04; + if (FG(src, dataline)) + v |= 0x01; + return v; +} + STATIC_INLINE void PRGB(struct vidbuffer *dst, uae_u8 *dataline, uae_u8 r, uae_u8 g, uae_u8 b) { if (dst->pixbytes == 4) { @@ -171,6 +185,78 @@ static void clearmonitor(struct vidbuffer *dst) } } +static void blank_generic(struct vidbuffer *src, struct vidbuffer *dst, int oddlines) +{ + int y, vdbl; + int ystart, yend, isntsc; + + isntsc = (beamcon0 & 0x20) ? 0 : 1; + if (!(currprefs.chipset_mask & CSMASK_ECS_AGNUS)) + isntsc = currprefs.ntscmode ? 1 : 0; + + vdbl = gfxvidinfo.ychange; + + ystart = isntsc ? VBLANK_ENDLINE_NTSC : VBLANK_ENDLINE_PAL; + yend = isntsc ? MAXVPOS_NTSC : MAXVPOS_PAL; + + for (y = ystart; y < yend; y++) { + int yoff = (((y * 2 + oddlines) - src->yoffset) / vdbl); + if (yoff < 0) + continue; + if (yoff >= src->inheight) + continue; + uae_u8 *dstline = dst->bufmem + (((y * 2 + oddlines) - dst->yoffset) / vdbl) * dst->rowbytes; + memset(dstline, 0, dst->inwidth * dst->pixbytes); + } +} + +static uae_s8 dctv_chroma[1600]; +static uae_u8 dctv_luma[1600]; + +static const uae_u16 dctv_tables[] = { + 0xF9AF, 0xF9C9, 0xF9E2, 0xF9FC, 0xFA15, 0xFA2F, 0xFA48, 0xFA62, + 0xFA7B, 0xFA95, 0xFAAE, 0xFAC8, 0xFAE1, 0xFAFB, 0xFB14, 0xFB2E, + 0xFB47, 0xFB61, 0xFB7A, 0xFB94, 0xFBAD, 0xFBC7, 0xFBE0, 0xFBFA, + 0xFC13, 0xFC2D, 0xFC46, 0xFC60, 0xFC79, 0xFC93, 0xFCAC, 0xFCC6, + 0xFCDF, 0xFCF9, 0xFD12, 0xFD2C, 0xFD45, 0xFD5F, 0xFD78, 0xFD92, + 0xFDAB, 0xFDC5, 0xFDDE, 0xFDF8, 0xFE11, 0xFE2B, 0xFE44, 0xFE5E, + 0xFE77, 0xFE91, 0xFEAA, 0xFEC4, 0xFEDD, 0xFEF7, 0xFF10, 0xFF2A, + 0xFF43, 0xFF5D, 0xFF76, 0xFF90, 0xFFA9, 0xFFC3, 0xFFDC, 0xFFF6, + 0x000F, 0x0029, 0x0042, 0x005C, 0x0075, 0x008F, 0x00A8, 0x00C2, + 0x00DB, 0x00F5, 0x010E, 0x0128, 0x0141, 0x015B, 0x0174, 0x018E, + 0x01A7, 0x01C1, 0x01DA, 0x01F4, 0x020D, 0x0227, 0x0240, 0x025A, + 0x0273, 0x028D, 0x02A6, 0x02C0, 0x02D9, 0x02F3, 0x030C, 0x0326, + 0x033F, 0x0359, 0x0372, 0x038C, 0x03A5, 0x03BF, 0x03D8, 0x03F2, + 0x040B, 0x0425, 0x043E, 0x0458, 0x0471, 0x048B, 0x04A4, 0x04BE, + 0x04D7, 0x04F1, 0x050A, 0x0524, 0x053D, 0x0557, 0x0570, 0x058A, + 0x05A3, 0x05BD, 0x05D6, 0x05F0, 0x0609, 0x0623, 0x063C, 0x0656, + 0x066F, 0x0689, 0x06A2, 0x06BC, 0x06D5, 0x06EF, 0x0708, 0x0722, + 0x073B, 0x0755, 0x076E, 0x0788, 0x07A1, 0x07BB, 0x07D4, 0x07EE, + 0x0807, 0x0821, 0x083A, 0x0854, 0x086D, 0x0887, 0x08A0, 0x08BA, + 0x08D3, 0x08ED, 0x0906, 0x0920, 0x0939, 0x0953, 0x096C, 0x0986, + 0x099F, 0x09B9, 0x09D2, 0x09EC, 0x0A05, 0x0A1F, 0x0A38, 0x0A52, + 0x0A6B, 0x0A85, 0x0A9E, 0x0AB8, 0x0AD1, 0x0AEB, 0x0B04, 0x0B1E, + 0x0B37, 0x0B51, 0x0B6A, 0x0B84, 0x0B9D, 0x0BB7, 0x0BD0, 0x0BEA, + 0x0C03, 0x0C1D, 0x0C36, 0x0C50, 0x0C69, 0x0C83, 0x0C9C, 0x0CB6, + 0x0CCF, 0x0CE9, 0x0D02, 0x0D1C, 0x0D35, 0x0D4F, 0x0D68, 0x0D82, + 0x0D9B, 0x0DB5, 0x0DCE, 0x0DE8, 0x0E01, 0x0E1B, 0x0E34, 0x0E4E, + 0x0E67, 0x0E81, 0x0E9A, 0x0EB4, 0x0ECD, 0x0EE7, 0x0F00, 0x0F1A, + 0x0F33, 0x0F4D, 0x0F66, 0x0F80, 0x0F99, 0x0FB3, 0x0FCC, 0x0FE6, + 0x0FFF, 0x1019, 0x1032, 0x104C, 0x1065, 0x107F, 0x1098, 0x10B2, + 0x10CB, 0x10E5, 0x10FE, 0x1118, 0x1131, 0x114B, 0x1164, 0x117E, + 0x1197, 0x11B1, 0x11CA, 0x11E4, 0x11FD, 0x1217, 0x1230, 0x124A, + 0x1263, 0x127D, 0x1296, 0x12B0, 0x12C9, 0x12E3, 0x12FC, 0x1316 +}; + +STATIC_INLINE int minmax(int v, int min, int max) +{ + if (v < min) + v = min; + if (v > max) + v = max; + return v; +} + static bool dctv(struct vidbuffer *src, struct vidbuffer *dst, bool doublelines, int oddlines) { int y, x, vdbl, hdbl; @@ -191,8 +277,13 @@ static bool dctv(struct vidbuffer *src, struct vidbuffer *dst, bool doublelines, oddlines = 1; + memset(dctv_luma, 0x40, sizeof dctv_luma); + + int signature_detected = -1; + int signature_x = -1; + int linenr = 0; uae_u8 r, g, b; - for (y = ystart; y < yend; y += 2) { + for (y = ystart; y < yend; y++) { int yoff = (((y * 2 + oddlines) - src->yoffset) / vdbl); if (yoff < 0) continue; @@ -201,6 +292,7 @@ static bool dctv(struct vidbuffer *src, struct vidbuffer *dst, bool doublelines, uae_u8 *line = src->bufmem + yoff * src->rowbytes; uae_u8 *dstline = dst->bufmem + (((y * 2 + oddlines) - dst->yoffset) / vdbl) * dst->rowbytes; +#if 0 if (y < 60) { write_log(_T("%d:\n"), y); for (x = 22; x < 300; x += 1) { @@ -214,53 +306,99 @@ static bool dctv(struct vidbuffer *src, struct vidbuffer *dst, bool doublelines, } write_log(_T("\n")); } +#endif - for (x = 1; x < src->inwidth; x += 4) { + int signature_cnt = -1; + bool signature_line = false; + int firstnz = -1; + bool sign = false; + int oddeven = 0; + uae_u8 prev = 0; + uae_u8 vals[3] = { 0x40, 0x40, 0x40 }; + int chrsum = 0; + uae_s8 *chrbuf = dctv_chroma + 10; + uae_u8 *lumabuf = dctv_luma + 10; + int zigzagoffset = 0; + int prevtval = 0; + for (x = 0; x < src->inwidth; x++) { uae_u8 *s = line + ((x << 1) / hdbl) * src->pixbytes; - uae_u8 *d = dstline + ((x << 1) / hdbl) * dst->pixbytes; + uae_u8 *d = dstline + ((x << 1) / hdbl) * dst->pixbytes + zigzagoffset; uae_u8 *s2 = s + src->rowbytes; uae_u8 *d2 = d + dst->rowbytes; - uae_u8 newval = FIRGB(src, s); - - r = newval << 4; - g = newval << 4; - b = newval << 4; + uae_u8 newval = DCTV_FIRBG(src, s); + uae_u8 val = prev | newval; - for (int xx = 0; xx < 4; xx++) { - PRGB(dst, d + dst->pixbytes * xx, r, g, b); - PRGB(dst, d + dst->rowbytes + dst->pixbytes * xx, r, g, b); + if (firstnz < 0 && newval) { + firstnz = 0; + if (newval == 0x14) { + zigzagoffset = -1 * dst->pixbytes; + oddeven = -2; + } else { + zigzagoffset = 0; + oddeven = -2; + } } + if (oddeven > 0) { + if (!val) + val = 64; + int tval = minmax(val, 64, 224); + if (tval != val) + tval = prevtval; + prevtval = tval; + + uae_s16 luma = (uae_s16)dctv_tables[tval]; + tval = minmax(luma / 16, 0, 255); + uae_u8 v1 = (uae_u8)tval; + + r = b = g = v1; + + if (val < 64) { + r = 0x80 + val * 2; + b = g = 0; + } else if (val > 224) { + r = b = 0; + g = 0x80 + (val - 224) * 2; + } + + + sign = !sign; + + PRGB(dst, d - dst->pixbytes, r, g, b); + PRGB(dst, d, r, g, b); + if (doublelines) { + PRGB(dst, d2 - dst->pixbytes, r, g, b); + PRGB(dst, d2, r, g, b); + } + } + if (oddeven >= 0) + oddeven = oddeven ? 0 : 1; + else + oddeven++; + prev = newval << 1; } } dst->nativepositioning = true; return true; } -static void blank_generic(struct vidbuffer *src, struct vidbuffer *dst, int oddlines) +static bool do_dctv(struct vidbuffer *src, struct vidbuffer *dst) { - int y, vdbl; - int ystart, yend, isntsc; - - isntsc = (beamcon0 & 0x20) ? 0 : 1; - if (!(currprefs.chipset_mask & CSMASK_ECS_AGNUS)) - isntsc = currprefs.ntscmode ? 1 : 0; - - vdbl = gfxvidinfo.ychange; - - ystart = isntsc ? VBLANK_ENDLINE_NTSC : VBLANK_ENDLINE_PAL; - yend = isntsc ? MAXVPOS_NTSC : MAXVPOS_PAL; - - for (y = ystart; y < yend; y++) { - int yoff = (((y * 2 + oddlines) - src->yoffset) / vdbl); - if (yoff < 0) - continue; - if (yoff >= src->inheight) - continue; - uae_u8 *dstline = dst->bufmem + (((y * 2 + oddlines) - dst->yoffset) / vdbl) * dst->rowbytes; - memset(dstline, 0, dst->inwidth * dst->pixbytes); + bool v; + if (interlace_seen) { + if (currprefs.gfx_iscanlines) { + v = dctv(src, dst, false, lof_store ? 0 : 1); + if (v && currprefs.gfx_iscanlines > 1) + blank_generic(src, dst, lof_store ? 1 : 0); + } else { + v = dctv(src, dst, false, 0); + v |= dctv(src, dst, false, 1); + } + } else { + v = dctv(src, dst, true, 0); } + return v; } static uae_u8 *sm_frame_buffer; @@ -1782,7 +1920,7 @@ static bool emulate_specialmonitors2(struct vidbuffer *src, struct vidbuffer *ds } else if (currprefs.monitoremu == MONITOREMU_GRAFFITI) { return graffiti(src, dst); } else if (currprefs.monitoremu == MONITOREMU_DCTV) { - return dctv(src, dst, false, 0); + return do_dctv(src, dst); } else if (currprefs.monitoremu == MONITOREMU_HAM_E || currprefs.monitoremu == MONITOREMU_HAM_E_PLUS) { return do_hame(src, dst); } else if (currprefs.monitoremu == MONITOREMU_VIDEODAC18) { diff --git a/x86.cpp b/x86.cpp index 01fa503b..27734839 100644 --- a/x86.cpp +++ b/x86.cpp @@ -2970,7 +2970,7 @@ addrbank *x86_bridge_init(struct romconfig *rc, int type) load_vga_bios(); } - xb->pc_jumpers = (xb->settings & 0xff) ^ ((0x80 | 0x40) | (0x20 | 0x10)); + xb->pc_jumpers = (xb->settings & 0xff) ^ ((0x80 | 0x40) | (0x20 | 0x10 | 0x01 | 0x02)); int ramsize = (xb->settings >> 2) & 3; switch(ramsize) { -- 2.47.3