static const TCHAR *agnusmodel[] = { _T("default"), _T("velvet"), _T("a1000"), _T("ocs"), _T("ecs"), _T("aga"), 0 };
static const TCHAR *agnussize[] = { _T("default"), _T("512k"), _T("1m"), _T("2m"), 0 };
static const TCHAR *denisemodel[] = { _T("default"), _T("velvet"), _T("a1000_noehb"), _T("a1000"), _T("ocs"), _T("ecs"), _T("aga"), 0 };
+static const TCHAR *kbtype[] = {
+ _T("disconnected"),
+ _T("UAE"),
+ _T("a500_6570-036"),
+ _T("a600_6570-036"),
+ _T("a1000_6500-1"),
+ _T("a1000_6570-036"),
+ _T("a1200_6805"),
+ _T("a2000_8039"),
+ _T("ax000_6570-036"),
+ NULL
+};
struct hdcontrollerconfig
{
cfgfile_write_bool(f, _T("fm801_pci"), p->obs_sound_fm801);
#endif
- cfgfile_dwrite_bool(f, _T("keyboard_connected"), p->keyboard_connected);
+ cfgfile_dwrite_bool(f, _T("keyboard_connected"), p->keyboard_mode >= 0);
+ cfgfile_dwrite_bool(f, _T("keyboard_nkro"), p->keyboard_nkro);
+ cfgfile_dwrite_strarr(f, _T("keyboard_type"), kbtype, p->keyboard_mode + 1);
cfgfile_write_str (f, _T("kbd_lang"), (p->keyboard_lang == KBD_LANG_DE ? _T("de")
: p->keyboard_lang == KBD_LANG_DK ? _T("dk")
: p->keyboard_lang == KBD_LANG_ES ? _T("es")
}
return 1;
}
+ if (cfgfile_yesno(option, value, _T("keyboard_connected"), &dummybool)) {
+ p->keyboard_mode = dummybool ? 0 : -1;
+ return 1;
+ }
+ if (cfgfile_strval(option, value, _T("keyboard_type"), &p->keyboard_mode, kbtype, 0)) {
+ p->keyboard_mode--;
+ return 1;
+ }
if (cfgfile_yesno(option, value, _T("immediate_blits"), &p->immediate_blits)
|| cfgfile_yesno(option, value, _T("fpu_no_unimplemented"), &p->fpu_no_unimplemented)
|| cfgfile_yesno(option, value, _T("gfxcard_dacswitch"), &p->rtg_dacswitch)
|| cfgfile_yesno(option, value, _T("gfxcard_multithread"), &p->rtg_multithread)
|| cfgfile_yesno(option, value, _T("synchronize_clock"), &p->tod_hack)
- || cfgfile_yesno(option, value, _T("keyboard_connected"), &p->keyboard_connected)
|| cfgfile_coords(option, value, _T("lightpen_offset"), &p->lightpen_offset[0], &p->lightpen_offset[1])
|| cfgfile_yesno(option, value, _T("lightpen_crosshair"), &p->lightpen_crosshair)
|| cfgfile_yesno(option, value, _T("harddrive_write_protect"), &p->harddrive_read_only)
|| cfgfile_yesno(option, value, _T("uae_hide_autoconfig"), &p->uae_hide_autoconfig)
|| cfgfile_yesno(option, value, _T("board_custom_order"), &p->autoconfig_custom_sort)
+ || cfgfile_yesno(option, value, _T("keyboard_nkro"), &p->keyboard_nkro)
|| cfgfile_yesno(option, value, _T("uaeserial"), &p->uaeserial))
return 1;
inputdevice_joyport_config_store(p, _T("kbd1"), 1, -1, -1, 0, 0);
}
p->keyboard_lang = KBD_LANG_US;
- p->keyboard_connected = true;
+ p->keyboard_mode = 0;
+ p->keyboard_nkro = true;
p->produce_sound = 3;
p->sound_stereo = SND_STEREO;
p->immediate_blits = 0;
p->produce_sound = 2;
p->nr_floppies = 0;
- p->keyboard_connected = false;
+ p->keyboard_mode = -1;
p->floppyslots[0].dfxtype = DRV_NONE;
p->floppyslots[1].dfxtype = DRV_NONE;
p->floppyslots[2].dfxtype = DRV_PC_35_ONLY_80;
p->immediate_blits = 0;
p->produce_sound = 2;
p->nr_floppies = 0;
- p->keyboard_connected = false;
+ p->keyboard_mode = -1;
p->cpuboard_settings |= 0x10;
p->floppyslots[0].dfxtype = DRV_NONE;
p->floppyslots[1].dfxtype = DRV_NONE;
#include "scsi.h"
#include "rtc.h"
#include "devices.h"
+#include "keyboard_mcu.h"
#define CIAA_DEBUG_R 0
#define CIAA_DEBUG_W 0
int resetwarning_do(int canreset)
{
- if (!currprefs.keyboard_connected)
+ if (currprefs.keyboard_mode < 0)
return 0;
if (resetwarning_phase || regs.halted > 0) {
/* just force reset if second reset happens during resetwarning */
{
}
-static void keyreq (void)
+void cia_keyreq(uae_u8 code)
{
#if KB_DEBUG
write_log(_T("code=%02x (%02x)\n"), kbcode, (uae_u8)(~((kbcode >> 1) | (kbcode << 7))));
#endif
- cia[0].sdr = kbcode;
- kblostsynccnt = 8 * maxvpos * 8; // 8 frames * 8 bits.
+ cia[0].sdr = code;
+ if (currprefs.keyboard_mode == 0) {
+ kblostsynccnt = 8 * maxvpos * 8; // 8 frames * 8 bits.
+ }
CIA_sync_interrupt(0, ICR_SP);
}
{
if (connect) {
write_log(_T("Keyboard connected\n"));
+ if (currprefs.keyboard_mode > 0) {
+ keymcu_reset();
+ }
} else {
write_log(_T("Keyboard disconnected\n"));
}
resetwarning_phase = 0;
}
+static bool keymcu_execute(void)
+{
+ bool handshake = (cia[0].t[0].cr & 0x40) != 0 && (cia[0].sdr_buf & 0x80) == 0;
+
+#if 1
+ extern int blop;
+ if (blop & 1) {
+ handshake = true;
+ }
+#endif
+
+ bool cyclemode = false;
+ if (currprefs.keyboard_mode == KB_A500_6570 ||
+ currprefs.keyboard_mode == KB_A600_6570 ||
+ currprefs.keyboard_mode == KB_A1000_6570 ||
+ currprefs.keyboard_mode == KB_Ax000_6570)
+ {
+ cyclemode = keymcu_run(handshake);
+ }
+ if (currprefs.keyboard_mode == KB_A1200_6805) {
+ cyclemode = keymcu2_run(handshake);
+ }
+ if (currprefs.keyboard_mode == KB_A2000_8039) {
+ cyclemode = keymcu3_run(handshake);
+ }
+ return cyclemode;
+}
+
+static void keymcu_event(uae_u32 v)
+{
+ bool cyclemode = keymcu_execute();
+ if (cyclemode) {
+ // execute few times / scanline, does not need to be accurate
+ // because keyboard MCU has separate not that accurate clock crystal.
+ event2_newevent_x_remove(keymcu_event);
+ event2_newevent_xx(-1, 27 * CYCLE_UNIT, 0, keymcu_event);
+ }
+}
+
+static void keymcu_do(void)
+{
+ keymcu_event(0);
+}
+
static void check_keyboard(void)
{
- if (currprefs.keyboard_connected) {
+ if (currprefs.keyboard_mode >= 0) {
if ((keys_available() || kbstate < 3) && !kblostsynccnt ) {
switch (kbstate)
{
kbcode = ~get_next_key();
break;
}
- keyreq();
+ cia_keyreq(kbcode);
}
} else {
while (keys_available()) {
if (currprefs.tod_hack && cia[0].todon) {
do_tod_hack(dotod);
}
- } else if (currprefs.keyboard_connected) {
- // custom hsync
- if (resetwarning_phase) {
- resetwarning_check();
- while (keys_available()) {
- get_next_key();
- }
+ } else {
+ if (currprefs.keyboard_mode > 0) {
+ keymcu_do();
} else {
- if ((hsync_counter & 15) == 0) {
- check_keyboard();
+ if (currprefs.keyboard_mode == 0) {
+ // custom hsync
+ if (resetwarning_phase) {
+ resetwarning_check();
+ while (keys_available()) {
+ get_next_key();
+ }
+ } else {
+ if ((hsync_counter & 15) == 0) {
+ check_keyboard();
+ }
+ }
+ } else {
+ while (keys_available()) {
+ get_next_key();
+ }
}
}
- } else {
- while (keys_available()) {
- get_next_key();
- }
}
if (!ciahsync) {
// Increase CIA-A TOD if delayed from previous line
cia_delayed_tod(0);
}
-
}
static void calc_led(int old_led)
if (kblostsynccnt <= 0) {
kblostsynccnt = 0;
kbcode = 0;
- keyreq();
+ cia_keyreq(kbcode);
#if KB_DEBUG
write_log(_T("lostsync\n"));
#endif
case 13:
case 15:
CIA_update();
+ if (currprefs.keyboard_mode > 0 && reg == 12) {
+ keymcu_do();
+ }
WriteCIAReg(0, reg, val);
CIA_calctimers();
break;
case 14:
- CIA_update();
- // keyboard handshake handling
- if (currprefs.cpuboard_type != 0 && (val & 0x40) != (c->t[0].cr & 0x40)) {
- /* bleh, Phase5 CPU timed early boot key check fix.. */
- if (m68k_getpc() >= 0xf00000 && m68k_getpc() < 0xf80000)
- check_keyboard();
- }
- if ((val & CR_INMODE1) != 0 && (c->t[0].cr & CR_INMODE1) == 0) {
- // handshake start
- if (kblostsynccnt > 0 && currprefs.cs_kbhandshake) {
- kbhandshakestart = get_cycles();
- }
-#if KB_DEBUG
- write_log(_T("KB_ACK_START %02x->%02x %08x\n"), c->t[0].cr, val, M68K_GETPC);
-#endif
- } else if ((val & CR_INMODE1) == 0 && (c->t[0].cr & CR_INMODE1) != 0) {
- // handshake end
- /* todo: check if low to high or high to low only */
- if (kblostsynccnt > 0 && currprefs.cs_kbhandshake) {
- evt_t len = get_cycles() - kbhandshakestart;
- if (len < currprefs.cs_kbhandshake * CYCLE_UNIT) {
- write_log(_T("Keyboard handshake pulse length %d < %d (CCKs)\n"), len / CYCLE_UNIT, currprefs.cs_kbhandshake);
+ {
+ CIA_update();
+ bool handshake = (val & CR_INMODE1) != (c->t[0].cr & CR_INMODE1);
+ if (currprefs.keyboard_mode == 0) {
+ // keyboard handshake handling
+ if (currprefs.cpuboard_type != 0 && handshake) {
+ /* bleh, Phase5 CPU timed early boot key check fix.. */
+ if (m68k_getpc() >= 0xf00000 && m68k_getpc() < 0xf80000)
+ check_keyboard();
}
- }
- kblostsynccnt = 0;
+ if ((val & CR_INMODE1) != 0 && (c->t[0].cr & CR_INMODE1) == 0) {
+ // handshake start
+ if (kblostsynccnt > 0 && currprefs.cs_kbhandshake) {
+ kbhandshakestart = get_cycles();
+ }
+#if KB_DEBUG
+ write_log(_T("KB_ACK_START %02x->%02x %08x\n"), c->t[0].cr, val, M68K_GETPC);
+#endif
+ } else if ((val & CR_INMODE1) == 0 && (c->t[0].cr & CR_INMODE1) != 0) {
+ // handshake end
+ /* todo: check if low to high or high to low only */
+ if (kblostsynccnt > 0 && currprefs.cs_kbhandshake) {
+ evt_t len = get_cycles() - kbhandshakestart;
+ if (len < currprefs.cs_kbhandshake * CYCLE_UNIT) {
+ write_log(_T("Keyboard handshake pulse length %d < %d (CCKs)\n"), len / CYCLE_UNIT, currprefs.cs_kbhandshake);
+ }
+ }
+ kblostsynccnt = 0;
#if KB_DEBUG
- write_log(_T("KB_ACK_END %02x->%02x %08x\n"), c->t[0].cr, val, M68K_GETPC);
+ write_log(_T("KB_ACK_END %02x->%02x %08x\n"), c->t[0].cr, val, M68K_GETPC);
#endif
+ }
+ }
+ WriteCIAReg(0, reg, val);
+ CIA_calctimers();
+ if (currprefs.keyboard_mode > 0 && handshake) {
+ keymcu_do();
+ }
}
- WriteCIAReg(0, reg, val);
- CIA_calctimers();
break;
}
}
#endif
#include "draco.h"
#include "dsp3210/dsp_glue.h"
+#include "keyboard_mcu.h"
#define MAX_DEVICE_ITEMS 64
#ifdef RETROPLATFORM
rp_reset();
#endif
+ keymcu_reset();
+ keymcu2_reset();
+ keymcu3_reset();
uae_int_requested = 0;
}
#ifdef WITH_DRACO
draco_free();
#endif
+ keymcu_free();
+ keymcu2_free();
+ keymcu3_free();
execute_device_items(device_leaves, device_leave_cnt);
}
#ifdef WITH_DRACO
draco_init();
#endif
+ keymcu_init();
+ keymcu2_init();
+ keymcu3_init();
}
void devices_restore_start(void)
NULL
}
};
+static const struct expansionboardsettings keyboard_settings[] = {
+ {
+ _T("Options\0") _T("-\0") _T("RAM fault\0") _T("ROM fault\0") _T("Watchdog fault\0"),
+ _T("kbmcuopt\0") _T("-\0") _T("ramf\0") _T("romf\0") _T("wdf\0"),
+ true
+ },
+ {
+ _T("Special feature enable"),
+ _T("sfe")
+ },
+ {
+ NULL
+ }
+};
+
static struct expansionboardsettings *netsettings[] = {
ethernet_settings,
// misc
+ {
+ _T("keyboard"), _T("Keyboard"), NULL,
+ NULL, NULL, NULL, NULL, ROMTYPE_KBMCU| ROMTYPE_NONE, 0, 0, BOARD_IGNORE, true,
+ NULL, 0,
+ false, EXPANSIONTYPE_INTERNAL,
+ 0, 0, 0, false, NULL,
+ false, 0, keyboard_settings
+ },
{
_T("pcmciasram"), _T("PCMCIA SRAM"), NULL,
NULL, gayle_init_board_common_pcmcia, NULL, NULL, ROMTYPE_PCMCIASRAM | ROMTYPE_NOT, 0, 0, BOARD_NONAUTOCONFIG_BEFORE, true,
extern void gui_filename (int, const TCHAR *);
extern void gui_fps (int fps, int idle, int color);
extern void gui_changesettings (void);
+extern void gui_fps (int fps, int lines, bool lace, int idle, int color);
extern void gui_lock (void);
extern void gui_unlock (void);
extern void gui_flicker_led (int, int, int);
#define LED_HD 5
#define LED_CD 6
#define LED_FPS 7
-#define LED_CPU 8
-#define LED_SND 9
-#define LED_MD 10
-#define LED_NET 11
-#define LED_MAX 12
+#define LED_LINES 8
+#define LED_CPU 9
+#define LED_SND 10
+#define LED_MD 11
+#define LED_NET 12
+#define LED_CAPS 13
+#define LED_MAX 14
struct gui_info_drive {
bool drive_motor; /* motor on off */
struct gui_info
{
- bool powerled; /* state of power led */
- uae_u8 powerled_brightness; /* 0 to 255 */
- uae_s8 drive_side; /* floppy side */
- uae_s8 hd; /* harddrive */
- uae_s8 cd; /* CD */
+ bool powerled; /* state of power led */
+ uae_u8 powerled_brightness; /* 0 to 255 */
+ bool capslock; /* caps lock state if KB MCU mode */
+ uae_s8 drive_side; /* floppy side */
+ uae_s8 hd; /* harddrive */
+ uae_s8 cd; /* CD */
uae_s8 md; /* CD32 or CDTV internal storage */
uae_s8 net; /* network */
- int cpu_halted;
- int fps, idle;
+ int cpu_halted;
+ int fps, lines, lace, idle;
int fps_color;
- int sndbuf, sndbuf_status;
+ int sndbuf, sndbuf_status;
bool sndbuf_avail;
struct gui_info_drive drives[4];
};
--- /dev/null
+
+void keymcu_reset(void);
+void keymcu_init(void);
+void keymcu_free(void);
+bool keymcu_run(bool);
+
+void keymcu2_reset(void);
+void keymcu2_init(void);
+void keymcu2_free(void);
+bool keymcu2_run(bool);
+
+void keymcu3_reset(void);
+void keymcu3_init(void);
+void keymcu3_free(void);
+bool keymcu3_run(bool);
+
+void cia_keyreq(uae_u8);
\ No newline at end of file
--- /dev/null
+//============================================================================
+// Name : mos6502
+// Author : Gianluca Ghettini
+// Version : 1.0
+// Copyright :
+// Description : A MOS 6502 CPU emulator written in C++
+//============================================================================
+
+#pragma once
+#include <stdint.h>
+
+class mos6502
+{
+private:
+ // register reset values
+ uint8_t reset_A;
+ uint8_t reset_X;
+ uint8_t reset_Y;
+ uint8_t reset_sp;
+ uint8_t reset_status;
+
+ // registers
+ uint8_t A; // accumulator
+ uint8_t X; // X-index
+ uint8_t Y; // Y-index
+
+ // stack pointer
+ uint8_t sp;
+
+ // program counter
+ uint16_t pc;
+
+ // status register
+ uint8_t status;
+
+ typedef void (mos6502::*CodeExec)(uint16_t);
+ typedef uint16_t (mos6502::*AddrExec)();
+
+ struct Instr
+ {
+ AddrExec addr;
+ CodeExec code;
+ uint8_t cycles;
+ };
+
+ static Instr InstrTable[256];
+
+ void Exec(Instr i);
+
+ bool illegalOpcode;
+
+ // addressing modes
+ uint16_t Addr_ACC(); // ACCUMULATOR
+ uint16_t Addr_IMM(); // IMMEDIATE
+ uint16_t Addr_ABS(); // ABSOLUTE
+ uint16_t Addr_ZER(); // ZERO PAGE
+ uint16_t Addr_ZEX(); // INDEXED-X ZERO PAGE
+ uint16_t Addr_ZEY(); // INDEXED-Y ZERO PAGE
+ uint16_t Addr_ABX(); // INDEXED-X ABSOLUTE
+ uint16_t Addr_ABY(); // INDEXED-Y ABSOLUTE
+ uint16_t Addr_IMP(); // IMPLIED
+ uint16_t Addr_REL(); // RELATIVE
+ uint16_t Addr_INX(); // INDEXED-X INDIRECT
+ uint16_t Addr_INY(); // INDEXED-Y INDIRECT
+ uint16_t Addr_ABI(); // ABSOLUTE INDIRECT
+
+ // opcodes (grouped as per datasheet)
+ void Op_ADC(uint16_t src);
+ void Op_AND(uint16_t src);
+ void Op_ASL(uint16_t src); void Op_ASL_ACC(uint16_t src);
+ void Op_BCC(uint16_t src);
+ void Op_BCS(uint16_t src);
+
+ void Op_BEQ(uint16_t src);
+ void Op_BIT(uint16_t src);
+ void Op_BMI(uint16_t src);
+ void Op_BNE(uint16_t src);
+ void Op_BPL(uint16_t src);
+
+ void Op_BRK(uint16_t src);
+ void Op_BVC(uint16_t src);
+ void Op_BVS(uint16_t src);
+ void Op_CLC(uint16_t src);
+ void Op_CLD(uint16_t src);
+
+ void Op_CLI(uint16_t src);
+ void Op_CLV(uint16_t src);
+ void Op_CMP(uint16_t src);
+ void Op_CPX(uint16_t src);
+ void Op_CPY(uint16_t src);
+
+ void Op_DEC(uint16_t src);
+ void Op_DEX(uint16_t src);
+ void Op_DEY(uint16_t src);
+ void Op_EOR(uint16_t src);
+ void Op_INC(uint16_t src);
+
+ void Op_INX(uint16_t src);
+ void Op_INY(uint16_t src);
+ void Op_JMP(uint16_t src);
+ void Op_JSR(uint16_t src);
+ void Op_LDA(uint16_t src);
+
+ void Op_LDX(uint16_t src);
+ void Op_LDY(uint16_t src);
+ void Op_LSR(uint16_t src); void Op_LSR_ACC(uint16_t src);
+ void Op_NOP(uint16_t src);
+ void Op_ORA(uint16_t src);
+
+ void Op_PHA(uint16_t src);
+ void Op_PHP(uint16_t src);
+ void Op_PLA(uint16_t src);
+ void Op_PLP(uint16_t src);
+ void Op_ROL(uint16_t src); void Op_ROL_ACC(uint16_t src);
+
+ void Op_ROR(uint16_t src); void Op_ROR_ACC(uint16_t src);
+ void Op_RTI(uint16_t src);
+ void Op_RTS(uint16_t src);
+ void Op_SBC(uint16_t src);
+ void Op_SEC(uint16_t src);
+ void Op_SED(uint16_t src);
+
+ void Op_SEI(uint16_t src);
+ void Op_STA(uint16_t src);
+ void Op_STX(uint16_t src);
+ void Op_STY(uint16_t src);
+ void Op_TAX(uint16_t src);
+
+ void Op_TAY(uint16_t src);
+ void Op_TSX(uint16_t src);
+ void Op_TXA(uint16_t src);
+ void Op_TXS(uint16_t src);
+ void Op_TYA(uint16_t src);
+
+ void Op_ILLEGAL(uint16_t src);
+
+ // IRQ, reset, NMI vectors
+ static const uint16_t irqVectorH = 0xFFFF;
+ static const uint16_t irqVectorL = 0xFFFE;
+ static const uint16_t rstVectorH = 0xFFFD;
+ static const uint16_t rstVectorL = 0xFFFC;
+ static const uint16_t nmiVectorH = 0xFFFB;
+ static const uint16_t nmiVectorL = 0xFFFA;
+
+ // read/write/clock-cycle callbacks
+ typedef void (*BusWrite)(uint16_t, uint8_t);
+ typedef uint8_t (*BusRead)(uint16_t);
+ typedef void (*ClockCycle)(mos6502*);
+ BusRead Read;
+ BusWrite Write;
+ ClockCycle Cycle;
+
+ // stack operations
+ inline void StackPush(uint8_t byte);
+ inline uint8_t StackPop();
+
+public:
+ enum CycleMethod {
+ INST_COUNT,
+ CYCLE_COUNT,
+ };
+ mos6502(BusRead r, BusWrite w, ClockCycle c = nullptr);
+ void NMI();
+ void IRQ();
+ void Reset();
+ void Run(
+ int32_t cycles,
+ uint64_t& cycleCount,
+ CycleMethod cycleMethod = CYCLE_COUNT);
+ void RunEternally(); // until it encounters a illegal opcode
+ // useful when running e.g. WOZ Monitor
+ // no need to worry about cycle exhaus-
+ // tion
+ uint16_t GetPC();
+ uint8_t GetS();
+ uint8_t GetP();
+ uint8_t GetA();
+ uint8_t GetX();
+ uint8_t GetY();
+ void SetResetS(uint8_t value);
+ void SetResetP(uint8_t value);
+ void SetResetA(uint8_t value);
+ void SetResetX(uint8_t value);
+ void SetResetY(uint8_t value);
+ void SetPC(uint16_t value);
+ void SetP(uint8_t value);
+ uint8_t GetResetS();
+ uint8_t GetResetP();
+ uint8_t GetResetA();
+ uint8_t GetResetX();
+ uint8_t GetResetY();
+};
struct wh gfx_size_fs_xtra[GFX_SIZE_EXTRA_NUM];
};
+#define KB_DISCONNECTED -1
+#define KB_UAE 0
+#define KB_A500_6570 1
+#define KB_A600_6570 2
+#define KB_A1000_6500 3
+#define KB_A1000_6570 4
+#define KB_A1200_6805 5
+#define KB_A2000_8039 6
+#define KB_Ax000_6570 7
+
struct uae_prefs {
struct strlist *all_lines;
float blitter_speed_throttle;
unsigned int chipset_mask;
bool chipset_hr;
- bool keyboard_connected;
+ bool display_calibration;
+ int keyboard_mode;
+ bool keyboard_nkro;
bool ntscmode;
bool genlock;
int genlock_image;
extern uae_u8 *restore_keyboard(uae_u8 *);
extern uae_u8 *save_keyboard(size_t *,uae_u8*);
+extern uae_u8 *restore_kbmcu(uae_u8 *);
+extern uae_u8 *save_kbmcu(size_t *,uae_u8*);
+extern uae_u8 *restore_kbmcu2(uae_u8 *);
+extern uae_u8 *save_kbmcu2(size_t *,uae_u8*);
+extern uae_u8 *restore_kbmcu3(uae_u8 *);
+extern uae_u8 *save_kbmcu3(size_t *,uae_u8*);
+
extern uae_u8 *restore_akiko(uae_u8 *src);
extern uae_u8 *save_akiko(size_t *len, uae_u8*);
extern void restore_akiko_finish(void);
return;
}
- if (key == AK_RESETWARNING) {
+ if (currprefs.keyboard_mode > 0) {
+ if (!currprefs.cs_resetwarning) {
+ if (keyboardresetkeys() || key == AK_RESETWARNING) {
+ int r = keybuf[AK_LALT] | keybuf[AK_RALT];
+ if (r) {
+ keyboard_reset_seq_mode = 2;
+ custom_reset(true, true);
+ cpu_inreset();
+ } else {
+ custom_reset(false, true);
+ cpu_inreset();
+ keyboard_reset_seq_mode = 1;
+ }
+ }
+ }
+ } else if (key == AK_RESETWARNING) {
if (resetwarning_do(0)) {
keyboard_reset_seq_mode = 3;
}
} else {
keyboard_reset_seq_mode = 4;
}
+ } else {
+ uae_reset(0, 1);
}
}
memcpy (&tmp, &prefs->jports[portswap], sizeof (struct jport));
memcpy (&prefs->jports[portswap], &prefs->jports[portswap + 1], sizeof (struct jport));
memcpy (&prefs->jports[portswap + 1], &tmp, sizeof (struct jport));
+
inputdevice_updateconfig(NULL, prefs);
}
--- /dev/null
+// Altirra - Atari 800/800XL/5200 emulator
+// Coprocessor library - 65802 emulator
+// Copyright (C) 2009-2015 Avery Lee
+//
+// 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, see <http://www.gnu.org/licenses/>.
+//
+// As a special exception, this library can also be redistributed and/or
+// modified under an alternate license. See COPYING.RMT in the same source
+// archive for details.
+
+#include <string>
+#include "co8048.h"
+
+ATCoProc8048::ATCoProc8048() {
+}
+
+void ATCoProc8048::SetProgramBanks(const void *p0, const void *p1) {
+ mpProgramBanks[0] = (const uint8 *)p0;
+ mpProgramBanks[1] = (const uint8 *)p1;
+
+ mpProgramBank = mpProgramBanks[mbPBK];
+}
+
+uint8 ATCoProc8048::ReadByte(uint8 addr) const {
+ return mRAM[addr];
+}
+
+void ATCoProc8048::WriteByte(uint8 addr, uint8 val) {
+ mRAM[addr] = val;
+}
+
+void ATCoProc8048::ColdReset() {
+ memset(mRAM, 0, sizeof mRAM);
+ mA = 0;
+ mT = 0;
+
+ WarmReset();
+}
+
+void ATCoProc8048::WarmReset() {
+ mPSW = 0x08;
+ mPC = 0;
+ mbF1 = false;
+ mbTF = false;
+ mbIF = false;
+ mbPBK = false;
+ mbDBF = false;
+ mbIrqEnabled = true;
+ mpRegBank = &mRAM[0];
+ mpProgramBank = mpProgramBanks[0];
+
+ mbTimerActive = false;
+
+ mP1 = 0xFF;
+ mP2 = 0xFF;
+ mpFnWritePort(0, 0xFF);
+ mpFnWritePort(1, 0xFF);
+
+ mTStatesLeft = 4;
+}
+
+void ATCoProc8048::AssertIrq() {
+ mbIrqPending = true;
+
+ if (mbIF)
+ mbIrqAttention = true;
+}
+
+void ATCoProc8048::NegateIrq() {
+ mbIrqPending = false;
+}
+
+void ATCoProc8048::Run() {
+ static const uint8 kInsnBytes[256]={
+// 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ 1,1,1,2,2,1,1,1,1,1,1,1,1,1,1,1, // 1x
+ 1,1,2,2,2,1,2,1,1,1,1,1,1,1,1,1, // 1x
+ 1,1,1,2,2,1,2,1,1,1,1,1,1,1,1,1, // 2x
+ 1,1,2,1,2,1,2,1,1,1,1,1,1,1,1,1, // 3x
+ 1,1,1,2,2,1,2,1,1,1,1,1,1,1,1,1, // 4x
+ 1,1,2,2,2,1,2,1,1,1,1,1,1,1,1,1, // 5x
+ 1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1, // 6x
+ 1,1,2,1,2,1,2,1,1,1,1,1,1,1,1,1, // 7x
+ 1,1,2,1,2,1,2,1,2,2,2,1,1,1,1,1, // 8x
+ 1,1,2,1,2,1,2,1,2,2,2,1,1,1,1,1, // 9x
+ 1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1, // Ax
+ 2,2,2,1,2,1,2,1,2,2,2,2,2,2,2,2, // Bx
+ 1,1,2,1,2,1,2,1,1,1,1,1,1,1,1,1, // Cx
+ 1,1,2,2,2,1,1,1,1,1,1,1,1,1,1,1, // Dx
+ 1,1,2,1,2,1,2,1,2,2,2,2,2,2,2,2, // Ex
+ 1,1,2,1,2,1,2,1,1,1,1,1,1,1,1,1, // Fx
+ };
+
+ static const uint8 kInsnCycles[256]={
+// 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ 1,1,2,2,2,1,1,1,2,2,2,1,1,1,1,1, // 0x
+ 1,1,2,2,2,1,2,1,1,1,1,1,1,1,1,1, // 1x
+ 1,1,1,2,2,1,2,1,1,1,1,1,1,1,1,1, // 2x
+ 1,1,2,1,2,1,2,1,2,2,2,1,1,1,1,1, // 3x
+ 1,1,1,2,2,1,2,1,1,1,1,1,1,1,1,1, // 4x
+ 1,1,2,2,2,1,2,1,1,1,1,1,1,1,1,1, // 5x
+ 1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1, // 6x
+ 1,1,2,1,2,1,2,1,1,1,1,1,1,1,1,1, // 7x
+ 2,2,2,2,2,1,2,1,2,2,2,1,1,1,1,1, // 8x
+ 2,2,2,2,2,1,2,1,2,2,2,1,2,2,2,1, // 9x
+ 2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1, // Ax
+ 2,2,2,2,2,1,2,1,2,2,2,2,2,2,2,2, // Bx
+ 1,1,2,1,2,1,2,1,1,1,1,1,1,1,1,1, // Cx
+ 1,1,2,2,2,1,1,1,1,1,1,1,1,1,1,1, // Dx
+ 1,1,2,2,2,1,2,1,2,2,2,2,2,2,2,2, // Ex
+ 1,1,2,1,2,1,2,1,1,1,1,1,1,1,1,1, // Fx
+ };
+
+ mCyclesLeft += mCyclesSaved;
+ mCyclesSaved = 0;
+
+ while(mCyclesLeft > 0) {
+ if (mbIrqAttention) {
+ mbIrqAttention = false;
+
+ if (mbIrqEnabled) {
+ if (mbIrqPending && mbIF)
+ DispatchIrq();
+ }
+ }
+
+ if (mbTIF && !mbTF && mbTimerActive) {
+ UpdateTimer();
+ if (mbTimerIrqPending && mbIrqEnabled)
+ DispatchIrq();
+ }
+
+ const uint8 opcode = mpProgramBank[mPC];
+ const uint8 insnCycles = kInsnCycles[opcode];
+
+ mTStatesLeft = insnCycles;
+
+ if (mCyclesLeft < mTStatesLeft) {
+ mCyclesSaved = mCyclesLeft;
+ mCyclesLeft = 0;
+ break;
+ }
+
+ const uint8 operand = mpProgramBank[mPC + 1];
+
+ mCyclesLeft -= insnCycles;
+
+ mPC = (mPC + kInsnBytes[opcode]) & 0x7FF;
+
+ switch(opcode) {
+ case 0x68: // ADD A,Rr
+ case 0x69:
+ case 0x6A:
+ case 0x6B:
+ case 0x6C:
+ case 0x6D:
+ case 0x6E:
+ case 0x6F:
+ {
+ const uint8 r = mpRegBank[opcode - 0x68];
+ uint32 result = (uint32)mA + r;
+
+ mPSW &= 0x3F;
+ mPSW |= (result >> 1) & 0x80;
+
+ if ((mA ^ r ^ result) & 0x10)
+ mPSW |= 0x40;
+
+ mA = (uint8)result;
+ }
+ break;
+
+ case 0x60: // ADD A,@Rr
+ case 0x61:
+ {
+ const uint8 r = mRAM[mpRegBank[opcode - 0x60]];
+ uint32 result = (uint32)mA + r;
+
+ mPSW &= 0x3F;
+ mPSW |= (result >> 1) & 0x80;
+
+ if ((mA ^ r ^ result) & 0x10)
+ mPSW |= 0x40;
+
+ mA = (uint8)result;
+ }
+ break;
+
+ case 0x03: // ADD A,#imm
+ {
+ const uint8 r = operand;
+ uint32 result = (uint32)mA + r;
+
+ mPSW &= 0x3F;
+ mPSW |= (result >> 1) & 0x80;
+
+ if ((mA ^ r ^ result) & 0x10)
+ mPSW |= 0x40;
+
+ mA = (uint8)result;
+ }
+ break;
+
+ case 0x78: // ADDC A,Rr
+ case 0x79:
+ case 0x7A:
+ case 0x7B:
+ case 0x7C:
+ case 0x7D:
+ case 0x7E:
+ case 0x7F:
+ {
+ const uint8 r = mpRegBank[opcode - 0x78];
+ uint32 result = (uint32)mA + r + (mPSW >> 7);
+
+ mPSW &= 0x3F;
+ mPSW |= (result >> 1) & 0x80;
+
+ if ((mA ^ r ^ result) & 0x10)
+ mPSW |= 0x40;
+
+ mA = (uint8)result;
+ }
+ break;
+
+ case 0x70: // ADDC A,@Rr
+ case 0x71:
+ {
+ const uint8 r = mRAM[mpRegBank[opcode - 0x70]];
+ uint32 result = (uint32)mA + r + (mPSW >> 7);
+
+ mPSW &= 0x3F;
+ mPSW |= (result >> 1) & 0x80;
+
+ if ((mA ^ r ^ result) & 0x10)
+ mPSW |= 0x40;
+
+ mA = (uint8)result;
+ }
+ break;
+
+ case 0x13: // ADDC A,#imm
+ {
+ const uint8 r = operand;
+ uint32 result = (uint32)mA + r + (mPSW >> 7);
+
+ mPSW &= 0x3F;
+ mPSW |= (result >> 1) & 0x80;
+
+ if ((mA ^ r ^ result) & 0x10)
+ mPSW |= 0x40;
+
+ mA = (uint8)result;
+ }
+ break;
+
+ case 0x58: // ANL A,Rr
+ case 0x59:
+ case 0x5A:
+ case 0x5B:
+ case 0x5C:
+ case 0x5D:
+ case 0x5E:
+ case 0x5F:
+ mA &= mpRegBank[opcode - 0x58];
+ break;
+
+ case 0x50: // ANL A,@Rr
+ case 0x51:
+ mA &= mRAM[mpRegBank[opcode - 0x50]];
+ break;
+
+ case 0x53: // ANL A,#data
+ mA &= operand;
+ break;
+
+ // case 0x98: // ANL BUS,#data
+
+ case 0x99: // ANL P1,#data
+ {
+ const uint8 r = mP1 & operand;
+
+ if (mP1 != r) {
+ mP1 = r;
+
+ mpFnWritePort(0, r);
+ }
+ }
+ break;
+
+ case 0x9A: // ANL P2,#data
+ {
+ const uint8 r = mP2 & operand;
+
+ if (mP2 != r) {
+ mP2 = r;
+
+ mpFnWritePort(1, r);
+ }
+ }
+ break;
+
+ case 0x14: // CALL address
+ case 0x34:
+ case 0x54:
+ case 0x74:
+ case 0x94:
+ case 0xB4:
+ case 0xD4:
+ case 0xF4:
+ {
+ uint8 *stackEntry = &mRAM[0x08 + (mPSW & 7) * 2];
+
+ stackEntry[0] = (uint8)mPC;
+ stackEntry[1] = (uint8)((mPC >> 8) + (mPSW & 0xF0) + (mbPBK ? 0x08 : 0x00));
+
+ mPSW = (mPSW - 0x07) | 0x08;
+
+ mbPBK = mbDBF;
+ mPC = ((uint32)(opcode & 0xE0) << 3) + operand;
+ mpProgramBank = mpProgramBanks[mbPBK];
+ }
+ break;
+
+ case 0x27: // CLR A
+ mA = 0;
+ break;
+
+ case 0x97: // CLR C
+ mPSW &= 0x7F;
+ break;
+
+ case 0xA5: // CLR F1
+ mbF1 = false;
+ break;
+
+ case 0x85: // CLR F0
+ mPSW &= 0xDF;
+ break;
+
+ case 0x37: // CPL A
+ mA = ~mA;
+ break;
+
+ case 0xA7: // CPL C
+ mPSW ^= 0x80;
+ break;
+
+ case 0x95: // CPL F0
+ mPSW ^= 0x20;
+ break;
+
+ case 0xB5: // CPL F1
+ mbF1 = !mbF1;
+ break;
+
+ case 0x57: // DA A
+ {
+ uint32 r = mA;
+
+ if ((r & 0x0F) >= 0x0A || (mPSW & 0x40))
+ r += 0x06;
+
+ if (r >= 0xA0 || (mPSW & 0x80))
+ r += 0x60;
+
+ mPSW &= 0x7F;
+ mPSW |= (r >> 1) & 0x80;
+ }
+ break;
+
+ case 0x07: // DEC A
+ --mA;
+ break;
+
+ case 0xC8: // DEC Rr
+ case 0xC9:
+ case 0xCA:
+ case 0xCB:
+ case 0xCC:
+ case 0xCD:
+ case 0xCE:
+ case 0xCF:
+ --mpRegBank[opcode - 0xC8];
+ break;
+
+ case 0x15: // DIS I
+ mbIF = false;
+ break;
+
+ case 0x35: // DIS TCNTI
+ mbTIF = false;
+ mbTimerIrqPending = false;
+ break;
+
+ case 0xE8: // DJNZ Rr,address
+ case 0xE9:
+ case 0xEA:
+ case 0xEB:
+ case 0xEC:
+ case 0xED:
+ case 0xEE:
+ case 0xEF:
+ if (--mpRegBank[opcode - 0xE8])
+ mPC = ((mPC - 1) & 0x700) + operand;
+ break;
+
+ case 0x05: // EN I
+ mbIF = true;
+ mbIrqAttention |= mbIrqPending;
+ break;
+
+ case 0x25: // EN TCNTI
+ mbTIF = true;
+ mbIrqAttention |= mbTF;
+
+ DispatchIrq();
+ break;
+
+ case 0x08: // IN A,BUS
+ mA = mpFnReadBus();
+ break;
+
+ case 0x09: // IN A,P1
+ mA = mpFnReadPort(0, mP1);
+ break;
+
+ case 0x0A: // IN A,P2
+ mA = mpFnReadPort(1, mP2);
+ break;
+
+ case 0x17: // INC A
+ ++mA;
+ break;
+
+ case 0x18: // INC Rr
+ case 0x19:
+ case 0x1A:
+ case 0x1B:
+ case 0x1C:
+ case 0x1D:
+ case 0x1E:
+ case 0x1F:
+ ++mpRegBank[opcode - 0x18];
+ break;
+
+ case 0x10: // INC @Rr
+ case 0x11: // INC @Rr
+ ++mRAM[mpRegBank[opcode - 0x10]];
+ break;
+
+ case 0x12: // JBb address
+ case 0x32:
+ case 0x52:
+ case 0x72:
+ case 0x92:
+ case 0xB2:
+ case 0xD2:
+ case 0xF2:
+ if (mA & (1 << ((opcode >> 5) & 7)))
+ mPC = ((mPC - 1) & 0x700) + operand;
+ break;
+
+ case 0xF6: // JC address
+ if (mPSW & 0x80)
+ mPC = ((mPC - 1) & 0x700) + operand;
+ break;
+
+ case 0xB6: // JF0 address
+ if (mPSW & 0x20)
+ mPC = ((mPC - 1) & 0x700) + operand;
+ break;
+
+ case 0x76: // JF1 address
+ if (mbF1)
+ mPC = ((mPC - 1) & 0x700) + operand;
+ break;
+
+ case 0x04: // JMP address
+ case 0x24:
+ case 0x44:
+ case 0x64:
+ case 0x84:
+ case 0xA4:
+ case 0xC4:
+ case 0xE4:
+ mbPBK = mbDBF;
+ mPC = ((uint32)(opcode & 0xE0) << 3) + operand;
+ mpProgramBank = mpProgramBanks[mbPBK];
+ break;
+
+ case 0xB3: // JMPP @A
+ {
+ const uint32 pageBase = ((mPC - 1) & 0x700);
+ mPC = pageBase + mpProgramBank[pageBase + mA];
+ }
+ break;
+
+ case 0xE6: // JNC address
+ if (!(mPSW & 0x80))
+ mPC = ((mPC - 1) & 0x700) + operand;
+ break;
+
+ case 0x86: // JNI address
+ if (mbIrqPending)
+ mPC = ((mPC - 1) & 0x700) + operand;
+ break;
+
+ case 0x26: // JNT0 address
+ if (!mpFnReadT0())
+ mPC = ((mPC - 1) & 0x700) + operand;
+ break;
+
+ case 0x46: // JNT1 address
+ if (!mpFnReadT1())
+ mPC = ((mPC - 1) & 0x700) + operand;
+ break;
+
+ case 0x96: // JNZ address
+ if (mA)
+ mPC = ((mPC - 1) & 0x700) + operand;
+ break;
+
+ case 0x16: // JTF address
+ if (!mbTF && mbTimerActive)
+ UpdateTimer();
+
+ if (mbTF) {
+ mbTF = false;
+ UpdateTimer();
+ UpdateTimerDeadline();
+ mPC = ((mPC - 1) & 0x700) + operand;
+ }
+ break;
+
+ case 0x36: // JT0 address
+ if (mpFnReadT0())
+ mPC = ((mPC - 1) & 0x700) + operand;
+ break;
+
+ case 0x56: // JT1 address
+ if (mpFnReadT1())
+ mPC = ((mPC - 1) & 0x700) + operand;
+ break;
+
+ case 0xC6: // JZ address
+ if (!mA)
+ mPC = ((mPC - 1) & 0x700) + operand;
+ break;
+
+ case 0x23: // MOV A,#data
+ mA = operand;
+ break;
+
+ case 0xC7: // MOV A,PSW
+ mA = mPSW;
+ break;
+
+ case 0xF8: // MOV A,Rr
+ case 0xF9:
+ case 0xFA:
+ case 0xFB:
+ case 0xFC:
+ case 0xFD:
+ case 0xFE:
+ case 0xFF:
+ mA = mpRegBank[opcode - 0xF8];
+ break;
+
+ case 0xF0: // MOV A,@Rr
+ case 0xF1:
+ mA = mRAM[mpRegBank[opcode - 0xF0]];
+ break;
+
+ case 0x42: // MOV A,T
+ if (mbTimerActive)
+ UpdateTimer();
+
+ mA = mT;
+ break;
+
+ case 0xD7: // MOV PSW,A
+ mPSW = mA | 0x08;
+ mpRegBank = mPSW & 0x10 ? &mRAM[0x18] : mRAM;
+ break;
+
+ case 0xA8: // MOV Rr,A
+ case 0xA9:
+ case 0xAA:
+ case 0xAB:
+ case 0xAC:
+ case 0xAD:
+ case 0xAE:
+ case 0xAF:
+ mpRegBank[opcode - 0xA8] = mA;
+ break;
+
+ case 0xB8: // MOV Rr,#data
+ case 0xB9:
+ case 0xBA:
+ case 0xBB:
+ case 0xBC:
+ case 0xBD:
+ case 0xBE:
+ case 0xBF:
+ mpRegBank[opcode - 0xB8] = operand;
+ break;
+
+ case 0xA0: // MOV @Rr,A
+ case 0xA1:
+ mRAM[mpRegBank[opcode - 0xA0]] = mA;
+ break;
+
+ case 0xB0: // MOV @Rr,#data
+ case 0xB1:
+ mRAM[mpRegBank[opcode - 0xB0]] = operand;
+ break;
+
+ case 0x62: // MOV T,A
+ mT = mA;
+ if (mbTimerActive)
+ UpdateTimerDeadline();
+ break;
+
+ case 0xA3: // MOVP A,@A
+ mA = mpProgramBank[((mPC - 1) & 0x700) + mA];
+ break;
+
+ case 0xE3: // MOVP3 A,@A
+ // MOVP3 is documented as always setting A8-11 to 0011
+ // regardless of the current state of DBF or PC[11], so we
+ // need to force bank 0.
+ mA = mpProgramBanks[0][0x300 + mA];
+ break;
+
+ case 0x80: // MOVX A,@Rr
+ case 0x81:
+ mA = mpRegBank[opcode - 0x80];
+ break;
+
+ case 0x90: // MOVX @Rr,A
+ case 0x91:
+ mpRegBank[opcode - 0x90], mA;
+ break;
+
+ case 0x00: // NOP
+ break;
+
+ case 0x48: // ORL A,Rr
+ case 0x49:
+ case 0x4A:
+ case 0x4B:
+ case 0x4C:
+ case 0x4D:
+ case 0x4E:
+ case 0x4F:
+ mA |= mpRegBank[opcode - 0x48];
+ break;
+
+ case 0x40: // ORL A,@Rr
+ case 0x41:
+ mA |= mRAM[mpRegBank[opcode - 0x40]];
+ break;
+
+ case 0x43: // ORL A,#data
+ mA |= operand;
+ break;
+
+ // case 0x88: // ORL BUS,#data
+ case 0x89: // ORL P1,#data
+ {
+ const uint8 r = mP1 | operand;
+
+ if (mP1 != r) {
+ mP1 = r;
+
+ mpFnWritePort(0, r);
+ }
+ }
+ break;
+
+ case 0x8A: // ORL P2,#data
+ {
+ const uint8 r = mP2 | operand;
+
+ if (mP2 != r) {
+ mP2 = r;
+
+ mpFnWritePort(1, r);
+ }
+ }
+ break;
+
+ // case 0x38: // OUTL BUS,A
+
+ case 0x39: // OUTL P1,A
+ if (mP1 != mA) {
+ mP1 = mA;
+ mpFnWritePort(0, mA);
+ }
+ break;
+
+ case 0x3A: // OUTL P2,A
+ if (mP2 != mA) {
+ mP2 = mA;
+ mpFnWritePort(1, mA);
+ }
+ break;
+
+ case 0x83: // RET
+ {
+ mPSW = (mPSW - 1) | 0x08;
+
+ const uint8 *stackEntry = &mRAM[0x08 + (mPSW & 7)*2];
+
+ mbPBK = (stackEntry[1] & 0x08) != 0;
+ mpProgramBank = mpProgramBanks[mbPBK];
+
+ mPC = (uint32)stackEntry[0] + (((uint32)stackEntry[1] & 0x07) << 8);
+ }
+ break;
+
+ case 0x93: // RETR
+ {
+ mPSW = (mPSW - 1) | 0x08;
+
+ const uint8 *stackEntry = &mRAM[0x08 + (mPSW & 7)*2];
+
+ mbPBK = (stackEntry[1] & 0x08) != 0;
+ mpProgramBank = mpProgramBanks[mbPBK];
+
+ mPC = (uint32)stackEntry[0] + (((uint32)stackEntry[1] & 0x07) << 8);
+ mPSW &= stackEntry[1] | 0x0F;
+ mpRegBank = (mPSW & 0x10) ? &mRAM[0x18] : mRAM;
+
+ mbIrqEnabled = true;
+
+ DispatchIrq();
+ }
+ break;
+
+ case 0xE7: // RL A
+ mA = (mA + mA) + (mA >> 7);
+ break;
+
+ case 0xF7: // RLC A
+ {
+ uint32 r = (uint32)mA + mA;
+
+ mA = (uint8)(r + (mPSW >> 7));
+ mPSW = (mPSW & 0x7F) + ((r >> 1) & 0x80);
+ }
+ break;
+
+ case 0x77: // RR A
+ mA = (mA >> 1) + (mA << 7);
+ break;
+
+ case 0x67: // RRC A
+ {
+ uint8 r = mA;
+
+ mA = (uint8)((mA >> 1) + (mPSW & 0x80));
+ mPSW = (mPSW & 0x7F) + (r << 7);
+ }
+ break;
+
+ case 0xE5: // SEL MB0
+ mbDBF = false;
+ break;
+
+ case 0xF5: // SEL MB1
+ mbDBF = true;
+ break;
+
+ case 0xC5: // SEL RB0
+ mPSW &= 0xEF;
+ mpRegBank = mRAM;
+ break;
+
+ case 0xD5: // SEL RB1
+ mPSW |= 0x10;
+ mpRegBank = &mRAM[0x18];
+ break;
+
+ case 0x65: // STOP TCNT
+ if (mbTimerActive) {
+ mbTimerActive = false;
+
+ UpdateTimer();
+ }
+ break;
+
+ // case 0x45: // STRT TCNT
+
+ case 0x55: // STRT T
+ mbTimerActive = true;
+ UpdateTimerDeadline();
+ break;
+
+ case 0x47: // SWAP A
+ mA = (mA << 4) + (mA >> 4);
+ break;
+
+ case 0x28: // XCH A,Rr
+ case 0x29:
+ case 0x2A:
+ case 0x2B:
+ case 0x2C:
+ case 0x2D:
+ case 0x2E:
+ case 0x2F:
+ {
+ uint8 *r = &mpRegBank[opcode - 0x28];
+ uint8 t = mA;
+ mA = *r;
+ *r = t;
+ }
+ break;
+
+ case 0x20: // XCH A,@Rr
+ case 0x21:
+ {
+ uint8 *r = &mRAM[mpRegBank[opcode - 0x20]];
+ uint8 t = mA;
+ mA = *r;
+ *r = t;
+ }
+ break;
+
+ case 0xD8: // XRL A,Rr
+ case 0xD9:
+ case 0xDA:
+ case 0xDB:
+ case 0xDC:
+ case 0xDD:
+ case 0xDE:
+ case 0xDF:
+ mA ^= mpRegBank[opcode - 0xD8];
+ break;
+
+ case 0xD0: // XRL A,@Rr
+ case 0xD1:
+ mA ^= mRAM[mpRegBank[opcode - 0xD0]];
+ break;
+
+ case 0xD3: // XRL A,#data
+ mA ^= operand;
+ break;
+
+ default:
+ mCyclesLeft = 0;
+ mPC = (mPC - 1) & 0x7FF;
+ break;
+ }
+ }
+
+force_exit:
+ ;
+}
+
+void ATCoProc8048::DispatchIrq() {
+ if (!mbIrqEnabled)
+ return;
+
+ if (mbIF && mbIrqPending) {
+ mbIrqEnabled = false;
+
+ uint8 *stackEntry = &mRAM[0x08 + (mPSW & 7) * 2];
+
+ stackEntry[0] = (uint8)mPC;
+ stackEntry[1] = (uint8)((mPC >> 8) + (mPSW & 0xF0) + (mbPBK ? 0x08 : 0x00));
+
+ mPSW = (mPSW - 0x07) | 0x08;
+
+ mbPBK = false;
+ mpProgramBank = mpProgramBanks[false];
+ mPC = 3;
+ } else if (mbTIF && mbTimerIrqPending) {
+ mbIrqEnabled = false;
+ mbTimerIrqPending = false;
+
+ uint8 *stackEntry = &mRAM[0x08 + (mPSW & 7) * 2];
+
+ stackEntry[0] = (uint8)mPC;
+ stackEntry[1] = (uint8)((mPC >> 8) + (mPSW & 0xF0) + (mbPBK ? 0x08 : 0x00));
+
+ mPSW = (mPSW - 0x07) | 0x08;
+
+ mbPBK = false;
+ mpProgramBank = mpProgramBanks[false];
+ mPC = 7;
+ }
+}
+
+void ATCoProc8048::UpdateTimer() {
+ const uint32 delta = (mCyclesBase - mCyclesLeft) - mTimerDeadline;
+ mT = (uint8)(delta >> 5);
+
+ if (!mbTF && !(delta & (UINT32_C(1) << 31))) {
+ mbTF = true;
+
+ if (mbTIF)
+ mbTimerIrqPending = true;
+
+ mTimerDeadline += 32 * 256;
+ }
+}
+
+void ATCoProc8048::UpdateTimerDeadline() {
+ mTimerDeadline = ((mCyclesBase - mCyclesLeft) & ~UINT32_C(31)) + ((0x100 - (uint32)mT) << 5);
+}
--- /dev/null
+// Altirra - Atari 800/800XL/5200 aemulator
+// Coprocessor library - 65802 emulator
+// Copyright (C) 2009-2015 Avery Lee
+//
+// 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, see <http://www.gnu.org/licenses/>.
+//
+// As a special exception, this library can also be redistributed and/or
+// modified under an alternate license. See COPYING.RMT in the same source
+// archive for details.
+
+#include <stdint.h>
+#include <stdlib.h>
+
+typedef uint8_t uint8;
+typedef uint16_t uint16;
+typedef uint32_t uint32;
+typedef int32_t sint32;
+
+#ifndef f_ATCOPROC_CO8048_H
+#define f_ATCOPROC_CO8048_H
+
+//#include <vd2/system/function.h>
+
+class ATCoProc8048 {
+public:
+ ATCoProc8048();
+
+ void SetProgramBanks(const void *p0, const void *p1);
+
+ uint16 GetPC() const { return mPC; }
+
+ uint8 GetSP() const { return mPSW & 7; }
+ uint32 GetStepStackLevel() const { return (uint32)mPSW << 29; }
+ uint8 GetPort1Output() const { return mP1; }
+ uint8 GetPort2Output() const { return mP2; }
+
+ uint32 GetTime() const { return mCyclesBase - mCyclesLeft; }
+ uint32 GetTimeBase() const { return mCyclesBase; }
+
+ const uint8 *GetInternalRAM() const { return mRAM; }
+ uint8 *GetInternalRAM() { return mRAM; }
+ uint8 ReadByte(uint8 addr) const;
+ void WriteByte(uint8 addr, uint8 val);
+
+ void ColdReset();
+ void WarmReset();
+
+ void AssertIrq();
+ void NegateIrq();
+
+ uint32 GetTStatesPending() const { return mTStatesLeft; }
+ uint32 GetCyclesLeft() const { return mCyclesLeft; }
+ void AddCycles(sint32 cycles) { mCyclesBase += cycles; mCyclesLeft += cycles; }
+ void Run();
+
+ void DispatchIrq();
+ void UpdateTimer();
+ void UpdateTimerDeadline();
+
+ int mTStatesLeft = 0;
+
+ uint8 mA;
+ uint8 mPSW;
+ uint8 *mpRegBank;
+ const uint8 *mpProgramBanks[2];
+ const uint8 *mpProgramBank;
+
+ uint8 mT = 0;
+ uint8 mP1 = 0xFF;
+ uint8 mP2 = 0xFF;
+ bool mbDBF = false;
+ bool mbPBK = false;
+ bool mbIF = false;
+ bool mbTIF = false;
+ bool mbTF = false;
+ bool mbF1 = false;
+ bool mbIrqEnabled = false;
+ bool mbIrqPending = false;
+ bool mbIrqAttention = false;
+ bool mbTimerIrqPending = false;
+
+ uint16 mPC = 0;
+ sint32 mCyclesLeft = 0;
+ uint32 mCyclesBase = 0;
+ uint32 mCyclesSaved = 0;
+
+ bool mbTimerActive = false;
+ uint32 mTimerDeadline = 0;
+
+ const uint8 *mpNextState = nullptr;
+ uint8 mReadOpcodeState = 0;
+
+ alignas(2) uint8 mRAM[256];
+
+ static const uint8 kInitialState;
+ static const uint8 kInitialStateNoBreak;
+ static const uint8 kIrqSequence[];
+};
+
+void mpFnWritePort(int, uint8);
+uint8 mpFnReadBus(void);
+void mpFnWriteBus(uint8);
+uint8 mpFnReadPort(int, uint8);
+uint8 mpFnReadT0(void);
+uint8 mpFnReadT1(void);
+
+#endif // f_ATCOPROC_CO8048_H
--- /dev/null
+/*
+* UAE - The Un*x Amiga Emulator
+*
+* Keyboard MCU emulation
+* 6500-1 (early A1000 keyboards. ROM not yet dumped)
+* CSG 6570-036 is same MCU as 6500-1 with ROM update that fixes key ghosting.
+*
+* Copyright 2024 Toni Wilen
+*/
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "options.h"
+#include "rommgr.h"
+#include "zfile.h"
+#include "events.h"
+#include "keyboard_mcu.h"
+#include "keybuf.h"
+#include "mos6502.h"
+#include "inputdevice.h"
+#include "gui.h"
+#include "savestate.h"
+
+int kb_mcu_log = 0;
+
+static uae_u8 mcu_rom[2048];
+static uae_u8 mcu_ram[0x40];
+static uae_u8 mcu_io[0x10];
+static uae_u8 matrix[128];
+static uae_u32 mcu_wd;
+static bool mcu_caps_led;
+static mos6502 *mcu;
+static evt_t lastcycle, kclk_reset_start;
+static uae_u8 kbdata, kbdatacnt;
+static bool kbhandshake;
+static bool rom_loaded;
+static int fakemode;
+static bool state_loaded;
+static int mcu_flags;
+
+// 15*6 matrix
+static const uae_u8 matrixkeys[] = {
+ 0x5f,0x4c,0x4f,0x4e,0x4d,0x4a,
+ 0x59,0x0d,0x44,0x46,0x41,0x0f,
+ 0x58,0x0c,0x1b,0x2b,0x40,0x1d,
+ 0x57,0x0b,0x1a,0x2a,0x3b,0x2d,
+ 0x56,0x0a,0x19,0x29,0x3a,0x3d,
+ 0x5c,0x09,0x18,0x28,0x39,0x43,
+ 0x55,0x08,0x17,0x27,0x38,0x1e,
+ 0x5b,0x07,0x16,0x26,0x37,0x2e,
+ 0x54,0x06,0x15,0x25,0x36,0x3e,
+ 0x53,0x05,0x14,0x24,0x35,0x3c,
+ 0x52,0x04,0x13,0x23,0x34,0x1f,
+ 0x51,0x03,0x12,0x22,0x33,0x2f,
+ 0x50,0x02,0x11,0x21,0x32,0x3f,
+ 0x5a,0x01,0x10,0x20,0x31,0x5e,
+ 0x45,0x00,0x42,0x62,0x30,0x5d,
+ // not connected in matrix but included in ROM matrix table
+ 0x49,0x48,0x47,0x2c,0x1c,0x0e
+};
+
+static void key_to_matrix(uae_u8 code)
+{
+ uae_u8 c = code >> 1;
+ if (code & 1) {
+ matrix[c] = 0;
+ if (kb_mcu_log & 1) {
+ write_log("release %02x\n", c);
+ }
+ } else {
+ matrix[c] = 1;
+ if (kb_mcu_log & 1) {
+ write_log("press %02x\n", c);
+ }
+ }
+}
+
+static void keymcu_irq(void)
+{
+ uae_u8 c = mcu_io[15];
+ if ((c & (0x80 | 0x10)) == (0x80 | 0x10) ||
+ (c & (0x40 | 0x08)) == (0x40 | 0x08) ||
+ (c & (0x20 | 0x04)) == (0x20 | 0x04)) {
+ if (kb_mcu_log & 4) {
+ write_log("%04x %04x IRQ %02x\n", mcu_wd, mcu->GetPC(), c);
+ }
+ mcu->IRQ();
+ }
+}
+
+// This should be in CIA emulation but it is simpler to have it here.
+static void get_kbit(bool v)
+{
+ if (kbhandshake && !fakemode) {
+ return;
+ }
+ kbdata <<= 1;
+ kbdata |= v ? 1 : 0;
+ kbdatacnt++;
+ if (kbdatacnt >= 8) {
+ kbdatacnt = 0;
+ if (kb_mcu_log & 1) {
+ uae_u8 code = (kbdata >> 1) | (kbdata << 7);
+ write_log("got keycode %02x\n", code ^ 0xff);
+ }
+ if (fakemode) {
+ fakemode = 10000;
+ } else {
+ cia_keyreq(kbdata);
+ }
+ }
+}
+
+static uae_u8 mcu_io_read(int addr)
+{
+ uint8_t v = mcu_io[addr];
+
+ if (kb_mcu_log & 2) {
+ write_log("%04x %04x IOR %d = %02x\n", mcu_wd, mcu->GetPC(), addr, v);
+ }
+
+ switch (addr)
+ {
+ case 0: // PORTA: KDAT=0,KCLK=1,2-7 = Matrix column read
+ {
+ if (kbhandshake || fakemode > 1) {
+ v &= ~1;
+ }
+
+ int row = mcu_io[2] | ((mcu_io[3] & 0x7f) << 8);
+
+ if (!currprefs.keyboard_nkro) {
+ // matrix without diodes
+ for (int i = 0; i < 15; i++) {
+ if (!(row & (1 << i))) {
+ const uae_u8 *mr = matrixkeys + i * 6;
+ for (int j = 0; j < 6; j++) {
+ if (matrix[mr[j]]) {
+ for(int ii = 0; ii < 15; ii++) {
+ if ((row & (1 << ii)) && ii != i) {
+ const uae_u8 *mr2 = matrixkeys + ii * 6;
+ if (matrix[mr2[j]]) {
+ row &= ~(1 << ii);
+ i = -1;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < 15; i++) {
+ if (!(row & (1 << i))) {
+ const uae_u8 *mr = matrixkeys + i * 6;
+ for (int j = 0; j < 6; j++) {
+ if (matrix[mr[j]]) {
+ v &= ~(4 << j);
+ }
+ }
+ }
+ }
+ }
+ break;
+ case 1: // PORTB: RSHIFT=0,RALT=1,RAMIGA=2,CTRL=3,LSHIFT=4,LALT=5,LAMIGA=6,CAPSLED=7
+ {
+ if (matrix[0x61]) {
+ v &= ~0x01;
+ }
+ if (matrix[0x65]) {
+ v &= ~0x02;
+ }
+ if (matrix[0x67]) {
+ v &= ~0x04;
+ }
+ if (matrix[0x63]) {
+ v &= ~0x08;
+ }
+ if (matrix[0x60]) {
+ v &= ~0x10;
+ }
+ if (matrix[0x64]) {
+ v &= ~0x20;
+ }
+ if (matrix[0x66]) {
+ v &= ~0x40;
+ }
+ }
+ break;
+ case 7:
+ mcu_io[15] &= ~0x80;
+ break;
+ }
+ return v;
+}
+
+static void mcu_io_write(int addr, uae_u8 v)
+{
+ if (kb_mcu_log & 2) {
+ write_log("%04x %04X IOW %d = %02x\n", mcu_wd, mcu->GetPC(), addr, v);
+ }
+
+ switch (addr)
+ {
+ case 0xf: // CONTROL
+ mcu_io[addr] = v;
+ break;
+ case 0x8: // UPPER LATCH AND TRANSFER LATCH TO COUNTER
+ mcu_io[4] = v;
+ mcu_io[7] = mcu_io[5];
+ mcu_io[6] = mcu_io[4];
+ mcu_io[15] &= ~0x80;
+ break;
+ case 9: // CLEAR PA0 POS EDGE DETECT
+ mcu_io[15] &= ~0x40;
+ break;
+ case 10: // CLEAR PA1 NEG EDGE DETECT
+ mcu_io[15] &= ~0x20;
+ break;
+ case 0x03: // PORTD
+ // bit7 = watchdog reset
+ if (!(mcu_io[3] & 0x80) && (v & 0x80)) {
+ mcu_wd = 0;
+ if (kb_mcu_log & 2) {
+ write_log("KBMCU WD clear PC=%04x\n", mcu->GetPC());
+ }
+ }
+ mcu_io[addr] = v;
+ break;
+ case 2: // PORTC
+ mcu_io[addr] = v;
+ break;
+ case 1: // PORTB
+ // bit7 = CAPS LED
+ if (mcu_caps_led != ((v & 0x80) != 0)) {
+ mcu_caps_led = (v & 0x80) != 0;
+ gui_data.capslock = mcu_caps_led;
+ if (!fakemode) {
+ gui_led(LED_CAPS, gui_data.capslock, -1);
+ }
+ if (kb_mcu_log & 1) {
+ write_log("KBMCU: CAPS = %d\n", mcu_caps_led);
+ }
+ }
+ mcu_io[addr] = v;
+ break;
+ case 0: // PORTA
+ {
+ uae_u8 vv = v;
+ if (kbhandshake || fakemode > 1) {
+ vv &= ~1;
+ }
+ // PA0 (KDAT)
+ if ((mcu_io[0] & 0x01) != (vv & 0x01)) {
+ if (kb_mcu_log & 1) {
+ write_log("KDAT=%d KCLK=%d HS=%d CNT=%d PC=%04x\n", (vv & 0x01) != 0, (vv & 0x02) != 0, kbhandshake, kbdatacnt, mcu->GetPC());
+ }
+ if ((vv & 0x01)) {
+ mcu_io[15] |= 0x40;
+ keymcu_irq();
+ }
+ }
+ // PA1 (KCLK)
+ if ((mcu_io[0] & 0x02) != (vv & 0x02)) {
+ if (kb_mcu_log & 1) {
+ write_log("KCLK=%d KDAT=%d HS=%d CNT=%d PC=%04x\n", (vv & 0x02) != 0, (vv & 0x01) != 0, kbhandshake, kbdatacnt, mcu->GetPC());
+ }
+ if (!(vv & 0x02)) {
+ mcu_io[15] |= 0x20;
+ keymcu_irq();
+ if (currprefs.cs_resetwarning) {
+ kclk_reset_start = get_cycles() + CYCLE_UNIT * 1500000;
+ }
+ } else {
+ kclk_reset_start = 0;
+ }
+ if (vv & 0x02) {
+ get_kbit((vv & 0x01) != 0);
+ }
+ }
+ mcu_io[addr] = v;
+ }
+ break;
+ default:
+ mcu_io[addr] = v;
+ break;
+ }
+}
+
+static void keymcu_res(void)
+{
+ mcu_io[3] = mcu_io[2] = mcu_io[1] = mcu_io[0] = 0xff;
+ mcu_wd = 0;
+ mcu_io[15] = 0;
+ kclk_reset_start = 0;
+ mcu->Reset();
+}
+
+static void dec_counter(void)
+{
+ mcu_io[7]--;
+ if (mcu_io[7] == 0xff) {
+ mcu_io[6]--;
+ if (mcu_io[6] == 0xff) {
+ mcu_io[15] |= 0x80;
+ mcu_io[7] = mcu_io[5];
+ mcu_io[6] = mcu_io[4];
+ keymcu_irq();
+ }
+ }
+ mcu_wd++;
+ // WD TIMER fault
+ if ((mcu_flags & 3) == 3) {
+ mcu_wd = 0;
+ }
+ // Watchdog is about 40ms
+ if (mcu_wd >= 60000) {
+ if (kb_mcu_log & 1) {
+ write_log("KBMCU WD reset\n");
+ }
+ keymcu_res();
+ }
+}
+
+static uint8_t MemoryRead(uint16_t address)
+{
+ uint8_t v = 0;
+ if (address >= 0x80 && address < 0x90) {
+ v = mcu_io_read(address - 0x80);
+ } else if (address >= 0x800) {
+ address &= 0x7ff;
+ v = mcu_rom[address];
+ // ROM fault
+ if ((mcu_flags & 3) == 1) {
+ if (address == 0) {
+ v ^= 0x55;
+ }
+ }
+ } else {
+ address &= 0x3f;
+ v = mcu_ram[address];
+ }
+ return v;
+}
+static void MemoryWrite(uint16_t address, uint8_t value)
+{
+ if (address >= 0x80 && address < 0x90) {
+ mcu_io_write(address - 0x80, value);
+ } else if (address < 0x800) {
+ address &= 0x3f;
+ // RAM fault
+ if ((mcu_flags & 3) == 2) {
+ if (address == 0x3f) {
+ value = 0xff;
+ }
+ }
+ mcu_ram[address] = value;
+ }
+}
+
+static bool ismcu(void)
+{
+ return currprefs.keyboard_mode == KB_A500_6570 ||
+ currprefs.keyboard_mode == KB_A600_6570 ||
+ currprefs.keyboard_mode == KB_A1000_6570 ||
+ currprefs.keyboard_mode == KB_Ax000_6570;
+}
+
+void keymcu_reset(void)
+{
+ if (ismcu()) {
+ if (!state_loaded) {
+ memset(mcu_ram, 0, sizeof mcu_ram);
+ memset(mcu_io, 0, sizeof mcu_io);
+ memset(matrix, 0, sizeof matrix);
+ kbhandshake = false;
+ }
+ rom_loaded = false;
+
+ memset(mcu_rom, 0, sizeof mcu_rom);
+ struct zfile *zf = NULL;
+ const TCHAR *path = NULL;
+ struct boardromconfig *brc = get_device_rom_new(&currprefs, ROMTYPE_KBMCU, 0, NULL);
+ if (brc) {
+ mcu_flags = brc->roms[0].device_settings;
+ if (brc->roms[0].romfile[0]) {
+ path = brc->roms[0].romfile;
+ zf = zfile_fopen(path, _T("rb"));
+ }
+ }
+ if (!zf) {
+ int ids[] = { 321, -1 };
+ struct romlist *rl = getromlistbyids(ids, NULL);
+ if (rl) {
+ path = rl->path;
+ zf = read_rom(rl->rd);
+ }
+ }
+ if (zf) {
+ zfile_fread(mcu_rom, sizeof(mcu_rom), 1, zf);
+ zfile_fclose(zf);
+ write_log(_T("Loaded 6500-1/6570-036 KB MCU ROM '%s'\n"), path);
+ rom_loaded = true;
+ } else {
+ write_log(_T("Failed to load 6500-1/6570-036 KB MCU ROM\n"));
+ }
+ if (state_loaded) {
+ uint16_t pc = mcu->GetPC();
+ uint8_t status = mcu->GetP();
+ mcu->Reset();
+ mcu->SetPC(pc);
+ mcu->SetP(status);
+ gui_data.capslock = mcu_caps_led;
+ } else {
+ keymcu_res();
+ if (isrestore()) {
+ // if loading statefile without keyboard state: execute MCU code until init phase is done
+ fakemode = 1;
+ uint64_t cycleCount = 0;
+ for (int i = 0; i < 1000000; i++) {
+ mcu->Run(1, cycleCount, mos6502::CYCLE_COUNT);
+ if (fakemode > 1) {
+ fakemode--;
+ if (fakemode == 1) {
+ mcu_io[15] |= 0x40;
+ keymcu_irq();
+ }
+ }
+ }
+ fakemode = 0;
+ }
+ lastcycle = get_cycles();
+ }
+ }
+ state_loaded = false;
+}
+
+void keymcu_free(void)
+{
+ if (mcu) {
+ delete mcu;
+ mcu = NULL;
+ }
+ state_loaded = false;
+}
+
+static void ClockCycle(mos6502 *m)
+{
+ dec_counter();
+ keymcu_irq();
+}
+
+void keymcu_init(void)
+{
+ mcu = new mos6502(MemoryRead, MemoryWrite, ClockCycle);
+ mcu->Reset();
+ state_loaded = false;
+}
+
+bool keymcu_run(bool handshake)
+{
+ if (ismcu() && rom_loaded) {
+ bool hs = kbhandshake;
+ kbhandshake = handshake;
+ if (!handshake && hs) {
+ if (kb_mcu_log & 1) {
+ write_log("handshake off\n");
+ }
+ mcu_io[15] |= 0x40;
+ keymcu_irq();
+ kbdatacnt = 0;
+ } else if (handshake && !hs) {
+ if (kb_mcu_log & 1) {
+ write_log("handshake on\n");
+ }
+ kbdatacnt = 0;
+ }
+ evt_t c = get_cycles();
+ int m = CYCLE_UNIT * (currprefs.ntscmode ? 3579545 : 3546895) / 1500000;
+ int cycles = (c - lastcycle) / m;
+ if (cycles > 0) {
+ uint64_t cycleCount = 0;
+ if (mcu) {
+ mcu->Run(cycles, cycleCount, mos6502::CYCLE_COUNT);
+ }
+ lastcycle += cycles * m;
+ }
+ if (kclk_reset_start > 0 && kclk_reset_start < c) {
+ write_log("Keyboard MCU generated system reset\n");
+ inputdevice_do_kb_reset();
+ }
+ }
+ while (keys_available()) {
+ uae_u8 kbcode = get_next_key();
+ key_to_matrix(kbcode);
+ }
+ return kbdatacnt >= 3;
+}
+
+#ifdef SAVESTATE
+
+uae_u8 *save_kbmcu(size_t *len, uae_u8 *dstptr)
+{
+ if (!mcu || !ismcu()) {
+ return NULL;
+ }
+
+ uae_u8 *dstbak, *dst;
+ if (dstptr) {
+ dstbak = dst = dstptr;
+ } else {
+ dstbak = dst = xmalloc(uae_u8, 1000 + sizeof(mcu_ram) + sizeof(mcu_io) + sizeof(matrix));
+ }
+
+ save_u32(1);
+ save_u32((kbhandshake ? 1 : 0) | (mcu_caps_led ? 2 : 0));
+ save_u32(mcu_wd);
+ save_u8(kbdata);
+ save_u8(kbdatacnt);
+ save_u64(lastcycle);
+ save_u64(kclk_reset_start);
+ for (int i = 0; i < sizeof(mcu_ram); i++) {
+ save_u8(mcu_ram[i]);
+ }
+ for (int i = 0; i < sizeof(mcu_io); i++) {
+ save_u8(mcu_io[i]);
+ }
+ for (int i = 0; i < sizeof(matrix); i++) {
+ save_u8(matrix[i]);
+ }
+ save_u8(mcu->GetA());
+ save_u8(mcu->GetX());
+ save_u8(mcu->GetY());
+ save_u8(mcu->GetP());
+ save_u8(mcu->GetS());
+ save_u16(mcu->GetPC());
+
+ *len = dst - dstbak;
+ return dstbak;
+}
+
+uae_u8* restore_kbmcu(uae_u8 *src)
+{
+ if (!mcu || !ismcu()) {
+ return NULL;
+ }
+
+ int v = restore_u32();
+ if (!(v & 1)) {
+ return NULL;
+ }
+ uae_u32 flags = restore_u32();
+ kbhandshake = flags != 0;
+ mcu_caps_led = flags & 2;
+ mcu_wd = restore_u32();
+ kbdata = restore_u8();
+ kbdatacnt = restore_u8();
+ lastcycle = restore_u64();
+ kclk_reset_start = restore_u64();
+ for (int i = 0; i < sizeof(mcu_ram); i++) {
+ mcu_ram[i] = restore_u8();
+ }
+ for (int i = 0; i < sizeof(mcu_io); i++) {
+ mcu_io[i] = restore_u8();
+ }
+ for (int i = 0; i < sizeof(matrix); i++) {
+ matrix[i] = restore_u8();
+ }
+ mcu->SetResetA(restore_u8());
+ mcu->SetResetX(restore_u8());
+ mcu->SetResetY(restore_u8());
+ mcu->SetResetP(restore_u8());
+ mcu->SetResetS(restore_u8());
+ mcu->SetPC(restore_u16());
+
+ state_loaded = true;
+
+ return src;
+}
+
+#endif
\ No newline at end of file
--- /dev/null
+/*
+* UAE - The Un*x Amiga Emulator
+*
+* Keyboard MCU emulation (A1200 M68HC05)
+*
+* Copyright 2024 Toni Wilen
+*/
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "options.h"
+#include "rommgr.h"
+#include "zfile.h"
+#include "events.h"
+#include "keyboard_mcu.h"
+#include "keybuf.h"
+#include "inputdevice.h"
+#include "gui.h"
+#include "savestate.h"
+#include "m6805/m68emu.h"
+
+static struct M68_CTX ctx;
+
+extern int kb_mcu_log;
+
+static uae_u8 mcu_rom[8192];
+static uae_u8 mcu_ram[320];
+static uae_u8 mcu_io[32];
+static uae_u8 mcu_option;
+static uae_u8 matrix[128];
+static uae_u8 mcu_status_read;
+static uae_u8 mcu_dec_ps;
+static bool state_loaded;
+static bool mcu_caps_led;
+static bool rom_loaded;
+static uae_u8 mcu_timer_latch_low;
+static bool mcu_timer_latched;
+static bool mcu_input_capture_latch, mcu_output_compare_latch;
+static evt_t lastcycle;
+static bool kbhandshake;
+static bool mcu_ram0, mcu_ram1;
+static int fakemode;
+static uae_u8 kbdata, kbdatacnt;
+static uae_s32 mcu_wd, mcu_res;
+static int mcu_flags;
+
+// 15*6 matrix
+static const uae_u8 matrixkeys[] = {
+ 0x45,0x00,0x42,0x62,0x30,0x5d,
+ 0x5a,0x01,0x10,0x20,0x31,0x5e,
+ 0x50,0x02,0x11,0x21,0x32,0x3f,
+ 0x51,0x03,0x12,0x22,0x33,0x2f,
+ 0x52,0x04,0x13,0x23,0x34,0x1f,
+ 0x53,0x05,0x14,0x24,0x35,0x3c,
+ 0x54,0x06,0x15,0x25,0x36,0x3e,
+ 0x5b,0x07,0x16,0x26,0x37,0x2e,
+ 0x55,0x08,0x17,0x27,0x38,0x1e,
+ 0x5c,0x09,0x18,0x28,0x39,0x43,
+ 0x56,0x0a,0x19,0x29,0x3a,0x3d,
+ 0x57,0x0b,0x1a,0x2a,0x3b,0x2d,
+ 0x58,0x0c,0x1b,0x2b,0x40,0x1d,
+ 0x59,0x0d,0x44,0x46,0x41,0x0f,
+ 0x5f,0x4c,0x4f,0x4e,0x4d,0x4a
+};
+
+static void key_to_matrix(uae_u8 code)
+{
+ uae_u8 c = code >> 1;
+ if (code & 1) {
+ matrix[c] = 0;
+ if (kb_mcu_log & 1) {
+ write_log("release %02x\n", c);
+ }
+ } else {
+ matrix[c] = 1;
+ if (kb_mcu_log & 1) {
+ write_log("press %02x\n", c);
+ }
+ }
+}
+
+// This should be in CIA emulation but it is simpler to have it here.
+static void get_kbit(bool v)
+{
+ if (kbhandshake && !fakemode) {
+ return;
+ }
+ kbdata <<= 1;
+ kbdata |= (v ? 1 : 0);
+ kbdatacnt++;
+ if (kbdatacnt >= 8) {
+ kbdatacnt = 0;
+ if (kb_mcu_log & 1) {
+ uae_u8 code = (kbdata >> 1) | (kbdata << 7);
+ write_log("got keycode %02x\n", code ^ 0xff);
+ }
+ if (fakemode) {
+ fakemode = 10000;
+ } else {
+ cia_keyreq(kbdata);
+ }
+ }
+}
+
+static void keymcu_irq(void)
+{
+ if (mcu_io[0x12] & mcu_io[0x13] & (0x80 | 0x40 | 0x20)) {
+ if (kb_mcu_log & 2) {
+ write_log("%04x %04x IRQ %02x\n", mcu_wd, ctx.reg_pc, mcu_io[0x12] & mcu_io[0x13]);
+ }
+ m68_set_interrupt_line(&ctx, M68_INT_TIMER1);
+ }
+}
+
+static void check_input_capture(uae_u8 v)
+{
+ if ((v & 0x01) == ((mcu_io[0x12] >> 1) & 1) && !mcu_input_capture_latch) {
+ mcu_io[0x14] = mcu_io[0x18];
+ mcu_io[0x15] = mcu_io[0x19];
+ mcu_io[0x13] |= 1 << 7; // INPUT CAPTURE
+ keymcu_irq();
+ }
+}
+
+static uae_u8 mcu_io_read(int addr)
+{
+ uint8_t v = mcu_io[addr];
+
+ if (kb_mcu_log & 2) {
+ write_log("%04x IOR %04x = %02x\n", ctx.reg_pc, addr, v);
+ }
+
+ switch (addr)
+ {
+ case 0x13: // Read STATUS
+ mcu_status_read |= v;
+ break;
+ case 0x14: // INPUT CAPTURE HIGH
+ mcu_input_capture_latch = true;
+ break;
+ case 0x15: // Reset INPUT CAPTURE LOW
+ mcu_input_capture_latch = false;
+ if (mcu_status_read & (1 << 7)) {
+ mcu_status_read &= ~(1 << 7);
+ mcu_io[0x13] &= ~(1 << 7);
+ }
+ break;
+ case 0x17: // Reset OUTPUT COMPARE LOW
+ if (mcu_status_read & (1 << 6)) {
+ mcu_status_read &= ~(1 << 6);
+ mcu_io[0x13] &= ~(1 << 6);
+ }
+ break;
+ case 0x18: // TIMER HIGH
+ mcu_timer_latch_low = mcu_io[0x19];
+ mcu_timer_latched = true;
+ break;
+ case 0x19: // Reset TIMER LOW
+ if (mcu_timer_latched) {
+ mcu_timer_latched = false;
+ v = mcu_timer_latch_low;
+ }
+ if (mcu_status_read & (1 << 5)) {
+ mcu_status_read &= ~(1 << 5);
+ mcu_io[0x13] &= ~(1 << 5);
+ }
+ break;
+ case 0x1a: // ALT TIMER HIGH
+ mcu_timer_latch_low = mcu_io[0x19];
+ mcu_timer_latched = true;
+ v = mcu_io[0x18];
+ break;
+ case 0x1b: // ALT TIMER LOW
+ if (mcu_timer_latched) {
+ mcu_timer_latched = false;
+ v = mcu_timer_latch_low;
+ } else {
+ v = mcu_io[0x19];
+ }
+ break;
+
+ case 1: // PORTB: KDAT=0,KCLK=1,2-7 = Matrix column read
+ {
+ v &= ~3;
+ if (kbhandshake || fakemode > 1) {
+ v |= 2;
+ } else {
+ v |= 3;
+ }
+ // Pullups in key lines
+ v |= 0x80 | 0x40 | 0x20 | 0x10 | 0x08 | 0x04;
+
+ // row is PORTA + PORTC
+ int row = mcu_io[0] | ((mcu_io[2] & 0x3f) << 8) | ((mcu_io[2] & 0x80) << 7);
+
+ if (!currprefs.keyboard_nkro) {
+ // matrix without diodes
+ for (int i = 0; i < 15; i++) {
+ if (!(row & (1 << i))) {
+ const uae_u8 *mr = matrixkeys + i * 6;
+ for (int j = 0; j < 6; j++) {
+ if (matrix[mr[j]]) {
+ for(int ii = 0; ii < 15; ii++) {
+ if ((row & (1 << ii)) && ii != i) {
+ const uae_u8 *mr2 = matrixkeys + ii * 6;
+ if (matrix[mr2[j]]) {
+ row &= ~(1 << ii);
+ i = -1;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < 15; i++) {
+ if (!(row & (1 << i))) {
+ const uae_u8 *mr = matrixkeys + i * 6;
+ for (int j = 0; j < 6; j++) {
+ if (matrix[mr[j]]) {
+ v &= ~(4 << j);
+ }
+ }
+ }
+ }
+
+ v &= ~mcu_io[addr + 4];
+ v |= mcu_io[addr] & mcu_io[addr + 4];
+ }
+ break;
+ case 3: // PORTD: RSHIFT=0,RALT=1,RAMIGA=2,CTRL=3,LSHIFT=4,LALT=5,LAMIGA=7
+ {
+ v |= ~0x40; // Pullups in all key lines
+ if (matrix[0x61]) {
+ v &= ~0x01;
+ }
+ if (matrix[0x65]) {
+ v &= ~0x02;
+ }
+ if (matrix[0x67]) {
+ v &= ~0x04;
+ }
+ if (matrix[0x63]) {
+ v &= ~0x08;
+ }
+ if (matrix[0x60]) {
+ v &= ~0x10;
+ }
+ if (matrix[0x64]) {
+ v &= ~0x20;
+ }
+ if (matrix[0x66]) {
+ v &= ~0x80;
+ }
+ }
+ break;
+ case 0: // PORTA
+ case 2: // PORTC
+ v &= ~mcu_io[addr + 4];
+ v |= mcu_io[addr] & mcu_io[addr + 4];
+ break;
+ }
+
+ return v;
+}
+
+static void check_porta(uint16_t addr, uae_u8 old, uae_u8 vv)
+{
+ // PA0 (KDAT)
+ if ((old & 0x01) != (vv & 0x01)) {
+ if (kb_mcu_log & 1) {
+ write_log("KDAT=%d KCLK=%d HS=%d CNT=%d PC=%04x\n", (vv & 0x01) != 0, (vv & 0x02) != 0, kbhandshake, kbdatacnt, ctx.reg_pc);
+ }
+ check_input_capture(vv);
+ }
+ // PA1 (KCLK)
+ if ((old & 0x02) != (vv & 0x02)) {
+ if (kb_mcu_log & 1) {
+ write_log("KCLK=%d KDAT=%d HS=%d CNT=%d PC=%04x\n", (vv & 0x02) != 0, (vv & 0x01) != 0, kbhandshake, kbdatacnt, ctx.reg_pc);
+ }
+ if ((vv & 0x02) && (mcu_io[addr + 4] & 2)) {
+ get_kbit((vv & 0x01) != 0);
+ }
+ }
+}
+
+static void mcu_io_write(uint16_t addr, uae_u8 v)
+{
+
+ if (kb_mcu_log & 2) {
+ write_log("%04x IOW %04x = %02x\n", ctx.reg_pc, addr, v);
+ }
+
+ switch (addr)
+ {
+ case 0x16: // OUTPUT COMPARE HIGH
+ mcu_output_compare_latch = true;
+ mcu_io[addr] = v;
+ break;
+ case 0x17: // Reset OUTPUT COMPARE LOW
+ mcu_output_compare_latch = false;
+ if (mcu_status_read & (1 << 6)) {
+ mcu_status_read &= ~(1 << 6);
+ mcu_io[0x13] &= ~(1 << 6);
+ }
+ mcu_io[addr] = v;
+ break;
+ case 0x12: // TIMER CONTROL
+ v &= (0x80 | 0x40 | 0x20 | 0x02 | 0x01);
+ mcu_io[addr] = v;
+ keymcu_irq();
+ break;
+
+ case 3: // PORTD
+ mcu_io[addr] = v;
+ break;
+ case 2: // PORTC
+ // bit7 = CAPS LED
+ if (mcu_caps_led != ((v & 0x80) != 0)) {
+ mcu_caps_led = (v & 0x80) != 0;
+ gui_data.capslock = mcu_caps_led == 0;
+ if (!fakemode) {
+ gui_led(LED_CAPS, gui_data.capslock, -1);
+ }
+ if (kb_mcu_log & 1) {
+ write_log("KBMCU: CAPS = %d\n", mcu_caps_led);
+ }
+ }
+ mcu_io[addr] = v;
+ break;
+ case 0: // PORTA
+ mcu_io[addr] = v;
+ break;
+ case 1: // PORTB
+ {
+ uae_u8 vv = v;
+ if (kbhandshake || fakemode > 1) {
+ vv &= ~1;
+ }
+ // if input mode: external pullup -> 1
+ if (!(mcu_io[addr + 4] & 1) && !(vv & 1)) {
+ vv |= 1;
+ }
+ if (!(mcu_io[addr + 4] & 2) && !(vv & 2)) {
+ vv |= 2;
+ }
+ check_porta(addr, mcu_io[addr], vv);
+ mcu_io[addr] = v;
+ }
+ break;
+ case 5: // PORTB data direction
+ {
+ uae_u8 dv = mcu_io[addr - 4];
+ uae_u8 olddc = mcu_io[addr];
+ // if input mode: external pullup -> 1
+ if (!(v & 1) && !(dv & 1)) {
+ dv |= 1;
+ }
+ if (!(v & 2) && !(dv & 2)) {
+ dv |= 2;
+ }
+ check_porta(addr, mcu_io[addr - 4], dv);
+ mcu_io[addr] = v;
+ }
+ break;
+ // read only registers
+ case 0x13:
+ case 0x14:
+ case 0x15:
+ case 0x18:
+ case 0x19:
+ case 0x1a:
+ case 0x1b:
+ break;
+ default:
+ mcu_io[addr] = v;
+ break;
+ }}
+
+static uint8_t readfunc(struct M68_CTX* ctx, const uint16_t addr)
+{
+ uint8_t v = 0;
+ uint16_t a = addr & 0x1fff;
+ if (a < 0x20) {
+ v = mcu_io_read(addr);
+ } else if (a >= 0x20 && a < 0x30 && mcu_ram0) {
+ v = 0xff;
+ } else if (a >= 0x50 && a < 0x100) {
+ v = mcu_ram[a - 0x30];
+ // RAM fault
+ if ((mcu_flags & 3) == 2) {
+ if (a == 0x80) {
+ v ^= 0x55;
+ }
+ }
+ } else if (a >= 0x30 && a < 0x50 && mcu_ram0) {
+ v = mcu_ram[a - 0x30];
+ } else if (a >= 0x20 && a < 0x30 && !mcu_ram0) {
+ v = mcu_rom[a];
+ } else if (a >= 0x40 && a < 0x50) {
+ v = mcu_rom[a];
+ } else if (a >= 0x100 && a < 0x160 && mcu_ram1) {
+ v = mcu_ram[a - 0x30];
+ } else if (a == 0x1fdf) {
+ v = mcu_option;
+ } else if (a >= 0x100) {
+ v = mcu_rom[a];
+ // ROM fault
+ if ((mcu_flags & 3) == 1) {
+ if (a == 0x100) {
+ v ^= 0x55;
+ }
+ }
+ }
+ return v;
+}
+
+void writefunc(struct M68_CTX *ctx, const uint16_t addr, const uint8_t data)
+{
+ uint16_t a = addr & 0x1fff;
+ if (a < 0x20) {
+ mcu_io_write(addr, data);
+ } else if (a == 0x1fdf) {
+ mcu_option = data;
+ mcu_ram0 = (data & 0x80) != 0;
+ mcu_ram1 = (data & 0x40) != 0;
+ } else if (a == 0x1ff0) {
+ if (!(data & 1)) {
+ mcu_wd = 0;
+ }
+ } else if (a >= 0x30 && a < 0x50 && mcu_ram0) {
+ mcu_ram[a - 0x30] = data;
+ } else if (a >= 0x50 && a < 0x100) {
+ mcu_ram[a - 0x30] = data;
+ } else if (a >= 0x100 && a < 0x160 && mcu_ram1) {
+ mcu_ram[a - 0x30] = data;
+ }
+}
+
+static void keymcu_res(void)
+{
+ m68_reset(&ctx);
+ ctx.irq = (mcu_flags & 4) == 0;
+ mcu_wd = 0;
+ mcu_res = 0;
+ mcu_input_capture_latch = false;
+ mcu_output_compare_latch = false;
+ mcu_io[0] = 0;
+ mcu_io[1] = 0;
+ mcu_io[2] = 0;
+ mcu_io[3] = 0;
+ mcu_io[4] = 0;
+ mcu_io[5] = 0;
+ mcu_io[6] = 0;
+ mcu_option = (0x02 | 0x08);
+ mcu_io[0x0a] = 0;
+ mcu_io[0x0b] = 0;
+ mcu_io[0x12] = 0;
+ mcu_io[0x13] = 0;
+ mcu_io[0x18] = 0xff;
+ mcu_io[0x19] = 0xfc;
+}
+
+static void dec_counter(void)
+{
+ mcu_dec_ps++;
+ if ((mcu_dec_ps & 3) == 0) {
+ mcu_wd++;
+ // WD TIMER fault
+ if ((mcu_flags & 3) == 3) {
+ mcu_wd = 0;
+ }
+ if (mcu_wd >= 32768) {
+ bool res = mcu_res < 0;
+ keymcu_res();
+ if (kb_mcu_log & 1) {
+ write_log("KBMCU WD reset\n");
+ }
+ if (res) {
+ mcu_res = 1;
+ }
+ return;
+ }
+ if (mcu_res > 0) {
+ mcu_res++;
+ if (mcu_res >= 128) {
+ write_log("Keyboard MCU generated system reset\n");
+ inputdevice_do_kb_reset();
+ keymcu_res();
+ return;
+ }
+ }
+ mcu_io[0x19]++;
+ if (mcu_io[0x19] == 0x00) {
+ mcu_io[0x18]++;
+ if (mcu_io[0x18] == 0x00) {
+ mcu_io[0x13] |= 1 << 5; // TIMER OVERFLOW
+ keymcu_irq();
+ }
+ }
+ if (mcu_io[0x19] == mcu_io[0x17] && mcu_io[0x18] == mcu_io[0x16] && !mcu_output_compare_latch) {
+ mcu_io[0x13] |= 1 << 6; // OUTPUT COMPARE
+ keymcu_irq();
+ if ((mcu_io[0x12] & 1) == 0) {
+ if (mcu_res < 0) {
+ // KB_RESET active
+ mcu_res = 1;
+ if (kb_mcu_log & 1) {
+ write_log("KBMCU KB_RESET ACTIVE\n");
+ }
+ }
+ } else {
+ if (mcu_res > 0) {
+ if (kb_mcu_log & 1) {
+ write_log("KBMCU KB_RESET INACTIVE\n");
+ }
+ }
+ mcu_res = -1;
+ }
+ }
+ }
+}
+
+void keymcu2_reset(void)
+{
+ if (currprefs.keyboard_mode == KB_A1200_6805) {
+ if (!state_loaded) {
+ memset(mcu_ram, 0, sizeof mcu_ram);
+ memset(mcu_io, 0, sizeof mcu_io);
+ memset(matrix, 0, sizeof matrix);
+ kbhandshake = false;
+ mcu_option = 0;
+ mcu_wd = 0;
+ mcu_res = 0;
+ }
+ rom_loaded = false;
+
+ memset(mcu_rom, 0, sizeof mcu_rom);
+ struct zfile *zf = NULL;
+ const TCHAR *path = NULL;
+ struct boardromconfig *brc = get_device_rom_new(&currprefs, ROMTYPE_KBMCU, 0, NULL);
+ if (brc) {
+ mcu_flags = brc->roms[0].device_settings;
+ if (brc->roms[0].romfile[0]) {
+ path = brc->roms[0].romfile;
+ zf = zfile_fopen(path, _T("rb"));
+ }
+ }
+ if (!zf) {
+ int ids[] = { 322, -1 };
+ struct romlist *rl = getromlistbyids(ids, NULL);
+ if (rl) {
+ path = rl->path;
+ zf = read_rom(rl->rd);
+ }
+ }
+ if (zf) {
+ zfile_fread(mcu_rom, sizeof(mcu_rom), 1, zf);
+ zfile_fclose(zf);
+ write_log(_T("Loaded 6805 KB MCU ROM '%s'\n"), path);
+ rom_loaded = true;
+ } else {
+ write_log(_T("Failed to load 6805 KB MCU ROM\n"));
+ }
+ if (state_loaded) {
+ gui_data.capslock = mcu_caps_led == 0;
+ } else {
+ keymcu_res();
+ if (isrestore()) {
+ // if loading statefile without keyboard state: execute MCU code until init phase is done
+ fakemode = 1;
+ uint64_t cycleCount = 0;
+ for (int i = 0; i < 1000000; i++) {
+ uint64_t cyc = m68_exec_cycle(&ctx);
+ while (cyc > 0) {
+ dec_counter();
+ cyc--;
+ }
+ if (fakemode > 1) {
+ fakemode--;
+ if (fakemode == 1) {
+ check_input_capture(0);
+ check_input_capture(1);
+ }
+ }
+ }
+ fakemode = 0;
+ }
+ lastcycle = get_cycles();
+ }
+ }
+ state_loaded = false;
+}
+
+void keymcu2_free(void)
+{
+ state_loaded = false;
+}
+
+void keymcu2_init(void)
+{
+ ctx.read_mem = &readfunc;
+ ctx.write_mem = &writefunc;
+ ctx.opdecode = NULL;
+ m68_init(&ctx, M68_CPU_HC05C4);
+ keymcu_reset();
+ state_loaded = false;
+}
+
+bool keymcu2_run(bool handshake)
+{
+ if (currprefs.keyboard_mode == KB_A1200_6805 && rom_loaded) {
+ bool hs = kbhandshake;
+ kbhandshake = handshake;
+ if (!handshake && hs) {
+ if (kb_mcu_log & 1) {
+ write_log("handshake off\n");
+ }
+ check_input_capture(1);
+ kbdatacnt = 0;
+ } else if (handshake && !hs) {
+ if (kb_mcu_log & 1) {
+ write_log("handshake on\n");
+ }
+ check_input_capture(0);
+ kbdatacnt = 0;
+ }
+ evt_t c = get_cycles();
+ int m = CYCLE_UNIT * (currprefs.ntscmode ? 3579545 : 3546895) / 1500000;
+ int cycles = (c - lastcycle) / m;
+ lastcycle += cycles * m;
+ while (cycles > 0) {
+ uint64_t cyc = m68_exec_cycle(&ctx);
+ cycles -= cyc;
+ while (cyc > 0) {
+ dec_counter();
+ cyc--;
+ }
+ }
+ }
+ while (keys_available()) {
+ uae_u8 kbcode = get_next_key();
+ key_to_matrix(kbcode);
+ }
+ return kbdatacnt >= 3;
+}
+
+#ifdef SAVESTATE
+
+uae_u8 *save_kbmcu2(size_t *len, uae_u8 *dstptr)
+{
+ if (currprefs.keyboard_mode != KB_A1200_6805) {
+ return NULL;
+ }
+
+ uae_u8 *dstbak, *dst;
+ if (dstptr) {
+ dstbak = dst = dstptr;
+ } else {
+ dstbak = dst = xmalloc(uae_u8, 1000 + sizeof(mcu_ram) + sizeof(mcu_io) + sizeof(matrix));
+ }
+
+ save_u32(1);
+ save_u32((kbhandshake ? 1 : 0) | (ctx.is_stopped ? 2 : 0) | (ctx.is_waiting ? 4 : 0) |
+ (mcu_timer_latched ? 8 : 0) | (mcu_input_capture_latch ? 0x10 : 0) | (mcu_output_compare_latch ? 0x20 : 0) |
+ (mcu_caps_led ? 0x40 : 0));
+ save_u32(mcu_wd);
+ save_u8(kbdata);
+ save_u8(kbdatacnt);
+ save_u64(lastcycle);
+ save_u32(mcu_res);
+ save_u8(mcu_option);
+ save_u8(mcu_status_read);
+ save_u8(mcu_dec_ps);
+ save_u8(mcu_timer_latch_low);
+ for (int i = 0; i < sizeof(mcu_ram); i++) {
+ save_u8(mcu_ram[i]);
+ }
+ for (int i = 0; i < sizeof(mcu_io); i++) {
+ save_u8(mcu_io[i]);
+ }
+ for (int i = 0; i < sizeof(matrix); i++) {
+ save_u8(matrix[i]);
+ }
+ save_u8(ctx.reg_acc);
+ save_u8(ctx.reg_x);
+ save_u16(ctx.reg_pc);
+ save_u16(ctx.pc_next);
+ save_u16(ctx.reg_sp);
+ save_u8(ctx.reg_ccr);
+ save_u8(ctx.pending_interrupts);
+
+ *len = dst - dstbak;
+ return dstbak;
+}
+
+uae_u8* restore_kbmcu2(uae_u8 *src)
+{
+ if (currprefs.keyboard_mode != KB_A1200_6805) {
+ return NULL;
+ }
+
+ int v = restore_u32();
+ if (!(v & 1)) {
+ return NULL;
+ }
+
+ uae_u32 flags = restore_u32();
+ kbhandshake = flags != 0;
+ ctx.is_stopped = (flags & 2) != 0;
+ ctx.is_waiting = (flags & 4) != 0;
+ mcu_timer_latched = (flags & 8) != 0;
+ mcu_input_capture_latch = (flags & 0x10) != 0;
+ mcu_output_compare_latch = (flags & 0x20) != 0;
+ mcu_caps_led = (flags & 0x40) != 0;
+ mcu_wd = restore_u32();
+ kbdata = restore_u8();
+ kbdatacnt = restore_u8();
+ lastcycle = restore_u64();
+ mcu_res = restore_u32();
+ mcu_option = restore_u8();
+ mcu_status_read = restore_u8();
+ mcu_dec_ps = restore_u8();
+ mcu_timer_latch_low = restore_u8();
+ for (int i = 0; i < sizeof(mcu_ram); i++) {
+ mcu_ram[i] = restore_u8();
+ }
+ for (int i = 0; i < sizeof(mcu_io); i++) {
+ mcu_io[i] = restore_u8();
+ }
+ for (int i = 0; i < sizeof(matrix); i++) {
+ matrix[i] = restore_u8();
+ }
+ ctx.reg_acc = restore_u8();
+ ctx.reg_x = restore_u8();
+ ctx.reg_pc = restore_u16();
+ ctx.pc_next = restore_u16();
+ ctx.reg_sp = restore_u16();
+ ctx.reg_ccr = restore_u8();
+ ctx.pending_interrupts = restore_u8();
+
+ state_loaded = true;
+
+ return src;
+}
+
+#endif
\ No newline at end of file
--- /dev/null
+/*
+* UAE - The Un*x Amiga Emulator
+*
+* Keyboard MCU emulation (D8039HLC, A2000 Cherry)
+*
+* Copyright 2024 Toni Wilen
+*/
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "options.h"
+#include "rommgr.h"
+#include "zfile.h"
+#include "events.h"
+#include "keyboard_mcu.h"
+#include "keybuf.h"
+#include "inputdevice.h"
+#include "gui.h"
+#include "savestate.h"
+#include "8048/co8048.h"
+
+extern int kb_mcu_log;
+
+static uae_u8 mcu_rom[2048];
+static uae_u8 mcu_io[2];
+static uae_u8 matrix[128];
+static ATCoProc8048 *mcu;
+static bool state_loaded;
+static bool mcu_caps_led;
+static bool rom_loaded;
+static bool kbhandshake;
+static uae_u8 kbdata, kbdatacnt;
+static evt_t lastcycle;
+static evt_t kclk_reset_start;
+static int fakemode;
+static uae_u32 mcu_wd;
+static bool mcu_t0;
+static int mcu_flags;
+
+// 13x8 matrix
+static const uae_u8 matrixkeys[] = {
+ 0x55,0x59,0x0A,0x06,0x36,0x25,0x19,0x15,
+ 0x52,0x41,0xFF,0x05,0x35,0x24,0x44,0x14,
+ 0x51,0xFF,0xFF,0x02,0x32,0x21,0xFF,0x11,
+ 0x45,0xFF,0x30,0x01,0x31,0x20,0x62,0x10,
+ 0x54,0xFF,0x40,0x03,0x33,0x22,0x65,0x12,
+ 0x5D,0x5C,0x3F,0x4A,0x43,0x1F,0x5E,0x2F,
+ 0x5A,0x5B,0x3E,0x3D,0x1E,0x1D,0x2E,0x2D,
+ 0x50,0xFF,0x64,0x00,0x60,0x63,0x66,0x42,
+ 0x5F,0x46,0x4C,0x4E,0x3C,0x0F,0x4F,0x4D,
+ 0x57,0xFF,0x3A,0x07,0x37,0x26,0x29,0x16,
+ 0x58,0x0B,0x1A,0x09,0x39,0x28,0x2A,0x18,
+ 0x56,0x0C,0x1B,0x08,0x38,0x27,0x2B,0x17,
+ 0x53,0x0D,0x67,0x04,0x34,0x23,0x61,0x13
+};
+
+static void key_to_matrix(uae_u8 code)
+{
+ uae_u8 c = code >> 1;
+ if (code & 1) {
+ matrix[c] = 0;
+ if (kb_mcu_log & 1) {
+ write_log("release %02x\n", c);
+ }
+ } else {
+ matrix[c] = 1;
+ if (kb_mcu_log & 1) {
+ write_log("press %02x\n", c);
+ }
+ }
+}
+
+// This should be in CIA emulation but it is simpler to have it here.
+static void get_kbit(bool v)
+{
+ if (kbhandshake && !fakemode) {
+ return;
+ }
+ kbdata <<= 1;
+ kbdata |= (v ? 1 : 0);
+ kbdatacnt++;
+ if (kbdatacnt >= 8) {
+ kbdatacnt = 0;
+ if (kb_mcu_log & 1) {
+ uae_u8 code = (kbdata >> 1) | (kbdata << 7);
+ write_log("got keycode %02x\n", code ^ 0xff);
+ }
+ if (fakemode) {
+ mcu->AssertIrq();
+ fakemode = 10000;
+ } else {
+ cia_keyreq(kbdata);
+ }
+ }
+}
+
+void mpFnWritePort(int p, uint8 v)
+{
+ if (kb_mcu_log & 2) {
+ write_log("%04x write port %d = %02x\n", mcu->GetPC(), p, v);
+ }
+
+ uae_u8 o = mcu_io[p];
+ if (p == 1) {
+
+ if (mcu_caps_led != ((v & 0x20) != 0)) {
+ mcu_caps_led = (v & 0x20) != 0;
+ gui_data.capslock = mcu_caps_led == 0;
+ if (!fakemode) {
+ gui_led(LED_CAPS, gui_data.capslock, -1);
+ }
+
+ if (kb_mcu_log & 1) {
+ write_log("KBMCU: CAPS = %d\n", mcu_caps_led);
+ }
+ }
+
+ if ((o ^ v) & 0x80) {
+ if (v & 0x80) {
+ get_kbit(((o & 0x40) ? 1 : 0) != 0);
+ kclk_reset_start = 0;
+ } else {
+ if (currprefs.cs_resetwarning) {
+ kclk_reset_start = get_cycles() + CYCLE_UNIT * 1800000;
+ }
+ }
+
+ if (kb_mcu_log & 1) {
+ write_log("KCLK = %d\n", (v & 0x80) != 0);
+ }
+ }
+ if ((o ^ v) & 0x40) {
+ if (kb_mcu_log & 1) {
+ write_log("KDAT = %d\n", (v & 0x40) != 0);
+ }
+ }
+ }
+
+ //write_log("%04x write port %02x %02x\n", mcu->GetPC(), mcu_io[0], mcu_io[1]);
+
+ mcu_io[p] = v;
+}
+void mpFnWriteBus(uint8 v)
+{
+ write_log("%04x write bus = %02x\n", mcu->GetPC(), v);
+}
+uint8 mpFnReadBus(void)
+{
+ uint8 v = 0;
+
+ uint8 io2 = mcu_io[1];
+ int row = mcu_io[0];
+ if (io2 & 1) {
+ row |= 0x1000;
+ }
+ if (io2 & 2) {
+ row |= 0x0800;
+ }
+ if (io2 & 4) {
+ row |= 0x0400;
+ }
+ if (io2 & 8) {
+ row |= 0x0200;
+ }
+ if (io2 & 0x10) {
+ row |= 0x0100;
+ }
+
+ for (int i = 0; i < 13; i++) {
+ if ((row & (1 << i))) {
+ const uae_u8 *mr = matrixkeys + i * 8;
+ for (int j = 0; j < 8; j++) {
+ if (mr[j] < 0x80) {
+ if (matrix[mr[j]]) {
+ v |= 1 << j;
+ }
+ }
+ }
+ }
+ }
+
+ if (kb_mcu_log & 2) {
+ write_log("%04x read bus = %02x\n", mcu->GetPC(), v);
+ }
+
+ return v;
+}
+uint8 mpFnReadPort(int p, uint8 vv)
+{
+ uint8 v = mcu_io[p];
+
+ if (kb_mcu_log & 2) {
+ write_log("%04x read port %d = %02x\n", mcu->GetPC(), p, v);
+ }
+ return v;
+}
+uint8 mpFnReadT0(void)
+{
+ uint8 v = 0;
+ if (kb_mcu_log & 2) {
+ write_log("%04x read T0 = %02x\n", mcu->GetPC(), v);
+ }
+ return v;
+}
+uint8 mpFnReadT1(void)
+{
+ uint8 v = 0;
+ if (kb_mcu_log & 2) {
+ write_log("%04x read T1 = %02x\n", mcu->GetPC(), v);
+ }
+ return v;
+}
+
+static void keymcu_res(void)
+{
+ mcu->ColdReset();
+ mcu->NegateIrq();
+ kclk_reset_start = 0;
+}
+
+void keymcu3_reset(void)
+{
+ if (currprefs.keyboard_mode == KB_A2000_8039) {
+ if (!state_loaded) {
+ memset(mcu_io, 0xff, sizeof mcu_io);
+ memset(matrix, 0, sizeof matrix);
+ kbhandshake = false;
+ }
+ rom_loaded = false;
+
+ memset(mcu_rom, 0, sizeof mcu_rom);
+ struct zfile *zf = NULL;
+ const TCHAR *path = NULL;
+ struct boardromconfig *brc = get_device_rom_new(&currprefs, ROMTYPE_KBMCU, 0, NULL);
+ if (brc) {
+ mcu_flags = brc->roms[0].device_settings;
+ if (brc->roms[0].romfile[0]) {
+ path = brc->roms[0].romfile;
+ zf = zfile_fopen(path, _T("rb"));
+ }
+ }
+ if(!zf) {
+ int ids[] = { 323, -1 };
+ struct romlist *rl = getromlistbyids(ids, NULL);
+ if (rl) {
+ path = rl->path;
+ zf = read_rom(rl->rd);
+ }
+ }
+ if (zf) {
+ zfile_fread(mcu_rom, sizeof(mcu_rom), 1, zf);
+ zfile_fclose(zf);
+ write_log(_T("Loaded 8039 KB MCU ROM '%s'\n"), path);
+ rom_loaded = true;
+ } else {
+ write_log(_T("Failed to load 8039 KB MCU ROM\n"));
+ }
+ if (state_loaded) {
+ gui_data.capslock = mcu_caps_led == 0;
+ } else {
+ keymcu_res();
+ if (isrestore()) {
+ // if loading statefile without keyboard state: execute MCU code until init phase is done
+ fakemode = 1;
+ for (int i = 0; i < 3000000; i++) {
+ mcu->AddCycles(1);
+ mcu->Run();
+ if (fakemode > 1) {
+ fakemode--;
+ if (fakemode == 1) {
+ mcu->NegateIrq();
+ }
+ }
+ }
+ fakemode = 0;
+ }
+ }
+ lastcycle = get_cycles();
+ }
+ state_loaded = false;
+}
+
+void keymcu3_free(void)
+{
+ delete mcu;
+ mcu = NULL;
+ state_loaded = false;
+}
+
+void keymcu3_init(void)
+{
+ mcu = new ATCoProc8048();
+ mcu->ColdReset();
+ mcu->SetProgramBanks(mcu_rom, mcu_rom);
+ keymcu_reset();
+ state_loaded = false;
+}
+
+bool keymcu3_run(bool handshake)
+{
+ if (currprefs.keyboard_mode == KB_A2000_8039 && rom_loaded) {
+ bool hs = kbhandshake;
+ kbhandshake = handshake;
+ if (!handshake && hs) {
+ if (kb_mcu_log & 1) {
+ write_log("handshake off\n");
+ }
+ kbdatacnt = 0;
+ mcu->NegateIrq();
+ } else if (handshake && !hs) {
+ if (kb_mcu_log & 1) {
+ write_log("handshake on\n");
+ }
+ kbdatacnt = 0;
+ mcu->AssertIrq();
+ }
+ evt_t c = get_cycles();
+ int m = CYCLE_UNIT * (currprefs.ntscmode ? 3579545 : 3546895) / (6000000 / (5 * 3));
+ int cycles = (c - lastcycle) / m;
+ lastcycle += cycles * m;
+ mcu->AddCycles(cycles);
+ mcu->Run();
+ if (kclk_reset_start > 0 && kclk_reset_start < c) {
+ write_log("Keyboard MCU system reset\n");
+ inputdevice_do_kb_reset();
+ }
+ }
+ while (keys_available()) {
+ uae_u8 kbcode = get_next_key();
+ key_to_matrix(kbcode);
+ }
+ return kbdatacnt >= 3;
+}
+
+#ifdef SAVESTATE
+
+uae_u8 *save_kbmcu3(size_t *len, uae_u8 *dstptr)
+{
+ if (currprefs.keyboard_mode != KB_A2000_8039) {
+ return NULL;
+ }
+
+ uae_u8 *dstbak, *dst;
+ if (dstptr) {
+ dstbak = dst = dstptr;
+ } else {
+ dstbak = dst = xmalloc(uae_u8, 1000 + 128 + sizeof(mcu_io) + sizeof(matrix));
+ }
+
+ save_u32(1);
+ save_u32((kbhandshake ? 1 : 0) | (mcu->mbTimerActive ? 2 : 0) | (mcu->mbIrqAttention ? 4 : 0) |
+ (mcu->mbIrqEnabled ? 8 : 0) | (mcu->mbF1 ? 16 : 0) | (mcu->mbTF ? 32 : 0) |
+ (mcu->mbIF ? 64 : 0) | (mcu->mbPBK ? 128 : 0) | (mcu->mbDBF ? 256 : 0) |
+ (mcu->mbIrqPending ? 512 : 0) | (mcu->mbTimerIrqPending ? 1024 : 0));
+ save_u32(mcu_wd);
+ save_u8(kbdata);
+ save_u8(kbdatacnt);
+ save_u64(lastcycle);
+ save_u64(kclk_reset_start);
+ for (int i = 0; i < 128; i++) {
+ save_u8(mcu->mRAM[i]);
+ }
+ for (int i = 0; i < sizeof(mcu_io); i++) {
+ save_u8(mcu_io[i]);
+ }
+ for (int i = 0; i < sizeof(matrix); i++) {
+ save_u8(matrix[i]);
+ }
+ save_u8(mcu->mA);
+ save_u8(mcu->mT);
+ save_u8(mcu->mPSW);
+ save_u16(mcu->mPC);
+ save_u8(mcu->mP1);
+ save_u8(mcu->mP2);
+ save_u8(mcu->mTStatesLeft);
+
+ *len = dst - dstbak;
+ return dstbak;
+}
+
+uae_u8 *restore_kbmcu3(uae_u8* src)
+{
+ if (currprefs.keyboard_mode != KB_A2000_8039) {
+ return NULL;
+ }
+
+ uae_u32 v = restore_u32();
+ if (!(v & 1)) {
+ return src;
+ }
+ v = restore_u32();
+ kbhandshake = v & 1;
+ mcu->mbTimerActive = (v & 2) != 0;
+ mcu->mbIrqAttention = (v & 4) != 0;
+ mcu->mbIrqEnabled = (v & 8) != 0;
+ mcu->mbF1 = (v & 16) != 0;
+ mcu->mbTF = (v & 32) != 0;
+ mcu->mbIF = (v & 64) != 0;
+ mcu->mbPBK = (v & 128) != 0;
+ mcu->mbDBF = (v & 256) != 0;
+ mcu->mbIrqPending = (v & 512) != 0;
+ mcu->mbTimerIrqPending = (v & 1024) != 0;
+ mcu_wd = restore_u32();
+ kbdata = restore_u8();
+ kbdatacnt = restore_u8();
+ lastcycle = restore_u64();
+ kclk_reset_start = restore_u64();
+ for (int i = 0; i < 128; i++) {
+ mcu->mRAM[i] = restore_u8();
+ }
+ for (int i = 0; i < sizeof(mcu_io); i++) {
+ mcu_io[i] = restore_u8();
+ }
+ for (int i = 0; i < sizeof(matrix); i++) {
+ matrix[i] = restore_u8();
+ }
+ mcu->mA = restore_u8();
+ mcu->mT = restore_u8();
+ mcu->mPSW = restore_u8();
+ mcu->mPC = restore_u16();
+ mcu->mP1 = restore_u8();
+ mcu->mP2 = restore_u8();
+ mcu->mTStatesLeft = restore_u8();
+
+ state_loaded = true;
+ return src;
+}
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef M68_INTERNAL_H
+#define M68_INTERNAL_H
+
+#include <stdint.h>
+
+//! Addressing modes
+typedef enum {
+ AMODE_DIRECT,
+ AMODE_DIRECT_REL,
+ AMODE_DIRECT_JUMP,
+ AMODE_EXTENDED,
+ AMODE_EXTENDED_JUMP,
+ AMODE_IMMEDIATE,
+ AMODE_INDEXED0,
+ AMODE_INDEXED0_JUMP,
+ AMODE_INDEXED1,
+ AMODE_INDEXED1_JUMP,
+ AMODE_INDEXED2,
+ AMODE_INDEXED2_JUMP,
+ AMODE_INHERENT,
+ AMODE_INHERENT_A,
+ AMODE_INHERENT_X,
+ AMODE_RELATIVE,
+ AMODE_ILLEGAL,
+ AMODE_MAX
+} M68_AMODE;
+
+
+typedef struct M68_OPTABLE_ENT {
+ char * mnem; /* instruction mnemonic */
+ M68_AMODE amode; /* addressing mode */
+ uint8_t cycles; /* number of cycles to execute */
+ bool write_only; /* is write-only? only supported for direct, extended and indexed */
+ bool (*opfunc)(M68_CTX *ctx, const uint8_t opcode, uint8_t *param); /* opcode exec function */
+} M68_OPTABLE_ENT;
+
+
+extern M68_OPTABLE_ENT m68hc05_optable[256];
+
+// M68HC vector addresses.
+static const uint16_t _M68_RESET_VECTOR = 0xFFFE;
+static const uint16_t _M68_SWI_VECTOR = 0xFFFC;
+static const uint16_t _M68_INT_VECTOR = 0xFFFA;
+static const uint16_t _M68_TMR1_VECTOR = 0xFFF8;
+
+// TODO - need to have an m68_int function which allows vector address to be passed at runtime
+
+void jump_to_vector(M68_CTX *ctx,uint16_t addr);
+
+
+
+/**
+ * Force one or more flag bits to a given state
+ *
+ * @param ctx Emulation context
+ * @param ccr_bits CCR bit map (OR of M68_CCR_x constants)
+ * @param state State to set -- true for set, false for clear
+ */
+static inline void force_flags(M68_CTX *ctx, const uint8_t ccr_bits, const bool state)
+{
+ if (state) {
+ ctx->reg_ccr |= ccr_bits;
+ } else {
+ ctx->reg_ccr &= ~ccr_bits;
+ }
+
+ // Force CCR top 3 bits to 1
+ ctx->reg_ccr |= 0xE0;
+}
+
+/**
+ * Get the state of a CCR flag bit
+ *
+ * @param ctx Emulation context
+ * @param ccr_bits CCR bit (M68_CCR_x constant)
+ */
+static inline bool get_flag(M68_CTX *ctx, const uint8_t ccr_bit)
+{
+ return (ctx->reg_ccr & ccr_bit) ? true : false;
+}
+
+/**
+ * Push a byte onto the stack
+ *
+ * @param ctx Emulation context
+ * @param value Byte to PUSH
+ */
+static inline void push_byte(M68_CTX *ctx, const uint8_t value)
+{
+ ctx->write_mem(ctx, ctx->reg_sp, value);
+ ctx->reg_sp = ((ctx->reg_sp - 1) & ctx->sp_and) | ctx->sp_or;
+}
+
+/**
+ * Pop a byte off of the stack
+ *
+ * @param ctx Emulation context
+ * @return Byte popped off of the stack
+ */
+static inline uint8_t pop_byte(M68_CTX *ctx)
+{
+ ctx->reg_sp = ((ctx->reg_sp + 1) & ctx->sp_and) | ctx->sp_or;
+ return ctx->read_mem(ctx, ctx->reg_sp);
+}
+
+
+
+#endif // M68_INTERNAL_H
--- /dev/null
+#include <assert.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include "m68emu.h"
+#include "m68_internal.h"
+
+
+/****************************************************************************
+ * HELPER FUNCTIONS
+ ****************************************************************************/
+
+/**
+ * Carry flag calculation method selection.
+ *
+ * Instructions calculate the carry flag state in different ways:
+ *
+ * * ADC, ADD: (A7 && M7) || (M7 && !R7) || (!R7 && A7)
+ * * ASL, LSL, ROL: b7
+ * * ASR, LSR, ROR: b0
+ * * BRCLR, BRSET: Mn
+ * * CLC, MUL: 0
+ * * NEG: R != 0
+ * * CMP, CPX*, SBC: (!A7 && M7) || (M7 && R7) || (R7 && !A7)
+ * (* CPX: substitute X7 in place of A7)
+ *
+ * The shift and negation instructions handle carry themselves.
+ * This means update_flags() only needs to implement Add and Subtract carry
+ * logic.
+ *
+ * CARRY_ADD: Addition carry
+ * CARRY_SUB: Subtraction carry
+ * CARRY_UNDEFINED: Raise an assertion failure if this is ever encountered
+ *
+ * We could in theory have CARRY_CLEAR and CARRY_SET in here, but I think it's
+ * preferable to have an explicit force_flags() call for the carry instead of
+ * hiding carry set/clear inside this call.
+ */
+typedef enum {
+ CARRY_ADD,
+ CARRY_SUB,
+ CARRY_UNDEFINED
+} M68_CARRY_TYPE;
+
+/**
+ * Update the CCR flag bits after an arithmetic operation.
+ *
+ * @param ctx Emulation context
+ * @param ccr_bits CCR bit map (OR of M68_CCR_x constants)
+ * @param a Accumulator initial value (or X-register for CPX)
+ * @param m Operation parameter
+ * @param r Operation result
+ */
+static inline void update_flags(M68_CTX *ctx, const uint8_t ccr_bits, const uint8_t a, const uint8_t m, const uint8_t r, const M68_CARRY_TYPE carryMode)
+{
+ // Half Carry
+ if (ccr_bits & M68_CCR_H) {
+ if (( (a & 0x08) && (m & 0x08)) ||
+ ( (m & 0x08) && !(r & 0x08)) ||
+ (!(r & 0x08) && (a & 0x08))) {
+ ctx->reg_ccr |= M68_CCR_H;
+ } else {
+ ctx->reg_ccr &= ~M68_CCR_H;
+ }
+ }
+
+ // Negative
+ if (ccr_bits & M68_CCR_N) {
+ if (r & 0x80) {
+ ctx->reg_ccr |= M68_CCR_N;
+ } else {
+ ctx->reg_ccr &= ~M68_CCR_N;
+ }
+ }
+
+ // Zero
+ if (ccr_bits & M68_CCR_Z) {
+ if (r == 0) {
+ ctx->reg_ccr |= M68_CCR_Z;
+ } else {
+ ctx->reg_ccr &= ~M68_CCR_Z;
+ }
+ }
+
+ // Carry
+ // TODO: Carry is calculated in different ways depending on instruction. Implement the different modes.
+ if (ccr_bits & M68_CCR_C) {
+ bool newCarry;
+ switch (carryMode) {
+ case CARRY_ADD:
+ newCarry =
+ (( (a & 0x80) && (m & 0x80)) ||
+ ( (m & 0x80) && !(r & 0x80)) ||
+ (!(r & 0x80) && (a & 0x80)));
+ break;
+
+ case CARRY_SUB:
+ newCarry =
+ ((!(a & 0x80) && (m & 0x80)) ||
+ ( (m & 0x80) && (r & 0x80)) ||
+ ( (r & 0x80) && !(a & 0x80)));
+ break;
+
+ default:
+ assert(0);
+ }
+
+ if (newCarry) {
+ ctx->reg_ccr |= M68_CCR_C;
+ } else {
+ ctx->reg_ccr &= ~M68_CCR_C;
+ }
+ }
+
+ // Force CCR top 3 bits to 1
+ ctx->reg_ccr |= 0xE0;
+}
+
+
+/****************************************************************************
+ * OPCODE IMPLEMENTATION
+ ****************************************************************************/
+
+/* **
+ * Opcode implementation rules:
+ *
+ * - Branch and jump opcodes (AMODE_RELATIVE, AMODE_*_JUMP)
+ * - Return true to take the branch.
+ * - Return false to continue execution from the next instruction.
+ * - General opcodes
+ * - Return 'true' to write the new value of 'param' back to the source.
+ *
+ * When the opfunc is entered, the PC will point to the next instruction. This
+ * is to make sure the opfunc doesn't need to worry about correcting pushed
+ * return addresses -- which would require a case for every opcode.
+ */
+
+
+/// ADC: Add with carry
+static bool m68op_ADC(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ uint16_t result = ctx->reg_acc + *param + (ctx->reg_ccr & M68_CCR_C ? 1 : 0);
+
+ update_flags(ctx, M68_CCR_H | M68_CCR_N | M68_CCR_Z | M68_CCR_C, ctx->reg_acc, *param, result, CARRY_ADD);
+ ctx->reg_acc = result;
+
+ // Don't write back, affects ACC and flags only
+ return false;
+}
+
+/// ADD: Add
+static bool m68op_ADD(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ uint16_t result = ctx->reg_acc + *param;
+
+ update_flags(ctx, M68_CCR_H | M68_CCR_N | M68_CCR_Z | M68_CCR_C, ctx->reg_acc, *param, result, CARRY_ADD);
+ ctx->reg_acc = result;
+
+ // Don't write back, affects ACC and flags only
+ return false;
+}
+
+/// AND: Logical AND
+static bool m68op_AND(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ uint16_t result = ctx->reg_acc & *param;
+
+ update_flags(ctx, M68_CCR_N | M68_CCR_Z, ctx->reg_acc, *param, result, CARRY_UNDEFINED);
+ ctx->reg_acc = result;
+
+ // Don't write back, affects ACC and flags only
+ return false;
+}
+
+/// ASL: Arithmetic shift left (same as LSL)
+static bool m68op_ASL(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ uint16_t result = (*param << 1) & 0xFE;
+
+ update_flags(ctx, M68_CCR_N | M68_CCR_Z, ctx->reg_acc, *param, result, CARRY_UNDEFINED);
+ force_flags(ctx, M68_CCR_C, *param & 0x80);
+
+ // Result is written back to the source (in-place)
+ *param = result;
+ return true;
+}
+
+/// ASR: Arithmetic shift right
+static bool m68op_ASR(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ uint16_t result = (*param >> 1) | (*param & 0x80);
+
+ update_flags(ctx, M68_CCR_N | M68_CCR_Z, ctx->reg_acc, *param, result, CARRY_UNDEFINED);
+ force_flags(ctx, M68_CCR_C, *param & 1);
+
+ // Result is written back to the source (in-place)
+ *param = result;
+ return true;
+}
+
+/// BCC: Branch carry clear (same as BHS)
+static bool m68op_BCC(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ return (!get_flag(ctx, M68_CCR_C));
+}
+
+/// BCLR: Clear bit in memory
+static bool m68op_BCLR(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ // Extract the bit number from the opcode
+ uint8_t bitnum = (opcode & 0x0F) >> 1;
+
+ *param &= ~(1 << bitnum);
+
+ // Result is written back to the source (in-place)
+ return true;
+}
+
+/// BCS: Branch carry set
+static bool m68op_BCS(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ return (get_flag(ctx, M68_CCR_C));
+}
+
+/// BEQ: Branch if equal
+static bool m68op_BEQ(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ return (get_flag(ctx, M68_CCR_Z));
+}
+
+/// BHCC: Branch if half-carry clear
+static bool m68op_BHCC(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ return (!get_flag(ctx, M68_CCR_H));
+}
+
+/// BHCS: Branch if half-carry set
+static bool m68op_BHCS(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ return (get_flag(ctx, M68_CCR_H));
+}
+
+/// BHI: Branch if higher
+static bool m68op_BHI(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ return (!get_flag(ctx, M68_CCR_C) && !get_flag(ctx, M68_CCR_Z));
+}
+
+// BHS: see BCC
+
+/// BIH: Branch if /IRQ high
+static bool m68op_BIH(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ return (ctx->irq);
+}
+
+/// BIL: Branch if /IRQ low
+static bool m68op_BIL(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ return (!ctx->irq);
+}
+
+/// BIT: Bit test memory with accumulator
+static bool m68op_BIT(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ uint16_t result = ctx->reg_acc & *param;
+
+ update_flags(ctx, M68_CCR_N | M68_CCR_Z, ctx->reg_acc, *param, result, CARRY_UNDEFINED);
+
+ // Don't change the memory or the accumulator
+ return *param;
+}
+
+// BLO: see BCS
+
+/// BLS: Branch if lower or same
+static bool m68op_BLS(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ return (get_flag(ctx, M68_CCR_C) || get_flag(ctx, M68_CCR_Z));
+}
+
+/// BNC: Branch if interrupt mask is clear
+static bool m68op_BMC(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ return (!get_flag(ctx, M68_CCR_I));
+}
+
+/// BMI: Branch if minus
+static bool m68op_BMI(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ return (get_flag(ctx, M68_CCR_N));
+}
+
+/// BMS: Branch if interrupt mask is set
+static bool m68op_BMS(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ return (get_flag(ctx, M68_CCR_I));
+}
+
+/// BNE: Branch if not equal
+static bool m68op_BNE(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ return (!get_flag(ctx, M68_CCR_Z));
+}
+
+/// BPL: Branch if plus
+static bool m68op_BPL(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ return (!get_flag(ctx, M68_CCR_N));
+}
+
+/// BRA: Branch always
+static bool m68op_BRA(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ // Always take the branch
+ return true;
+}
+
+/// BRCLR: Branch if bit clear
+static bool m68op_BRCLR(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ // Extract the bit number from the opcode
+ uint8_t bitnum = (opcode & 0x0F) >> 1;
+
+ // Carry flag is set to the bit state
+ force_flags(ctx, M68_CCR_C, *param & (1 << bitnum) ? 1 : 0);
+
+ return !(*param & (1 << bitnum));
+}
+
+/// BRN: Branch never
+static bool m68op_BRN(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ // Don't take the branch
+ return false;
+}
+
+/// BRSET: Branch if bit set
+static bool m68op_BRSET(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ // Extract the bit number from the opcode
+ uint8_t bitnum = (opcode & 0x0F) >> 1;
+
+ // Carry flag is set to the bit state
+ force_flags(ctx, M68_CCR_C, *param & (1 << bitnum) ? 1 : 0);
+
+ return (*param & (1 << bitnum));
+}
+
+/// BSET: Bit set
+static bool m68op_BSET(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ // Extract the bit number from the opcode
+ uint8_t bitnum = (opcode & 0x0F) >> 1;
+
+ *param |= (1 << bitnum);
+
+ // Result is written back to the source (in-place)
+ return true;
+}
+
+/// BSR: Branch to subroutine
+static bool m68op_BSR(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ // push return address onto stack
+ uint16_t ra = ctx->pc_next;
+ push_byte(ctx, ra & 0xff);
+ push_byte(ctx, (ra >> 8) & 0xff);
+
+ // take the branch
+ return true;
+}
+
+/// CLC: Clear carry
+static bool m68op_CLC(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ force_flags(ctx, M68_CCR_C, 0);
+
+ // Inherent operation, nothing to write back
+ return false;
+}
+
+/// CLI: Clear interrupt mask
+static bool m68op_CLI(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ force_flags(ctx, M68_CCR_I, 0);
+
+ // Inherent operation, nothing to write back
+ return false;
+}
+
+/// CLR: Clear accumulator, X or register
+static bool m68op_CLR(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ force_flags(ctx, M68_CCR_N, 0);
+ force_flags(ctx, M68_CCR_Z, 1);
+
+ // Result is written back to the source (in-place)
+ *param = 0;
+ return true;
+}
+
+/// CMP: Compare accumulator with memory
+static bool m68op_CMP(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ uint8_t result = ctx->reg_acc - *param;
+ update_flags(ctx, M68_CCR_N | M68_CCR_Z | M68_CCR_C, ctx->reg_acc, *param, result, CARRY_SUB);
+
+ // CMP affects flags only, not the parameter or accumulator
+ return false;
+}
+
+/// COM: Complement
+static bool m68op_COM(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ uint8_t result = ~*param;
+ update_flags(ctx, M68_CCR_N | M68_CCR_Z, ctx->reg_acc, *param, result, CARRY_UNDEFINED);
+ force_flags(ctx, M68_CCR_C, 1);
+
+ // Result is written back to the source (in-place)
+ *param = result;
+ return true;
+}
+
+/// CPX: Compare index register with memory
+static bool m68op_CPX(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ uint8_t result = ctx->reg_x - *param;
+ update_flags(ctx, M68_CCR_N | M68_CCR_Z | M68_CCR_C, ctx->reg_x, *param, result, CARRY_SUB);
+
+ // CPX affects flags only, not the parameter or accumulator
+ return false;
+}
+
+/// DEC: Decrement
+static bool m68op_DEC(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ uint8_t result = *param - 1;
+ update_flags(ctx, M68_CCR_N | M68_CCR_Z, ctx->reg_acc, *param, result, CARRY_UNDEFINED);
+
+ // Result is written back to the source (in-place)
+ *param = result;
+ return true;
+}
+
+/// EOR: Exclusive-OR accumulator with memory
+static bool m68op_EOR(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ uint8_t result = ctx->reg_acc ^ *param;
+
+ update_flags(ctx, M68_CCR_N | M68_CCR_Z, ctx->reg_acc, *param, result, CARRY_UNDEFINED);
+ ctx->reg_acc = result;
+
+ // Don't write back, affects ACC and flags only
+ return false;
+}
+
+/// INC: Increment
+static bool m68op_INC(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ uint8_t result = *param + 1;
+ update_flags(ctx, M68_CCR_N | M68_CCR_Z, ctx->reg_acc, *param, result, CARRY_UNDEFINED);
+
+ // Result is written back to the source (in-place)
+ *param = result;
+ return true;
+}
+
+/// JMP: Long jump
+static bool m68op_JMP(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ return true;
+}
+
+/// JSR: Jump subroutine
+static bool m68op_JSR(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ // push return address onto stack
+ uint16_t ra = ctx->pc_next;
+ push_byte(ctx, ra & 0xff);
+ push_byte(ctx, (ra >> 8) & 0xff);
+
+ // take the branch
+ return true;
+}
+
+/// LDA: Load accumulator
+static bool m68op_LDA(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ ctx->reg_acc = *param;
+ update_flags(ctx, M68_CCR_N | M68_CCR_Z, ctx->reg_acc, *param, *param, CARRY_UNDEFINED);
+
+ // Don't write back, affects ACC and flags only
+ return false;
+}
+
+/// LDX: Load index
+static bool m68op_LDX(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ ctx->reg_x = *param;
+ update_flags(ctx, M68_CCR_N | M68_CCR_Z, ctx->reg_acc, *param, *param, CARRY_UNDEFINED);
+
+ // Don't write back, affects X and flags only
+ return false;
+}
+
+/// LSR: Logical shift right
+static bool m68op_LSR(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ uint16_t result = (*param >> 1);
+
+ update_flags(ctx, M68_CCR_Z, ctx->reg_acc, *param, result, CARRY_UNDEFINED);
+ force_flags(ctx, M68_CCR_N, 0);
+ force_flags(ctx, M68_CCR_C, *param & 1);
+
+ // Result is written back to the source (in-place)
+ *param = result;
+ return true;
+}
+
+/// MUL: Multiply
+static bool m68op_MUL(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ uint16_t result = (uint16_t)ctx->reg_x * (uint16_t)ctx->reg_acc;
+
+ ctx->reg_x = (result >> 8) & 0xff;
+ ctx->reg_acc = result & 0xff;
+
+ force_flags(ctx, M68_CCR_H | M68_CCR_C, 0);
+
+ // Inherent operation, nothing to write back
+ return false;
+}
+
+/// NEG: Negate (2's complement)
+static bool m68op_NEG(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ uint16_t result = 0 - *param;
+
+ update_flags(ctx, M68_CCR_N | M68_CCR_Z, ctx->reg_acc, *param, result, CARRY_UNDEFINED);
+ force_flags(ctx, M68_CCR_C, result != 0);
+ ctx->reg_acc = result;
+
+ // Don't write back, affects ACC and flags only
+ return false;
+}
+
+/// NOP: No operation
+static bool m68op_NOP(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ // Do nothing
+ return false;
+}
+
+/// ORA: Inclusive-OR
+static bool m68op_ORA(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ uint16_t result = ctx->reg_acc | *param;
+
+ update_flags(ctx, M68_CCR_N | M68_CCR_Z, ctx->reg_acc, *param, result, CARRY_UNDEFINED);
+ ctx->reg_acc = result;
+
+ // Don't write back, affects ACC and flags only
+ return false;
+}
+
+/// ROL: Rotate left
+static bool m68op_ROL(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ uint16_t result = ((*param << 1) | (get_flag(ctx, M68_CCR_C) ? 1 : 0)) & 0xFF;
+
+ update_flags(ctx, M68_CCR_N | M68_CCR_Z, ctx->reg_acc, *param, result, CARRY_UNDEFINED);
+ force_flags(ctx, M68_CCR_C, *param & 0x80);
+
+ // Result is written back to the source (in-place)
+ *param = result;
+ return true;
+}
+
+/// ROR: Rotate right
+static bool m68op_ROR(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ uint16_t result = ((*param >> 1) | (get_flag(ctx, M68_CCR_C) ? 0x80 : 0)) & 0xFF;
+
+ update_flags(ctx, M68_CCR_N | M68_CCR_Z, ctx->reg_acc, *param, result, CARRY_UNDEFINED);
+ force_flags(ctx, M68_CCR_C, *param & 1);
+
+ // Result is written back to the source (in-place)
+ *param = result;
+ return true;
+}
+
+/// RSP: Reset stack pointer
+static bool m68op_RSP(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ ctx->reg_sp = 0xFF; // TODO INITIAL_SP constant?
+
+ // Inherent operation, nothing to write back
+ return false;
+}
+
+/// RTI: Return from interrupt
+static bool m68op_RTI(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ // pop CCR, ACCA, X
+ ctx->reg_ccr = pop_byte(ctx);
+ ctx->reg_acc = pop_byte(ctx);
+ ctx->reg_x = pop_byte(ctx);
+
+ // pop PCH:PCL
+ // This is split up to force instruction sequencing (ref C99, sequence points!)
+ uint16_t new_pc;
+ new_pc = (uint16_t)pop_byte(ctx) << 8;
+ new_pc |= pop_byte(ctx);
+ ctx->pc_next = new_pc & ctx->pc_and;
+
+ // Inherent operation, nothing to write back
+ return false;
+}
+
+/// RTS: Return from subroutine
+static bool m68op_RTS(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ // pop PCH:PCL
+ // This is split up to force instruction sequencing (ref C99, sequence points!)
+ uint16_t new_pc;
+ new_pc = (uint16_t)pop_byte(ctx) << 8;
+ new_pc |= pop_byte(ctx);
+ ctx->pc_next = new_pc & ctx->pc_and;
+
+ // Inherent operation, nothing to write back
+ return false;}
+
+/// SBC: Subtract with carry
+static bool m68op_SBC(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ uint16_t result = ctx->reg_acc - *param - (ctx->reg_ccr & M68_CCR_C ? 1 : 0);
+
+ update_flags(ctx, M68_CCR_N | M68_CCR_Z | M68_CCR_C, ctx->reg_acc, *param, result, CARRY_SUB);
+ ctx->reg_acc = result;
+
+ // Don't write back, affects ACC and flags only
+ return false;
+}
+
+/// SEC: Set carry flag
+static bool m68op_SEC(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ force_flags(ctx, M68_CCR_C, 1);
+
+ // Inherent operation, nothing to write back
+ return false;
+}
+
+/// SEI: Set interrupt mask flag (disable interrupts)
+static bool m68op_SEI(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ force_flags(ctx, M68_CCR_I, 1);
+
+ // Inherent operation, nothing to write back
+ return false;
+}
+
+/// STA: Store accumulator
+static bool m68op_STA(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ update_flags(ctx, M68_CCR_N | M68_CCR_Z, ctx->reg_acc, *param, ctx->reg_acc, CARRY_UNDEFINED);
+
+ // Accumulator is written to memory
+ *param = ctx->reg_acc;
+ return true;
+}
+
+/// STOP: Enable IRQs, stop oscillator
+static bool m68op_STOP(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ force_flags(ctx, M68_CCR_I, 0);
+ ctx->is_stopped = true;
+
+ // Inherent operation, nothing to write back
+ return false;
+}
+
+/// STX: Store X register
+static bool m68op_STX(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ update_flags(ctx, M68_CCR_N | M68_CCR_Z, ctx->reg_x, *param, ctx->reg_x, CARRY_UNDEFINED);
+
+ // X register is written to memory
+ *param = ctx->reg_x;
+ return true;
+}
+
+/// SUB: Subtract
+static bool m68op_SUB(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ uint16_t result = ctx->reg_acc - *param;
+
+ update_flags(ctx, M68_CCR_N | M68_CCR_Z | M68_CCR_C, ctx->reg_acc, *param, result, CARRY_SUB);
+ ctx->reg_acc = result;
+
+ // Don't write back, affects ACC and flags only
+ return false;
+}
+
+/// SWI: Software Interrupt
+static bool m68op_SWI(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ // PC will already have been advanced by the emulation loop
+
+ jump_to_vector(ctx,_M68_SWI_VECTOR);
+ // Inherent operation, nothing to write back
+ return false;
+}
+
+/// TAX: Transfer A to X
+static bool m68op_TAX(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ ctx->reg_x = ctx->reg_acc;
+
+ // Inherent operation, nothing to write back
+ return false;
+}
+
+/// TST: Test if negative or zero
+static bool m68op_TST(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ update_flags(ctx, M68_CCR_N | M68_CCR_Z, 0, 0, *param, CARRY_UNDEFINED);
+
+ // Contents of the tested register or memory location are left unaltered.
+ return false;
+}
+
+/// TXA: Transfer X to ACC
+static bool m68op_TXA(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ ctx->reg_acc = ctx->reg_x;
+
+ // Inherent operation, nothing to write back
+ return false;
+}
+
+/// WAIT: Wait for interrupt. Like STOP, but leaves peripherals running.
+static bool m68op_WAIT(M68_CTX *ctx, const uint8_t opcode, uint8_t *param)
+{
+ force_flags(ctx, M68_CCR_I, 0);
+ ctx->is_waiting = true;
+
+ // Inherent operation, nothing to write back
+ return false;
+}
+
+
+/****************************************************************************
+ * OPCODE TABLES
+ ****************************************************************************/
+
+#include "m68_optab_hc05.h"
+
--- /dev/null
+M68_OPTABLE_ENT m68hc05_optable[256] = {
+ { "BRSET", AMODE_DIRECT_REL, 5, false, &m68op_BRSET },
+ { "BRCLR", AMODE_DIRECT_REL, 5, false, &m68op_BRCLR },
+ { "BRSET", AMODE_DIRECT_REL, 5, false, &m68op_BRSET },
+ { "BRCLR", AMODE_DIRECT_REL, 5, false, &m68op_BRCLR },
+ { "BRSET", AMODE_DIRECT_REL, 5, false, &m68op_BRSET },
+ { "BRCLR", AMODE_DIRECT_REL, 5, false, &m68op_BRCLR },
+ { "BRSET", AMODE_DIRECT_REL, 5, false, &m68op_BRSET },
+ { "BRCLR", AMODE_DIRECT_REL, 5, false, &m68op_BRCLR },
+ { "BRSET", AMODE_DIRECT_REL, 5, false, &m68op_BRSET },
+ { "BRCLR", AMODE_DIRECT_REL, 5, false, &m68op_BRCLR },
+ { "BRSET", AMODE_DIRECT_REL, 5, false, &m68op_BRSET },
+ { "BRCLR", AMODE_DIRECT_REL, 5, false, &m68op_BRCLR },
+ { "BRSET", AMODE_DIRECT_REL, 5, false, &m68op_BRSET },
+ { "BRCLR", AMODE_DIRECT_REL, 5, false, &m68op_BRCLR },
+ { "BRSET", AMODE_DIRECT_REL, 5, false, &m68op_BRSET },
+ { "BRCLR", AMODE_DIRECT_REL, 5, false, &m68op_BRCLR },
+ { "BSET", AMODE_DIRECT, 5, false, &m68op_BSET },
+ { "BCLR", AMODE_DIRECT, 5, false, &m68op_BCLR },
+ { "BSET", AMODE_DIRECT, 5, false, &m68op_BSET },
+ { "BCLR", AMODE_DIRECT, 5, false, &m68op_BCLR },
+ { "BSET", AMODE_DIRECT, 5, false, &m68op_BSET },
+ { "BCLR", AMODE_DIRECT, 5, false, &m68op_BCLR },
+ { "BSET", AMODE_DIRECT, 5, false, &m68op_BSET },
+ { "BCLR", AMODE_DIRECT, 5, false, &m68op_BCLR },
+ { "BSET", AMODE_DIRECT, 5, false, &m68op_BSET },
+ { "BCLR", AMODE_DIRECT, 5, false, &m68op_BCLR },
+ { "BSET", AMODE_DIRECT, 5, false, &m68op_BSET },
+ { "BCLR", AMODE_DIRECT, 5, false, &m68op_BCLR },
+ { "BSET", AMODE_DIRECT, 5, false, &m68op_BSET },
+ { "BCLR", AMODE_DIRECT, 5, false, &m68op_BCLR },
+ { "BSET", AMODE_DIRECT, 5, false, &m68op_BSET },
+ { "BCLR", AMODE_DIRECT, 5, false, &m68op_BCLR },
+ { "BRA", AMODE_RELATIVE, 3, false, &m68op_BRA },
+ { "BRN", AMODE_RELATIVE, 3, false, &m68op_BRN },
+ { "BHI", AMODE_RELATIVE, 3, false, &m68op_BHI },
+ { "BLS", AMODE_RELATIVE, 3, false, &m68op_BLS },
+ { "BCC", AMODE_RELATIVE, 3, false, &m68op_BCC },
+ { "BCS", AMODE_RELATIVE, 3, false, &m68op_BCS },
+ { "BNE", AMODE_RELATIVE, 3, false, &m68op_BNE },
+ { "BEQ", AMODE_RELATIVE, 3, false, &m68op_BEQ },
+ { "BHCC", AMODE_RELATIVE, 3, false, &m68op_BHCC },
+ { "BHCS", AMODE_RELATIVE, 3, false, &m68op_BHCS },
+ { "BPL", AMODE_RELATIVE, 3, false, &m68op_BPL },
+ { "BMI", AMODE_RELATIVE, 3, false, &m68op_BMI },
+ { "BMC", AMODE_RELATIVE, 3, false, &m68op_BMC },
+ { "BMS", AMODE_RELATIVE, 3, false, &m68op_BMS },
+ { "BIL", AMODE_RELATIVE, 3, false, &m68op_BIL },
+ { "BIH", AMODE_RELATIVE, 3, false, &m68op_BIH },
+ { "NEG", AMODE_DIRECT, 5, false, &m68op_NEG },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "COM", AMODE_DIRECT, 5, false, &m68op_COM },
+ { "LSR", AMODE_DIRECT, 5, false, &m68op_LSR },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "ROR", AMODE_DIRECT, 5, false, &m68op_ROR },
+ { "ASR", AMODE_DIRECT, 5, false, &m68op_ASR },
+ { "ASL", AMODE_DIRECT, 5, false, &m68op_ASL },
+ { "ROL", AMODE_DIRECT, 5, false, &m68op_ROL },
+ { "DEC", AMODE_DIRECT, 5, false, &m68op_DEC },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "INC", AMODE_DIRECT, 5, false, &m68op_INC },
+ { "TST", AMODE_DIRECT, 4, false, &m68op_TST },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "CLR", AMODE_DIRECT, 5, true, &m68op_CLR },
+ { "NEGA", AMODE_INHERENT_A, 3, false, &m68op_NEG },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "MUL", AMODE_INHERENT, 11, false, &m68op_MUL },
+ { "COMA", AMODE_INHERENT_A, 3, false, &m68op_COM },
+ { "LSRA", AMODE_INHERENT_A, 3, false, &m68op_LSR },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "RORA", AMODE_INHERENT_A, 3, false, &m68op_ROR },
+ { "ASRA", AMODE_INHERENT_A, 3, false, &m68op_ASR },
+ { "ASLA", AMODE_INHERENT_A, 3, false, &m68op_ASL },
+ { "ROLA", AMODE_INHERENT_A, 3, false, &m68op_ROL },
+ { "DECA", AMODE_INHERENT_A, 3, false, &m68op_DEC },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "INCA", AMODE_INHERENT_A, 3, false, &m68op_INC },
+ { "TSTA", AMODE_INHERENT_A, 3, false, &m68op_TST },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "CLRA", AMODE_INHERENT_A, 3, true, &m68op_CLR },
+ { "NEGX", AMODE_INHERENT_X, 3, false, &m68op_NEG },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "COMX", AMODE_INHERENT_X, 3, false, &m68op_COM },
+ { "LSRX", AMODE_INHERENT_X, 3, false, &m68op_LSR },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "RORX", AMODE_INHERENT_X, 3, false, &m68op_ROR },
+ { "ASRX", AMODE_INHERENT_X, 3, false, &m68op_ASR },
+ { "ASLX", AMODE_INHERENT_A, 3, false, &m68op_ASL },
+ { "ROLX", AMODE_INHERENT_X, 3, false, &m68op_ROL },
+ { "DECX", AMODE_INHERENT_X, 3, false, &m68op_DEC },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "INCX", AMODE_INHERENT_X, 3, false, &m68op_INC },
+ { "TSTX", AMODE_INHERENT_X, 3, false, &m68op_TST },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "CLRX", AMODE_INHERENT_X, 3, true, &m68op_CLR },
+ { "NEG", AMODE_INDEXED1, 6, false, &m68op_NEG },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "COM", AMODE_INDEXED1, 6, false, &m68op_COM },
+ { "LSR", AMODE_INDEXED1, 6, false, &m68op_LSR },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "ROR", AMODE_INDEXED1, 6, false, &m68op_ROR },
+ { "ASR", AMODE_INDEXED1, 6, false, &m68op_ASR },
+ { "ASL", AMODE_INDEXED1, 6, false, &m68op_ASL },
+ { "ROL", AMODE_INDEXED1, 6, false, &m68op_ROL },
+ { "DEC", AMODE_INDEXED1, 6, false, &m68op_DEC },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "INC", AMODE_INDEXED1, 6, false, &m68op_INC },
+ { "TST", AMODE_INDEXED1, 5, false, &m68op_TST },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "CLR", AMODE_INDEXED1, 6, true, &m68op_CLR },
+ { "NEG", AMODE_INDEXED0, 5, false, &m68op_NEG },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "COM", AMODE_INDEXED0, 5, false, &m68op_COM },
+ { "LSR", AMODE_INDEXED0, 5, false, &m68op_LSR },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "ROR", AMODE_INDEXED0, 5, false, &m68op_ROR },
+ { "ASR", AMODE_INDEXED0, 5, false, &m68op_ASR },
+ { "ASL", AMODE_INDEXED0, 5, false, &m68op_ASL },
+ { "ROL", AMODE_INDEXED0, 5, false, &m68op_ROL },
+ { "DEC", AMODE_INDEXED0, 5, false, &m68op_DEC },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "INC", AMODE_INDEXED0, 5, false, &m68op_INC },
+ { "TST", AMODE_INDEXED0, 4, false, &m68op_TST },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "CLR", AMODE_INDEXED0, 5, true, &m68op_CLR },
+ { "RTI", AMODE_INHERENT, 9, false, &m68op_RTI },
+ { "RTS", AMODE_INHERENT, 6, false, &m68op_RTS },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "SWI", AMODE_INHERENT, 10, false, &m68op_SWI },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "STOP", AMODE_INHERENT, 2, false, &m68op_STOP },
+ { "WAIT", AMODE_INHERENT, 2, false, &m68op_WAIT },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "TAX", AMODE_INHERENT, 2, false, &m68op_TAX },
+ { "CLC", AMODE_INHERENT, 2, false, &m68op_CLC },
+ { "SEC", AMODE_INHERENT, 2, false, &m68op_SEC },
+ { "CLI", AMODE_INHERENT, 2, false, &m68op_CLI },
+ { "SEI", AMODE_INHERENT, 2, false, &m68op_SEI },
+ { "RSP", AMODE_INHERENT, 2, false, &m68op_RSP },
+ { "NOP", AMODE_INHERENT, 2, false, &m68op_NOP },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "TXA", AMODE_INHERENT, 2, false, &m68op_TXA },
+ { "SUB", AMODE_IMMEDIATE, 2, false, &m68op_SUB },
+ { "CMP", AMODE_IMMEDIATE, 2, false, &m68op_CMP },
+ { "SBC", AMODE_IMMEDIATE, 2, false, &m68op_SBC },
+ { "CPX", AMODE_IMMEDIATE, 2, false, &m68op_CPX },
+ { "AND", AMODE_IMMEDIATE, 2, false, &m68op_AND },
+ { "BIT", AMODE_IMMEDIATE, 2, false, &m68op_BIT },
+ { "LDA", AMODE_IMMEDIATE, 2, false, &m68op_LDA },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "EOR", AMODE_IMMEDIATE, 2, false, &m68op_EOR },
+ { "ADC", AMODE_IMMEDIATE, 2, false, &m68op_ADC },
+ { "ORA", AMODE_IMMEDIATE, 2, false, &m68op_ORA },
+ { "ADD", AMODE_IMMEDIATE, 2, false, &m68op_ADD },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "BSR", AMODE_RELATIVE, 6, false, &m68op_BSR },
+ { "LDX", AMODE_IMMEDIATE, 2, false, &m68op_LDX },
+ { "ILLEGAL", AMODE_ILLEGAL, 0, 0, NULL },
+ { "SUB", AMODE_DIRECT, 3, false, &m68op_SUB },
+ { "CMP", AMODE_DIRECT, 3, false, &m68op_CMP },
+ { "SBC", AMODE_DIRECT, 3, false, &m68op_SBC },
+ { "CPX", AMODE_DIRECT, 3, false, &m68op_CPX },
+ { "AND", AMODE_DIRECT, 3, false, &m68op_AND },
+ { "BIT", AMODE_DIRECT, 3, false, &m68op_BIT },
+ { "LDA", AMODE_DIRECT, 3, false, &m68op_LDA },
+ { "STA", AMODE_DIRECT, 4, true, &m68op_STA },
+ { "EOR", AMODE_DIRECT, 3, false, &m68op_EOR },
+ { "ADC", AMODE_DIRECT, 3, false, &m68op_ADC },
+ { "ORA", AMODE_DIRECT, 3, false, &m68op_ORA },
+ { "ADD", AMODE_DIRECT, 3, false, &m68op_ADD },
+ { "JMP", AMODE_DIRECT_JUMP, 2, false, &m68op_JMP },
+ { "JSR", AMODE_DIRECT_JUMP, 5, false, &m68op_JSR },
+ { "LDX", AMODE_DIRECT, 3, false, &m68op_LDX },
+ { "STX", AMODE_DIRECT, 4, true, &m68op_STX },
+ { "SUB", AMODE_EXTENDED, 4, false, &m68op_SUB },
+ { "CMP", AMODE_EXTENDED, 4, false, &m68op_CMP },
+ { "SBC", AMODE_EXTENDED, 4, false, &m68op_SBC },
+ { "CPX", AMODE_EXTENDED, 4, false, &m68op_CPX },
+ { "AND", AMODE_EXTENDED, 4, false, &m68op_AND },
+ { "BIT", AMODE_EXTENDED, 4, false, &m68op_BIT },
+ { "LDA", AMODE_EXTENDED, 4, false, &m68op_LDA },
+ { "STA", AMODE_EXTENDED, 5, true, &m68op_STA },
+ { "EOR", AMODE_EXTENDED, 4, false, &m68op_EOR },
+ { "ADC", AMODE_EXTENDED, 4, false, &m68op_ADC },
+ { "ORA", AMODE_EXTENDED, 4, false, &m68op_ORA },
+ { "ADD", AMODE_EXTENDED, 4, false, &m68op_ADD },
+ { "JMP", AMODE_EXTENDED_JUMP, 3, false, &m68op_JMP },
+ { "JSR", AMODE_EXTENDED_JUMP, 6, false, &m68op_JSR },
+ { "LDX", AMODE_EXTENDED, 4, false, &m68op_LDX },
+ { "STX", AMODE_EXTENDED, 5, true, &m68op_STX },
+ { "SUB", AMODE_INDEXED2, 5, false, &m68op_SUB },
+ { "CMP", AMODE_INDEXED2, 5, false, &m68op_CMP },
+ { "SBC", AMODE_INDEXED2, 5, false, &m68op_SBC },
+ { "CPX", AMODE_INDEXED2, 5, false, &m68op_CPX },
+ { "AND", AMODE_INDEXED2, 5, false, &m68op_AND },
+ { "BIT", AMODE_INDEXED2, 5, false, &m68op_BIT },
+ { "LDA", AMODE_INDEXED2, 5, false, &m68op_LDA },
+ { "STA", AMODE_INDEXED2, 6, true, &m68op_STA },
+ { "EOR", AMODE_INDEXED2, 5, false, &m68op_EOR },
+ { "ADC", AMODE_INDEXED2, 5, false, &m68op_ADC },
+ { "ORA", AMODE_INDEXED2, 5, false, &m68op_ORA },
+ { "ADD", AMODE_INDEXED2, 5, false, &m68op_ADD },
+ { "JMP", AMODE_INDEXED2_JUMP, 4, false, &m68op_JMP },
+ { "JSR", AMODE_INDEXED2_JUMP, 7, false, &m68op_JSR },
+ { "LDX", AMODE_INDEXED2, 5, false, &m68op_LDX },
+ { "STX", AMODE_INDEXED2, 6, true, &m68op_STX },
+ { "SUB", AMODE_INDEXED1, 4, false, &m68op_SUB },
+ { "CMP", AMODE_INDEXED1, 4, false, &m68op_CMP },
+ { "SBC", AMODE_INDEXED1, 4, false, &m68op_SBC },
+ { "CPX", AMODE_INDEXED1, 4, false, &m68op_CPX },
+ { "AND", AMODE_INDEXED1, 4, false, &m68op_AND },
+ { "BIT", AMODE_INDEXED1, 4, false, &m68op_BIT },
+ { "LDA", AMODE_INDEXED1, 4, false, &m68op_LDA },
+ { "STA", AMODE_INDEXED1, 5, true, &m68op_STA },
+ { "EOR", AMODE_INDEXED1, 4, false, &m68op_EOR },
+ { "ADC", AMODE_INDEXED1, 4, false, &m68op_ADC },
+ { "ORA", AMODE_INDEXED1, 4, false, &m68op_ORA },
+ { "ADD", AMODE_INDEXED1, 4, false, &m68op_ADD },
+ { "JMP", AMODE_INDEXED1_JUMP, 3, false, &m68op_JMP },
+ { "JSR", AMODE_INDEXED1_JUMP, 6, false, &m68op_JSR },
+ { "LDX", AMODE_INDEXED1, 4, false, &m68op_LDX },
+ { "STX", AMODE_INDEXED1, 5, true, &m68op_STX },
+ { "SUB", AMODE_INDEXED0, 3, false, &m68op_SUB },
+ { "CMP", AMODE_INDEXED0, 3, false, &m68op_CMP },
+ { "SBC", AMODE_INDEXED0, 3, false, &m68op_SBC },
+ { "CPX", AMODE_INDEXED0, 3, false, &m68op_CPX },
+ { "AND", AMODE_INDEXED0, 3, false, &m68op_AND },
+ { "BIT", AMODE_INDEXED0, 3, false, &m68op_BIT },
+ { "LDA", AMODE_INDEXED0, 3, false, &m68op_LDA },
+ { "STA", AMODE_INDEXED0, 4, true, &m68op_STA },
+ { "EOR", AMODE_INDEXED0, 3, false, &m68op_EOR },
+ { "ADC", AMODE_INDEXED0, 3, false, &m68op_ADC },
+ { "ORA", AMODE_INDEXED0, 3, false, &m68op_ORA },
+ { "ADD", AMODE_INDEXED0, 3, false, &m68op_ADD },
+ { "JMP", AMODE_INDEXED0_JUMP, 2, false, &m68op_JMP },
+ { "JSR", AMODE_INDEXED0_JUMP, 5, false, &m68op_JSR },
+ { "LDX", AMODE_INDEXED0, 3, false, &m68op_LDX },
+ { "STX", AMODE_INDEXED0, 4, true, &m68op_STX },
+};
--- /dev/null
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include "m68emu.h"
+#include "m68_internal.h"
+
+void m68_init(M68_CTX *ctx, const M68_CPUTYPE cpuType)
+{
+ switch (cpuType) {
+ case M68_CPU_HC05C4:
+ // 68HC05SC21 is based on the 68HC05C4 core.
+ // SP is 13 bits.
+ // 7 MSBs are permanently set to 0000011
+ // 6 LSBs are passed through
+ // Address range: 0xC0 to 0xFF
+ ctx->sp_and = 0x003F;
+ ctx->sp_or = 0x00C0;
+
+ // PC is 13 bits too
+ ctx->pc_and = 0x1FFF;
+ break;
+ case M68_CPU_HD6805V1:
+ ctx->pc_and=0x0FFF;
+ // Address range: 0xC0 to 0xFF ?
+ ctx->sp_and = 0x003F;
+ ctx->sp_or = 0x00C0;
+ break;
+ default:
+ assert(0);
+ }
+
+ ctx->cpuType = cpuType;
+ ctx->trace = false;
+ ctx->pending_interrupts = 0;
+ m68_reset(ctx);
+}
+
+void m68_reset(M68_CTX *ctx)
+{
+ // Read the reset vector
+ ctx->reg_pc = _M68_RESET_VECTOR & ctx->pc_and;
+ uint16_t rstvec = (uint16_t)ctx->read_mem(ctx, ctx->reg_pc) << 8;
+ rstvec |= ctx->read_mem(ctx, ctx->reg_pc+1);
+
+ // Set PC to the reset vector
+ ctx->reg_pc = rstvec & ctx->pc_and;
+ ctx->pc_next = ctx->reg_pc;
+
+ // Reset stack pointer to 0xFF
+ ctx->reg_sp = 0xFF;
+
+ // Set the I bit in the CCR to 1 (mask off interrupts)
+ ctx->reg_ccr |= M68_CCR_I;
+
+ // Clear STOP and WAIT latches
+ ctx->is_stopped = ctx->is_waiting = 0;
+
+ // Clear external interrupt latch
+ ctx->irq = 0;
+}
+
+
+void m68_set_interrupt_line(M68_CTX * ctx,M68_INTERRUPT i){
+ if (i == M68_INT_IRQ){
+ ctx->irq=true;
+ }
+ ctx->pending_interrupts |= (1 << i);
+}
+
+void jump_to_vector(M68_CTX *ctx,uint16_t addr)
+{
+ push_byte(ctx, ctx->pc_next & 0xFF);
+ push_byte(ctx, ctx->pc_next >> 8);
+ push_byte(ctx, ctx->reg_x);
+ push_byte(ctx, ctx->reg_acc);
+ push_byte(ctx, ctx->reg_ccr);
+
+ // Mask further interrupts
+ force_flags(ctx, M68_CCR_I, 1);
+
+ // Vector fetch
+ uint16_t vector;
+ vector = (uint16_t)ctx->read_mem(ctx, addr & ctx->pc_and) << 8;
+ vector |= ctx->read_mem(ctx, (addr+1) & ctx->pc_and);
+ ctx->pc_next = vector;
+}
+
+uint64_t m68_exec_cycle(M68_CTX *ctx)
+{
+ uint8_t opval;
+ M68_OPTABLE_ENT *opcode;
+
+ // Save current program counter
+ ctx->reg_pc = ctx->pc_next;
+
+ if (ctx->pending_interrupts && get_flag(ctx,M68_CCR_I)==0){
+ if (ctx->pending_interrupts & (1<<M68_INT_IRQ)) {
+ ctx->pending_interrupts &= ~(1<<M68_INT_IRQ);
+ jump_to_vector(ctx,_M68_INT_VECTOR);
+ } else if (ctx->pending_interrupts& (1<<M68_INT_TIMER1)) {
+ ctx->pending_interrupts &= ~(1<<M68_INT_TIMER1);
+ jump_to_vector(ctx,_M68_TMR1_VECTOR);
+ }
+ return 11;
+ }
+
+ // Fetch and decode opcode
+ opval = ctx->read_mem(ctx, ctx->pc_next++);
+ if (ctx->opdecode != NULL) {
+ opval = ctx->opdecode(ctx, opval);
+ }
+ switch (ctx->cpuType) {
+ case M68_CPU_HC05C4:
+ case M68_CPU_HD6805V1:
+ opcode = &m68hc05_optable[opval];
+ break;
+ default:
+ assert(0);
+ }
+
+ if (ctx->trace) {
+ printf("M68 EXEC: pc %04X sp %02X opval %02X mnem '%s' amode %d cycles %d\n",
+ ctx->reg_pc, ctx->reg_sp, opval, opcode->mnem, opcode->amode, opcode->cycles);
+ }
+
+ // Read the opcode parameter bytes, if any
+ uint8_t opParam; // parameter
+ uint16_t dirPtr; // direct pointer
+ uint16_t opNextPC; // next PC (if branch or jump)
+ bool opResult;
+
+ switch(opcode->amode) {
+ case AMODE_DIRECT:
+ // Direct addressing: parameter is an address in zero page
+ dirPtr = ctx->read_mem(ctx, ctx->pc_next++);
+ if (!opcode->write_only) {
+ opParam = ctx->read_mem(ctx, dirPtr);
+ }
+ break;
+
+ case AMODE_DIRECT_JUMP:
+ // Direct addressing, jump
+ opNextPC = ctx->read_mem(ctx, ctx->pc_next++);
+ opParam = -1;
+ break;
+
+ case AMODE_DIRECT_REL:
+ // Direct + relative addressing: parameter is an address in zero page
+ // followed by a relative jump address.
+ // Direct
+ dirPtr = ctx->read_mem(ctx, ctx->pc_next++);
+ opParam = ctx->read_mem(ctx, dirPtr);
+ // Relative
+ opNextPC = ctx->pc_next + 1;
+ opNextPC += (int8_t)ctx->read_mem(ctx, ctx->pc_next++);
+ break;
+
+ case AMODE_EXTENDED:
+ // Extended addressing: parameter is a 16-bit address
+ dirPtr = (uint16_t)ctx->read_mem(ctx, ctx->pc_next++) << 8;
+ dirPtr |= ctx->read_mem(ctx, ctx->pc_next++);
+ if (!opcode->write_only) {
+ opParam = ctx->read_mem(ctx, dirPtr);
+ }
+ break;
+
+ case AMODE_EXTENDED_JUMP:
+ // Extended addressing, jump
+ opNextPC = (uint16_t)ctx->read_mem(ctx, ctx->pc_next++) << 8;
+ opNextPC |= ctx->read_mem(ctx, ctx->pc_next++);
+ opParam = -1;
+ break;
+
+ case AMODE_IMMEDIATE:
+ // Immediate addressing: parameter is an immediate value following the opcode
+ opParam = ctx->read_mem(ctx, ctx->pc_next++);
+ break;
+
+ case AMODE_INDEXED0:
+ // Indexed with no offset. Take the X register as an address.
+ dirPtr = ctx->reg_x;
+ if (!opcode->write_only) {
+ opParam = ctx->read_mem(ctx, dirPtr);
+ }
+ break;
+
+ case AMODE_INDEXED0_JUMP:
+ // Indexed jump with no offset. Take the X register as an address.
+ opNextPC = ctx->reg_x;
+ opParam = -1;
+ break;
+
+ case AMODE_INDEXED1:
+ // Indexed with 1-byte offset. Add X and offset.
+ dirPtr = (uint16_t)ctx->read_mem(ctx, ctx->pc_next++) + ctx->reg_x;
+ if (!opcode->write_only) {
+ opParam = ctx->read_mem(ctx, dirPtr);
+ }
+ break;
+
+ case AMODE_INDEXED1_JUMP:
+ // Indexed jump with 1-byte offset. Take the X register as an address.
+ opNextPC = (uint16_t)ctx->read_mem(ctx, ctx->pc_next++) + ctx->reg_x;
+ opParam = -1;
+ break;
+
+ case AMODE_INDEXED2:
+ // Indexed with 2-byte offset. Add X and offset.
+ dirPtr = (uint16_t)ctx->read_mem(ctx, ctx->pc_next++) << 8;
+ dirPtr |= ctx->read_mem(ctx, ctx->pc_next++);
+ dirPtr += ctx->reg_x;
+ if (!opcode->write_only) {
+ opParam = ctx->read_mem(ctx, dirPtr);
+ }
+ break;
+
+ case AMODE_INDEXED2_JUMP:
+ // Indexed jump with 2-byte offset. Add X and offset.
+ opNextPC = (uint16_t)ctx->read_mem(ctx, ctx->pc_next++) << 8;
+ opNextPC |= ctx->read_mem(ctx, ctx->pc_next++);
+ opNextPC += ctx->reg_x;
+ opParam = -1;
+ break;
+
+ case AMODE_INHERENT:
+ // Inherent addressing, affects nothing.
+ opParam = -1;
+ break;
+
+ case AMODE_INHERENT_A:
+ // Inherent addressing, affects Accumulator.
+ opParam = ctx->reg_acc;
+ break;
+
+ case AMODE_INHERENT_X:
+ // Inherent addressing, affects X register.
+ opParam = ctx->reg_x;
+ break;
+
+ case AMODE_RELATIVE:
+ // Relative addressing: signed relative branch or jump.
+ opNextPC = ctx->pc_next + 1;
+ opNextPC += (int8_t)ctx->read_mem(ctx, ctx->pc_next++);
+ break;
+
+ case AMODE_ILLEGAL:
+ case AMODE_MAX:
+ printf("ILLEGAL M68 EXEC: pc %04X sp %02X opval %02X mnem '%s' amode %d cycles %d\n",
+ ctx->reg_pc, ctx->reg_sp, opval, opcode->mnem, opcode->amode, opcode->cycles);
+
+ // Illegal instruction
+ assert(1==2);
+ break;
+ }
+
+ // Execute opcode
+ opResult = opcode->opfunc(ctx, opval, &opParam);
+ if (ctx->trace) {
+ if (opResult) {
+ printf("\t-> %3d (0x%02X)\n", opParam, opParam);
+ }
+ }
+
+ // Write back result (param)
+ switch(opcode->amode) {
+ case AMODE_DIRECT:
+ case AMODE_EXTENDED:
+ case AMODE_INDEXED0:
+ case AMODE_INDEXED1:
+ case AMODE_INDEXED2:
+ // Direct addressing: parameter is an address in zero page
+ // Extended addressing: parameter is a 16-bit address
+ // Indexed with no offset. Take the X register as an address.
+ // Indexed with 1-byte offset. Add X and offset.
+ // Indexed with 2-byte offset. Add X and offset.
+ if (opResult) {
+ ctx->write_mem(ctx, dirPtr, opParam);
+ }
+ break;
+
+ case AMODE_DIRECT_JUMP:
+ case AMODE_EXTENDED_JUMP:
+ case AMODE_INDEXED0_JUMP:
+ case AMODE_INDEXED1_JUMP:
+ case AMODE_INDEXED2_JUMP:
+ case AMODE_DIRECT_REL:
+ case AMODE_RELATIVE:
+ // Direct + relative addressing: parameter is an address in zero page
+ // followed by a signed relative jump address.
+ // Relative addressing: signed relative branch or jump.
+ //
+ // If the opfunc returned true, take the jump.
+ if (opResult) {
+ ctx->pc_next = opNextPC & ctx->pc_and;
+ }
+ break;
+
+ case AMODE_IMMEDIATE:
+ // Immediate addressing: parameter is an immediate value and cannot be written back.
+ break;
+
+ case AMODE_INHERENT:
+ // Inherent addressing, affects nothing.
+ break;
+
+ case AMODE_INHERENT_A:
+ // Inherent addressing, affects Accumulator.
+ if (opResult) {
+ ctx->reg_acc = opParam;
+ }
+ break;
+
+ case AMODE_INHERENT_X:
+ // Inherent addressing, affects X register.
+ if (opResult) {
+ ctx->reg_x = opParam;
+ }
+ break;
+
+ case AMODE_ILLEGAL:
+ case AMODE_MAX:
+ // Illegal instruction
+ assert(1==2);
+ break;
+ }
+
+ // Return number of cycles executed
+ return opcode->cycles;
+}
+
--- /dev/null
+#ifndef M68EMU_H
+#define M68EMU_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+typedef enum {
+ M68_CPU_HC05C4,
+ M68_CPU_HD6805V1
+} M68_CPUTYPE;
+
+typedef enum{
+ M68_INT_IRQ,
+ M68_INT_TIMER1
+} M68_INTERRUPT;
+
+
+struct M68_CTX;
+
+typedef uint8_t (*M68_READMEM_F) (struct M68_CTX *ctx, const uint16_t addr);
+typedef void (*M68_WRITEMEM_F) (struct M68_CTX *ctx, const uint16_t addr, const uint8_t data);
+typedef uint8_t (*M68_OPDECODE_F) (struct M68_CTX *ctx, const uint8_t value);
+
+
+/**
+ * Emulation context structure
+ */
+typedef struct M68_CTX {
+ uint8_t reg_acc; ///< Accumulator register
+ uint8_t reg_x; ///< X-index register
+ uint16_t reg_sp; ///< Stack pointer
+ uint16_t reg_pc; ///< Program counter for current instruction
+ uint16_t pc_next; ///< Program counter for next instruction
+ uint8_t reg_ccr; ///< Condition code register
+ M68_CPUTYPE cpuType; ///< CPU type
+ bool irq; ///< IRQ input state
+ uint8_t pending_interrupts;
+ uint16_t sp_and, sp_or; ///< Stack pointer AND/OR masks
+ uint16_t pc_and; ///< Program counter AND mask
+ bool is_stopped; ///< True if processor is stopped
+ bool is_waiting; ///< True if processor is WAITing
+ M68_READMEM_F read_mem; ///< Memory read callback
+ M68_WRITEMEM_F write_mem; ///< Memory write callback
+ M68_OPDECODE_F opdecode; ///< Opcode decode function, or NULL
+ bool trace;
+} M68_CTX;
+
+
+/* CCR bits */
+#define M68_CCR_H 0x10 /* Half carry */
+#define M68_CCR_I 0x08 /* Interrupt mask */
+#define M68_CCR_N 0x04 /* Negative */
+#define M68_CCR_C 0x02 /* Carry/borrow */
+#define M68_CCR_Z 0x01 /* Zero */
+
+
+void m68_init(M68_CTX *ctx, const M68_CPUTYPE cpuType);
+void m68_reset(M68_CTX *ctx);
+uint64_t m68_exec_cycle(M68_CTX *ctx);
+void m68_set_interrupt_line(M68_CTX * ctx,M68_INTERRUPT i);
+
+
+#endif // M68EMU_H
if (currprefs.cpuboard_settings & 0x10) {
inputdevice_draco_key(kc);
}
- if (!currprefs.keyboard_connected) {
+ if (currprefs.keyboard_mode < 0) {
return 1;
}
}
--- /dev/null
+#include "mos6502.h"
+
+#define NEGATIVE 0x80
+#define OVERFLOW 0x40
+#define CONSTANT 0x20
+#define BREAK 0x10
+#define DECIMAL 0x08
+#define INTERRUPT 0x04
+#define ZERO 0x02
+#define CARRY 0x01
+
+#define SET_NEGATIVE(x) (x ? (status |= NEGATIVE) : (status &= (~NEGATIVE)) )
+#define SET_OVERFLOW(x) (x ? (status |= OVERFLOW) : (status &= (~OVERFLOW)) )
+//#define SET_CONSTANT(x) (x ? (status |= CONSTANT) : (status &= (~CONSTANT)) )
+//#define SET_BREAK(x) (x ? (status |= BREAK) : (status &= (~BREAK)) )
+#define SET_DECIMAL(x) (x ? (status |= DECIMAL) : (status &= (~DECIMAL)) )
+#define SET_INTERRUPT(x) (x ? (status |= INTERRUPT) : (status &= (~INTERRUPT)) )
+#define SET_ZERO(x) (x ? (status |= ZERO) : (status &= (~ZERO)) )
+#define SET_CARRY(x) (x ? (status |= CARRY) : (status &= (~CARRY)) )
+
+#define IF_NEGATIVE() ((status & NEGATIVE) ? true : false)
+#define IF_OVERFLOW() ((status & OVERFLOW) ? true : false)
+#define IF_CONSTANT() ((status & CONSTANT) ? true : false)
+#define IF_BREAK() ((status & BREAK) ? true : false)
+#define IF_DECIMAL() ((status & DECIMAL) ? true : false)
+#define IF_INTERRUPT() ((status & INTERRUPT) ? true : false)
+#define IF_ZERO() ((status & ZERO) ? true : false)
+#define IF_CARRY() ((status & CARRY) ? true : false)
+
+mos6502::Instr mos6502::InstrTable[256];
+
+mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c)
+ : reset_A(0x00)
+ , reset_X(0x00)
+ , reset_Y(0x00)
+ , reset_sp(0xFD)
+ , reset_status(CONSTANT)
+{
+ Write = (BusWrite)w;
+ Read = (BusRead)r;
+ Cycle = (ClockCycle)c;
+
+ static bool initialized = false;
+ if (initialized) return;
+ initialized = true;
+
+ Instr instr;
+ // fill jump table with ILLEGALs
+ instr.addr = &mos6502::Addr_IMP;
+ instr.code = &mos6502::Op_ILLEGAL;
+ for(int i = 0; i < 256; i++)
+ {
+ InstrTable[i] = instr;
+ }
+
+ // insert opcodes
+
+ instr.addr = &mos6502::Addr_IMM;
+ instr.code = &mos6502::Op_ADC;
+ instr.cycles = 2;
+ InstrTable[0x69] = instr;
+ instr.addr = &mos6502::Addr_ABS;
+ instr.code = &mos6502::Op_ADC;
+ instr.cycles = 4;
+ InstrTable[0x6D] = instr;
+ instr.addr = &mos6502::Addr_ZER;
+ instr.code = &mos6502::Op_ADC;
+ instr.cycles = 3;
+ InstrTable[0x65] = instr;
+ instr.addr = &mos6502::Addr_INX;
+ instr.code = &mos6502::Op_ADC;
+ instr.cycles = 6;
+ InstrTable[0x61] = instr;
+ instr.addr = &mos6502::Addr_INY;
+ instr.code = &mos6502::Op_ADC;
+ instr.cycles = 6;
+ InstrTable[0x71] = instr;
+ instr.addr = &mos6502::Addr_ZEX;
+ instr.code = &mos6502::Op_ADC;
+ instr.cycles = 4;
+ InstrTable[0x75] = instr;
+ instr.addr = &mos6502::Addr_ABX;
+ instr.code = &mos6502::Op_ADC;
+ instr.cycles = 4;
+ InstrTable[0x7D] = instr;
+ instr.addr = &mos6502::Addr_ABY;
+ instr.code = &mos6502::Op_ADC;
+ instr.cycles = 4;
+ InstrTable[0x79] = instr;
+
+ instr.addr = &mos6502::Addr_IMM;
+ instr.code = &mos6502::Op_AND;
+ instr.cycles = 2;
+ InstrTable[0x29] = instr;
+ instr.addr = &mos6502::Addr_ABS;
+ instr.code = &mos6502::Op_AND;
+ instr.cycles = 4;
+ InstrTable[0x2D] = instr;
+ instr.addr = &mos6502::Addr_ZER;
+ instr.code = &mos6502::Op_AND;
+ instr.cycles = 3;
+ InstrTable[0x25] = instr;
+ instr.addr = &mos6502::Addr_INX;
+ instr.code = &mos6502::Op_AND;
+ instr.cycles = 6;
+ InstrTable[0x21] = instr;
+ instr.addr = &mos6502::Addr_INY;
+ instr.code = &mos6502::Op_AND;
+ instr.cycles = 5;
+ InstrTable[0x31] = instr;
+ instr.addr = &mos6502::Addr_ZEX;
+ instr.code = &mos6502::Op_AND;
+ instr.cycles = 4;
+ InstrTable[0x35] = instr;
+ instr.addr = &mos6502::Addr_ABX;
+ instr.code = &mos6502::Op_AND;
+ instr.cycles = 4;
+ InstrTable[0x3D] = instr;
+ instr.addr = &mos6502::Addr_ABY;
+ instr.code = &mos6502::Op_AND;
+ instr.cycles = 4;
+ InstrTable[0x39] = instr;
+
+ instr.addr = &mos6502::Addr_ABS;
+ instr.code = &mos6502::Op_ASL;
+ instr.cycles = 6;
+ InstrTable[0x0E] = instr;
+ instr.addr = &mos6502::Addr_ZER;
+ instr.code = &mos6502::Op_ASL;
+ instr.cycles = 5;
+ InstrTable[0x06] = instr;
+ instr.addr = &mos6502::Addr_ACC;
+ instr.code = &mos6502::Op_ASL_ACC;
+ instr.cycles = 2;
+ InstrTable[0x0A] = instr;
+ instr.addr = &mos6502::Addr_ZEX;
+ instr.code = &mos6502::Op_ASL;
+ instr.cycles = 6;
+ InstrTable[0x16] = instr;
+ instr.addr = &mos6502::Addr_ABX;
+ instr.code = &mos6502::Op_ASL;
+ instr.cycles = 7;
+ InstrTable[0x1E] = instr;
+
+ instr.addr = &mos6502::Addr_REL;
+ instr.code = &mos6502::Op_BCC;
+ instr.cycles = 2;
+ InstrTable[0x90] = instr;
+
+ instr.addr = &mos6502::Addr_REL;
+ instr.code = &mos6502::Op_BCS;
+ instr.cycles = 2;
+ InstrTable[0xB0] = instr;
+
+ instr.addr = &mos6502::Addr_REL;
+ instr.code = &mos6502::Op_BEQ;
+ instr.cycles = 2;
+ InstrTable[0xF0] = instr;
+
+ instr.addr = &mos6502::Addr_ABS;
+ instr.code = &mos6502::Op_BIT;
+ instr.cycles = 4;
+ InstrTable[0x2C] = instr;
+ instr.addr = &mos6502::Addr_ZER;
+ instr.code = &mos6502::Op_BIT;
+ instr.cycles = 3;
+ InstrTable[0x24] = instr;
+
+ instr.addr = &mos6502::Addr_REL;
+ instr.code = &mos6502::Op_BMI;
+ instr.cycles = 2;
+ InstrTable[0x30] = instr;
+
+ instr.addr = &mos6502::Addr_REL;
+ instr.code = &mos6502::Op_BNE;
+ instr.cycles = 2;
+ InstrTable[0xD0] = instr;
+
+ instr.addr = &mos6502::Addr_REL;
+ instr.code = &mos6502::Op_BPL;
+ instr.cycles = 2;
+ InstrTable[0x10] = instr;
+
+ instr.addr = &mos6502::Addr_IMP;
+ instr.code = &mos6502::Op_BRK;
+ instr.cycles = 7;
+ InstrTable[0x00] = instr;
+
+ instr.addr = &mos6502::Addr_REL;
+ instr.code = &mos6502::Op_BVC;
+ instr.cycles = 2;
+ InstrTable[0x50] = instr;
+
+ instr.addr = &mos6502::Addr_REL;
+ instr.code = &mos6502::Op_BVS;
+ instr.cycles = 2;
+ InstrTable[0x70] = instr;
+
+ instr.addr = &mos6502::Addr_IMP;
+ instr.code = &mos6502::Op_CLC;
+ instr.cycles = 2;
+ InstrTable[0x18] = instr;
+
+ instr.addr = &mos6502::Addr_IMP;
+ instr.code = &mos6502::Op_CLD;
+ instr.cycles = 2;
+ InstrTable[0xD8] = instr;
+
+ instr.addr = &mos6502::Addr_IMP;
+ instr.code = &mos6502::Op_CLI;
+ instr.cycles = 2;
+ InstrTable[0x58] = instr;
+
+ instr.addr = &mos6502::Addr_IMP;
+ instr.code = &mos6502::Op_CLV;
+ instr.cycles = 2;
+ InstrTable[0xB8] = instr;
+
+ instr.addr = &mos6502::Addr_IMM;
+ instr.code = &mos6502::Op_CMP;
+ instr.cycles = 2;
+ InstrTable[0xC9] = instr;
+ instr.addr = &mos6502::Addr_ABS;
+ instr.code = &mos6502::Op_CMP;
+ instr.cycles = 4;
+ InstrTable[0xCD] = instr;
+ instr.addr = &mos6502::Addr_ZER;
+ instr.code = &mos6502::Op_CMP;
+ instr.cycles = 3;
+ InstrTable[0xC5] = instr;
+ instr.addr = &mos6502::Addr_INX;
+ instr.code = &mos6502::Op_CMP;
+ instr.cycles = 6;
+ InstrTable[0xC1] = instr;
+ instr.addr = &mos6502::Addr_INY;
+ instr.code = &mos6502::Op_CMP;
+ instr.cycles = 3;
+ InstrTable[0xD1] = instr;
+ instr.addr = &mos6502::Addr_ZEX;
+ instr.code = &mos6502::Op_CMP;
+ instr.cycles = 4;
+ InstrTable[0xD5] = instr;
+ instr.addr = &mos6502::Addr_ABX;
+ instr.code = &mos6502::Op_CMP;
+ instr.cycles = 4;
+ InstrTable[0xDD] = instr;
+ instr.addr = &mos6502::Addr_ABY;
+ instr.code = &mos6502::Op_CMP;
+ instr.cycles = 4;
+ InstrTable[0xD9] = instr;
+
+ instr.addr = &mos6502::Addr_IMM;
+ instr.code = &mos6502::Op_CPX;
+ instr.cycles = 2;
+ InstrTable[0xE0] = instr;
+ instr.addr = &mos6502::Addr_ABS;
+ instr.code = &mos6502::Op_CPX;
+ instr.cycles = 4;
+ InstrTable[0xEC] = instr;
+ instr.addr = &mos6502::Addr_ZER;
+ instr.code = &mos6502::Op_CPX;
+ instr.cycles = 3;
+ InstrTable[0xE4] = instr;
+
+ instr.addr = &mos6502::Addr_IMM;
+ instr.code = &mos6502::Op_CPY;
+ instr.cycles = 2;
+ InstrTable[0xC0] = instr;
+ instr.addr = &mos6502::Addr_ABS;
+ instr.code = &mos6502::Op_CPY;
+ instr.cycles = 4;
+ InstrTable[0xCC] = instr;
+ instr.addr = &mos6502::Addr_ZER;
+ instr.code = &mos6502::Op_CPY;
+ instr.cycles = 3;
+ InstrTable[0xC4] = instr;
+
+ instr.addr = &mos6502::Addr_ABS;
+ instr.code = &mos6502::Op_DEC;
+ instr.cycles = 6;
+ InstrTable[0xCE] = instr;
+ instr.addr = &mos6502::Addr_ZER;
+ instr.code = &mos6502::Op_DEC;
+ instr.cycles = 5;
+ InstrTable[0xC6] = instr;
+ instr.addr = &mos6502::Addr_ZEX;
+ instr.code = &mos6502::Op_DEC;
+ instr.cycles = 6;
+ InstrTable[0xD6] = instr;
+ instr.addr = &mos6502::Addr_ABX;
+ instr.code = &mos6502::Op_DEC;
+ instr.cycles = 7;
+ InstrTable[0xDE] = instr;
+
+ instr.addr = &mos6502::Addr_IMP;
+ instr.code = &mos6502::Op_DEX;
+ instr.cycles = 2;
+ InstrTable[0xCA] = instr;
+
+ instr.addr = &mos6502::Addr_IMP;
+ instr.code = &mos6502::Op_DEY;
+ instr.cycles = 2;
+ InstrTable[0x88] = instr;
+
+ instr.addr = &mos6502::Addr_IMM;
+ instr.code = &mos6502::Op_EOR;
+ instr.cycles = 2;
+ InstrTable[0x49] = instr;
+ instr.addr = &mos6502::Addr_ABS;
+ instr.code = &mos6502::Op_EOR;
+ instr.cycles = 4;
+ InstrTable[0x4D] = instr;
+ instr.addr = &mos6502::Addr_ZER;
+ instr.code = &mos6502::Op_EOR;
+ instr.cycles = 3;
+ InstrTable[0x45] = instr;
+ instr.addr = &mos6502::Addr_INX;
+ instr.code = &mos6502::Op_EOR;
+ instr.cycles = 6;
+ InstrTable[0x41] = instr;
+ instr.addr = &mos6502::Addr_INY;
+ instr.code = &mos6502::Op_EOR;
+ instr.cycles = 5;
+ InstrTable[0x51] = instr;
+ instr.addr = &mos6502::Addr_ZEX;
+ instr.code = &mos6502::Op_EOR;
+ instr.cycles = 4;
+ InstrTable[0x55] = instr;
+ instr.addr = &mos6502::Addr_ABX;
+ instr.code = &mos6502::Op_EOR;
+ instr.cycles = 4;
+ InstrTable[0x5D] = instr;
+ instr.addr = &mos6502::Addr_ABY;
+ instr.code = &mos6502::Op_EOR;
+ instr.cycles = 4;
+ InstrTable[0x59] = instr;
+
+ instr.addr = &mos6502::Addr_ABS;
+ instr.code = &mos6502::Op_INC;
+ instr.cycles = 6;
+ InstrTable[0xEE] = instr;
+ instr.addr = &mos6502::Addr_ZER;
+ instr.code = &mos6502::Op_INC;
+ instr.cycles = 5;
+ InstrTable[0xE6] = instr;
+ instr.addr = &mos6502::Addr_ZEX;
+ instr.code = &mos6502::Op_INC;
+ instr.cycles = 6;
+ InstrTable[0xF6] = instr;
+ instr.addr = &mos6502::Addr_ABX;
+ instr.code = &mos6502::Op_INC;
+ instr.cycles = 7;
+ InstrTable[0xFE] = instr;
+
+ instr.addr = &mos6502::Addr_IMP;
+ instr.code = &mos6502::Op_INX;
+ instr.cycles = 2;
+ InstrTable[0xE8] = instr;
+
+ instr.addr = &mos6502::Addr_IMP;
+ instr.code = &mos6502::Op_INY;
+ instr.cycles = 2;
+ InstrTable[0xC8] = instr;
+
+ instr.addr = &mos6502::Addr_ABS;
+ instr.code = &mos6502::Op_JMP;
+ instr.cycles = 3;
+ InstrTable[0x4C] = instr;
+ instr.addr = &mos6502::Addr_ABI;
+ instr.code = &mos6502::Op_JMP;
+ instr.cycles = 5;
+ InstrTable[0x6C] = instr;
+
+ instr.addr = &mos6502::Addr_ABS;
+ instr.code = &mos6502::Op_JSR;
+ instr.cycles = 6;
+ InstrTable[0x20] = instr;
+
+ instr.addr = &mos6502::Addr_IMM;
+ instr.code = &mos6502::Op_LDA;
+ instr.cycles = 2;
+ InstrTable[0xA9] = instr;
+ instr.addr = &mos6502::Addr_ABS;
+ instr.code = &mos6502::Op_LDA;
+ instr.cycles = 4;
+ InstrTable[0xAD] = instr;
+ instr.addr = &mos6502::Addr_ZER;
+ instr.code = &mos6502::Op_LDA;
+ instr.cycles = 3;
+ InstrTable[0xA5] = instr;
+ instr.addr = &mos6502::Addr_INX;
+ instr.code = &mos6502::Op_LDA;
+ instr.cycles = 6;
+ InstrTable[0xA1] = instr;
+ instr.addr = &mos6502::Addr_INY;
+ instr.code = &mos6502::Op_LDA;
+ instr.cycles = 5;
+ InstrTable[0xB1] = instr;
+ instr.addr = &mos6502::Addr_ZEX;
+ instr.code = &mos6502::Op_LDA;
+ instr.cycles = 4;
+ InstrTable[0xB5] = instr;
+ instr.addr = &mos6502::Addr_ABX;
+ instr.code = &mos6502::Op_LDA;
+ instr.cycles = 4;
+ InstrTable[0xBD] = instr;
+ instr.addr = &mos6502::Addr_ABY;
+ instr.code = &mos6502::Op_LDA;
+ instr.cycles = 4;
+ InstrTable[0xB9] = instr;
+
+ instr.addr = &mos6502::Addr_IMM;
+ instr.code = &mos6502::Op_LDX;
+ instr.cycles = 2;
+ InstrTable[0xA2] = instr;
+ instr.addr = &mos6502::Addr_ABS;
+ instr.code = &mos6502::Op_LDX;
+ instr.cycles = 4;
+ InstrTable[0xAE] = instr;
+ instr.addr = &mos6502::Addr_ZER;
+ instr.code = &mos6502::Op_LDX;
+ instr.cycles = 3;
+ InstrTable[0xA6] = instr;
+ instr.addr = &mos6502::Addr_ABY;
+ instr.code = &mos6502::Op_LDX;
+ instr.cycles = 4;
+ InstrTable[0xBE] = instr;
+ instr.addr = &mos6502::Addr_ZEY;
+ instr.code = &mos6502::Op_LDX;
+ instr.cycles = 4;
+ InstrTable[0xB6] = instr;
+
+ instr.addr = &mos6502::Addr_IMM;
+ instr.code = &mos6502::Op_LDY;
+ instr.cycles = 2;
+ InstrTable[0xA0] = instr;
+ instr.addr = &mos6502::Addr_ABS;
+ instr.code = &mos6502::Op_LDY;
+ instr.cycles = 4;
+ InstrTable[0xAC] = instr;
+ instr.addr = &mos6502::Addr_ZER;
+ instr.code = &mos6502::Op_LDY;
+ instr.cycles = 3;
+ InstrTable[0xA4] = instr;
+ instr.addr = &mos6502::Addr_ZEX;
+ instr.code = &mos6502::Op_LDY;
+ instr.cycles = 4;
+ InstrTable[0xB4] = instr;
+ instr.addr = &mos6502::Addr_ABX;
+ instr.code = &mos6502::Op_LDY;
+ instr.cycles = 4;
+ InstrTable[0xBC] = instr;
+
+ instr.addr = &mos6502::Addr_ABS;
+ instr.code = &mos6502::Op_LSR;
+ instr.cycles = 6;
+ InstrTable[0x4E] = instr;
+ instr.addr = &mos6502::Addr_ZER;
+ instr.code = &mos6502::Op_LSR;
+ instr.cycles = 5;
+ InstrTable[0x46] = instr;
+ instr.addr = &mos6502::Addr_ACC;
+ instr.code = &mos6502::Op_LSR_ACC;
+ instr.cycles = 2;
+ InstrTable[0x4A] = instr;
+ instr.addr = &mos6502::Addr_ZEX;
+ instr.code = &mos6502::Op_LSR;
+ instr.cycles = 6;
+ InstrTable[0x56] = instr;
+ instr.addr = &mos6502::Addr_ABX;
+ instr.code = &mos6502::Op_LSR;
+ instr.cycles = 7;
+ InstrTable[0x5E] = instr;
+
+ instr.addr = &mos6502::Addr_IMP;
+ instr.code = &mos6502::Op_NOP;
+ instr.cycles = 2;
+ InstrTable[0xEA] = instr;
+
+ instr.addr = &mos6502::Addr_IMM;
+ instr.code = &mos6502::Op_ORA;
+ instr.cycles = 2;
+ InstrTable[0x09] = instr;
+ instr.addr = &mos6502::Addr_ABS;
+ instr.code = &mos6502::Op_ORA;
+ instr.cycles = 4;
+ InstrTable[0x0D] = instr;
+ instr.addr = &mos6502::Addr_ZER;
+ instr.code = &mos6502::Op_ORA;
+ instr.cycles = 3;
+ InstrTable[0x05] = instr;
+ instr.addr = &mos6502::Addr_INX;
+ instr.code = &mos6502::Op_ORA;
+ instr.cycles = 6;
+ InstrTable[0x01] = instr;
+ instr.addr = &mos6502::Addr_INY;
+ instr.code = &mos6502::Op_ORA;
+ instr.cycles = 5;
+ InstrTable[0x11] = instr;
+ instr.addr = &mos6502::Addr_ZEX;
+ instr.code = &mos6502::Op_ORA;
+ instr.cycles = 4;
+ InstrTable[0x15] = instr;
+ instr.addr = &mos6502::Addr_ABX;
+ instr.code = &mos6502::Op_ORA;
+ instr.cycles = 4;
+ InstrTable[0x1D] = instr;
+ instr.addr = &mos6502::Addr_ABY;
+ instr.code = &mos6502::Op_ORA;
+ instr.cycles = 4;
+ InstrTable[0x19] = instr;
+
+ instr.addr = &mos6502::Addr_IMP;
+ instr.code = &mos6502::Op_PHA;
+ instr.cycles = 3;
+ InstrTable[0x48] = instr;
+
+ instr.addr = &mos6502::Addr_IMP;
+ instr.code = &mos6502::Op_PHP;
+ instr.cycles = 3;
+ InstrTable[0x08] = instr;
+
+ instr.addr = &mos6502::Addr_IMP;
+ instr.code = &mos6502::Op_PLA;
+ instr.cycles = 4;
+ InstrTable[0x68] = instr;
+
+ instr.addr = &mos6502::Addr_IMP;
+ instr.code = &mos6502::Op_PLP;
+ instr.cycles = 4;
+ InstrTable[0x28] = instr;
+
+ instr.addr = &mos6502::Addr_ABS;
+ instr.code = &mos6502::Op_ROL;
+ instr.cycles = 6;
+ InstrTable[0x2E] = instr;
+ instr.addr = &mos6502::Addr_ZER;
+ instr.code = &mos6502::Op_ROL;
+ instr.cycles = 5;
+ InstrTable[0x26] = instr;
+ instr.addr = &mos6502::Addr_ACC;
+ instr.code = &mos6502::Op_ROL_ACC;
+ instr.cycles = 2;
+ InstrTable[0x2A] = instr;
+ instr.addr = &mos6502::Addr_ZEX;
+ instr.code = &mos6502::Op_ROL;
+ instr.cycles = 6;
+ InstrTable[0x36] = instr;
+ instr.addr = &mos6502::Addr_ABX;
+ instr.code = &mos6502::Op_ROL;
+ instr.cycles = 7;
+ InstrTable[0x3E] = instr;
+
+ instr.addr = &mos6502::Addr_ABS;
+ instr.code = &mos6502::Op_ROR;
+ instr.cycles = 6;
+ InstrTable[0x6E] = instr;
+ instr.addr = &mos6502::Addr_ZER;
+ instr.code = &mos6502::Op_ROR;
+ instr.cycles = 5;
+ InstrTable[0x66] = instr;
+ instr.addr = &mos6502::Addr_ACC;
+ instr.code = &mos6502::Op_ROR_ACC;
+ instr.cycles = 2;
+ InstrTable[0x6A] = instr;
+ instr.addr = &mos6502::Addr_ZEX;
+ instr.code = &mos6502::Op_ROR;
+ instr.cycles = 6;
+ InstrTable[0x76] = instr;
+ instr.addr = &mos6502::Addr_ABX;
+ instr.code = &mos6502::Op_ROR;
+ instr.cycles = 7;
+ InstrTable[0x7E] = instr;
+
+ instr.addr = &mos6502::Addr_IMP;
+ instr.code = &mos6502::Op_RTI;
+ instr.cycles = 6;
+ InstrTable[0x40] = instr;
+
+ instr.addr = &mos6502::Addr_IMP;
+ instr.code = &mos6502::Op_RTS;
+ instr.cycles = 6;
+ InstrTable[0x60] = instr;
+
+ instr.addr = &mos6502::Addr_IMM;
+ instr.code = &mos6502::Op_SBC;
+ instr.cycles = 2;
+ InstrTable[0xE9] = instr;
+ instr.addr = &mos6502::Addr_ABS;
+ instr.code = &mos6502::Op_SBC;
+ instr.cycles = 4;
+ InstrTable[0xED] = instr;
+ instr.addr = &mos6502::Addr_ZER;
+ instr.code = &mos6502::Op_SBC;
+ instr.cycles = 3;
+ InstrTable[0xE5] = instr;
+ instr.addr = &mos6502::Addr_INX;
+ instr.code = &mos6502::Op_SBC;
+ instr.cycles = 6;
+ InstrTable[0xE1] = instr;
+ instr.addr = &mos6502::Addr_INY;
+ instr.code = &mos6502::Op_SBC;
+ instr.cycles = 5;
+ InstrTable[0xF1] = instr;
+ instr.addr = &mos6502::Addr_ZEX;
+ instr.code = &mos6502::Op_SBC;
+ instr.cycles = 4;
+ InstrTable[0xF5] = instr;
+ instr.addr = &mos6502::Addr_ABX;
+ instr.code = &mos6502::Op_SBC;
+ instr.cycles = 4;
+ InstrTable[0xFD] = instr;
+ instr.addr = &mos6502::Addr_ABY;
+ instr.code = &mos6502::Op_SBC;
+ instr.cycles = 4;
+ InstrTable[0xF9] = instr;
+
+ instr.addr = &mos6502::Addr_IMP;
+ instr.code = &mos6502::Op_SEC;
+ instr.cycles = 2;
+ InstrTable[0x38] = instr;
+
+ instr.addr = &mos6502::Addr_IMP;
+ instr.code = &mos6502::Op_SED;
+ instr.cycles = 2;
+ InstrTable[0xF8] = instr;
+
+ instr.addr = &mos6502::Addr_IMP;
+ instr.code = &mos6502::Op_SEI;
+ instr.cycles = 2;
+ InstrTable[0x78] = instr;
+
+ instr.addr = &mos6502::Addr_ABS;
+ instr.code = &mos6502::Op_STA;
+ instr.cycles = 4;
+ InstrTable[0x8D] = instr;
+ instr.addr = &mos6502::Addr_ZER;
+ instr.code = &mos6502::Op_STA;
+ instr.cycles = 3;
+ InstrTable[0x85] = instr;
+ instr.addr = &mos6502::Addr_INX;
+ instr.code = &mos6502::Op_STA;
+ instr.cycles = 6;
+ InstrTable[0x81] = instr;
+ instr.addr = &mos6502::Addr_INY;
+ instr.code = &mos6502::Op_STA;
+ instr.cycles = 6;
+ InstrTable[0x91] = instr;
+ instr.addr = &mos6502::Addr_ZEX;
+ instr.code = &mos6502::Op_STA;
+ instr.cycles = 4;
+ InstrTable[0x95] = instr;
+ instr.addr = &mos6502::Addr_ABX;
+ instr.code = &mos6502::Op_STA;
+ instr.cycles = 5;
+ InstrTable[0x9D] = instr;
+ instr.addr = &mos6502::Addr_ABY;
+ instr.code = &mos6502::Op_STA;
+ instr.cycles = 5;
+ InstrTable[0x99] = instr;
+
+ instr.addr = &mos6502::Addr_ABS;
+ instr.code = &mos6502::Op_STX;
+ instr.cycles = 4;
+ InstrTable[0x8E] = instr;
+ instr.addr = &mos6502::Addr_ZER;
+ instr.code = &mos6502::Op_STX;
+ instr.cycles = 3;
+ InstrTable[0x86] = instr;
+ instr.addr = &mos6502::Addr_ZEY;
+ instr.code = &mos6502::Op_STX;
+ instr.cycles = 4;
+ InstrTable[0x96] = instr;
+
+ instr.addr = &mos6502::Addr_ABS;
+ instr.code = &mos6502::Op_STY;
+ instr.cycles = 4;
+ InstrTable[0x8C] = instr;
+ instr.addr = &mos6502::Addr_ZER;
+ instr.code = &mos6502::Op_STY;
+ instr.cycles = 3;
+ InstrTable[0x84] = instr;
+ instr.addr = &mos6502::Addr_ZEX;
+ instr.code = &mos6502::Op_STY;
+ instr.cycles = 4;
+ InstrTable[0x94] = instr;
+
+ instr.addr = &mos6502::Addr_IMP;
+ instr.code = &mos6502::Op_TAX;
+ instr.cycles = 2;
+ InstrTable[0xAA] = instr;
+
+ instr.addr = &mos6502::Addr_IMP;
+ instr.code = &mos6502::Op_TAY;
+ instr.cycles = 2;
+ InstrTable[0xA8] = instr;
+
+ instr.addr = &mos6502::Addr_IMP;
+ instr.code = &mos6502::Op_TSX;
+ instr.cycles = 2;
+ InstrTable[0xBA] = instr;
+
+ instr.addr = &mos6502::Addr_IMP;
+ instr.code = &mos6502::Op_TXA;
+ instr.cycles = 2;
+ InstrTable[0x8A] = instr;
+
+ instr.addr = &mos6502::Addr_IMP;
+ instr.code = &mos6502::Op_TXS;
+ instr.cycles = 2;
+ InstrTable[0x9A] = instr;
+
+ instr.addr = &mos6502::Addr_IMP;
+ instr.code = &mos6502::Op_TYA;
+ instr.cycles = 2;
+ InstrTable[0x98] = instr;
+
+ return;
+}
+
+uint16_t mos6502::Addr_ACC()
+{
+ return 0; // not used
+}
+
+uint16_t mos6502::Addr_IMM()
+{
+ return pc++;
+}
+
+uint16_t mos6502::Addr_ABS()
+{
+ uint16_t addrL;
+ uint16_t addrH;
+ uint16_t addr;
+
+ addrL = Read(pc++);
+ addrH = Read(pc++);
+
+ addr = addrL + (addrH << 8);
+
+ return addr;
+}
+
+uint16_t mos6502::Addr_ZER()
+{
+ return Read(pc++);
+}
+
+uint16_t mos6502::Addr_IMP()
+{
+ return 0; // not used
+}
+
+uint16_t mos6502::Addr_REL()
+{
+ uint16_t offset;
+ uint16_t addr;
+
+ offset = (uint16_t)Read(pc++);
+ if (offset & 0x80) offset |= 0xFF00;
+ addr = pc + (int16_t)offset;
+ return addr;
+}
+
+uint16_t mos6502::Addr_ABI()
+{
+ uint16_t addrL;
+ uint16_t addrH;
+ uint16_t effL;
+ uint16_t effH;
+ uint16_t abs;
+ uint16_t addr;
+
+ addrL = Read(pc++);
+ addrH = Read(pc++);
+
+ abs = (addrH << 8) | addrL;
+
+ effL = Read(abs);
+
+#ifndef CMOS_INDIRECT_JMP_FIX
+ effH = Read((abs & 0xFF00) + ((abs + 1) & 0x00FF) );
+#else
+ effH = Read(abs + 1);
+#endif
+
+ addr = effL + 0x100 * effH;
+
+ return addr;
+}
+
+uint16_t mos6502::Addr_ZEX()
+{
+ uint16_t addr = (Read(pc++) + X) & 0xFF;
+ return addr;
+}
+
+uint16_t mos6502::Addr_ZEY()
+{
+ uint16_t addr = (Read(pc++) + Y) & 0xFF;
+ return addr;
+}
+
+uint16_t mos6502::Addr_ABX()
+{
+ uint16_t addr;
+ uint16_t addrL;
+ uint16_t addrH;
+
+ addrL = Read(pc++);
+ addrH = Read(pc++);
+
+ addr = addrL + (addrH << 8) + X;
+ return addr;
+}
+
+uint16_t mos6502::Addr_ABY()
+{
+ uint16_t addr;
+ uint16_t addrL;
+ uint16_t addrH;
+
+ addrL = Read(pc++);
+ addrH = Read(pc++);
+
+ addr = addrL + (addrH << 8) + Y;
+ return addr;
+}
+
+
+uint16_t mos6502::Addr_INX()
+{
+ uint16_t zeroL;
+ uint16_t zeroH;
+ uint16_t addr;
+
+ zeroL = (Read(pc++) + X) & 0xFF;
+ zeroH = (zeroL + 1) & 0xFF;
+ addr = Read(zeroL) + (Read(zeroH) << 8);
+
+ return addr;
+}
+
+uint16_t mos6502::Addr_INY()
+{
+ uint16_t zeroL;
+ uint16_t zeroH;
+ uint16_t addr;
+
+ zeroL = Read(pc++);
+ zeroH = (zeroL + 1) & 0xFF;
+ addr = Read(zeroL) + (Read(zeroH) << 8) + Y;
+
+ return addr;
+}
+
+void mos6502::SetPC(uint16_t value)
+{
+ pc = value;
+}
+
+void mos6502::Reset()
+{
+ A = reset_A;
+ Y = reset_Y;
+ X = reset_X;
+
+ // load PC from reset vector
+ uint8_t pcl = Read(rstVectorL);
+ uint8_t pch = Read(rstVectorH);
+ pc = (pch << 8) + pcl;
+
+ sp = reset_sp;
+
+ status = reset_status | CONSTANT | BREAK;
+
+ illegalOpcode = false;
+
+ return;
+}
+
+void mos6502::StackPush(uint8_t byte)
+{
+ Write(0x0100 + sp, byte);
+ if(sp == 0x00) sp = 0xFF;
+ else sp--;
+}
+
+uint8_t mos6502::StackPop()
+{
+ if(sp == 0xFF) sp = 0x00;
+ else sp++;
+ return Read(0x0100 + sp);
+}
+
+void mos6502::IRQ()
+{
+ if(!IF_INTERRUPT())
+ {
+ //SET_BREAK(0);
+ StackPush((pc >> 8) & 0xFF);
+ StackPush(pc & 0xFF);
+ StackPush((status & ~BREAK) | CONSTANT);
+ SET_INTERRUPT(1);
+
+ // load PC from interrupt request vector
+ uint8_t pcl = Read(irqVectorL);
+ uint8_t pch = Read(irqVectorH);
+ pc = (pch << 8) + pcl;
+ }
+ return;
+}
+
+void mos6502::NMI()
+{
+ //SET_BREAK(0);
+ StackPush((pc >> 8) & 0xFF);
+ StackPush(pc & 0xFF);
+ StackPush((status & ~BREAK) | CONSTANT);
+ SET_INTERRUPT(1);
+
+ // load PC from non-maskable interrupt vector
+ uint8_t pcl = Read(nmiVectorL);
+ uint8_t pch = Read(nmiVectorH);
+ pc = (pch << 8) + pcl;
+ return;
+}
+
+void mos6502::Run(
+ int32_t cyclesRemaining,
+ uint64_t& cycleCount,
+ CycleMethod cycleMethod
+) {
+ uint8_t opcode;
+ Instr instr;
+
+ while(cyclesRemaining > 0 && !illegalOpcode)
+ {
+ // fetch
+ opcode = Read(pc++);
+
+ // decode
+ instr = InstrTable[opcode];
+
+ // execute
+ Exec(instr);
+ cycleCount += instr.cycles;
+ cyclesRemaining -=
+ cycleMethod == CYCLE_COUNT ? instr.cycles
+ /* cycleMethod == INST_COUNT */ : 1;
+
+ // run clock cycle callback
+ if (Cycle)
+ for(int i = 0; i < instr.cycles; i++)
+ Cycle(this);
+ }
+}
+
+void mos6502::RunEternally()
+{
+ uint8_t opcode;
+ Instr instr;
+
+ while(!illegalOpcode)
+ {
+ // fetch
+ opcode = Read(pc++);
+
+ // decode
+ instr = InstrTable[opcode];
+
+ // execute
+ Exec(instr);
+
+ // run clock cycle callback
+ if (Cycle)
+ for(int i = 0; i < instr.cycles; i++)
+ Cycle(this);
+ }
+}
+
+void mos6502::Exec(Instr i)
+{
+ uint16_t src = (this->*i.addr)();
+ (this->*i.code)(src);
+}
+
+uint16_t mos6502::GetPC()
+{
+ return pc;
+}
+
+uint8_t mos6502::GetS()
+{
+ return sp;
+}
+
+uint8_t mos6502::GetP()
+{
+ return status;
+}
+
+uint8_t mos6502::GetA()
+{
+ return A;
+}
+
+uint8_t mos6502::GetX()
+{
+ return X;
+}
+
+uint8_t mos6502::GetY()
+{
+ return Y;
+}
+
+void mos6502::SetResetS(uint8_t value)
+{
+ reset_sp = value;
+}
+
+void mos6502::SetResetP(uint8_t value)
+{
+ reset_status = value | CONSTANT | BREAK;
+}
+
+void mos6502::SetResetA(uint8_t value)
+{
+ reset_A = value;
+}
+
+void mos6502::SetResetX(uint8_t value)
+{
+ reset_X = value;
+}
+
+void mos6502::SetResetY(uint8_t value)
+{
+ reset_Y = value;
+}
+
+uint8_t mos6502::GetResetS()
+{
+ return reset_sp;
+}
+
+uint8_t mos6502::GetResetP()
+{
+ return reset_status;
+}
+
+uint8_t mos6502::GetResetA()
+{
+ return reset_A;
+}
+
+uint8_t mos6502::GetResetX()
+{
+ return reset_X;
+}
+
+uint8_t mos6502::GetResetY()
+{
+ return reset_Y;
+}
+
+void mos6502::SetP(uint8_t value)
+{
+ status = value;
+}
+
+void mos6502::Op_ILLEGAL(uint16_t src)
+{
+ illegalOpcode = true;
+}
+
+
+void mos6502::Op_ADC(uint16_t src)
+{
+ uint8_t m = Read(src);
+ unsigned int tmp = m + A + (IF_CARRY() ? 1 : 0);
+ SET_ZERO(!(tmp & 0xFF));
+ if (IF_DECIMAL())
+ {
+ if (((A & 0xF) + (m & 0xF) + (IF_CARRY() ? 1 : 0)) > 9) tmp += 6;
+ SET_NEGATIVE(tmp & 0x80);
+ SET_OVERFLOW(!((A ^ m) & 0x80) && ((A ^ tmp) & 0x80));
+ if (tmp > 0x99)
+ {
+ tmp += 96;
+ }
+ SET_CARRY(tmp > 0x99);
+ }
+ else
+ {
+ SET_NEGATIVE(tmp & 0x80);
+ SET_OVERFLOW(!((A ^ m) & 0x80) && ((A ^ tmp) & 0x80));
+ SET_CARRY(tmp > 0xFF);
+ }
+
+ A = tmp & 0xFF;
+ return;
+}
+
+
+
+void mos6502::Op_AND(uint16_t src)
+{
+ uint8_t m = Read(src);
+ uint8_t res = m & A;
+ SET_NEGATIVE(res & 0x80);
+ SET_ZERO(!res);
+ A = res;
+ return;
+}
+
+
+void mos6502::Op_ASL(uint16_t src)
+{
+ uint8_t m = Read(src);
+ SET_CARRY(m & 0x80);
+ m <<= 1;
+ m &= 0xFF;
+ SET_NEGATIVE(m & 0x80);
+ SET_ZERO(!m);
+ Write(src, m);
+ return;
+}
+
+void mos6502::Op_ASL_ACC(uint16_t src)
+{
+ uint8_t m = A;
+ SET_CARRY(m & 0x80);
+ m <<= 1;
+ m &= 0xFF;
+ SET_NEGATIVE(m & 0x80);
+ SET_ZERO(!m);
+ A = m;
+ return;
+}
+
+void mos6502::Op_BCC(uint16_t src)
+{
+ if (!IF_CARRY())
+ {
+ pc = src;
+ }
+ return;
+}
+
+
+void mos6502::Op_BCS(uint16_t src)
+{
+ if (IF_CARRY())
+ {
+ pc = src;
+ }
+ return;
+}
+
+void mos6502::Op_BEQ(uint16_t src)
+{
+ if (IF_ZERO())
+ {
+ pc = src;
+ }
+ return;
+}
+
+void mos6502::Op_BIT(uint16_t src)
+{
+ uint8_t m = Read(src);
+ uint8_t res = m & A;
+ SET_NEGATIVE(res & 0x80);
+ status = (status & 0x3F) | (uint8_t)(m & 0xC0) | CONSTANT | BREAK;
+ SET_ZERO(!res);
+ return;
+}
+
+void mos6502::Op_BMI(uint16_t src)
+{
+ if (IF_NEGATIVE())
+ {
+ pc = src;
+ }
+ return;
+}
+
+void mos6502::Op_BNE(uint16_t src)
+{
+ if (!IF_ZERO())
+ {
+ pc = src;
+ }
+ return;
+}
+
+void mos6502::Op_BPL(uint16_t src)
+{
+ if (!IF_NEGATIVE())
+ {
+ pc = src;
+ }
+ return;
+}
+
+void mos6502::Op_BRK(uint16_t src)
+{
+ pc++;
+ StackPush((pc >> 8) & 0xFF);
+ StackPush(pc & 0xFF);
+ StackPush(status | CONSTANT | BREAK);
+ SET_INTERRUPT(1);
+ pc = (Read(irqVectorH) << 8) + Read(irqVectorL);
+ return;
+}
+
+void mos6502::Op_BVC(uint16_t src)
+{
+ if (!IF_OVERFLOW())
+ {
+ pc = src;
+ }
+ return;
+}
+
+void mos6502::Op_BVS(uint16_t src)
+{
+ if (IF_OVERFLOW())
+ {
+ pc = src;
+ }
+ return;
+}
+
+void mos6502::Op_CLC(uint16_t src)
+{
+ SET_CARRY(0);
+ return;
+}
+
+void mos6502::Op_CLD(uint16_t src)
+{
+ SET_DECIMAL(0);
+ return;
+}
+
+void mos6502::Op_CLI(uint16_t src)
+{
+ SET_INTERRUPT(0);
+ return;
+}
+
+void mos6502::Op_CLV(uint16_t src)
+{
+ SET_OVERFLOW(0);
+ return;
+}
+
+void mos6502::Op_CMP(uint16_t src)
+{
+ unsigned int tmp = A - Read(src);
+ SET_CARRY(tmp < 0x100);
+ SET_NEGATIVE(tmp & 0x80);
+ SET_ZERO(!(tmp & 0xFF));
+ return;
+}
+
+void mos6502::Op_CPX(uint16_t src)
+{
+ unsigned int tmp = X - Read(src);
+ SET_CARRY(tmp < 0x100);
+ SET_NEGATIVE(tmp & 0x80);
+ SET_ZERO(!(tmp & 0xFF));
+ return;
+}
+
+void mos6502::Op_CPY(uint16_t src)
+{
+ unsigned int tmp = Y - Read(src);
+ SET_CARRY(tmp < 0x100);
+ SET_NEGATIVE(tmp & 0x80);
+ SET_ZERO(!(tmp & 0xFF));
+ return;
+}
+
+void mos6502::Op_DEC(uint16_t src)
+{
+ uint8_t m = Read(src);
+ m = (m - 1) & 0xFF;
+ SET_NEGATIVE(m & 0x80);
+ SET_ZERO(!m);
+ Write(src, m);
+ return;
+}
+
+void mos6502::Op_DEX(uint16_t src)
+{
+ uint8_t m = X;
+ m = (m - 1) & 0xFF;
+ SET_NEGATIVE(m & 0x80);
+ SET_ZERO(!m);
+ X = m;
+ return;
+}
+
+void mos6502::Op_DEY(uint16_t src)
+{
+ uint8_t m = Y;
+ m = (m - 1) & 0xFF;
+ SET_NEGATIVE(m & 0x80);
+ SET_ZERO(!m);
+ Y = m;
+ return;
+}
+
+void mos6502::Op_EOR(uint16_t src)
+{
+ uint8_t m = Read(src);
+ m = A ^ m;
+ SET_NEGATIVE(m & 0x80);
+ SET_ZERO(!m);
+ A = m;
+}
+
+void mos6502::Op_INC(uint16_t src)
+{
+ uint8_t m = Read(src);
+ m = (m + 1) & 0xFF;
+ SET_NEGATIVE(m & 0x80);
+ SET_ZERO(!m);
+ Write(src, m);
+}
+
+void mos6502::Op_INX(uint16_t src)
+{
+ uint8_t m = X;
+ m = (m + 1) & 0xFF;
+ SET_NEGATIVE(m & 0x80);
+ SET_ZERO(!m);
+ X = m;
+}
+
+void mos6502::Op_INY(uint16_t src)
+{
+ uint8_t m = Y;
+ m = (m + 1) & 0xFF;
+ SET_NEGATIVE(m & 0x80);
+ SET_ZERO(!m);
+ Y = m;
+}
+
+void mos6502::Op_JMP(uint16_t src)
+{
+ pc = src;
+}
+
+void mos6502::Op_JSR(uint16_t src)
+{
+ pc--;
+ StackPush((pc >> 8) & 0xFF);
+ StackPush(pc & 0xFF);
+ pc = src;
+}
+
+void mos6502::Op_LDA(uint16_t src)
+{
+ uint8_t m = Read(src);
+ SET_NEGATIVE(m & 0x80);
+ SET_ZERO(!m);
+ A = m;
+}
+
+void mos6502::Op_LDX(uint16_t src)
+{
+ uint8_t m = Read(src);
+ SET_NEGATIVE(m & 0x80);
+ SET_ZERO(!m);
+ X = m;
+}
+
+void mos6502::Op_LDY(uint16_t src)
+{
+ uint8_t m = Read(src);
+ SET_NEGATIVE(m & 0x80);
+ SET_ZERO(!m);
+ Y = m;
+}
+
+void mos6502::Op_LSR(uint16_t src)
+{
+ uint8_t m = Read(src);
+ SET_CARRY(m & 0x01);
+ m >>= 1;
+ SET_NEGATIVE(0);
+ SET_ZERO(!m);
+ Write(src, m);
+}
+
+void mos6502::Op_LSR_ACC(uint16_t src)
+{
+ uint8_t m = A;
+ SET_CARRY(m & 0x01);
+ m >>= 1;
+ SET_NEGATIVE(0);
+ SET_ZERO(!m);
+ A = m;
+}
+
+void mos6502::Op_NOP(uint16_t src)
+{
+ return;
+}
+
+void mos6502::Op_ORA(uint16_t src)
+{
+ uint8_t m = Read(src);
+ m = A | m;
+ SET_NEGATIVE(m & 0x80);
+ SET_ZERO(!m);
+ A = m;
+}
+
+void mos6502::Op_PHA(uint16_t src)
+{
+ StackPush(A);
+ return;
+}
+
+void mos6502::Op_PHP(uint16_t src)
+{
+ StackPush(status | CONSTANT | BREAK);
+ return;
+}
+
+void mos6502::Op_PLA(uint16_t src)
+{
+ A = StackPop();
+ SET_NEGATIVE(A & 0x80);
+ SET_ZERO(!A);
+ return;
+}
+
+void mos6502::Op_PLP(uint16_t src)
+{
+ status = StackPop() | CONSTANT | BREAK;
+ //SET_CONSTANT(1);
+ return;
+}
+
+void mos6502::Op_ROL(uint16_t src)
+{
+ uint16_t m = Read(src);
+ m <<= 1;
+ if (IF_CARRY()) m |= 0x01;
+ SET_CARRY(m > 0xFF);
+ m &= 0xFF;
+ SET_NEGATIVE(m & 0x80);
+ SET_ZERO(!m);
+ Write(src, m);
+ return;
+}
+
+void mos6502::Op_ROL_ACC(uint16_t src)
+{
+ uint16_t m = A;
+ m <<= 1;
+ if (IF_CARRY()) m |= 0x01;
+ SET_CARRY(m > 0xFF);
+ m &= 0xFF;
+ SET_NEGATIVE(m & 0x80);
+ SET_ZERO(!m);
+ A = m;
+ return;
+}
+
+void mos6502::Op_ROR(uint16_t src)
+{
+ uint16_t m = Read(src);
+ if (IF_CARRY()) m |= 0x100;
+ SET_CARRY(m & 0x01);
+ m >>= 1;
+ m &= 0xFF;
+ SET_NEGATIVE(m & 0x80);
+ SET_ZERO(!m);
+ Write(src, m);
+ return;
+}
+
+void mos6502::Op_ROR_ACC(uint16_t src)
+{
+ uint16_t m = A;
+ if (IF_CARRY()) m |= 0x100;
+ SET_CARRY(m & 0x01);
+ m >>= 1;
+ m &= 0xFF;
+ SET_NEGATIVE(m & 0x80);
+ SET_ZERO(!m);
+ A = m;
+ return;
+}
+
+void mos6502::Op_RTI(uint16_t src)
+{
+ uint8_t lo, hi;
+
+ status = StackPop() | CONSTANT | BREAK;
+
+ lo = StackPop();
+ hi = StackPop();
+
+ pc = (hi << 8) | lo;
+ return;
+}
+
+void mos6502::Op_RTS(uint16_t src)
+{
+ uint8_t lo, hi;
+
+ lo = StackPop();
+ hi = StackPop();
+
+ pc = ((hi << 8) | lo) + 1;
+ return;
+}
+
+void mos6502::Op_SBC(uint16_t src)
+{
+ uint8_t m = Read(src);
+ unsigned int tmp = A - m - (IF_CARRY() ? 0 : 1);
+ SET_NEGATIVE(tmp & 0x80);
+ SET_ZERO(!(tmp & 0xFF));
+ SET_OVERFLOW(((A ^ tmp) & 0x80) && ((A ^ m) & 0x80));
+
+ if (IF_DECIMAL())
+ {
+ if ( ((A & 0x0F) - (IF_CARRY() ? 0 : 1)) < (m & 0x0F)) tmp -= 6;
+ if (tmp > 0x99)
+ {
+ tmp -= 0x60;
+ }
+ }
+ SET_CARRY(tmp < 0x100);
+ A = (tmp & 0xFF);
+ return;
+}
+
+void mos6502::Op_SEC(uint16_t src)
+{
+ SET_CARRY(1);
+ return;
+}
+
+void mos6502::Op_SED(uint16_t src)
+{
+ SET_DECIMAL(1);
+ return;
+}
+
+void mos6502::Op_SEI(uint16_t src)
+{
+ SET_INTERRUPT(1);
+ return;
+}
+
+void mos6502::Op_STA(uint16_t src)
+{
+ Write(src, A);
+ return;
+}
+
+void mos6502::Op_STX(uint16_t src)
+{
+ Write(src, X);
+ return;
+}
+
+void mos6502::Op_STY(uint16_t src)
+{
+ Write(src, Y);
+ return;
+}
+
+void mos6502::Op_TAX(uint16_t src)
+{
+ uint8_t m = A;
+ SET_NEGATIVE(m & 0x80);
+ SET_ZERO(!m);
+ X = m;
+ return;
+}
+
+void mos6502::Op_TAY(uint16_t src)
+{
+ uint8_t m = A;
+ SET_NEGATIVE(m & 0x80);
+ SET_ZERO(!m);
+ Y = m;
+ return;
+}
+
+void mos6502::Op_TSX(uint16_t src)
+{
+ uint8_t m = sp;
+ SET_NEGATIVE(m & 0x80);
+ SET_ZERO(!m);
+ X = m;
+ return;
+}
+
+void mos6502::Op_TXA(uint16_t src)
+{
+ uint8_t m = X;
+ SET_NEGATIVE(m & 0x80);
+ SET_ZERO(!m);
+ A = m;
+ return;
+}
+
+void mos6502::Op_TXS(uint16_t src)
+{
+ sp = X;
+ return;
+}
+
+void mos6502::Op_TYA(uint16_t src)
+{
+ uint8_t m = Y;
+ SET_NEGATIVE(m & 0x80);
+ SET_ZERO(!m);
+ A = m;
+ return;
+}
capstable[5] = host_scrolllockstate;
capstable[6] = 0;
capslockstate = inputdevice_synccapslock (capslockstate, capstable);
+ if (currprefs.keyboard_mode == 0) {
+ gui_data.capslock = host_capslockstate;
+ gui_led(LED_CAPS, gui_data.capslock, -1);
+ }
return capslockstate;
}
int target_checkcapslock (int scancode, int *state)
{
- if (scancode != DIK_CAPITAL && scancode != DIK_NUMLOCK && scancode != DIK_SCROLL)
+ if (scancode != DIK_CAPITAL && scancode != DIK_NUMLOCK && scancode != DIK_SCROLL) {
return 0;
- if (*state == 0)
+ }
+ if (currprefs.keyboard_mode > 0) {
+ return 1;
+ }
+ if (*state == 0) {
return -1;
- if (scancode == DIK_CAPITAL)
+ }
+ if (scancode == DIK_CAPITAL) {
*state = host_capslockstate;
- if (scancode == DIK_NUMLOCK)
+ if (gui_data.capslock != (host_capslockstate != 0)) {
+ gui_data.capslock = host_capslockstate;
+ gui_led(LED_CAPS, gui_data.capslock, -1);
+ }
+ }
+ if (scancode == DIK_NUMLOCK) {
*state = host_numlockstate;
- if (scancode == DIK_SCROLL)
+ }
+ if (scancode == DIK_SCROLL) {
*state = host_scrolllockstate;
+ }
return 1;
}
#define IDC_BLITIMM 1174
#define IDC_BLITWAIT 1175
#define IDC_LORES 1176
-#define IDC_KEYBOARD_CONNECTED 1176
+#define IDC_KEYBOARDNKRO 1176
#define IDC_RATE2BOX 1177
#define IDC_SUBPIXEL 1177
#define IDC_AUTORESOLUTIONSELECT 1178
#define IDC_SOUND_OPENAL 1716
#define IDC_MONITOREMU_MON 1716
#define IDC_CS_CD32CD 1717
+#define IDC_KEYBOARDMODE 1717
#define IDC_CS_CD32C2P 1718
#define IDC_SOUND_PORTAUDIO 1718
#define IDC_CS_CD32NVRAM 1719
CONTROL "Keep aspect ratio",IDC_GENLOCK_KEEP_ASPECT,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_GROUP | WS_TABSTOP,13,262,214,10
COMBOBOX IDC_GENLOCKFILE,12,278,356,75,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP
PUSHBUTTON "...",IDC_GENLOCKFILESELECT,375,277,10,15
+ COMBOBOX IDC_KEYBOARDMODE,12,142,191,65,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ CONTROL "Keyboard N-key rollover [] Always emulate n-key rollover (no key ghosting or jamming when pressing multiple keys at the same time) even if selected emulated keyboard model does not support it.",IDC_KEYBOARDNKRO,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,162,150,10
+ GROUPBOX "Keyboard",IDC_STATIC,0,125,215,53
END
IDD_CHIPSET2 DIALOGEX 0, 0, 396, 316
setpaused (pause_emulation);
was_paused = pause_emulation;
mon->manual_painting_needed++;
- gui_fps (0, 0, 0);
+ gui_fps (0, 0, 0, 0, 0);
gui_led (LED_SND, 0, -1);
// we got just paused, report it to caller.
return 1;
log_ld = getval (np);
return 2;
}
+ if (!_tcscmp (arg, _T("kbmculog"))) {
+ kb_mcu_log = getval (np);
+ return 2;
+ }
if (!_tcscmp (arg, _T("midiinbuffer"))) {
midi_inbuflen = getval (np);
if (midi_inbuflen < 16000)
for (int i = 0; i < NUM_LEDS; i++)
gui_flicker_led(i, -1, -1);
gui_led(LED_POWER, gui_data.powerled, gui_data.powerled_brightness);
- gui_fps(0, 0, 0);
+ gui_fps(0, 0, 0, 0, 0);
if (gui_data.md >= 0)
gui_led(LED_MD, 0, -1);
for (int i = 0; i < 4; i++) {
RECT rc;
HLOCAL hloc;
LPINT lpParts;
- int drive_width, hd_width, cd_width, power_width;
- int fps_width, idle_width, snd_width, joy_width, net_width;
+ int drive_width, hd_width, cd_width, power_width, caps_width;
+ int fps_width, lines_width, idle_width, snd_width, joy_width, net_width;
int joys = currprefs.win32_statusbar > 1 ? 2 : 0;
- int num_parts = 12 + joys + 1;
+ int num_parts = LED_MAX + joys + 1;
float scale = 1.0;
WINDOWINFO wi;
int extra;
hd_width = (int)(24 * scale);
cd_width = (int)(24 * scale);
power_width = (int)(42 * scale);
+ caps_width = (int)(42 * scale);
+ lines_width = (int)(42 * scale);
fps_width = (int)(64 * scale);
idle_width = (int)(64 * scale);
net_width = (int)(24 * scale);
i++;
window_led_msg_start = i;
/* Calculate the right edge coordinate for each part, and copy the coords to the array. */
- int startx = rc.right - (drive_width * 4) - power_width - idle_width - fps_width - cd_width - hd_width - snd_width - net_width - joys * joy_width - extra;
+ int startx = rc.right - (drive_width * 4) - power_width - caps_width - idle_width - fps_width - lines_width - cd_width - hd_width - snd_width - net_width - joys * joy_width - extra;
for (int j = 0; j < joys; j++) {
lpParts[i] = startx;
i++;
// fps
lpParts[i] = lpParts[i - 1] + idle_width;
i++;
- // power
+ // lines
lpParts[i] = lpParts[i - 1] + fps_width;
i++;
+ // power
+ lpParts[i] = lpParts[i - 1] + lines_width;
+ i++;
+ // caps
+ lpParts[i] = lpParts[i - 1] + power_width;
+ i++;
i1 = i;
// hd
- lpParts[i] = lpParts[i - 1] + power_width;
+ lpParts[i] = lpParts[i - 1] + caps_width;
i++;
// cd
lpParts[i] = lpParts[i - 1] + hd_width;
ew(hDlg, IDC_GENLOCKFILESELECT, genlock && (workprefs.genlock_image >= 6 || (workprefs.genlock_image >= 3 && workprefs.genlock_image < 5)) ? TRUE : FALSE);
ew(hDlg, IDC_MONITOREMU_MON, workprefs.monitoremu != 0);
+
+ if (workprefs.keyboard_mode == KB_UAE || workprefs.keyboard_mode == KB_A2000_8039) {
+ if (!workprefs.keyboard_nkro) {
+ workprefs.keyboard_nkro = true;
+ CheckDlgButton(hDlg, IDC_KEYBOARDNKRO, TRUE);
+ }
+ ew(hDlg, IDC_KEYBOARDNKRO, FALSE);
+ } else {
+ ew(hDlg, IDC_KEYBOARDNKRO, TRUE);
+ }
+
}
static const int fakerefreshrates[] = { 50, 60, 100, 120, 0 };
CheckDlgButton(hDlg, IDC_GENLOCK, workprefs.genlock);
CheckDlgButton(hDlg, IDC_BLITIMM, workprefs.immediate_blits);
CheckDlgButton(hDlg, IDC_BLITWAIT, workprefs.waiting_blits);
- CheckDlgButton(hDlg, IDC_KEYBOARD_CONNECTED, workprefs.keyboard_connected);
+ CheckDlgButton(hDlg, IDC_KEYBOARDNKRO, workprefs.keyboard_nkro);
+ xSendDlgItemMessage(hDlg, IDC_KEYBOARDMODE, CB_SETCURSEL, workprefs.keyboard_mode + 1, 0);
CheckDlgButton(hDlg, IDC_SUBPIXEL, workprefs.chipset_hr);
xSendDlgItemMessage(hDlg, IDC_CS_HVCSYNC, CB_SETCURSEL, workprefs.cs_hvcsync, 0);
workprefs.immediate_blits = ischecked (hDlg, IDC_BLITIMM);
workprefs.waiting_blits = ischecked (hDlg, IDC_BLITWAIT) ? 1 : 0;
workprefs.chipset_hr = ischecked(hDlg, IDC_SUBPIXEL);
- workprefs.keyboard_connected = ischecked(hDlg, IDC_KEYBOARD_CONNECTED) ? 1 : 0;
+ workprefs.keyboard_nkro = ischecked(hDlg, IDC_KEYBOARDNKRO);
+ nn = xSendDlgItemMessage(hDlg, IDC_KEYBOARDMODE, CB_GETCURSEL, 0, 0);
+ if (nn != CB_ERR) {
+ workprefs.keyboard_mode = nn - 1;
+ }
int val = xSendDlgItemMessage(hDlg, IDC_CS_HVCSYNC, CB_GETCURSEL, 0, 0L);
if (val != CB_ERR)
workprefs.cs_hvcsync = val;
}
}
+static void appendkbmcurom(TCHAR *s, bool hasrom)
+{
+ if (!hasrom) {
+ _tcscat(s, _T(" [ROM not found]"));
+ }
+}
+
static INT_PTR CALLBACK ChipsetDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
static int recursive = 0;
{
pages[CHIPSET_ID] = hDlg;
currentpage = CHIPSET_ID;
+ int ids1[] = { 321, -1 };
+ int ids2[] = { 322, -1 };
+ int ids3[] = { 323, -1 };
+ struct romlist *has65001 = NULL;
+ struct romlist *has657036 = getromlistbyids(ids1, NULL);
+ struct romlist *has6805 = getromlistbyids(ids2, NULL);
+ struct romlist *has8039 = getromlistbyids(ids3, NULL);
+
+ xSendDlgItemMessage(hDlg, IDC_KEYBOARDMODE, CB_RESETCONTENT, 0, 0);
+ xSendDlgItemMessage(hDlg, IDC_KEYBOARDMODE, CB_ADDSTRING, 0, (LPARAM)_T("Keyboard disconnected"));
+ xSendDlgItemMessage(hDlg, IDC_KEYBOARDMODE, CB_ADDSTRING, 0, (LPARAM)_T("UAE High level emulation"));
+ _tcscpy(tmp, _T("A500 / A500 + (6570 - 036 MCU)"));
+ appendkbmcurom(tmp, has657036);
+ xSendDlgItemMessage(hDlg, IDC_KEYBOARDMODE, CB_ADDSTRING, 0, tmp);
+ _tcscpy(tmp, _T("A600(6570 - 036 MCU)"));
+ appendkbmcurom(tmp, has657036);
+ xSendDlgItemMessage(hDlg, IDC_KEYBOARDMODE, CB_ADDSTRING, 0, tmp);
+ _tcscpy(tmp, _T("A1000 (6500-1 MCU. ROM not yet dumped)"));
+ appendkbmcurom(tmp, has65001);
+ xSendDlgItemMessage(hDlg, IDC_KEYBOARDMODE, CB_ADDSTRING, 0, tmp);
+ _tcscpy(tmp, _T("A1000 (6570-036 MCU)"));
+ appendkbmcurom(tmp, has657036);
+ xSendDlgItemMessage(hDlg, IDC_KEYBOARDMODE, CB_ADDSTRING, 0, tmp);
+ _tcscpy(tmp, _T("A1200 (68HC05C MCU)"));
+ appendkbmcurom(tmp, has6805);
+ xSendDlgItemMessage(hDlg, IDC_KEYBOARDMODE, CB_ADDSTRING, 0, tmp);
+ _tcscpy(tmp, _T("A2000 (Cherry, 8039 MCU)"));
+ appendkbmcurom(tmp, has8039);
+ xSendDlgItemMessage(hDlg, IDC_KEYBOARDMODE, CB_ADDSTRING, 0, tmp);
+ _tcscpy(tmp, _T("A2000/A3000/A4000 (6570-036 MCU)"));
+ appendkbmcurom(tmp, has657036);
+ xSendDlgItemMessage(hDlg, IDC_KEYBOARDMODE, CB_ADDSTRING, 0, tmp);
xSendDlgItemMessage(hDlg, IDC_CS_EXT, CB_RESETCONTENT, 0, 0);
xSendDlgItemMessage(hDlg, IDC_CS_EXT, CB_ADDSTRING, 0, (LPARAM)_T("Custom"));
}
}
-void gui_fps (int fps, int idle, int color)
+void gui_fps (int fps, int lines, bool lace, int idle, int color)
{
gui_data.fps = fps;
+ gui_data.lines = lines;
+ gui_data.lace = lace;
gui_data.idle = idle;
gui_data.fps_color = color;
- 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);
+ gui_led(LED_FPS, 0, -1);
+ gui_led(LED_LINES, 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
return;
tt = NULL;
if (led >= LED_DF0 && led <= LED_DF3) {
- pos = 7 + (led - LED_DF0);
+ pos = 9 + (led - LED_DF0);
ptr = drive_text + pos * LED_STRING_WIDTH;
if (gui_data.drives[led - 1].drive_disabled)
_tcscpy (ptr, _T(""));
if (gui_data.drives[led - 1].floppy_protected)
writeprotected = 1;
} else if (led == LED_POWER) {
- pos = 3;
+ pos = 4;
ptr = _tcscpy(drive_text + pos * LED_STRING_WIDTH, _T("Power"));
center = 1;
+ } else if (led == LED_CAPS) {
+ pos = 5;
+ ptr = _tcscpy(drive_text + pos * LED_STRING_WIDTH, _T("Caps"));
+ center = 1;
} else if (led == LED_HD) {
- pos = 4;
+ pos = 7;
ptr = _tcscpy(drive_text + pos * LED_STRING_WIDTH, _T("HD"));
center = 1;
if (on > 1)
writing = 1;
} else if (led == LED_CD) {
- pos = 5;
+ pos = 6;
ptr = _tcscpy(drive_text + pos * LED_STRING_WIDTH, _T("CD"));
center = 1;
if (on >= 0) {
on &= 1;
}
} else if (led == LED_NET) {
- pos = 6;
+ pos = 8;
ptr = _tcscpy(drive_text + pos * LED_STRING_WIDTH, _T("N"));
center = 1;
if (on > 1)
writing = 1;
+ } else if (led == LED_LINES) {
+ pos = 3;
+ ptr = drive_text + pos * LED_STRING_WIDTH;
+ _stprintf(ptr, _T("%d%c"), gui_data.lines, gui_data.lace ? 'i' : 'p');
+ on = 1;
} else if (led == LED_FPS) {
float fps = gui_data.fps / 10.0f;
extern float p96vblank;
on = 0;
}
} else if (led == LED_MD) {
- pos = 7 + 3;
+ pos = 9 + 3;
ptr = _tcscpy(drive_text + pos * LED_STRING_WIDTH, _T("NV"));
}
<ClCompile Include="..\..\ini.cpp" />
<ClCompile Include="..\..\inputrecord.cpp" />
<ClCompile Include="..\..\isofs.cpp" />
+ <ClCompile Include="..\..\kbmcu\8048\co8048.cpp" />
+ <ClCompile Include="..\..\kbmcu\keyboard_mcu_6500_1.cpp" />
+ <ClCompile Include="..\..\kbmcu\keyboard_mcu_6805.cpp" />
+ <ClCompile Include="..\..\kbmcu\keyboard_mcu_d8039hlc .cpp" />
+ <ClCompile Include="..\..\kbmcu\m6805\m68emu.cpp" />
+ <ClCompile Include="..\..\kbmcu\m6805\m68_ops.cpp" />
<ClCompile Include="..\..\logging.cpp" />
<ClCompile Include="..\..\luascript.cpp" />
<ClCompile Include="..\..\mame\a2410.cpp" />
<ClCompile Include="..\..\mame\tm34010\tms34010.cpp" />
<ClCompile Include="..\..\midiemu.cpp" />
+ <ClCompile Include="..\..\mos6502.cpp" />
<ClCompile Include="..\..\ncr9x_scsi.cpp" />
<ClCompile Include="..\..\newcpu_common.cpp" />
<ClCompile Include="..\..\pcem\386.cpp" />
<Filter Include="dsp3210">
<UniqueIdentifier>{6f046035-4e6d-4038-a65f-d789a89ee702}</UniqueIdentifier>
</Filter>
+ <Filter Include="kbmcu">
+ <UniqueIdentifier>{b60c3d87-d969-4982-8508-e9fdfc29a312}</UniqueIdentifier>
+ </Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\ahidsound_dsonly.cpp">
<ClCompile Include="..\..\pcem\vid_bt482_ramdac.cpp">
<Filter>pcem</Filter>
</ClCompile>
+ <ClCompile Include="..\..\kbmcu\keyboard_mcu_6500_1.cpp">
+ <Filter>kbmcu</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\kbmcu\keyboard_mcu_6805.cpp">
+ <Filter>kbmcu</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\kbmcu\keyboard_mcu_d8039hlc .cpp">
+ <Filter>kbmcu</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\kbmcu\m6805\m68_ops.cpp">
+ <Filter>kbmcu</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\kbmcu\m6805\m68emu.cpp">
+ <Filter>kbmcu</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\kbmcu\8048\co8048.cpp">
+ <Filter>kbmcu</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\mos6502.cpp">
+ <Filter>common</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\resources\35floppy.ico">
}
}
-
struct romdata *getromdatabypath (const TCHAR *path)
{
int i;
return NULL;
}
-#define NEXT_ROM_ID 322
+#define NEXT_ROM_ID 324
#if NEXT_ROM_ID >= MAX_ROMMGR_ROMS
#error Increase MAX_ROMMGR_ROMS!
{ _T("Cloanto Amiga Forever 2010 ROM key"), 0, 0, 0, 0, 0, 1544, 73, 0, 1, ROMTYPE_KEY, 0, 0, NULL,
0x8c4dd05c, 0x05034f62,0x0b5bb7b2,0x86954ea9,0x164fdb90,0xfb2897a4 },
- { _T("6500/1 Keyboard MCU ROM"), 0, 0, 0, 0, _T("KBDMCU\0"), 2048, 321, 0, 0, ROMTYPE_KBMCU, 0, 0, NULL,
+ { _T("6570-036 Keyboard MCU ROM"), 0, 0, 0, 0, _T("KBDMCU\0"), 2048, 321, 0, 0, ROMTYPE_KBMCU, 0, 0, NULL,
0x4a3fc332, 0x83b21d0c, 0x8b93fc9b, 0x9b3b287f, 0xde4ec8f3, 0xbadac5a2 },
+ { _T("68HC05 Keyboard MCU ROM"), 0, 0, 0, 0, _T("KBDMCU\0"), 8192, 322, 0, 0, ROMTYPE_KBMCU, 0, 0, NULL,
+ 0x2a77eec4, 0x301ec6a6, 0x9404457d, 0x912c89e3, 0xfc54095e, 0xda9f0e93 },
+ { _T("D8039HLC Keyboard MCU ROM"), 0, 0, 0, 0, _T("KBDMCU\0"), 2048, 323, 0, 0, ROMTYPE_KBMCU, 0, 0, NULL,
+ 0xc23d280e, 0xb5c4b8c3, 0x8b9e4a86, 0x4abc871d, 0x048bd1c3, 0xa02c8432 },
{ _T("KS ROM v23.93 (Velvet)"), 23, 93, 23, 93, _T("VELVET\0"), 131072, 125, 0, 0, ROMTYPE_KICK, 0, 0, NULL,
0xadcb44c9, 0x7c36b2ba,0x298da3da,0xce60d0ba,0x8511d470,0x76a40d5c, NULL, NULL, 4 },
end = restore_disk2 (3, chunk);
else if (!_tcscmp (name, _T("KEYB")))
end = restore_keyboard (chunk);
+ else if (!_tcscmp (name, _T("KBM1")))
+ end = restore_kbmcu(chunk);
+ else if (!_tcscmp (name, _T("KBM2")))
+ end = restore_kbmcu2(chunk);
+ else if (!_tcscmp (name, _T("KBM3")))
+ end = restore_kbmcu3(chunk);
#ifdef AUTOCONFIG
else if (!_tcscmp (name, _T("EXPA")))
end = restore_expansion (chunk);
save_chunk (f, dst, len, _T("KEYB"), 0);
xfree (dst);
+ dst = save_kbmcu(&len, NULL);
+ save_chunk(f, dst, len, _T("KBM1"), 0);
+ xfree (dst);
+ dst = save_kbmcu2(&len, NULL);
+ save_chunk(f, dst, len, _T("KBM2"), 0);
+ xfree (dst);
+ dst = save_kbmcu3(&len, NULL);
+ save_chunk(f, dst, len, _T("KBM3"), 0);
+ xfree (dst);
+
#ifdef AUTOCONFIG
// new
i = 0;
struct floppyslot *fs = &currprefs.floppyslots[pled];
struct gui_info_drive *gid = &gui_data.drives[pled];
int track = gid->drive_track;
- pos = 7 + pled;
+ pos = 8 + pled;
on_rgb = 0x00cc00;
if (!gid->drive_disabled) {
num1 = -1;
on_rgb &= 0xffffff;
off_rgb = rgbmuldiv(on_rgb, 2, 4);
on_rgb2 = rgbmuldiv(on_rgb, 2, 3);
+ } else if (led == LED_CAPS) {
+ pos = 4;
+ on_rgb = 0xcc9900;
+ on = gui_data.capslock;
+ off_rgb = (on_rgb & 0xfefefe) >> 1;
} else if (led == LED_POWER) {
pos = 3;
on_rgb = ((gui_data.powerled_brightness * 10 / 16) + 0x33) << 16;
on = 1;
off_rgb = 0x330000;
} else if (led == LED_CD) {
- pos = 5;
+ pos = 6;
if (gui_data.cd >= 0) {
on = gui_data.cd & (LED_CD_AUDIO | LED_CD_ACTIVE);
on_rgb = (on & LED_CD_AUDIO) ? 0x00cc00 : 0x0000cc;
num3 = 12;
}
} else if (led == LED_HD) {
- pos = 4;
+ pos = 5;
if (gui_data.hd >= 0) {
on = gui_data.hd;
on_rgb = on == 2 ? 0xcc0000 : 0x0000cc;
} else if (led == LED_MD) {
// DF3 reused as internal non-volatile ram led (cd32/cdtv)
if (gui_data.drives[3].drive_disabled && gui_data.md >= 0) {
- pos = 7 + 3;
+ pos = 8 + 3;
if (gui_data.md >= 0) {
on = gui_data.md;
on_rgb = on == 2 ? 0xcc0000 : 0x00cc00;
continue;
}
} else if (led == LED_NET) {
- pos = 6;
+ pos = 7;
if (gui_data.net >= 0) {
on = gui_data.net;
on_rgb = 0;