From e0aa2d00c82ba2ce050738d492bfbefa9b575843 Mon Sep 17 00:00:00 2001 From: ekeeke31 Date: Mon, 1 Nov 2010 18:08:24 +0000 Subject: [PATCH] .added PRO Action Replay hardware emulation --- source/cart_hw/areplay.c | 299 +++++++++++++++++++++++ source/cart_hw/{datel.h => areplay.h} | 17 +- source/cart_hw/cart_hw.c | 8 +- source/cart_hw/datel.c | 333 -------------------------- source/genesis.c | 8 +- source/shared.h | 2 +- 6 files changed, 320 insertions(+), 347 deletions(-) create mode 100644 source/cart_hw/areplay.c rename source/cart_hw/{datel.h => areplay.h} (73%) delete mode 100644 source/cart_hw/datel.c diff --git a/source/cart_hw/areplay.c b/source/cart_hw/areplay.c new file mode 100644 index 0000000..9e0c148 --- /dev/null +++ b/source/cart_hw/areplay.c @@ -0,0 +1,299 @@ +/**************************************************************************** + * Genesis Plus + * Action Replay / Pro Action Replay emulation + * + * Copyright (C) 2009 Eke-Eke (GCN/Wii port) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + ***************************************************************************/ + +#include "shared.h" + +#define TYPE_PRO1 0x12 +#define TYPE_PRO2 0x22 + +static struct +{ + uint8 enabled; + uint8 status; + uint8 *rom; + uint8 *ram; + uint16 regs[13]; + uint16 old[4]; + uint16 data[4]; + uint32 addr[4]; +} action_replay; + +static void ar_write_regs(uint32 address, uint32 data); +static void ar_write_regs_2(uint32 address, uint32 data); +static void ar_write_ram_8(uint32 address, uint32 data); + +void areplay_init(void) +{ + memset(&action_replay,0,sizeof(action_replay)); + if (cart.romsize > 0x800000) return; + + /* Open Action Replay ROM */ + FILE *f = fopen(AR_ROM,"rb"); + if (!f) return; + + /* store Action replay ROM + RAM above cartridge ROM + SRAM */ + action_replay.rom = cart.rom + 0x800000; + action_replay.ram = cart.rom + 0x810000; + + /* ROM size */ + fseek(f, 0, SEEK_END); + int size = ftell(f); + fseek(f, 0, SEEK_SET); + + /* detect Action Replay board type */ + switch (size) + { + case 0x8000: + { + /* normal Action Replay (32K) */ + action_replay.enabled = TYPE_AR; + + /* internal registers mapped at $010000-$01ffff */ + m68k_memory_map[0x01].write16 = ar_write_regs; + + break; + } + + case 0x10000: + case 0x20000: + { + /* read Stack Pointer */ + uint8 sp[4]; + fread(&sp, 4, 1, f); + fseek(f, 0, SEEK_SET); + + /* Detect board version */ + if (sp[1] == 0x42) + { + /* PRO Action Replay 1 (64/128K) */ + action_replay.enabled = TYPE_PRO1; + + /* internal registers mapped at $010000-$01ffff */ + m68k_memory_map[0x01].write16 = ar_write_regs; + } + else if (sp[1] == 0x60) + { + /* PRO Action Replay 2 (64K) */ + action_replay.enabled = TYPE_PRO2; + + /* internal registers mapped at $100000-$10ffff */ + m68k_memory_map[0x10].write16 = ar_write_regs_2; + } + + /* internal RAM (64k), mapped at $420000-$42ffff or $600000-$60ffff */ + if (action_replay.enabled) + { + m68k_memory_map[sp[1]].base = action_replay.ram; + m68k_memory_map[sp[1]].read8 = NULL; + m68k_memory_map[sp[1]].read16 = NULL; + m68k_memory_map[sp[1]].write8 = ar_write_ram_8; + m68k_memory_map[sp[1]].write16 = NULL; + } + + break; + } + + default: + { + break; + } + } + + if (action_replay.enabled) + { + /* Load ROM */ + int i = 0; + while (i < size) + { + fread(action_replay.rom+i,0x1000,1,f); + i += 0x1000; + } + +#ifdef LSB_FIRST + /* Byteswap ROM */ + uint8 temp; + for(i = 0; i < size; i += 2) + { + temp = action_replay.rom[i]; + action_replay.rom[i] = action_replay.rom[i+1]; + action_replay.rom[i+1] = temp; + } +#endif + } + + fclose(f); +} + +void areplay_shutdown(void) +{ + /* clear existing patches */ + areplay_set_status(AR_SWITCH_OFF); + + /* disable device by default */ + action_replay.enabled = 0; +} + +void areplay_reset(int hard_reset) +{ + if (action_replay.enabled) + { + /* reset internal registers */ + memset(action_replay.regs, 0, sizeof(action_replay.regs)); + memset(action_replay.old, 0, sizeof(action_replay.old)); + memset(action_replay.data, 0, sizeof(action_replay.data)); + memset(action_replay.addr, 0, sizeof(action_replay.addr)); + + /* by default, internal ROM is mapped at $000000-$00FFFF */ + m68k_memory_map[0].base = action_replay.rom; + + /* internal RAM is cleared on power ON */ + if (hard_reset) + { + memset(action_replay.ram,0xff,0x10000); + } + } +} + +int areplay_get_status(void) +{ + if (action_replay.enabled) + { + return action_replay.status; + } + + return -1; +} + +void areplay_set_status(int status) +{ + if (action_replay.enabled) + { + /* no Trainer mode for normal Action Replay */ + if ((action_replay.enabled == TYPE_AR) && (status == AR_SWITCH_TRAINER)) + { + status = AR_SWITCH_OFF; + } + + /* check status changes */ + switch (status) + { + case AR_SWITCH_OFF: + case AR_SWITCH_TRAINER: + { + /* check that patches were previously enabled */ + if (action_replay.status == AR_SWITCH_ON) + { + /* restore original data */ + *(uint16 *)(cart.rom + action_replay.addr[0]) = action_replay.old[0]; + *(uint16 *)(cart.rom + action_replay.addr[1]) = action_replay.old[1]; + *(uint16 *)(cart.rom + action_replay.addr[2]) = action_replay.old[2]; + *(uint16 *)(cart.rom + action_replay.addr[3]) = action_replay.old[3]; + } + break; + } + + case AR_SWITCH_ON: + { + /* check that patches were previously disabled */ + if (action_replay.status != AR_SWITCH_ON) + { + /* decode patch data */ + action_replay.data[0] = action_replay.regs[0]; + action_replay.data[1] = action_replay.regs[4]; + action_replay.data[2] = action_replay.regs[7]; + action_replay.data[3] = action_replay.regs[10]; + + /* decode patch address ($000000-$7fffff) */ + action_replay.addr[0] = (action_replay.regs[1] | ((action_replay.regs[2] & 0x3f00) << 8)) << 1; + action_replay.addr[1] = (action_replay.regs[5] | ((action_replay.regs[6] & 0x3f00) << 8)) << 1; + action_replay.addr[2] = (action_replay.regs[8] | ((action_replay.regs[9] & 0x3f00) << 8)) << 1; + action_replay.addr[3] = (action_replay.regs[11] | ((action_replay.regs[12] & 0x3f00) << 8)) << 1; + + /* save original data */ + action_replay.old[0] = *(uint16 *)(cart.rom + action_replay.addr[0]); + action_replay.old[1] = *(uint16 *)(cart.rom + action_replay.addr[1]); + action_replay.old[2] = *(uint16 *)(cart.rom + action_replay.addr[2]); + action_replay.old[3] = *(uint16 *)(cart.rom + action_replay.addr[3]); + + /* patch new data */ + *(uint16 *)(cart.rom + action_replay.addr[0]) = action_replay.data[0]; + *(uint16 *)(cart.rom + action_replay.addr[1]) = action_replay.data[1]; + *(uint16 *)(cart.rom + action_replay.addr[2]) = action_replay.data[2]; + *(uint16 *)(cart.rom + action_replay.addr[3]) = action_replay.data[3]; + } + break; + } + + default: + { + return; + } + } + + /* update status */ + action_replay.status = status; + } +} + +static void ar_write_regs(uint32 address, uint32 data) +{ + /* register offset */ + int offset = (address & 0xffff) >> 1; + if (offset > 12) + { + m68k_unused_16_w(address,data); + return; + } + + /* update internal register */ + action_replay.regs[offset] = data; + + /* MODE register */ + if (action_replay.regs[3] == 0xffff) + { + /* check switch status */ + if (action_replay.status == AR_SWITCH_ON) + { + /* reset existing patches */ + areplay_set_status(AR_SWITCH_OFF); + areplay_set_status(AR_SWITCH_ON); + } + + /* enable Cartridge ROM */ + m68k_memory_map[0].base = cart.rom; + } +} + +static void ar_write_regs_2(uint32 address, uint32 data) +{ + /* enable Cartridge ROM */ + if (((address & 0xff) == 0x78) && (data == 0xffff)) + { + m68k_memory_map[0].base = cart.rom; + } +} + +static void ar_write_ram_8(uint32 address, uint32 data) +{ + /* byte writes are handled as word writes, with LSB duplicated in MSB (/LWR is not used) */ + *(uint16 *)(action_replay.ram + (address & 0xfffe)) = (data | (data << 8)); +} + diff --git a/source/cart_hw/datel.h b/source/cart_hw/areplay.h similarity index 73% rename from source/cart_hw/datel.h rename to source/cart_hw/areplay.h index ee8503f..4c11508 100644 --- a/source/cart_hw/datel.h +++ b/source/cart_hw/areplay.h @@ -19,12 +19,17 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ***************************************************************************/ -#ifndef _DATEL_H_ -#define _DATEL_H_ +#ifndef _AREPLAY_H_ +#define _AREPLAY_H_ -extern void datel_init(void); -extern void datel_shutdown(void); -extern void datel_reset(int hard_reset); -extern void datel_switch(int enable); +#define AR_SWITCH_OFF (0) +#define AR_SWITCH_ON (1) +#define AR_SWITCH_TRAINER (2) + +extern void areplay_init(void); +extern void areplay_shutdown(void); +extern void areplay_reset(int hard_reset); +extern void areplay_set_status(int status); +extern int areplay_get_status(void); #endif diff --git a/source/cart_hw/cart_hw.c b/source/cart_hw/cart_hw.c index 2223724..7d57c8d 100644 --- a/source/cart_hw/cart_hw.c +++ b/source/cart_hw/cart_hw.c @@ -302,9 +302,9 @@ void cart_hw_init() LOCK-ON ***********************************************/ - /* clear all existing patches */ + /* clear existing patches */ ggenie_shutdown(); - datel_shutdown(); + areplay_shutdown(); /* initialize extra hardware */ cart.lock_on = 0; @@ -315,7 +315,7 @@ void cart_hw_init() break; case TYPE_AR: - datel_init(); + areplay_init(); break; case TYPE_SK: @@ -477,7 +477,7 @@ void cart_hw_reset() break; case TYPE_AR: - datel_reset(1); + areplay_reset(1); break; case TYPE_SK: diff --git a/source/cart_hw/datel.c b/source/cart_hw/datel.c deleted file mode 100644 index 455fb3e..0000000 --- a/source/cart_hw/datel.c +++ /dev/null @@ -1,333 +0,0 @@ -/**************************************************************************** - * Genesis Plus - * DATEL Action Replay / Pro Action Replay emulation - * - * Copyright (C) 2009 Eke-Eke (GCN/Wii port) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - ***************************************************************************/ - -#include "shared.h" - -#define TYPE_PRO1 0x12 -#define TYPE_PRO2 0x22 - -struct -{ - uint8 enabled; - uint8 *rom; - uint8 *ram; - uint16 regs[13]; - uint16 old[4]; - uint16 data[4]; - uint32 addr[4]; -} action_replay; - -static void wram_write_byte(uint32 address, uint32 data); -static void wram_write_word(uint32 address, uint32 data); -static void ar_write_regs(uint32 address, uint32 data); -static void ar_write_regs_pro2(uint32 address, uint32 data); - -void datel_init(void) -{ - memset(&action_replay,0,sizeof(action_replay)); - - /* Open Action Replay ROM */ - FILE *f = fopen(AR_ROM,"rb"); - if (!f) - return; - - /* store Action replay ROM + RAM above cartridge ROM + SRAM */ - if (cart.romsize > 0x600000) return; - action_replay.rom = cart.rom + 0x600000; - action_replay.ram = cart.rom + 0x610000; - - /* ROM size */ - fseek(f, 0, SEEK_END); - int size = ftell(f); - - /* Detect Action Replay type */ - switch (size) - { - case 0x8000: /* ACTION REPLAY (32K) */ - { - action_replay.enabled = TYPE_AR; - break; - } - - case 0x10000: /* PRO ACTION REPLAY 2 (64K) */ - { - action_replay.enabled = TYPE_PRO2; - - /* RAM (64k) mapped at $600000-$60ffff */ - m68k_memory_map[0x60].base = action_replay.ram; - m68k_memory_map[0x60].read8 = NULL; - m68k_memory_map[0x60].read16 = NULL; - m68k_memory_map[0x60].write8 = NULL; - m68k_memory_map[0x60].write16 = NULL; - break; - } - - case 0x20000: /* PRO ACTION REPLAY (128K) */ - { - action_replay.enabled = TYPE_PRO1; - - /* RAM (64k) mapped at $420000-$42ffff */ - m68k_memory_map[0x42].base = action_replay.ram; - m68k_memory_map[0x42].read8 = NULL; - m68k_memory_map[0x42].read16 = NULL; - m68k_memory_map[0x42].write8 = NULL; - m68k_memory_map[0x42].write16 = NULL; - break; - } - - default: - { - fclose(f); - return; - } - } - - /* Load ROM */ - fseek(f, 0, SEEK_SET); - int i = 0; - while (i < size) - { - fread(action_replay.rom+i,0x1000,1,f); - i += 0x1000; - } - fclose(f); - -#ifdef LSB_FIRST - /* Byteswap ROM */ - uint8 temp; - for(i = 0; i < size; i += 2) - { - temp = action_replay.rom[i]; - action_replay.rom[i] = action_replay.rom[i+1]; - action_replay.rom[i+1] = temp; - } -#endif -} - -void datel_shutdown(void) -{ - if (action_replay.enabled) - { - datel_switch(0); - action_replay.enabled = 0; - } -} - -void datel_reset(int hard_reset) -{ - /* reset external mapping */ - switch (action_replay.enabled) - { - case TYPE_AR: - - /* internal registers mapped at $010000-$01ffff */ - m68k_memory_map[0x01].write16 = ar_write_regs; - - /* internal ROM mapped at $000000-$00ffff */ - m68k_memory_map[0].base = action_replay.rom; - break; - - case TYPE_PRO2: - - /* internal registers mapped at $100000-$10ffff */ - m68k_memory_map[0x10].write16 = ar_write_regs_pro2; - - /* internal ROM mapped at $000000-$00ffff */ - m68k_memory_map[0].base = action_replay.rom; - break; - - case TYPE_PRO1: - - /* internal registers mapped at $010000-$01ffff */ - m68k_memory_map[0x01].write16 = ar_write_regs; - - /* internal ROM mapped at $000000-$01ffff */ - m68k_memory_map[0].base = action_replay.rom; - m68k_memory_map[1].base = action_replay.rom + 0x10000; - break; - - default: - return; - } - - /* clear existing codes */ - datel_switch(0); - - /* reset internal state */ - memset(action_replay.regs,0,sizeof(action_replay.regs)); - memset(action_replay.old,0,sizeof(action_replay.old)); - memset(action_replay.data,0,sizeof(action_replay.data)); - memset(action_replay.addr,0,sizeof(action_replay.addr)); - - /* clear RAM on hard reset only */ - if (hard_reset) - memset(action_replay.ram,0,0x10000); -} - -void datel_switch(int enable) -{ - int i,use_wram = 0; - if (enable) - { - for (i=0; i<4; i++) - { - if (action_replay.data[i]) - { - /* store old values & patch new values */ - if (action_replay.addr[i] < 0x400000) - { - action_replay.old[i] = *(uint16 *)(cart.rom + (action_replay.addr[i]&~1)); - *(uint16 *)(cart.rom + (action_replay.addr[i]&~1)) = action_replay.data[i]; - } - else - { - use_wram = 1; - action_replay.old[i] = *(uint16 *)(work_ram + (action_replay.addr[i]&0xfffe)); - if (action_replay.data[i] & 0xff00) - *(uint16 *)(work_ram + (action_replay.addr[i]&0xfffe)) = action_replay.data[i]; - else - WRITE_BYTE(work_ram, (action_replay.addr[i]&0xfffe) + 1, action_replay.data[i] & 0xff); - } - } - } - - if (use_wram) - { - /* use specific WRAM write handlers */ - for (i=0xe0; i<0x100; i++) - { - m68k_memory_map[i].write8 = wram_write_byte; - m68k_memory_map[i].write16 = wram_write_word; - } - } - } - else - { - /* restore original data */ - for (i=0; i<4; i++) - { - if (action_replay.data[i]) - { - if (action_replay.addr[i] < 0x400000) - *(uint16 *)(cart.rom + action_replay.addr[i]) = action_replay.old[i]; - else - *(uint16 *)(work_ram + (action_replay.addr[i]&0xfffe)) = action_replay.old[i]; - } - } - - /* default WRAM write handlers */ - for (i=0xe0; i<0x100; i++) - { - m68k_memory_map[i].write8 = NULL; - m68k_memory_map[i].write16 = NULL; - } - } -} - - -static void wram_write_byte(uint32 address, uint32 data) -{ - int i; - for (i=0; i<4; i++) - { - if (action_replay.data[i]) - { - if ((address & 0xfffe) == (action_replay.addr[i] & 0xfffe)) - { - WRITE_BYTE(&action_replay.old[i], address & 1, data); - if (action_replay.data[i] & 0xff00) - return; - if ((address & 0xffff) == ((action_replay.addr[i]&0xfffe) + 1)) - return; - } - } - } - - WRITE_BYTE(work_ram, address & 0xffff, data); -} - -static void wram_write_word(uint32 address, uint32 data) -{ - *(uint16 *)(work_ram + (address & 0xffff)) = data; - - int i; - for (i=0; i<4; i++) - { - if (action_replay.data[i]) - { - if ((address & 0xffff) == (action_replay.addr[i] & 0xfffe)) - { - action_replay.old[i] = data; - if (action_replay.data[i] & 0xff00) - *(uint16 *)(work_ram + (address & 0xfffe)) = action_replay.data[i]; - else - WRITE_BYTE(work_ram, (action_replay.addr[i] & 0xfffe) + 1, action_replay.data[i]); - } - } - } -} - -static void ar_write_regs(uint32 address, uint32 data) -{ - /* register offset */ - int offset = (address & 0xffff) >> 1; - if (offset > 12) - { - m68k_unused_16_w(address,data); - return; - } - - /* update internal register */ - action_replay.regs[offset] = data; - - /* exit program */ - if (action_replay.regs[3] == 0xffff) - { - /* decode patch data */ - action_replay.data[0] = action_replay.regs[0]; - action_replay.data[1] = action_replay.regs[4]; - action_replay.data[2] = action_replay.regs[7]; - action_replay.data[3] = action_replay.regs[10]; - - /* decode patch address */ - action_replay.addr[0] = (action_replay.regs[1] | ((action_replay.regs[2] & 0x7f00) << 8)) << 1; - action_replay.addr[1] = (action_replay.regs[5] | ((action_replay.regs[6] & 0x7f00) << 8)) << 1; - action_replay.addr[2] = (action_replay.regs[8] | ((action_replay.regs[9] & 0x7f00) << 8)) << 1; - action_replay.addr[3] = (action_replay.regs[11] | ((action_replay.regs[12] & 0x7f00) << 8)) << 1; - - /* enable Cartridge ROM */ - m68k_memory_map[0].base = cart.rom; - m68k_memory_map[1].base = cart.rom + ((1<<16) & cart.mask); - - /* disable internal registers (?) */ - m68k_memory_map[0x01].write16 = m68k_unused_16_w; - - /* enable patches */ - datel_switch(1); - } -} - -static void ar_write_regs_pro2(uint32 address, uint32 data) -{ - /* enable Cartridge ROM */ - if (((address & 0xff) == 0x78) && (data == 0xffff)) - m68k_memory_map[0].base = cart.rom; -} diff --git a/source/genesis.c b/source/genesis.c index 7621dfb..427cf79 100644 --- a/source/genesis.c +++ b/source/genesis.c @@ -168,9 +168,11 @@ void gen_softreset(int state) } else { - /* Reset Pro Action Replay (required in Trainer mode) */ - if (config.lock_on == TYPE_AR) - datel_reset(0); + /* Reset PRO Action Replay (if switch is in TRAINER position) */ + if (areplay_get_status() == AR_SWITCH_TRAINER) + { + areplay_reset(0); + } /* 68k & Z80 could restart anywhere in VDP frame (Bonkers, Eternal Champions, X-Men 2) */ mcycles_68k = mcycles_z80 = (uint32)((MCYCLES_PER_LINE * lines_per_frame) * ((double)rand() / (double)RAND_MAX)); diff --git a/source/shared.h b/source/shared.h index dcec227..fa39bd0 100644 --- a/source/shared.h +++ b/source/shared.h @@ -27,7 +27,7 @@ #include "eeprom.h" #include "sram.h" #include "ggenie.h" -#include "datel.h" +#include "areplay.h" #include "svp.h" #include "osd.h"