diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.cs b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.cs index b10437c208..33c3f3ddc6 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.cs @@ -48,7 +48,8 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx64 SbrkHeapSizeKB = 256, SealedHeapSizeKB = 36 * 1024, InvisibleHeapSizeKB = 4 * 1024, - PlainHeapSizeKB = 64 + PlainHeapSizeKB = 64, + MmapHeapSizeKB = 512 }); using (_elf.EnterExit()) diff --git a/output/dll/gpgx.wbx b/output/dll/gpgx.wbx deleted file mode 100644 index c0e7a62168..0000000000 Binary files a/output/dll/gpgx.wbx and /dev/null differ diff --git a/output/dll/gpgx.wbx.gz b/output/dll/gpgx.wbx.gz new file mode 100644 index 0000000000..6350547613 Binary files /dev/null and b/output/dll/gpgx.wbx.gz differ diff --git a/waterbox/gpgx/core/cart_hw/md_cart.c b/waterbox/gpgx/core/cart_hw/md_cart.c index de7fc8f2a4..afefbeb5b7 100644 --- a/waterbox/gpgx/core/cart_hw/md_cart.c +++ b/waterbox/gpgx/core/cart_hw/md_cart.c @@ -1,1821 +1,1810 @@ -/**************************************************************************** - * Genesis Plus - * Mega Drive cartridge hardware support - * - * Copyright (C) 2007-2013 Eke-Eke (Genesis Plus GX) - * - * Many cartridge protections were initially documented by Haze - * (http://haze.mameworld.info/) - * - * Realtec mapper was documented by TascoDeluxe - * - * Redistribution and use of this code or any derivative works are permitted - * provided that the following conditions are met: - * - * - Redistributions may not be sold, nor may they be used in a commercial - * product or activity. - * - * - Redistributions that are modified from the original source must include the - * complete source code, including the source code for all components used by a - * binary built from the modified sources. However, as a special exception, the - * source code distributed need not include anything that is normally distributed - * (in either source or binary form) with the major components (compiler, kernel, - * and so on) of the operating system on which the executable runs, unless that - * component itself accompanies the executable. - * - * - Redistributions must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************************/ - -#include "shared.h" -#include "eeprom_i2c.h" -#include "eeprom_spi.h" -#include "gamepad.h" - -#define CART_CNT (55) - -/* Cart database entry */ -typedef struct -{ - uint16 chk_1; /* header checksum */ - uint16 chk_2; /* real checksum */ - uint8 bank_start; /* first mapped bank in $400000-$7fffff region */ - uint8 bank_end; /* last mapped bank in $400000-$7fffff region */ - cart_hw_t cart_hw; /* hardware description */ -} md_entry_t; - -/* Function prototypes */ -static void mapper_sega_w(uint32 data); -static void mapper_ssf2_w(uint32 address, uint32 data); -static void mapper_sf001_w(uint32 address, uint32 data); -static void mapper_sf002_w(uint32 address, uint32 data); -static void mapper_sf004_w(uint32 address, uint32 data); -static uint32 mapper_sf004_r(uint32 address); -static void mapper_t5740_w(uint32 address, uint32 data); -static uint32 mapper_t5740_r(uint32 address); -static uint32 mapper_smw_64_r(uint32 address); -static void mapper_smw_64_w(uint32 address, uint32 data); -static void mapper_realtec_w(uint32 address, uint32 data); -static void mapper_seganet_w(uint32 address, uint32 data); -static void mapper_32k_w(uint32 data); -static void mapper_64k_w(uint32 data); -static void mapper_64k_multi_w(uint32 address); -static uint32 mapper_radica_r(uint32 address); -static void default_time_w(uint32 address, uint32 data); -static void default_regs_w(uint32 address, uint32 data); -static uint32 default_regs_r(uint32 address); -static uint32 default_regs_r_16(uint32 address); -static uint32 custom_regs_r(uint32 address); -static void custom_regs_w(uint32 address, uint32 data); -static void custom_alt_regs_w(uint32 address, uint32 data); -static uint32 topshooter_r(uint32 address); -static void topshooter_w(uint32 address, uint32 data); -static uint32 tekken_regs_r(uint32 address); -static void tekken_regs_w(uint32 address, uint32 data); - -/* Games that need extra hardware emulation: - - copy protection device - - custom ROM banking device -*/ -static const md_entry_t rom_database[CART_CNT] = -{ -/* Funny World & Balloon Boy */ - {0x0000,0x06ab,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},1,0,NULL,NULL,NULL,mapper_realtec_w}}, -/* Whac-a-Critter */ - {0xffff,0xf863,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},1,0,NULL,NULL,NULL,mapper_realtec_w}}, -/* Earth Defense */ - {0xffff,0x44fb,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},1,0,NULL,NULL,NULL,mapper_realtec_w}}, - - -/* RADICA (Volume 1) (bad dump ?) */ - {0x0000,0x2326,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,1,mapper_radica_r,NULL,NULL,NULL}}, -/* RADICA (Volume 1) */ - {0x24f4,0xfc84,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,0,mapper_radica_r,NULL,NULL,NULL}}, -/* RADICA (Volume 2) */ - {0x104f,0x32e9,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,0,mapper_radica_r,NULL,NULL,NULL}}, - - -/* Tenchi wo Kurau III: Sangokushi Gaiden - Chinese Fighter */ - {0x9490,0x8180,0x40,0x6f,{{0x00,0x00,0x00,0x00},{0xf0000c,0xf0000c,0xf0000c,0xf0000c},{0x400000,0x400004,0x400008,0x40000c},0,1,NULL,NULL,default_regs_r,custom_alt_regs_w}}, - - -/* Top Fighter */ - {0x4eb9,0x5d8b,0x60,0x7f,{{0x00,0x00,0x00,0x00},{0xf00007,0xf00007,0xf00007,0xffffff},{0x600001,0x600003,0x600005,0x000000},0,1,NULL,NULL,default_regs_r,custom_regs_w}}, -/* Soul Edge VS Samurai Spirits */ - {0x00ff,0x5d34,0x60,0x7f,{{0x00,0x00,0x00,0x00},{0xf00007,0xf00007,0xf00007,0xffffff},{0x600001,0x600003,0x600005,0x000000},0,1,NULL,NULL,default_regs_r,custom_regs_w}}, -/* Mulan */ - {0x0404,0x1b40,0x60,0x7f,{{0x00,0x00,0x00,0x00},{0xf00007,0xf00007,0xf00007,0xffffff},{0x600001,0x600003,0x600005,0x000000},0,1,NULL,NULL,default_regs_r,custom_regs_w}}, -/* Pocket Monsters II */ - {0x47f9,0x17e5,0x60,0x7f,{{0x00,0x00,0x00,0x00},{0xf00007,0xf00007,0xf00007,0xffffff},{0x600001,0x600003,0x600005,0x000000},0,1,NULL,NULL,default_regs_r,custom_regs_w}}, -/* Lion King 3 */ - {0x0000,0x507c,0x60,0x7f,{{0x00,0x00,0x00,0x00},{0xf00007,0xf00007,0xf00007,0xffffff},{0x600001,0x600003,0x600005,0x000000},0,1,NULL,NULL,default_regs_r,custom_regs_w}}, -/* Super King Kong 99 */ - {0x0000,0x7d6e,0x60,0x7f,{{0x00,0x00,0x00,0x00},{0xf00007,0xf00007,0xf00007,0xffffff},{0x600001,0x600003,0x600005,0x000000},0,1,NULL,NULL,default_regs_r,custom_regs_w}}, -/* Gunfight 3-in-1 */ - {0x0000,0x6ff8,0x60,0x7f,{{0x00,0x00,0x00,0x00},{0xf00007,0xf00007,0xf00007,0xffffff},{0x600001,0x600003,0x600005,0x000000},0,1,NULL,NULL,default_regs_r,custom_regs_w}}, -/* Pokemon Stadium */ - {0x0000,0x843c,0x70,0x7f,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,1,NULL,NULL,NULL,custom_regs_w}}, - - -/* Tekken 3 Special (original dump) (a bootleg version also exists, with patched protection & different boot routine which reads unused !TIME mapped area) */ - {0x0000,0xc2f0,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,0,NULL,NULL,tekken_regs_r,tekken_regs_w}}, - - -/* Lion King 2 */ - {0xffff,0x1d9b,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xfffffd,0xfffffd,0xffffff,0xffffff},{0x400000,0x400004,0x000000,0x000000},0,0,NULL,NULL,default_regs_r,default_regs_w}}, -/* Squirell King */ - {0x0000,0x8ec8,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xfffffd,0xfffffd,0xffffff,0xffffff},{0x400000,0x400004,0x000000,0x000000},0,0,NULL,NULL,default_regs_r,default_regs_w}}, -/* Tiny Toon Adventures 3 */ - {0x2020,0xed9c,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xfffffd,0xfffffd,0xffffff,0xffffff},{0x400000,0x400004,0x000000,0x000000},0,0,NULL,NULL,default_regs_r,default_regs_w}}, -/* Lian Huan Pao - Barver Battle Saga (registers accessed by Z80, related to sound engine ?) */ - {0x30b9,0x1c2a,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xfffffd,0xfffffd,0xffffff,0xffffff},{0x400000,0x400004,0x000000,0x000000},0,0,NULL,NULL,default_regs_r,default_regs_w}}, -/* Shui Hu Zhuan (registers accessed by Z80, related to sound engine ?) */ - {0x6001,0x0211,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xfffffd,0xfffffd,0xffffff,0xffffff},{0x400000,0x400004,0x000000,0x000000},0,0,NULL,NULL,default_regs_r,default_regs_w}}, -/* Feng Shen Ying Jie Chuan (registers accessed by Z80, related to sound engine ?) */ - {0xffff,0x5d98,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xfffffd,0xfffffd,0xffffff,0xffffff},{0x400000,0x400004,0x000000,0x000000},0,0,NULL,NULL,default_regs_r,default_regs_w}}, -/* (*) Shui Hu - Feng Yun Zhuan (patched ROM, unused registers) */ - {0x3332,0x872b,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xfffffd,0xfffffd,0xffffff,0xffffff},{0x400000,0x400004,0x000000,0x000000},0,0,NULL,NULL,default_regs_r,default_regs_w}}, - - -/* (*) Chao Ji Da Fu Weng (patched ROM, various words witten to register, long word also read from $7E0000, unknown banking hardware ?) */ - {0xa697,0xa697,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x000000,0x000000,0x000000},0,0,NULL,NULL,NULL,default_regs_w}}, - -/* (*) Aq Renkan Awa (patched ROM, ON/OFF bit sequence is written to register, unknown banking hardware ?) */ - {0x8104,0x0517,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400001,0x000000,0x000000,0x000000},0,0,NULL,NULL,NULL,default_regs_w}}, - - -/* (*) Tun Shi Tian Di III (patched ROM, unused register) */ - {0x0000,0x9c5e,0x40,0x40,{{0xab,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400046,0x000000,0x000000,0x000000},0,0,NULL,NULL,default_regs_r,NULL}}, - - -/* Ma Jiang Qing Ren - Ji Ma Jiang Zhi */ - {0x0000,0x7037,0x40,0x40,{{0x90,0xd3,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x401000,0x000000,0x000000},0,0,NULL,NULL,default_regs_r,NULL}}, -/* Super Majon Club */ - {0x0000,0x3b95,0x40,0x40,{{0x90,0xd3,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x401000,0x000000,0x000000},0,0,NULL,NULL,default_regs_r,NULL}}, -/* Feng Kuang Tao Hua Yuan (original version from Creaton Softec Inc) (a bootleg version also exists with patched protection and minor title screen variations) */ - {0x0000,0x9dc4,0x40,0x40,{{0x90,0xd3,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x401000,0x000000,0x000000},0,0,NULL,NULL,default_regs_r,NULL}}, - - -/* (*) Jiu Ji Ma Jiang II - Ye Yan Bian (patched ROM, using expected register value - $0f - crashes the game) (uses 16-bits reads) */ - {0x0c44,0xba81,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x400006},0,0,NULL,NULL,default_regs_r_16,NULL}}, -/* 16 Zhang Ma Jiang (uses 16-bits reads) */ - {0xfb40,0x4bed,0x40,0x40,{{0x00,0xaa,0x00,0xf0},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x400002,0x000000,0x400006},0,0,NULL,NULL,default_regs_r_16,NULL}}, -/* 16 Tiles Mahjong II (uses 16-bits reads) */ - {0xffff,0x0903,0x40,0x40,{{0x00,0x00,0xc9,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x400004,0x000000},0,0,NULL,NULL,default_regs_r_16,NULL}}, -/* Thunderbolt II (uses 16-bits reads) */ - {0x0000,0x1585,0x40,0x40,{{0x55,0x0f,0xaa,0xf0},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,NULL,NULL,default_regs_r_16,NULL}}, - - -/* Super Bubble Bobble */ - {0x0000,0x16cd,0x40,0x40,{{0x55,0x0f,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x000000,0x000000},0,0,NULL,NULL,default_regs_r,NULL}}, -/* Tenchi wo Kurau II - The Battle of Red Cliffs (Unl) */ - {0x0000,0xed61,0x40,0x40,{{0x55,0x0f,0xaa,0xf0},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,NULL,NULL,default_regs_r,NULL}}, -/* Huan Le Tao Qi Shu - Smart Mouse */ - {0x0000,0x1a28,0x40,0x40,{{0x55,0x0f,0xaa,0xf0},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,NULL,NULL,default_regs_r,NULL}}, -/* (*) Hei Tao 2 - Super Big 2 (patched ROM, unused registers) */ - {0x0000,0x5843,0x40,0x40,{{0x55,0x0f,0xaa,0xf0},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,NULL,NULL,default_regs_r,NULL}}, -/* Mighty Morphin Power Rangers - The Fighting Edition */ - {0x0000,0x2288,0x40,0x40,{{0x55,0x0f,0xc9,0x18},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,NULL,NULL,default_regs_r,NULL}}, -/* Elf Wor */ - {0x0080,0x3dba,0x40,0x40,{{0x55,0x0f,0xc9,0x18},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,NULL,NULL,default_regs_r,NULL}}, -/* Ya-Se Chuanshuo */ - {0xffff,0xd472,0x40,0x40,{{0x63,0x98,0xc9,0x18},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,NULL,NULL,default_regs_r,NULL}}, -/* 777 Casino (For first one, 0x55 works as well. Other values are never used so they are guessed from on other unlicensed games using similar mapper) */ - {0x0000,0xf8d9,0x40,0x40,{{0x63,0x98,0xc9,0x18},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,NULL,NULL,default_regs_r,NULL}}, -/* Wu Kong Wai Zhuan (original) (a bootleg version also exists, with patched protection & modified SRAM test routine ?) */ - {0x0000,0x19ff,0x40,0x40,{{0x63,0x98,0xc9,0x18},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,NULL,NULL,default_regs_r,NULL}}, -/* Soul Blade */ - {0x0000,0x0c5b,0x40,0x40,{{0x63,0x98,0xc9,0xf0},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,NULL,NULL,default_regs_r,NULL}}, - - -/* King of Fighter 98 */ - {0x0000,0xd0a0,0x48,0x4f,{{0x00,0x00,0xaa,0xf0},{0xffffff,0xffffff,0xfc0000,0xfc0000},{0x000000,0x000000,0x480000,0x4c0000},0,0,NULL,NULL,default_regs_r,NULL}}, - - -/* Rockman X3 (bootleg version ? two last register returned values are ignored, note that 0xaa/0x18 would work as well) */ - {0x0000,0x9d0e,0x40,0x40,{{0x0c,0x00,0xc9,0xf0},{0xffffff,0xffffff,0xffffff,0xffffff},{0xa13000,0x000000,0x400004,0x400006},0,0,default_regs_r,NULL,default_regs_r,NULL}}, - - -/* (*) Dragon Ball Final Bout (patched ROM, in original code, different switches occurs depending on returned value $00-$0f) */ - {0xc65a,0xc65a,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0xa13000,0x000000,0x000000,0x000000},0,0,default_regs_r,NULL,NULL,NULL}}, -/* (*) Yang Jia Jiang - Yang Warrior Family (patched ROM, register value unused) */ - {0x0000,0x96b0,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0xa13000,0x000000,0x000000,0x000000},0,0,default_regs_r,NULL,NULL,NULL}}, -/* Super Mario 2 1998 */ - {0xffff,0x0474,0x00,0x00,{{0x0a,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0xa13000,0x000000,0x000000,0x000000},0,0,default_regs_r,NULL,NULL,NULL}}, -/* Super Mario World */ - {0x2020,0xb4eb,0x00,0x00,{{0x1c,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0xa13000,0x000000,0x000000,0x000000},0,0,default_regs_r,NULL,NULL,NULL}}, - - -/* King of Fighter 99 */ - {0x0000,0x021e,0x00,0x00,{{0x00,0x01,0x1f,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0xa13000,0xa13002,0xa1303e,0x000000},0,0,custom_regs_r,default_regs_w,NULL,NULL}}, -/* Pocket Monster */ - {0xd6fc,0x1eb1,0x00,0x00,{{0x00,0x01,0x1f,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0xa13000,0xa13002,0xa1303e,0x000000},0,0,custom_regs_r,default_regs_w,NULL,NULL}}, -/* Pocket Monster (bootleg version ? two last register returned values are ignored & first register test has been modified) */ - {0xd6fc,0x6319,0x00,0x00,{{0x14,0x01,0x1f,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0xa13000,0xa13002,0xa1303e,0x000000},0,0,default_regs_r,m68k_unused_8_w,NULL,NULL}}, -/* A Bug's Life (bootleg version ? two last register returned values are ignored & first register test has been modified ?) */ - {0x7f7f,0x2aad,0x00,0x00,{{0x28,0x01,0x1f,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0xa13000,0xa13002,0xa1303e,0x000000},0,0,default_regs_r,m68k_unused_8_w,NULL,NULL}}, - - -/* Game no Kanzume Otokuyou */ - {0x0000,0xf9d1,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,0,NULL,mapper_seganet_w,NULL,NULL}}, - - -/* Top Shooter (arcade hardware) */ - {0xffff,0x3632,0x20,0x20,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,0,NULL,NULL,topshooter_r,topshooter_w}} -}; - - -/************************************************************ - Cart Hardware initialization -*************************************************************/ - -void md_cart_init(void) -{ - int i; - - /*************************************************************************************************************** - CARTRIDGE ROM MIRRORING - *************************************************************************************************************** - - MD Cartridge area is mapped to $000000-$3fffff: - - -> when accessing ROM, 68k address lines A1 to A21 can be used by the internal cartridge hardware to decode - full 4MB address range. - -> depending on ROM total size and additional decoding hardware, some address lines might be ignored, - resulting in ROM mirroring. - - Cartridges can use either 8-bits (x2) or 16-bits (x1, x2) Mask ROM chips, each chip size is a factor of 2 bytes: - - -> two 8-bits chips are equivalent to one 16-bits chip, no specific address decoding is required, needed - address lines are simply connected to each chip, upper address lines are ignored and data lines are - connected appropriately to each chip (D0-D7 to one chip, D8-D15 to the other one). - ROM is generally mirrored each N bytes where N=2^(k+1) is the total ROM size (ROM1+ROM2,ROM1+ROM2,...) - - -> one single 16-bits chip do not need specific address decoding, address lines are simply connected - depending on the ROM size, upper address lines being ignored. - ROM is generally mirrored each N bytes where N=2^k is the size of the ROM chip (ROM1,ROM1,ROM1,...) - - -> two 16-bits chips of the same size are equivalent to one chip of double size, address decoding generally - is the same except that specific hardware is used (one address line is generally used for chip selection, - lower ones being used to address the chips and upper ones being ignored). - ROM is generally mirrored each N bytes where N=2^(k+1) is the total ROM size (ROM1,ROM2,ROM1,ROM2,...) - - -> two 16-bits chips with different size are mapped differently. Address decoding is done the same way as - above (one address line used for chip selection) but the ignored & required address lines differ from - one chip to another, which makes ROM mirroring different. - ROM2 size is generally half of ROM1 size and upper half ignored (ROM1,ROM2,XXXX,ROM1,ROM2,XXXX,...) - - From the emulator point of view, we only need to distinguish 2 cases: - - 1/ total ROM size is a factor of 2: ROM is mirrored each 2^k bytes. - - 2/ total ROM size is not a factor of 2: ROM is padded up to 2^k then mirrored each 2^k bytes. - - ******************************************************************************************************************/ - - /* calculate nearest size with factor of 2 */ - unsigned int size = 0x10000; - while (cart.romsize > size) - size <<= 1; - - /* Sonic & Knuckles */ - if (strstr(rominfo.international,"SONIC & KNUCKLES")) - { - /* disable ROM mirroring at $200000-$3fffff (normally mapped to external cartridge) */ - size = 0x400000; - } - - /* total ROM size is not a factor of 2 */ - /* TODO: handle all possible ROM configurations using cartridge database */ - if (cart.romsize < size) - { - if (size < MAXROMSIZE) - { - /* ROM is padded up to 2^k bytes */ - memset(cart.rom + cart.romsize, 0xff, size - cart.romsize); - } - else - { - /* ROM is padded up to max ROM size */ - memset(cart.rom + cart.romsize, 0xff, MAXROMSIZE - cart.romsize); - } - } - - /* ROM is mirrored each 2^k bytes */ - cart.mask = size - 1; - - /********************************************** - DEFAULT CARTRIDGE MAPPING - ***********************************************/ - for (i=0; i<0x40; i++) - { - /* cartridge ROM */ - m68k.memory_map[i].base = cart.rom + ((i<<16) & cart.mask); - m68k.memory_map[i].read8 = NULL; - m68k.memory_map[i].read16 = NULL; - m68k.memory_map[i].write8 = m68k_unused_8_w; - m68k.memory_map[i].write16 = m68k_unused_16_w; - zbank_memory_map[i].read = NULL; - zbank_memory_map[i].write = zbank_unused_w; - } - - for (i=0x40; i<0x80; i++) - { - /* unused area */ - m68k.memory_map[i].base = cart.rom + (i<<16); - m68k.memory_map[i].read8 = m68k_read_bus_8; - m68k.memory_map[i].read16 = m68k_read_bus_16; - m68k.memory_map[i].write8 = m68k_unused_8_w; - m68k.memory_map[i].write16 = m68k_unused_16_w; - zbank_memory_map[i].read = zbank_unused_r; - zbank_memory_map[i].write = zbank_unused_w; - } - - /* support for Quackshot REV 01 (real) dump */ - if (strstr(rominfo.product,"00004054-01") && (cart.romsize == 0x80000)) - { - /* $000000-$0fffff: first 256K mirrored (A18 not connected to ROM chip, A19 not decoded) */ - for (i=0x00; i<0x10; i++) - { - /* $200000-$3fffff: mirror of $000000-$1fffff (A21 not decoded) */ - m68k.memory_map[i].base = m68k.memory_map[i + 0x20].base = cart.rom + ((i & 0x03) << 16); - } - - /* $100000-$1fffff: second 256K mirrored (A20 connected to ROM chip A18) */ - for (i=0x10; i<0x20; i++) - { - /* $200000-$3fffff: mirror of $000000-$1fffff (A21 not decoded) */ - m68k.memory_map[i].base = m68k.memory_map[i + 0x20].base = cart.rom + 0x40000 + ((i & 0x03) << 16); - } - } - - /********************************************** - BACKUP MEMORY - ***********************************************/ - sram_init(); - eeprom_i2c_init(); - - /* external SRAM */ - if (sram.on && !sram.custom) - { - /* disabled on startup if ROM is mapped in same area */ - if (cart.romsize <= sram.start) - { - /* initialize m68k bus handlers */ - m68k.memory_map[sram.start >> 16].base = sram.sram; - m68k.memory_map[sram.start >> 16].read8 = sram_read_byte; - m68k.memory_map[sram.start >> 16].read16 = sram_read_word; - m68k.memory_map[sram.start >> 16].write8 = sram_write_byte; - m68k.memory_map[sram.start >> 16].write16 = sram_write_word; - zbank_memory_map[sram.start >> 16].read = sram_read_byte; - zbank_memory_map[sram.start >> 16].write = sram_write_byte; - } - } - - /********************************************** - SVP CHIP - ***********************************************/ - svp = NULL; - if (strstr(rominfo.international,"Virtua Racing")) - { - svp_init(); - - m68k.memory_map[0x30].base = svp->dram; - m68k.memory_map[0x30].read16 = NULL; - m68k.memory_map[0x30].write16 = svp_write_dram; - - m68k.memory_map[0x31].base = svp->dram + 0x10000; - m68k.memory_map[0x31].read16 = NULL; - m68k.memory_map[0x31].write16 = svp_write_dram; - - m68k.memory_map[0x39].read16 = svp_read_cell_1; - m68k.memory_map[0x3a].read16 = svp_read_cell_2; - } - - /********************************************** - J-CART - ***********************************************/ - cart.special = 0; - if ((strstr(rominfo.product,"00000000") && (rominfo.checksum == 0x168b)) || /* Super Skidmarks, Micro Machines Military */ - (strstr(rominfo.product,"00000000") && (rominfo.checksum == 0x165e)) || /* Pete Sampras Tennis (1991), Micro Machines 96 */ - (strstr(rominfo.product,"00000000") && (rominfo.checksum == 0xcee0)) || /* Micro Machines Military (bad) */ - (strstr(rominfo.product,"00000000") && (rominfo.checksum == 0x2c41)) || /* Micro Machines 96 (bad) */ - (strstr(rominfo.product,"XXXXXXXX") && (rominfo.checksum == 0xdf39)) || /* Sampras Tennis 96 */ - (strstr(rominfo.product,"T-123456") && (rominfo.checksum == 0x1eae)) || /* Sampras Tennis 96 */ - (strstr(rominfo.product,"T-120066") && (rominfo.checksum == 0x16a4)) || /* Pete Sampras Tennis (1994)*/ - strstr(rominfo.product,"T-120096")) /* Micro Machines 2 */ - { - if (cart.romsize <= 0x380000) /* just to be sure (checksum might not be enough) */ - { - cart.special |= HW_J_CART; - - /* force port 1 setting */ - if (input.system[1] != SYSTEM_WAYPLAY) - { - old_system[1] = input.system[1]; - input.system[1] = SYSTEM_MD_GAMEPAD; - } - - /* extra connectors mapped at $38xxxx or $3Fxxxx */ - m68k.memory_map[0x38].read16 = jcart_read; - m68k.memory_map[0x38].write16 = jcart_write; - m68k.memory_map[0x3f].read16 = jcart_read; - m68k.memory_map[0x3f].write16 = jcart_write; - } - } - - /********************************************** - LOCK-ON - ***********************************************/ - - /* clear existing patches */ - ggenie_shutdown(); - areplay_shutdown(); - - /* initialize extra hardware */ - switch (config.lock_on) - { - case TYPE_GG: - { - ggenie_init(); - break; - } - - case TYPE_AR: - { - areplay_init(); - break; - } - - case TYPE_SK: - { - FILE *f; - - /* store S&K ROM above cartridge ROM (and before backup memory) */ - if (cart.romsize > 0x600000) break; - - /* load Sonic & Knuckles ROM (2 MB) */ - f = fopen(SK_ROM,"rb"); - if (!f) break; - for (i=0; i<0x200000; i+=0x1000) - { - fread(cart.rom + 0x600000 + i, 0x1000, 1, f); - } - fclose(f); - - /* load Sonic 2 UPMEM ROM (256 KB) */ - f = fopen(SK_UPMEM,"rb"); - if (!f) break; - for (i=0; i<0x40000; i+=0x1000) - { - fread(cart.rom + 0x900000 + i, 0x1000, 1, f); - } - fclose(f); - -#ifdef LSB_FIRST - for (i=0; i<0x200000; i+=2) - { - /* Byteswap ROM */ - uint8 temp = cart.rom[i + 0x600000]; - cart.rom[i + 0x600000] = cart.rom[i + 0x600000 + 1]; - cart.rom[i + 0x600000 + 1] = temp; - } - - for (i=0; i<0x40000; i+=2) - { - /* Byteswap ROM */ - uint8 temp = cart.rom[i + 0x900000]; - cart.rom[i + 0x900000] = cart.rom[i + 0x900000 + 1]; - cart.rom[i + 0x900000 + 1] = temp; - } -#endif - - /* $000000-$1FFFFF is mapped to S&K ROM */ - for (i=0x00; i<0x20; i++) - { - m68k.memory_map[i].base = cart.rom + 0x600000 + (i << 16); - } - - cart.special |= HW_LOCK_ON; - break; - } - - default: - { - break; - } - } - - /********************************************** - CARTRIDGE EXTRA HARDWARE - ***********************************************/ - memset(&cart.hw, 0, sizeof(cart.hw)); - - /* search for game into database */ - for (i=0; i 0x400000) - { - /* assume linear ROM mapper without bankswitching (max. 10MB) */ - for (i=0x40; i<0xA0; i++) - { - m68k.memory_map[i].base = cart.rom + (i<<16); - m68k.memory_map[i].read8 = NULL; - m68k.memory_map[i].read16 = NULL; - zbank_memory_map[i].read = NULL; - } - } - - /* default write handler for !TIME range ($A130xx)*/ - if (!cart.hw.time_w) - { - cart.hw.time_w = default_time_w; - } -} - -/* hardware that need to be reseted on power on */ -void md_cart_reset(int hard_reset) -{ - int i; - - /* reset cartridge mapping */ - if (cart.hw.bankshift) - { - for (i=0x00; i<0x40; i++) - { - m68k.memory_map[i].base = cart.rom + ((i<<16) & cart.mask); - } - } - - /* SVP chip */ - if (svp) - { - svp_reset(); - } - - /* Lock-ON */ - switch (config.lock_on) - { - case TYPE_GG: - { - ggenie_reset(hard_reset); - break; - } - - case TYPE_AR: - { - areplay_reset(hard_reset); - break; - } - - case TYPE_SK: - { - if (cart.special & HW_LOCK_ON) - { - /* disable UPMEM chip at $300000-$3fffff */ - for (i=0x30; i<0x40; i++) - { - m68k.memory_map[i].base = cart.rom + ((i<<16) & cart.mask); - } - } - break; - } - - default: - { - break; - } - } -} - - -/************************************************************ - MAPPER handlers -*************************************************************/ - -/* - "official" ROM/SRAM bankswitch (Phantasy Star IV, Story of Thor/Beyond Oasis, Sonic 3 & Knuckles) -*/ -static void mapper_sega_w(uint32 data) -{ - int i; - - if (data & 1) - { - if (sram.on) - { - /* Backup RAM mapped to $200000-$20ffff (normally mirrored up to $3fffff but this breaks Sonic Megamix and no game need it) */ - m68k.memory_map[0x20].base = sram.sram; - m68k.memory_map[0x20].read8 = sram_read_byte; - m68k.memory_map[0x20].read16 = sram_read_word; - zbank_memory_map[0x20].read = sram_read_byte; - - /* Backup RAM write protection */ - if (data & 2) - { - m68k.memory_map[0x20].write8 = m68k_unused_8_w; - m68k.memory_map[0x20].write16 = m68k_unused_16_w; - zbank_memory_map[0x20].write = zbank_unused_w; - } - else - { - m68k.memory_map[0x20].write8 = sram_write_byte; - m68k.memory_map[0x20].write16 = sram_write_word; - zbank_memory_map[0x20].write = sram_write_byte; - } - } - - /* S&K lock-on chip */ - if ((cart.special & HW_LOCK_ON) && (config.lock_on == TYPE_SK)) - { - /* S2K upmem chip mapped to $300000-$3fffff (256K mirrored) */ - for (i=0x30; i<0x40; i++) - { - m68k.memory_map[i].base = (cart.rom + 0x900000) + ((i & 3) << 16); - } - } - } - else - { - /* cartridge ROM mapped to $200000-$3fffff */ - for (i=0x20; i<0x40; i++) - { - m68k.memory_map[i].base = cart.rom + ((i<<16) & cart.mask); - m68k.memory_map[i].read8 = NULL; - m68k.memory_map[i].read16 = NULL; - zbank_memory_map[i].read = NULL; - m68k.memory_map[i].write8 = m68k_unused_8_w; - m68k.memory_map[i].write16 = m68k_unused_16_w; - zbank_memory_map[i].write = zbank_unused_w; - } - } -} - -/* - Super Street Fighter 2 ROM bankswitch - documented by Bart Trzynadlowski (http://www.trzy.org/files/ssf2.txt) -*/ -static void mapper_ssf2_w(uint32 address, uint32 data) -{ - /* 8 x 512k banks */ - address = (address << 2) & 0x38; - - /* bank 0 remains unchanged */ - if (address) - { - uint32 i; - uint8 *src = cart.rom + (data << 19); - - for (i=0; i<8; i++) - { - m68k.memory_map[address++].base = src + (i<<16); - } - } -} - -/* - SF-001 mapper -*/ -static void mapper_sf001_w(uint32 address, uint32 data) -{ - switch ((address >> 8) & 0xf) - { - case 0xe: - { - int i; - - /* bit 6: enable / disable cartridge access */ - if (data & 0x40) - { - /* $000000-$3FFFFF is not mapped */ - for (i=0x00; i<0x40; i++) - { - m68k.memory_map[i].base = cart.rom + (i << 16); - m68k.memory_map[i].read8 = m68k_read_bus_8; - m68k.memory_map[i].read16 = m68k_read_bus_16; - m68k.memory_map[i].write8 = (i > 0x00) ? m68k_unused_8_w : mapper_sf001_w; - m68k.memory_map[i].write16 = (i > 0x00) ? m68k_unused_16_w : mapper_sf001_w; - zbank_memory_map[i].read = zbank_unused_r; - zbank_memory_map[i].write = (i > 0x00) ? m68k_unused_8_w : mapper_sf001_w; - } - } - - /* bit 7: enable / disable SRAM & ROM bankswitching */ - else if (data & 0x80) - { - /* 256K ROM bank #15 mapped to $000000-$03FFFF */ - for (i=0x00; i<0x04; i++) - { - m68k.memory_map[i].base = cart.rom + ((0x38 + i) << 16); - m68k.memory_map[i].read8 = NULL; - m68k.memory_map[i].read16 = NULL; - zbank_memory_map[i].read = NULL; - } - - /* 256K ROM banks #2 to #15 mapped to $040000-$3BFFFF (last revision) or $040000-$3FFFFF (older revisions) */ - for (i=0x04; i<(sram.start >> 16); i++) - { - m68k.memory_map[i].base = cart.rom + (i << 16); - m68k.memory_map[i].read8 = NULL; - m68k.memory_map[i].read16 = NULL; - zbank_memory_map[i].read = NULL; - } - - /* 32K static RAM mirrored into $3C0000-$3FFFFF (odd bytes only) (last revision only) */ - while (i<0x40) - { - m68k.memory_map[i].base = sram.sram; - m68k.memory_map[i].read8 = sram_read_byte; - m68k.memory_map[i].read16 = sram_read_word; - m68k.memory_map[i].write8 = sram_write_byte; - m68k.memory_map[i].write16 = sram_write_word; - zbank_memory_map[i].read = sram_read_byte; - zbank_memory_map[i].write = sram_write_byte; - i++; - } - } - else - { - /* 256K ROM banks #1 to #16 mapped to $000000-$3FFFFF (default) */ - for (i=0x00; i<0x40; i++) - { - m68k.memory_map[i].base = cart.rom + (i << 16); - m68k.memory_map[i].read8 = NULL; - m68k.memory_map[i].read16 = NULL; - m68k.memory_map[i].write8 = (i > 0x00) ? m68k_unused_8_w : mapper_sf001_w; - m68k.memory_map[i].write16 = (i > 0x00) ? m68k_unused_16_w : mapper_sf001_w; - zbank_memory_map[i].read = NULL; - zbank_memory_map[i].write = (i > 0x00) ? m68k_unused_8_w : mapper_sf001_w; - } - } - - /* bit 5: lock bankswitch hardware when set */ - if (data & 0x20) - { - /* disable bankswitch hardware access until hard reset */ - m68k.memory_map[0x00].write8 = m68k_unused_8_w; - m68k.memory_map[0x00].write16 = m68k_unused_16_w; - zbank_memory_map[0x00].write = m68k_unused_8_w; - } - - return; - } - - default: - { - m68k_unused_8_w(address, data); - return; - } - } -} - -/* - SF-002 mapper -*/ -static void mapper_sf002_w(uint32 address, uint32 data) -{ - int i; - if (data & 0x80) - { - /* $000000-$1BFFFF mapped to $200000-$3BFFFF */ - for (i=0x20; i<0x3C; i++) - { - m68k.memory_map[i].base = cart.rom + ((i & 0x1F) << 16); - } - } - else - { - /* $200000-$3BFFFF mapped to $200000-$3BFFFF */ - for (i=0x20; i<0x3C; i++) - { - m68k.memory_map[i].base = cart.rom + (i << 16); - } - } -} - -/* - SF-004 mapper -*/ -static void mapper_sf004_w(uint32 address, uint32 data) -{ - int i; - switch ((address >> 8) & 0xf) - { - case 0xd: - { - /* bit 7: enable/disable static RAM access */ - if (data & 0x80) - { - /* 32KB static RAM mirrored into $200000-$2FFFFF (odd bytes only) */ - for (i=0x20; i<0x30; i++) - { - m68k.memory_map[i].read8 = sram_read_byte; - m68k.memory_map[i].read16 = sram_read_word; - m68k.memory_map[i].write8 = sram_write_byte; - m68k.memory_map[i].write16 = sram_write_word; - zbank_memory_map[i].read = sram_read_byte; - zbank_memory_map[i].write = sram_write_byte; - } - } - else - { - /* 32KB static RAM disabled at $200000-$2FFFFF */ - for (i=0x20; i<0x30; i++) - { - m68k.memory_map[i].read8 = m68k_read_bus_8; - m68k.memory_map[i].read16 = m68k_read_bus_16; - m68k.memory_map[i].write8 = m68k_unused_8_w; - m68k.memory_map[i].write16 = m68k_unused_16_w; - zbank_memory_map[i].read = m68k_read_bus_8; - zbank_memory_map[i].write = m68k_unused_8_w; - } - } - - return; - } - - case 0x0e: - { - /* bit 5: enable / disable cartridge ROM access */ - if (data & 0x20) - { - /* $000000-$1FFFFF is not mapped */ - for (i=0x00; i<0x20; i++) - { - m68k.memory_map[i].read8 = m68k_read_bus_8; - m68k.memory_map[i].read16 = m68k_read_bus_16; - zbank_memory_map[i].read = m68k_read_bus_8; - } - } - - /* bit 6: enable / disable first page mirroring */ - else if (data & 0x40) - { - /* first page ROM bank */ - uint8 base = (m68k.memory_map[0x00].base - cart.rom) >> 16; - - /* 5 x 256K ROM banks mapped to $000000-$13FFFF, starting from first page ROM bank */ - for (i=0x00; i<0x14; i++) - { - m68k.memory_map[i].base = cart.rom + (((base + i) & 0x1f) << 16); - m68k.memory_map[i].read8 = NULL; - m68k.memory_map[i].read16 = NULL; - zbank_memory_map[i].read = NULL; - } - - /* $140000-$1FFFFF is not mapped */ - for (i=0x14; i<0x20; i++) - { - m68k.memory_map[i].read8 = m68k_read_bus_8; - m68k.memory_map[i].read16 = m68k_read_bus_16; - zbank_memory_map[i].read = m68k_read_bus_8; - } - } - else - { - /* first page 256K ROM bank mirrored into $000000-$1FFFFF */ - for (i=0x00; i<0x20; i++) - { - m68k.memory_map[i].base = m68k.memory_map[0].base + ((i & 0x03) << 16); - m68k.memory_map[i].read8 = NULL; - m68k.memory_map[i].read16 = NULL; - zbank_memory_map[i].read = NULL; - } - } - - /* bit 7: lock ROM bankswitching hardware when cleared */ - if (!(data & 0x80)) - { - /* disable bankswitch hardware access */ - m68k.memory_map[0x00].write8 = m68k_unused_8_w; - m68k.memory_map[0x00].write16 = m68k_unused_16_w; - zbank_memory_map[0x00].write = m68k_unused_8_w; - } - - return; - } - - case 0x0f: - { - /* bits 6-4: select first page ROM bank (8 x 256K ROM banks) */ - uint8 base = ((data >> 4) & 7) << 2; - - if (m68k.memory_map[0].base == m68k.memory_map[4].base) - { - /* selected 256K ROM bank mirrored into $000000-$1FFFFF */ - for (i=0x00; i<0x20; i++) - { - m68k.memory_map[i].base = cart.rom + ((base + (i & 0x03)) << 16); - } - } - else - { - /* 5 x 256K ROM banks mapped to $000000-$13FFFF, starting from selected bank */ - for (i=0x00; i<0x14; i++) - { - m68k.memory_map[i].base = cart.rom + (((base + i) & 0x1f) << 16); - } - } - - return; - } - - default: - { - m68k_unused_8_w(address, data); - return; - } - } -} - -static uint32 mapper_sf004_r(uint32 address) -{ - /* return first page 256K bank index ($00,$10,$20,...,$70) */ - return (((m68k.memory_map[0x00].base - cart.rom) >> 18) << 4); -} - -/* - T-5740xx-xx mapper -*/ -static void mapper_t5740_w(uint32 address, uint32 data) -{ - int i; - uint8 *base; - - switch (address & 0xff) - { - case 0x01: /* mode register */ - { - /* bits 7-4: unused ? */ - /* bit 3: enable SPI registers access ? */ - /* bit 2: not used ? */ - /* bit 1: enable bankswitch registers access ? */ - /* bit 0: always set, enable hardware access ? */ - return; - } - - case 0x03: /* page #5 register */ - { - /* map any of 16 x 512K ROM banks to $280000-$2FFFFF */ - base = cart.rom + ((data & 0x0f) << 19); - for (i=0x28; i<0x30; i++) - { - m68k.memory_map[i].base = base + ((i & 0x07) << 16); - } - return; - } - - case 0x05: /* page #6 register */ - { - /* map any of 16 x 512K ROM banks to $300000-$37FFFF */ - base = cart.rom + ((data & 0x0f) << 19); - for (i=0x30; i<0x38; i++) - { - m68k.memory_map[i].base = base + ((i & 0x07) << 16); - } - return; - } - - case 0x07: /* page #7 register */ - { - /* map any of 16 x 512K ROM banks to $380000-$3FFFFF */ - base = cart.rom + ((data & 0x0f) << 19); - for (i=0x38; i<0x40; i++) - { - m68k.memory_map[i].base = base + ((i & 0x07) << 16); - } - return; - } - - case 0x09: /* serial EEPROM SPI board support */ - { - eeprom_spi_write(data); - return; - } - - default: - { - /* unknown registers */ - m68k_unused_8_w(address, data); - return; - } - } -} - -static uint32 mapper_t5740_r(uint32 address) -{ - /* By default, first 32K of each eight 512K pages mapped in $000000-$3FFFFF are mirrored in the 512K page */ - /* mirroring is disabled/enabled when a specific number of words is being read from specific ROM addresses */ - /* Exact decoding isn't known but mirrored data is expected on startup when reading a few times from $181xx */ - /* this area doesn't seem to be accessed as byte later so it seems safe to always return mirrored data here */ - if ((address & 0xff00) == 0x8100) - { - return READ_BYTE(cart.rom , (address & 0x7fff)); - } - - return READ_BYTE(cart.rom, address); -} - -/* - Super Mario World 64 (unlicensed) mapper -*/ -static void mapper_smw_64_w(uint32 address, uint32 data) -{ - /* internal registers (saved to backup RAM) */ - switch ((address >> 16) & 0x07) - { - case 0x00: /* $60xxxx */ - { - if (address & 2) - { - /* $600003 data write mode ? */ - switch (sram.sram[0x00] & 0x07) - { - case 0x00: - { - /* update value returned at $660001-$660003 */ - sram.sram[0x06] = ((sram.sram[0x06] ^ sram.sram[0x01]) ^ data) & 0xFE; - break; - } - - case 0x01: - { - /* update value returned at $660005-$660007 */ - sram.sram[0x07] = data & 0xFE; - break; - } - - case 0x07: - { - /* update selected ROM bank (upper 512K) mapped at $610000-$61ffff */ - m68k.memory_map[0x61].base = m68k.memory_map[0x69].base = cart.rom + 0x080000 + ((data & 0x1c) << 14); - break; - } - - default: - { - /* unknown mode */ - break; - } - } - - /* $600003 data register */ - sram.sram[0x01] = data; - } - else - { - /* $600001 ctrl register */ - sram.sram[0x00] = data; - } - return; - } - - case 0x01: /* $61xxxx */ - { - if (address & 2) - { - /* $610003 ctrl register */ - sram.sram[0x02] = data; - } - return; - } - - case 0x04: /* $64xxxx */ - { - if (address & 2) - { - /* $640003 data register */ - sram.sram[0x04] = data; - } - else - { - /* $640001 data register */ - sram.sram[0x03] = data; - } - return; - } - - case 0x06: /* $66xxxx */ - { - /* unknown */ - return; - } - - case 0x07: /* $67xxxx */ - { - if (!(address & 2)) - { - /* $670001 ctrl register */ - sram.sram[0x05] = data; - - /* upper 512K ROM bank-switching enabled ? */ - if (sram.sram[0x02] & 0x80) - { - /* update selected ROM bank (upper 512K) mapped at $600000-$60ffff */ - m68k.memory_map[0x60].base = m68k.memory_map[0x68].base = cart.rom + 0x080000 + ((data & 0x1c) << 14); - } - } - return; - } - - default: /* not used */ - { - m68k_unused_8_w(address, data); - return; - } - } -} - -static uint32 mapper_smw_64_r(uint32 address) -{ - /* internal registers (saved to backup RAM) */ - switch ((address >> 16) & 0x03) - { - case 0x02: /* $66xxxx */ - { - switch ((address >> 1) & 7) - { - case 0x00: return sram.sram[0x06]; - case 0x01: return sram.sram[0x06] + 1; - case 0x02: return sram.sram[0x07]; - case 0x03: return sram.sram[0x07] + 1; - case 0x04: return sram.sram[0x08]; - case 0x05: return sram.sram[0x08] + 1; - case 0x06: return sram.sram[0x08] + 2; - case 0x07: return sram.sram[0x08] + 3; - } - } - - case 0x03: /* $67xxxx */ - { - uint8 data = (sram.sram[0x02] & 0x80) ? ((sram.sram[0x05] & 0x40) ? (sram.sram[0x03] & sram.sram[0x04]) : (sram.sram[0x03] ^ 0xFF)) : 0x00; - - if (address & 2) - { - /* $670003 */ - data &= 0x7f; - } - else - { - /* $66xxxx data registers update */ - if (sram.sram[0x05] & 0x80) - { - if (sram.sram[0x05] & 0x20) - { - /* update $660009-$66000f data register */ - sram.sram[0x08] = (sram.sram[0x04] << 2) & 0xFC; - } - else - { - /* update $660001-$660003 data register */ - sram.sram[0x06] = (sram.sram[0x01] ^ (sram.sram[0x03] << 1)) & 0xFE; - } - } - } - - return data; - } - - default: /* 64xxxx-$65xxxx */ - { - return 0x00; - } - } -} - -/* - Realtec ROM bankswitch (Earth Defend, Balloon Boy & Funny World, Whac-A-Critter) - (Note: register usage is inverted in TascoDlx documentation) -*/ -static void mapper_realtec_w(uint32 address, uint32 data) -{ - switch (address) - { - case 0x402000: - { - /* number of mapped 64k blocks (the written value is a number of 128k blocks) */ - cart.hw.regs[2] = data << 1; - return; - } - - case 0x404000: - { - /* 00000xxx */ - cart.hw.regs[0] = data & 7; - return; - } - - case 0x400000: - { - /* 00000yy1 */ - cart.hw.regs[1] = data & 6; - - /* ensure mapped size is not null */ - if (cart.hw.regs[2]) - { - /* mapped start address is 00yy xxx0 0000 0000 0000 0000 */ - uint32 base = (cart.hw.regs[0] << 1) | (cart.hw.regs[1] << 3); - - /* selected blocks are mirrored into the whole cartridge area */ - int i; - for (i=0x00; i<0x40; i++) - { - m68k.memory_map[i].base = &cart.rom[(base + (i % cart.hw.regs[2])) << 16]; - } - } - return; - } - } -} - -/* Game no Kanzume Otokuyou ROM Mapper */ -static void mapper_seganet_w(uint32 address, uint32 data) -{ - if ((address & 0xff) == 0xf1) - { - int i; - if (data & 1) - { - /* ROM Write protected */ - for (i=0; i<0x40; i++) - { - m68k.memory_map[i].write8 = m68k_unused_8_w; - m68k.memory_map[i].write16 = m68k_unused_16_w; - zbank_memory_map[i].write = zbank_unused_w; - } - } - else - { - /* ROM Write enabled */ - for (i=0; i<0x40; i++) - { - m68k.memory_map[i].write8 = NULL; - m68k.memory_map[i].write16 = NULL; - zbank_memory_map[i].write = NULL; - } - } - } -} - -/* - Custom ROM Bankswitch used in Soul Edge VS Samurai Spirits, Top Fighter, Mulan, Pocket Monsters II, Lion King 3, Super King Kong 99, Pokemon Stadium -*/ -static void mapper_32k_w(uint32 data) -{ - int i; - - /* 64 x 32k banks */ - if (data) - { - for (i=0; i<0x10; i++) - { - /* Remap to unused ROM area */ - m68k.memory_map[i].base = &cart.rom[0x400000 + (i << 16)]; - - /* address = address OR (value << 15) */ - memcpy(m68k.memory_map[i].base, cart.rom + ((i << 16) | (data & 0x3f) << 15), 0x8000); - memcpy(m68k.memory_map[i].base + 0x8000, cart.rom + ((i << 16) | ((data | 1) & 0x3f) << 15), 0x8000); - } - } - else - { - /* reset default $000000-$0FFFFF mapping */ - for (i=0; i<16; i++) - { - m68k.memory_map[i].base = &cart.rom[i << 16]; - } - } -} - -/* - Custom ROM Bankswitch used in Chinese Fighter III -*/ -static void mapper_64k_w(uint32 data) -{ - int i; - - /* 16 x 64k banks */ - if (data) - { - /* bank is mapped at $000000-$0FFFFF */ - for (i=0; i<16; i++) - { - m68k.memory_map[i].base = &cart.rom[(data & 0xf) << 16]; - } - } - else - { - /* reset default $000000-$0FFFFF mapping */ - for (i=0; i<16; i++) - { - m68k.memory_map[i].base = &cart.rom[(i & 0xf) << 16]; - } - } -} - -/* - Custom ROM Bankswitch used in pirate "Multi-in-1" cartridges, A Bug's Life, King of Fighter 99, Pocket Monster, Rockman X3 - */ -static void mapper_64k_multi_w(uint32 address) -{ - int i; - - /* 64 x 64k banks */ - for (i=0; i<64; i++) - { - m68k.memory_map[i].base = &cart.rom[((address++) & 0x3f) << 16]; - } -} - -/* - Custom ROM Bankswitch used in RADICA cartridges -*/ -static uint32 mapper_radica_r(uint32 address) -{ - int i = 0; - address = (address >> 1); - - /* 64 x 64k banks */ - for (i = 0; i < 64; i++) - { - m68k.memory_map[i].base = &cart.rom[((address++)& 0x3f)<< 16]; - } - - return 0xffff; -} - - -/************************************************************ - default !TIME signal handler -*************************************************************/ - -static void default_time_w(uint32 address, uint32 data) -{ - if (address < 0xa13040) - { - /* unlicensed cartridges mapper (default) */ - mapper_64k_multi_w(address); - return; - } - - /* official cartridges mapper (default) */ - mapper_sega_w(data); -} - - -/************************************************************ - Internal register handlers -*************************************************************/ - -static uint32 default_regs_r(uint32 address) -{ - int i; - for (i=0; i<4; i++) - { - if ((address & cart.hw.mask[i]) == cart.hw.addr[i]) - { - return cart.hw.regs[i]; - } - } - return m68k_read_bus_8(address); -} - -static uint32 default_regs_r_16(uint32 address) -{ - int i; - for (i=0; i<4; i++) - { - if ((address & cart.hw.mask[i]) == cart.hw.addr[i]) - { - return (cart.hw.regs[i] << 8); - } - } - return m68k_read_bus_16(address); -} - -static void default_regs_w(uint32 address, uint32 data) -{ - int i; - for (i=0; i<4; i++) - { - if ((address & cart.hw.mask[i]) == cart.hw.addr[i]) - { - cart.hw.regs[i] = data; - return; - } - } - m68k_unused_8_w(address, data); -} - -/* basic register shifting hardware (Bug's Life, Pocket Monster) */ -static uint32 custom_regs_r(uint32 address) -{ - int i; - for (i=0; i<4; i++) - { - if ((address & cart.hw.mask[i]) == cart.hw.addr[i]) - { - return cart.hw.regs[i] >> 1; - } - } - - return m68k_read_bus_8(address); -} - -/* custom register hardware (Top Fighter, Lion King III, Super Donkey Kong 99, Mulan, Pocket Monsters II, Pokemon Stadium) */ -static void custom_regs_w(uint32 address, uint32 data) -{ - uint8 temp; - - /* ROM bankswitch */ - if ((address >> 16) > 0x6f) - { - mapper_32k_w(data); - return; - } - - /* write register */ - default_regs_w(address, data); - - /* bitswapping */ - temp = cart.hw.regs[0]; - switch (cart.hw.regs[1] & 3) - { - case 0: - cart.hw.regs[2] = (temp << 1); - break; - - case 1: - cart.hw.regs[2] = (temp >> 1); - return; - - case 2: - cart.hw.regs[2] = ((temp >> 4) | ((temp & 0x0F) << 4)); - return; - - default: - cart.hw.regs[2] = (((temp >> 7) & 0x01) | ((temp >> 5) & 0x02) | - ((temp >> 3) & 0x04) | ((temp >> 1) & 0x08) | - ((temp << 1) & 0x10) | ((temp << 3) & 0x20) | - ((temp << 5) & 0x40) | ((temp << 7) & 0x80)); - return; - } -} - -/* alternate custom register hardware (Chinese Fighters III) */ -static void custom_alt_regs_w(uint32 address, uint32 data) -{ - /* ROM bankswitch */ - if ((address >> 16) > 0x5f) - { - mapper_64k_w(data); - return; - } - - /* write regs */ - default_regs_w(address, data); -} - - -/* "Tekken 3 Special" custom register hardware */ -static uint32 tekken_regs_r(uint32 address) -{ - /* data output */ - if ((address & 0x0e) == 0x02) - { - /* maybe depends on mode bits ? */ - return (cart.hw.regs[0] - 1); - } - - return m68k_read_bus_16(address); -} - -static void tekken_regs_w(uint32 address, uint32 data) -{ - switch (address & 0x0e) - { - case 0x00: - { - /* data output reset ? (game writes $FF before & after protection check) */ - cart.hw.regs[0]= 0x00; - break; - } - - case 0x02: - { - /* read only ? */ - break; - } - - case 0x0c: - { - /* data output mode bit 0 ? (game writes $01) */ - break; - } - - case 0x0e: - { - /* data output mode bit 1 ? (never written by game) */ - break; - } - - default: - { - /* data input (only connected to D0 ?)*/ - if (data & 1) - { - /* 4-bit hardware register ($400004 corresponds to bit0, $400006 to bit1, etc) */ - cart.hw.regs[0] |= 1 << (((address - 0x04) >> 1) & 3); - } - break; - } - } -} - -/* "Top Shooter" arcade board hardware */ -static uint32 topshooter_r(uint32 address) -{ - if (address < 0x202000) - { - uint8 temp = 0xff; - - switch (address & 0xff) - { - case 0x43: - { - if (input.pad[0] & INPUT_A) temp &= ~0x80; /* Shoot */ - if (input.pad[0] & INPUT_B) temp &= ~0x10; /* Bet */ - if (input.pad[0] & INPUT_START) temp &= ~0x20; /* Start */ - break; - } - - case 0x45: /* ??? (DOWN) & Service Mode (UP) */ - { - if (input.pad[0] & INPUT_UP) temp &= ~0x08; /* Service Mode */ - if (input.pad[0] & INPUT_DOWN) temp &= ~0x10; /* ???, used in service menu to select next option */ - break; - } - - case 0x47: - { - if (input.pad[0] & INPUT_RIGHT) temp &= ~0x03; /* Insert 10 coins */ - break; - } - - case 0x49: - { - if (input.pad[0] & INPUT_LEFT) temp &= ~0x03; /* Clear coins */ - if (input.pad[0] & INPUT_C) temp &= ~0x01; /* Insert XXX coins */ - break; - } - - case 0x51: - { - temp = 0xA5; - break; - } - - default: - { - temp = m68k_read_bus_8(address); - break; - } - } - return temp; - } - - return READ_BYTE(sram.sram , address & 0xffff); -} - -static void topshooter_w(uint32 address, uint32 data) -{ - if (address >= 0x202000) - { - WRITE_BYTE(sram.sram , address & 0xffff, data); - return; - } - - m68k_unused_8_w(address, data); -} - - -/* Sega Channel hardware (not emulated) */ -/* - -$A13004: BUSY ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? - -Unused read16 00A13004 (00005B54) -Unused read16 00A13004 (00005B70) -Unused read16 00A13006 (00005B7C) - -Unused read16 00A13004 (00005BC4) -Unused read16 00A13004 (00005BDA) - -Unused write16 00A13032 = 0004 (00005706) -Unused write16 00A130F0 = 0000 (0000570E) - -Unused write16 00A130F0 = 0000 (0000463E) -Unused write16 00A130F2 = 0001 (00004646) -Unused write16 00A130F4 = 0002 (0000464E) -Unused write16 00A130F6 = 0003 (00004656) -Unused write16 00A130F8 = 0004 (0000465E) -Unused write16 00A130FA = 0005 (00004666) - -Unused write16 00A13032 = 0004 (00005706) -Unused write16 00A13032 = 0104 (0000579E) - -Unused write16 00380000 = ACDC (00005718) -Unused write16 00380002 = 0000 (00005722) -Unused read16 00380000 (0000572C) -Unused write16 00A13032 = 0104 (0000579E) -Unused write16 00300000 = ACDC (000057B2) -Unused write16 00380000 = 0000 (000057BC) -Unused read16 00300000 (000057C6) - -static uint32 sega_channel_r(uint32 address) -{ - return m68k_read_bus_16(address);; -} - -static void sega_channel_w(uint32 address, uint32 data) -{ - m68k_unused_16_w(address, data); -} -*/ +/**************************************************************************** + * Genesis Plus + * Mega Drive cartridge hardware support + * + * Copyright (C) 2007-2013 Eke-Eke (Genesis Plus GX) + * + * Many cartridge protections were initially documented by Haze + * (http://haze.mameworld.info/) + * + * Realtec mapper was documented by TascoDeluxe + * + * Redistribution and use of this code or any derivative works are permitted + * provided that the following conditions are met: + * + * - Redistributions may not be sold, nor may they be used in a commercial + * product or activity. + * + * - Redistributions that are modified from the original source must include the + * complete source code, including the source code for all components used by a + * binary built from the modified sources. However, as a special exception, the + * source code distributed need not include anything that is normally distributed + * (in either source or binary form) with the major components (compiler, kernel, + * and so on) of the operating system on which the executable runs, unless that + * component itself accompanies the executable. + * + * - Redistributions must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************************/ + +#include "shared.h" +#include "eeprom_i2c.h" +#include "eeprom_spi.h" +#include "gamepad.h" + +#define CART_CNT (55) + +/* Cart database entry */ +typedef struct +{ + uint16 chk_1; /* header checksum */ + uint16 chk_2; /* real checksum */ + uint8 bank_start; /* first mapped bank in $400000-$7fffff region */ + uint8 bank_end; /* last mapped bank in $400000-$7fffff region */ + cart_hw_t cart_hw; /* hardware description */ +} md_entry_t; + +/* Function prototypes */ +static void mapper_sega_w(uint32 data); +static void mapper_ssf2_w(uint32 address, uint32 data); +static void mapper_sf001_w(uint32 address, uint32 data); +static void mapper_sf002_w(uint32 address, uint32 data); +static void mapper_sf004_w(uint32 address, uint32 data); +static uint32 mapper_sf004_r(uint32 address); +static void mapper_t5740_w(uint32 address, uint32 data); +static uint32 mapper_t5740_r(uint32 address); +static uint32 mapper_smw_64_r(uint32 address); +static void mapper_smw_64_w(uint32 address, uint32 data); +static void mapper_realtec_w(uint32 address, uint32 data); +static void mapper_seganet_w(uint32 address, uint32 data); +static void mapper_32k_w(uint32 data); +static void mapper_64k_w(uint32 data); +static void mapper_64k_multi_w(uint32 address); +static uint32 mapper_radica_r(uint32 address); +static void default_time_w(uint32 address, uint32 data); +static void default_regs_w(uint32 address, uint32 data); +static uint32 default_regs_r(uint32 address); +static uint32 default_regs_r_16(uint32 address); +static uint32 custom_regs_r(uint32 address); +static void custom_regs_w(uint32 address, uint32 data); +static void custom_alt_regs_w(uint32 address, uint32 data); +static uint32 topshooter_r(uint32 address); +static void topshooter_w(uint32 address, uint32 data); +static uint32 tekken_regs_r(uint32 address); +static void tekken_regs_w(uint32 address, uint32 data); + +/* Games that need extra hardware emulation: + - copy protection device + - custom ROM banking device +*/ +static const md_entry_t rom_database[CART_CNT] = +{ +/* Funny World & Balloon Boy */ + {0x0000,0x06ab,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},1,0,NULL,NULL,NULL,mapper_realtec_w}}, +/* Whac-a-Critter */ + {0xffff,0xf863,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},1,0,NULL,NULL,NULL,mapper_realtec_w}}, +/* Earth Defense */ + {0xffff,0x44fb,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},1,0,NULL,NULL,NULL,mapper_realtec_w}}, + + +/* RADICA (Volume 1) (bad dump ?) */ + {0x0000,0x2326,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,1,mapper_radica_r,NULL,NULL,NULL}}, +/* RADICA (Volume 1) */ + {0x24f4,0xfc84,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,0,mapper_radica_r,NULL,NULL,NULL}}, +/* RADICA (Volume 2) */ + {0x104f,0x32e9,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,0,mapper_radica_r,NULL,NULL,NULL}}, + + +/* Tenchi wo Kurau III: Sangokushi Gaiden - Chinese Fighter */ + {0x9490,0x8180,0x40,0x6f,{{0x00,0x00,0x00,0x00},{0xf0000c,0xf0000c,0xf0000c,0xf0000c},{0x400000,0x400004,0x400008,0x40000c},0,1,NULL,NULL,default_regs_r,custom_alt_regs_w}}, + + +/* Top Fighter */ + {0x4eb9,0x5d8b,0x60,0x7f,{{0x00,0x00,0x00,0x00},{0xf00007,0xf00007,0xf00007,0xffffff},{0x600001,0x600003,0x600005,0x000000},0,1,NULL,NULL,default_regs_r,custom_regs_w}}, +/* Soul Edge VS Samurai Spirits */ + {0x00ff,0x5d34,0x60,0x7f,{{0x00,0x00,0x00,0x00},{0xf00007,0xf00007,0xf00007,0xffffff},{0x600001,0x600003,0x600005,0x000000},0,1,NULL,NULL,default_regs_r,custom_regs_w}}, +/* Mulan */ + {0x0404,0x1b40,0x60,0x7f,{{0x00,0x00,0x00,0x00},{0xf00007,0xf00007,0xf00007,0xffffff},{0x600001,0x600003,0x600005,0x000000},0,1,NULL,NULL,default_regs_r,custom_regs_w}}, +/* Pocket Monsters II */ + {0x47f9,0x17e5,0x60,0x7f,{{0x00,0x00,0x00,0x00},{0xf00007,0xf00007,0xf00007,0xffffff},{0x600001,0x600003,0x600005,0x000000},0,1,NULL,NULL,default_regs_r,custom_regs_w}}, +/* Lion King 3 */ + {0x0000,0x507c,0x60,0x7f,{{0x00,0x00,0x00,0x00},{0xf00007,0xf00007,0xf00007,0xffffff},{0x600001,0x600003,0x600005,0x000000},0,1,NULL,NULL,default_regs_r,custom_regs_w}}, +/* Super King Kong 99 */ + {0x0000,0x7d6e,0x60,0x7f,{{0x00,0x00,0x00,0x00},{0xf00007,0xf00007,0xf00007,0xffffff},{0x600001,0x600003,0x600005,0x000000},0,1,NULL,NULL,default_regs_r,custom_regs_w}}, +/* Gunfight 3-in-1 */ + {0x0000,0x6ff8,0x60,0x7f,{{0x00,0x00,0x00,0x00},{0xf00007,0xf00007,0xf00007,0xffffff},{0x600001,0x600003,0x600005,0x000000},0,1,NULL,NULL,default_regs_r,custom_regs_w}}, +/* Pokemon Stadium */ + {0x0000,0x843c,0x70,0x7f,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,1,NULL,NULL,NULL,custom_regs_w}}, + + +/* Tekken 3 Special (original dump) (a bootleg version also exists, with patched protection & different boot routine which reads unused !TIME mapped area) */ + {0x0000,0xc2f0,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,0,NULL,NULL,tekken_regs_r,tekken_regs_w}}, + + +/* Lion King 2 */ + {0xffff,0x1d9b,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xfffffd,0xfffffd,0xffffff,0xffffff},{0x400000,0x400004,0x000000,0x000000},0,0,NULL,NULL,default_regs_r,default_regs_w}}, +/* Squirell King */ + {0x0000,0x8ec8,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xfffffd,0xfffffd,0xffffff,0xffffff},{0x400000,0x400004,0x000000,0x000000},0,0,NULL,NULL,default_regs_r,default_regs_w}}, +/* Tiny Toon Adventures 3 */ + {0x2020,0xed9c,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xfffffd,0xfffffd,0xffffff,0xffffff},{0x400000,0x400004,0x000000,0x000000},0,0,NULL,NULL,default_regs_r,default_regs_w}}, +/* Lian Huan Pao - Barver Battle Saga (registers accessed by Z80, related to sound engine ?) */ + {0x30b9,0x1c2a,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xfffffd,0xfffffd,0xffffff,0xffffff},{0x400000,0x400004,0x000000,0x000000},0,0,NULL,NULL,default_regs_r,default_regs_w}}, +/* Shui Hu Zhuan (registers accessed by Z80, related to sound engine ?) */ + {0x6001,0x0211,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xfffffd,0xfffffd,0xffffff,0xffffff},{0x400000,0x400004,0x000000,0x000000},0,0,NULL,NULL,default_regs_r,default_regs_w}}, +/* Feng Shen Ying Jie Chuan (registers accessed by Z80, related to sound engine ?) */ + {0xffff,0x5d98,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xfffffd,0xfffffd,0xffffff,0xffffff},{0x400000,0x400004,0x000000,0x000000},0,0,NULL,NULL,default_regs_r,default_regs_w}}, +/* (*) Shui Hu - Feng Yun Zhuan (patched ROM, unused registers) */ + {0x3332,0x872b,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xfffffd,0xfffffd,0xffffff,0xffffff},{0x400000,0x400004,0x000000,0x000000},0,0,NULL,NULL,default_regs_r,default_regs_w}}, + + +/* (*) Chao Ji Da Fu Weng (patched ROM, various words witten to register, long word also read from $7E0000, unknown banking hardware ?) */ + {0xa697,0xa697,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x000000,0x000000,0x000000},0,0,NULL,NULL,NULL,default_regs_w}}, + +/* (*) Aq Renkan Awa (patched ROM, ON/OFF bit sequence is written to register, unknown banking hardware ?) */ + {0x8104,0x0517,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400001,0x000000,0x000000,0x000000},0,0,NULL,NULL,NULL,default_regs_w}}, + + +/* (*) Tun Shi Tian Di III (patched ROM, unused register) */ + {0x0000,0x9c5e,0x40,0x40,{{0xab,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400046,0x000000,0x000000,0x000000},0,0,NULL,NULL,default_regs_r,NULL}}, + + +/* Ma Jiang Qing Ren - Ji Ma Jiang Zhi */ + {0x0000,0x7037,0x40,0x40,{{0x90,0xd3,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x401000,0x000000,0x000000},0,0,NULL,NULL,default_regs_r,NULL}}, +/* Super Majon Club */ + {0x0000,0x3b95,0x40,0x40,{{0x90,0xd3,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x401000,0x000000,0x000000},0,0,NULL,NULL,default_regs_r,NULL}}, +/* Feng Kuang Tao Hua Yuan (original version from Creaton Softec Inc) (a bootleg version also exists with patched protection and minor title screen variations) */ + {0x0000,0x9dc4,0x40,0x40,{{0x90,0xd3,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x401000,0x000000,0x000000},0,0,NULL,NULL,default_regs_r,NULL}}, + + +/* (*) Jiu Ji Ma Jiang II - Ye Yan Bian (patched ROM, using expected register value - $0f - crashes the game) (uses 16-bits reads) */ + {0x0c44,0xba81,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x400006},0,0,NULL,NULL,default_regs_r_16,NULL}}, +/* 16 Zhang Ma Jiang (uses 16-bits reads) */ + {0xfb40,0x4bed,0x40,0x40,{{0x00,0xaa,0x00,0xf0},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x400002,0x000000,0x400006},0,0,NULL,NULL,default_regs_r_16,NULL}}, +/* 16 Tiles Mahjong II (uses 16-bits reads) */ + {0xffff,0x0903,0x40,0x40,{{0x00,0x00,0xc9,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x400004,0x000000},0,0,NULL,NULL,default_regs_r_16,NULL}}, +/* Thunderbolt II (uses 16-bits reads) */ + {0x0000,0x1585,0x40,0x40,{{0x55,0x0f,0xaa,0xf0},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,NULL,NULL,default_regs_r_16,NULL}}, + + +/* Super Bubble Bobble */ + {0x0000,0x16cd,0x40,0x40,{{0x55,0x0f,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x000000,0x000000},0,0,NULL,NULL,default_regs_r,NULL}}, +/* Tenchi wo Kurau II - The Battle of Red Cliffs (Unl) */ + {0x0000,0xed61,0x40,0x40,{{0x55,0x0f,0xaa,0xf0},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,NULL,NULL,default_regs_r,NULL}}, +/* Huan Le Tao Qi Shu - Smart Mouse */ + {0x0000,0x1a28,0x40,0x40,{{0x55,0x0f,0xaa,0xf0},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,NULL,NULL,default_regs_r,NULL}}, +/* (*) Hei Tao 2 - Super Big 2 (patched ROM, unused registers) */ + {0x0000,0x5843,0x40,0x40,{{0x55,0x0f,0xaa,0xf0},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,NULL,NULL,default_regs_r,NULL}}, +/* Mighty Morphin Power Rangers - The Fighting Edition */ + {0x0000,0x2288,0x40,0x40,{{0x55,0x0f,0xc9,0x18},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,NULL,NULL,default_regs_r,NULL}}, +/* Elf Wor */ + {0x0080,0x3dba,0x40,0x40,{{0x55,0x0f,0xc9,0x18},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,NULL,NULL,default_regs_r,NULL}}, +/* Ya-Se Chuanshuo */ + {0xffff,0xd472,0x40,0x40,{{0x63,0x98,0xc9,0x18},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,NULL,NULL,default_regs_r,NULL}}, +/* 777 Casino (For first one, 0x55 works as well. Other values are never used so they are guessed from on other unlicensed games using similar mapper) */ + {0x0000,0xf8d9,0x40,0x40,{{0x63,0x98,0xc9,0x18},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,NULL,NULL,default_regs_r,NULL}}, +/* Wu Kong Wai Zhuan (original) (a bootleg version also exists, with patched protection & modified SRAM test routine ?) */ + {0x0000,0x19ff,0x40,0x40,{{0x63,0x98,0xc9,0x18},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,NULL,NULL,default_regs_r,NULL}}, +/* Soul Blade */ + {0x0000,0x0c5b,0x40,0x40,{{0x63,0x98,0xc9,0xf0},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,NULL,NULL,default_regs_r,NULL}}, + + +/* King of Fighter 98 */ + {0x0000,0xd0a0,0x48,0x4f,{{0x00,0x00,0xaa,0xf0},{0xffffff,0xffffff,0xfc0000,0xfc0000},{0x000000,0x000000,0x480000,0x4c0000},0,0,NULL,NULL,default_regs_r,NULL}}, + + +/* Rockman X3 (bootleg version ? two last register returned values are ignored, note that 0xaa/0x18 would work as well) */ + {0x0000,0x9d0e,0x40,0x40,{{0x0c,0x00,0xc9,0xf0},{0xffffff,0xffffff,0xffffff,0xffffff},{0xa13000,0x000000,0x400004,0x400006},0,0,default_regs_r,NULL,default_regs_r,NULL}}, + + +/* (*) Dragon Ball Final Bout (patched ROM, in original code, different switches occurs depending on returned value $00-$0f) */ + {0xc65a,0xc65a,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0xa13000,0x000000,0x000000,0x000000},0,0,default_regs_r,NULL,NULL,NULL}}, +/* (*) Yang Jia Jiang - Yang Warrior Family (patched ROM, register value unused) */ + {0x0000,0x96b0,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0xa13000,0x000000,0x000000,0x000000},0,0,default_regs_r,NULL,NULL,NULL}}, +/* Super Mario 2 1998 */ + {0xffff,0x0474,0x00,0x00,{{0x0a,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0xa13000,0x000000,0x000000,0x000000},0,0,default_regs_r,NULL,NULL,NULL}}, +/* Super Mario World */ + {0x2020,0xb4eb,0x00,0x00,{{0x1c,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0xa13000,0x000000,0x000000,0x000000},0,0,default_regs_r,NULL,NULL,NULL}}, + + +/* King of Fighter 99 */ + {0x0000,0x021e,0x00,0x00,{{0x00,0x01,0x1f,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0xa13000,0xa13002,0xa1303e,0x000000},0,0,custom_regs_r,default_regs_w,NULL,NULL}}, +/* Pocket Monster */ + {0xd6fc,0x1eb1,0x00,0x00,{{0x00,0x01,0x1f,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0xa13000,0xa13002,0xa1303e,0x000000},0,0,custom_regs_r,default_regs_w,NULL,NULL}}, +/* Pocket Monster (bootleg version ? two last register returned values are ignored & first register test has been modified) */ + {0xd6fc,0x6319,0x00,0x00,{{0x14,0x01,0x1f,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0xa13000,0xa13002,0xa1303e,0x000000},0,0,default_regs_r,m68k_unused_8_w,NULL,NULL}}, +/* A Bug's Life (bootleg version ? two last register returned values are ignored & first register test has been modified ?) */ + {0x7f7f,0x2aad,0x00,0x00,{{0x28,0x01,0x1f,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0xa13000,0xa13002,0xa1303e,0x000000},0,0,default_regs_r,m68k_unused_8_w,NULL,NULL}}, + + +/* Game no Kanzume Otokuyou */ + {0x0000,0xf9d1,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,0,NULL,mapper_seganet_w,NULL,NULL}}, + + +/* Top Shooter (arcade hardware) */ + {0xffff,0x3632,0x20,0x20,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,0,NULL,NULL,topshooter_r,topshooter_w}} +}; + + +/************************************************************ + Cart Hardware initialization +*************************************************************/ + +void md_cart_init(void) +{ + int i; + + /*************************************************************************************************************** + CARTRIDGE ROM MIRRORING + *************************************************************************************************************** + + MD Cartridge area is mapped to $000000-$3fffff: + + -> when accessing ROM, 68k address lines A1 to A21 can be used by the internal cartridge hardware to decode + full 4MB address range. + -> depending on ROM total size and additional decoding hardware, some address lines might be ignored, + resulting in ROM mirroring. + + Cartridges can use either 8-bits (x2) or 16-bits (x1, x2) Mask ROM chips, each chip size is a factor of 2 bytes: + + -> two 8-bits chips are equivalent to one 16-bits chip, no specific address decoding is required, needed + address lines are simply connected to each chip, upper address lines are ignored and data lines are + connected appropriately to each chip (D0-D7 to one chip, D8-D15 to the other one). + ROM is generally mirrored each N bytes where N=2^(k+1) is the total ROM size (ROM1+ROM2,ROM1+ROM2,...) + + -> one single 16-bits chip do not need specific address decoding, address lines are simply connected + depending on the ROM size, upper address lines being ignored. + ROM is generally mirrored each N bytes where N=2^k is the size of the ROM chip (ROM1,ROM1,ROM1,...) + + -> two 16-bits chips of the same size are equivalent to one chip of double size, address decoding generally + is the same except that specific hardware is used (one address line is generally used for chip selection, + lower ones being used to address the chips and upper ones being ignored). + ROM is generally mirrored each N bytes where N=2^(k+1) is the total ROM size (ROM1,ROM2,ROM1,ROM2,...) + + -> two 16-bits chips with different size are mapped differently. Address decoding is done the same way as + above (one address line used for chip selection) but the ignored & required address lines differ from + one chip to another, which makes ROM mirroring different. + ROM2 size is generally half of ROM1 size and upper half ignored (ROM1,ROM2,XXXX,ROM1,ROM2,XXXX,...) + + From the emulator point of view, we only need to distinguish 2 cases: + + 1/ total ROM size is a factor of 2: ROM is mirrored each 2^k bytes. + + 2/ total ROM size is not a factor of 2: ROM is padded up to 2^k then mirrored each 2^k bytes. + + ******************************************************************************************************************/ + + /* calculate nearest size with factor of 2 */ + unsigned int size = 0x10000; + while (cart.romsize > size) + size <<= 1; + + /* Sonic & Knuckles */ + if (strstr(rominfo.international,"SONIC & KNUCKLES")) + { + /* disable ROM mirroring at $200000-$3fffff (normally mapped to external cartridge) */ + size = 0x400000; + } + + /* total ROM size is not a factor of 2 */ + /* TODO: handle all possible ROM configurations using cartridge database */ + if (cart.romsize < size) + { + if (size < MAXROMSIZE) + { + /* ROM is padded up to 2^k bytes */ + memset(cart.rom + cart.romsize, 0xff, size - cart.romsize); + } + else + { + /* ROM is padded up to max ROM size */ + memset(cart.rom + cart.romsize, 0xff, MAXROMSIZE - cart.romsize); + } + } + + /* ROM is mirrored each 2^k bytes */ + cart.mask = size - 1; + + /********************************************** + DEFAULT CARTRIDGE MAPPING + ***********************************************/ + for (i=0; i<0x40; i++) + { + /* cartridge ROM */ + m68k.memory_map[i].base = cart.rom + ((i<<16) & cart.mask); + m68k.memory_map[i].read8 = NULL; + m68k.memory_map[i].read16 = NULL; + m68k.memory_map[i].write8 = m68k_unused_8_w; + m68k.memory_map[i].write16 = m68k_unused_16_w; + zbank_memory_map[i].read = NULL; + zbank_memory_map[i].write = zbank_unused_w; + } + + for (i=0x40; i<0x80; i++) + { + /* unused area */ + m68k.memory_map[i].base = cart.rom + (i<<16); + m68k.memory_map[i].read8 = m68k_read_bus_8; + m68k.memory_map[i].read16 = m68k_read_bus_16; + m68k.memory_map[i].write8 = m68k_unused_8_w; + m68k.memory_map[i].write16 = m68k_unused_16_w; + zbank_memory_map[i].read = zbank_unused_r; + zbank_memory_map[i].write = zbank_unused_w; + } + + /* support for Quackshot REV 01 (real) dump */ + if (strstr(rominfo.product,"00004054-01") && (cart.romsize == 0x80000)) + { + /* $000000-$0fffff: first 256K mirrored (A18 not connected to ROM chip, A19 not decoded) */ + for (i=0x00; i<0x10; i++) + { + /* $200000-$3fffff: mirror of $000000-$1fffff (A21 not decoded) */ + m68k.memory_map[i].base = m68k.memory_map[i + 0x20].base = cart.rom + ((i & 0x03) << 16); + } + + /* $100000-$1fffff: second 256K mirrored (A20 connected to ROM chip A18) */ + for (i=0x10; i<0x20; i++) + { + /* $200000-$3fffff: mirror of $000000-$1fffff (A21 not decoded) */ + m68k.memory_map[i].base = m68k.memory_map[i + 0x20].base = cart.rom + 0x40000 + ((i & 0x03) << 16); + } + } + + /********************************************** + BACKUP MEMORY + ***********************************************/ + sram_init(); + eeprom_i2c_init(); + + /* external SRAM */ + if (sram.on && !sram.custom) + { + /* disabled on startup if ROM is mapped in same area */ + if (cart.romsize <= sram.start) + { + /* initialize m68k bus handlers */ + m68k.memory_map[sram.start >> 16].base = sram.sram; + m68k.memory_map[sram.start >> 16].read8 = sram_read_byte; + m68k.memory_map[sram.start >> 16].read16 = sram_read_word; + m68k.memory_map[sram.start >> 16].write8 = sram_write_byte; + m68k.memory_map[sram.start >> 16].write16 = sram_write_word; + zbank_memory_map[sram.start >> 16].read = sram_read_byte; + zbank_memory_map[sram.start >> 16].write = sram_write_byte; + } + } + + /********************************************** + SVP CHIP + ***********************************************/ + svp = NULL; + if (strstr(rominfo.international,"Virtua Racing")) + { + svp_init(); + } + + /********************************************** + J-CART + ***********************************************/ + cart.special = 0; + if ((strstr(rominfo.product,"00000000") && (rominfo.checksum == 0x168b)) || /* Super Skidmarks, Micro Machines Military */ + (strstr(rominfo.product,"00000000") && (rominfo.checksum == 0x165e)) || /* Pete Sampras Tennis (1991), Micro Machines 96 */ + (strstr(rominfo.product,"00000000") && (rominfo.checksum == 0xcee0)) || /* Micro Machines Military (bad) */ + (strstr(rominfo.product,"00000000") && (rominfo.checksum == 0x2c41)) || /* Micro Machines 96 (bad) */ + (strstr(rominfo.product,"XXXXXXXX") && (rominfo.checksum == 0xdf39)) || /* Sampras Tennis 96 */ + (strstr(rominfo.product,"T-123456") && (rominfo.checksum == 0x1eae)) || /* Sampras Tennis 96 */ + (strstr(rominfo.product,"T-120066") && (rominfo.checksum == 0x16a4)) || /* Pete Sampras Tennis (1994)*/ + strstr(rominfo.product,"T-120096")) /* Micro Machines 2 */ + { + if (cart.romsize <= 0x380000) /* just to be sure (checksum might not be enough) */ + { + cart.special |= HW_J_CART; + + /* force port 1 setting */ + if (input.system[1] != SYSTEM_WAYPLAY) + { + old_system[1] = input.system[1]; + input.system[1] = SYSTEM_MD_GAMEPAD; + } + + /* extra connectors mapped at $38xxxx or $3Fxxxx */ + m68k.memory_map[0x38].read16 = jcart_read; + m68k.memory_map[0x38].write16 = jcart_write; + m68k.memory_map[0x3f].read16 = jcart_read; + m68k.memory_map[0x3f].write16 = jcart_write; + } + } + + /********************************************** + LOCK-ON + ***********************************************/ + + /* clear existing patches */ + ggenie_shutdown(); + areplay_shutdown(); + + /* initialize extra hardware */ + switch (config.lock_on) + { + case TYPE_GG: + { + ggenie_init(); + break; + } + + case TYPE_AR: + { + areplay_init(); + break; + } + + case TYPE_SK: + { + FILE *f; + + /* store S&K ROM above cartridge ROM (and before backup memory) */ + if (cart.romsize > 0x600000) break; + + /* load Sonic & Knuckles ROM (2 MB) */ + f = fopen(SK_ROM,"rb"); + if (!f) break; + for (i=0; i<0x200000; i+=0x1000) + { + fread(cart.rom + 0x600000 + i, 0x1000, 1, f); + } + fclose(f); + + /* load Sonic 2 UPMEM ROM (256 KB) */ + f = fopen(SK_UPMEM,"rb"); + if (!f) break; + for (i=0; i<0x40000; i+=0x1000) + { + fread(cart.rom + 0x900000 + i, 0x1000, 1, f); + } + fclose(f); + +#ifdef LSB_FIRST + for (i=0; i<0x200000; i+=2) + { + /* Byteswap ROM */ + uint8 temp = cart.rom[i + 0x600000]; + cart.rom[i + 0x600000] = cart.rom[i + 0x600000 + 1]; + cart.rom[i + 0x600000 + 1] = temp; + } + + for (i=0; i<0x40000; i+=2) + { + /* Byteswap ROM */ + uint8 temp = cart.rom[i + 0x900000]; + cart.rom[i + 0x900000] = cart.rom[i + 0x900000 + 1]; + cart.rom[i + 0x900000 + 1] = temp; + } +#endif + + /* $000000-$1FFFFF is mapped to S&K ROM */ + for (i=0x00; i<0x20; i++) + { + m68k.memory_map[i].base = cart.rom + 0x600000 + (i << 16); + } + + cart.special |= HW_LOCK_ON; + break; + } + + default: + { + break; + } + } + + /********************************************** + CARTRIDGE EXTRA HARDWARE + ***********************************************/ + memset(&cart.hw, 0, sizeof(cart.hw)); + + /* search for game into database */ + for (i=0; i 0x400000) + { + /* assume linear ROM mapper without bankswitching (max. 10MB) */ + for (i=0x40; i<0xA0; i++) + { + m68k.memory_map[i].base = cart.rom + (i<<16); + m68k.memory_map[i].read8 = NULL; + m68k.memory_map[i].read16 = NULL; + zbank_memory_map[i].read = NULL; + } + } + + /* default write handler for !TIME range ($A130xx)*/ + if (!cart.hw.time_w) + { + cart.hw.time_w = default_time_w; + } +} + +/* hardware that need to be reseted on power on */ +void md_cart_reset(int hard_reset) +{ + int i; + + /* reset cartridge mapping */ + if (cart.hw.bankshift) + { + for (i=0x00; i<0x40; i++) + { + m68k.memory_map[i].base = cart.rom + ((i<<16) & cart.mask); + } + } + + /* SVP chip */ + if (svp) + { + svp_reset(); + } + + /* Lock-ON */ + switch (config.lock_on) + { + case TYPE_GG: + { + ggenie_reset(hard_reset); + break; + } + + case TYPE_AR: + { + areplay_reset(hard_reset); + break; + } + + case TYPE_SK: + { + if (cart.special & HW_LOCK_ON) + { + /* disable UPMEM chip at $300000-$3fffff */ + for (i=0x30; i<0x40; i++) + { + m68k.memory_map[i].base = cart.rom + ((i<<16) & cart.mask); + } + } + break; + } + + default: + { + break; + } + } +} + + +/************************************************************ + MAPPER handlers +*************************************************************/ + +/* + "official" ROM/SRAM bankswitch (Phantasy Star IV, Story of Thor/Beyond Oasis, Sonic 3 & Knuckles) +*/ +static void mapper_sega_w(uint32 data) +{ + int i; + + if (data & 1) + { + if (sram.on) + { + /* Backup RAM mapped to $200000-$20ffff (normally mirrored up to $3fffff but this breaks Sonic Megamix and no game need it) */ + m68k.memory_map[0x20].base = sram.sram; + m68k.memory_map[0x20].read8 = sram_read_byte; + m68k.memory_map[0x20].read16 = sram_read_word; + zbank_memory_map[0x20].read = sram_read_byte; + + /* Backup RAM write protection */ + if (data & 2) + { + m68k.memory_map[0x20].write8 = m68k_unused_8_w; + m68k.memory_map[0x20].write16 = m68k_unused_16_w; + zbank_memory_map[0x20].write = zbank_unused_w; + } + else + { + m68k.memory_map[0x20].write8 = sram_write_byte; + m68k.memory_map[0x20].write16 = sram_write_word; + zbank_memory_map[0x20].write = sram_write_byte; + } + } + + /* S&K lock-on chip */ + if ((cart.special & HW_LOCK_ON) && (config.lock_on == TYPE_SK)) + { + /* S2K upmem chip mapped to $300000-$3fffff (256K mirrored) */ + for (i=0x30; i<0x40; i++) + { + m68k.memory_map[i].base = (cart.rom + 0x900000) + ((i & 3) << 16); + } + } + } + else + { + /* cartridge ROM mapped to $200000-$3fffff */ + for (i=0x20; i<0x40; i++) + { + m68k.memory_map[i].base = cart.rom + ((i<<16) & cart.mask); + m68k.memory_map[i].read8 = NULL; + m68k.memory_map[i].read16 = NULL; + zbank_memory_map[i].read = NULL; + m68k.memory_map[i].write8 = m68k_unused_8_w; + m68k.memory_map[i].write16 = m68k_unused_16_w; + zbank_memory_map[i].write = zbank_unused_w; + } + } +} + +/* + Super Street Fighter 2 ROM bankswitch + documented by Bart Trzynadlowski (http://www.trzy.org/files/ssf2.txt) +*/ +static void mapper_ssf2_w(uint32 address, uint32 data) +{ + /* 8 x 512k banks */ + address = (address << 2) & 0x38; + + /* bank 0 remains unchanged */ + if (address) + { + uint32 i; + uint8 *src = cart.rom + (data << 19); + + for (i=0; i<8; i++) + { + m68k.memory_map[address++].base = src + (i<<16); + } + } +} + +/* + SF-001 mapper +*/ +static void mapper_sf001_w(uint32 address, uint32 data) +{ + switch ((address >> 8) & 0xf) + { + case 0xe: + { + int i; + + /* bit 6: enable / disable cartridge access */ + if (data & 0x40) + { + /* $000000-$3FFFFF is not mapped */ + for (i=0x00; i<0x40; i++) + { + m68k.memory_map[i].base = cart.rom + (i << 16); + m68k.memory_map[i].read8 = m68k_read_bus_8; + m68k.memory_map[i].read16 = m68k_read_bus_16; + m68k.memory_map[i].write8 = (i > 0x00) ? m68k_unused_8_w : mapper_sf001_w; + m68k.memory_map[i].write16 = (i > 0x00) ? m68k_unused_16_w : mapper_sf001_w; + zbank_memory_map[i].read = zbank_unused_r; + zbank_memory_map[i].write = (i > 0x00) ? m68k_unused_8_w : mapper_sf001_w; + } + } + + /* bit 7: enable / disable SRAM & ROM bankswitching */ + else if (data & 0x80) + { + /* 256K ROM bank #15 mapped to $000000-$03FFFF */ + for (i=0x00; i<0x04; i++) + { + m68k.memory_map[i].base = cart.rom + ((0x38 + i) << 16); + m68k.memory_map[i].read8 = NULL; + m68k.memory_map[i].read16 = NULL; + zbank_memory_map[i].read = NULL; + } + + /* 256K ROM banks #2 to #15 mapped to $040000-$3BFFFF (last revision) or $040000-$3FFFFF (older revisions) */ + for (i=0x04; i<(sram.start >> 16); i++) + { + m68k.memory_map[i].base = cart.rom + (i << 16); + m68k.memory_map[i].read8 = NULL; + m68k.memory_map[i].read16 = NULL; + zbank_memory_map[i].read = NULL; + } + + /* 32K static RAM mirrored into $3C0000-$3FFFFF (odd bytes only) (last revision only) */ + while (i<0x40) + { + m68k.memory_map[i].base = sram.sram; + m68k.memory_map[i].read8 = sram_read_byte; + m68k.memory_map[i].read16 = sram_read_word; + m68k.memory_map[i].write8 = sram_write_byte; + m68k.memory_map[i].write16 = sram_write_word; + zbank_memory_map[i].read = sram_read_byte; + zbank_memory_map[i].write = sram_write_byte; + i++; + } + } + else + { + /* 256K ROM banks #1 to #16 mapped to $000000-$3FFFFF (default) */ + for (i=0x00; i<0x40; i++) + { + m68k.memory_map[i].base = cart.rom + (i << 16); + m68k.memory_map[i].read8 = NULL; + m68k.memory_map[i].read16 = NULL; + m68k.memory_map[i].write8 = (i > 0x00) ? m68k_unused_8_w : mapper_sf001_w; + m68k.memory_map[i].write16 = (i > 0x00) ? m68k_unused_16_w : mapper_sf001_w; + zbank_memory_map[i].read = NULL; + zbank_memory_map[i].write = (i > 0x00) ? m68k_unused_8_w : mapper_sf001_w; + } + } + + /* bit 5: lock bankswitch hardware when set */ + if (data & 0x20) + { + /* disable bankswitch hardware access until hard reset */ + m68k.memory_map[0x00].write8 = m68k_unused_8_w; + m68k.memory_map[0x00].write16 = m68k_unused_16_w; + zbank_memory_map[0x00].write = m68k_unused_8_w; + } + + return; + } + + default: + { + m68k_unused_8_w(address, data); + return; + } + } +} + +/* + SF-002 mapper +*/ +static void mapper_sf002_w(uint32 address, uint32 data) +{ + int i; + if (data & 0x80) + { + /* $000000-$1BFFFF mapped to $200000-$3BFFFF */ + for (i=0x20; i<0x3C; i++) + { + m68k.memory_map[i].base = cart.rom + ((i & 0x1F) << 16); + } + } + else + { + /* $200000-$3BFFFF mapped to $200000-$3BFFFF */ + for (i=0x20; i<0x3C; i++) + { + m68k.memory_map[i].base = cart.rom + (i << 16); + } + } +} + +/* + SF-004 mapper +*/ +static void mapper_sf004_w(uint32 address, uint32 data) +{ + int i; + switch ((address >> 8) & 0xf) + { + case 0xd: + { + /* bit 7: enable/disable static RAM access */ + if (data & 0x80) + { + /* 32KB static RAM mirrored into $200000-$2FFFFF (odd bytes only) */ + for (i=0x20; i<0x30; i++) + { + m68k.memory_map[i].read8 = sram_read_byte; + m68k.memory_map[i].read16 = sram_read_word; + m68k.memory_map[i].write8 = sram_write_byte; + m68k.memory_map[i].write16 = sram_write_word; + zbank_memory_map[i].read = sram_read_byte; + zbank_memory_map[i].write = sram_write_byte; + } + } + else + { + /* 32KB static RAM disabled at $200000-$2FFFFF */ + for (i=0x20; i<0x30; i++) + { + m68k.memory_map[i].read8 = m68k_read_bus_8; + m68k.memory_map[i].read16 = m68k_read_bus_16; + m68k.memory_map[i].write8 = m68k_unused_8_w; + m68k.memory_map[i].write16 = m68k_unused_16_w; + zbank_memory_map[i].read = m68k_read_bus_8; + zbank_memory_map[i].write = m68k_unused_8_w; + } + } + + return; + } + + case 0x0e: + { + /* bit 5: enable / disable cartridge ROM access */ + if (data & 0x20) + { + /* $000000-$1FFFFF is not mapped */ + for (i=0x00; i<0x20; i++) + { + m68k.memory_map[i].read8 = m68k_read_bus_8; + m68k.memory_map[i].read16 = m68k_read_bus_16; + zbank_memory_map[i].read = m68k_read_bus_8; + } + } + + /* bit 6: enable / disable first page mirroring */ + else if (data & 0x40) + { + /* first page ROM bank */ + uint8 base = (m68k.memory_map[0x00].base - cart.rom) >> 16; + + /* 5 x 256K ROM banks mapped to $000000-$13FFFF, starting from first page ROM bank */ + for (i=0x00; i<0x14; i++) + { + m68k.memory_map[i].base = cart.rom + (((base + i) & 0x1f) << 16); + m68k.memory_map[i].read8 = NULL; + m68k.memory_map[i].read16 = NULL; + zbank_memory_map[i].read = NULL; + } + + /* $140000-$1FFFFF is not mapped */ + for (i=0x14; i<0x20; i++) + { + m68k.memory_map[i].read8 = m68k_read_bus_8; + m68k.memory_map[i].read16 = m68k_read_bus_16; + zbank_memory_map[i].read = m68k_read_bus_8; + } + } + else + { + /* first page 256K ROM bank mirrored into $000000-$1FFFFF */ + for (i=0x00; i<0x20; i++) + { + m68k.memory_map[i].base = m68k.memory_map[0].base + ((i & 0x03) << 16); + m68k.memory_map[i].read8 = NULL; + m68k.memory_map[i].read16 = NULL; + zbank_memory_map[i].read = NULL; + } + } + + /* bit 7: lock ROM bankswitching hardware when cleared */ + if (!(data & 0x80)) + { + /* disable bankswitch hardware access */ + m68k.memory_map[0x00].write8 = m68k_unused_8_w; + m68k.memory_map[0x00].write16 = m68k_unused_16_w; + zbank_memory_map[0x00].write = m68k_unused_8_w; + } + + return; + } + + case 0x0f: + { + /* bits 6-4: select first page ROM bank (8 x 256K ROM banks) */ + uint8 base = ((data >> 4) & 7) << 2; + + if (m68k.memory_map[0].base == m68k.memory_map[4].base) + { + /* selected 256K ROM bank mirrored into $000000-$1FFFFF */ + for (i=0x00; i<0x20; i++) + { + m68k.memory_map[i].base = cart.rom + ((base + (i & 0x03)) << 16); + } + } + else + { + /* 5 x 256K ROM banks mapped to $000000-$13FFFF, starting from selected bank */ + for (i=0x00; i<0x14; i++) + { + m68k.memory_map[i].base = cart.rom + (((base + i) & 0x1f) << 16); + } + } + + return; + } + + default: + { + m68k_unused_8_w(address, data); + return; + } + } +} + +static uint32 mapper_sf004_r(uint32 address) +{ + /* return first page 256K bank index ($00,$10,$20,...,$70) */ + return (((m68k.memory_map[0x00].base - cart.rom) >> 18) << 4); +} + +/* + T-5740xx-xx mapper +*/ +static void mapper_t5740_w(uint32 address, uint32 data) +{ + int i; + uint8 *base; + + switch (address & 0xff) + { + case 0x01: /* mode register */ + { + /* bits 7-4: unused ? */ + /* bit 3: enable SPI registers access ? */ + /* bit 2: not used ? */ + /* bit 1: enable bankswitch registers access ? */ + /* bit 0: always set, enable hardware access ? */ + return; + } + + case 0x03: /* page #5 register */ + { + /* map any of 16 x 512K ROM banks to $280000-$2FFFFF */ + base = cart.rom + ((data & 0x0f) << 19); + for (i=0x28; i<0x30; i++) + { + m68k.memory_map[i].base = base + ((i & 0x07) << 16); + } + return; + } + + case 0x05: /* page #6 register */ + { + /* map any of 16 x 512K ROM banks to $300000-$37FFFF */ + base = cart.rom + ((data & 0x0f) << 19); + for (i=0x30; i<0x38; i++) + { + m68k.memory_map[i].base = base + ((i & 0x07) << 16); + } + return; + } + + case 0x07: /* page #7 register */ + { + /* map any of 16 x 512K ROM banks to $380000-$3FFFFF */ + base = cart.rom + ((data & 0x0f) << 19); + for (i=0x38; i<0x40; i++) + { + m68k.memory_map[i].base = base + ((i & 0x07) << 16); + } + return; + } + + case 0x09: /* serial EEPROM SPI board support */ + { + eeprom_spi_write(data); + return; + } + + default: + { + /* unknown registers */ + m68k_unused_8_w(address, data); + return; + } + } +} + +static uint32 mapper_t5740_r(uint32 address) +{ + /* By default, first 32K of each eight 512K pages mapped in $000000-$3FFFFF are mirrored in the 512K page */ + /* mirroring is disabled/enabled when a specific number of words is being read from specific ROM addresses */ + /* Exact decoding isn't known but mirrored data is expected on startup when reading a few times from $181xx */ + /* this area doesn't seem to be accessed as byte later so it seems safe to always return mirrored data here */ + if ((address & 0xff00) == 0x8100) + { + return READ_BYTE(cart.rom , (address & 0x7fff)); + } + + return READ_BYTE(cart.rom, address); +} + +/* + Super Mario World 64 (unlicensed) mapper +*/ +static void mapper_smw_64_w(uint32 address, uint32 data) +{ + /* internal registers (saved to backup RAM) */ + switch ((address >> 16) & 0x07) + { + case 0x00: /* $60xxxx */ + { + if (address & 2) + { + /* $600003 data write mode ? */ + switch (sram.sram[0x00] & 0x07) + { + case 0x00: + { + /* update value returned at $660001-$660003 */ + sram.sram[0x06] = ((sram.sram[0x06] ^ sram.sram[0x01]) ^ data) & 0xFE; + break; + } + + case 0x01: + { + /* update value returned at $660005-$660007 */ + sram.sram[0x07] = data & 0xFE; + break; + } + + case 0x07: + { + /* update selected ROM bank (upper 512K) mapped at $610000-$61ffff */ + m68k.memory_map[0x61].base = m68k.memory_map[0x69].base = cart.rom + 0x080000 + ((data & 0x1c) << 14); + break; + } + + default: + { + /* unknown mode */ + break; + } + } + + /* $600003 data register */ + sram.sram[0x01] = data; + } + else + { + /* $600001 ctrl register */ + sram.sram[0x00] = data; + } + return; + } + + case 0x01: /* $61xxxx */ + { + if (address & 2) + { + /* $610003 ctrl register */ + sram.sram[0x02] = data; + } + return; + } + + case 0x04: /* $64xxxx */ + { + if (address & 2) + { + /* $640003 data register */ + sram.sram[0x04] = data; + } + else + { + /* $640001 data register */ + sram.sram[0x03] = data; + } + return; + } + + case 0x06: /* $66xxxx */ + { + /* unknown */ + return; + } + + case 0x07: /* $67xxxx */ + { + if (!(address & 2)) + { + /* $670001 ctrl register */ + sram.sram[0x05] = data; + + /* upper 512K ROM bank-switching enabled ? */ + if (sram.sram[0x02] & 0x80) + { + /* update selected ROM bank (upper 512K) mapped at $600000-$60ffff */ + m68k.memory_map[0x60].base = m68k.memory_map[0x68].base = cart.rom + 0x080000 + ((data & 0x1c) << 14); + } + } + return; + } + + default: /* not used */ + { + m68k_unused_8_w(address, data); + return; + } + } +} + +static uint32 mapper_smw_64_r(uint32 address) +{ + /* internal registers (saved to backup RAM) */ + switch ((address >> 16) & 0x03) + { + case 0x02: /* $66xxxx */ + { + switch ((address >> 1) & 7) + { + case 0x00: return sram.sram[0x06]; + case 0x01: return sram.sram[0x06] + 1; + case 0x02: return sram.sram[0x07]; + case 0x03: return sram.sram[0x07] + 1; + case 0x04: return sram.sram[0x08]; + case 0x05: return sram.sram[0x08] + 1; + case 0x06: return sram.sram[0x08] + 2; + case 0x07: return sram.sram[0x08] + 3; + } + } + + case 0x03: /* $67xxxx */ + { + uint8 data = (sram.sram[0x02] & 0x80) ? ((sram.sram[0x05] & 0x40) ? (sram.sram[0x03] & sram.sram[0x04]) : (sram.sram[0x03] ^ 0xFF)) : 0x00; + + if (address & 2) + { + /* $670003 */ + data &= 0x7f; + } + else + { + /* $66xxxx data registers update */ + if (sram.sram[0x05] & 0x80) + { + if (sram.sram[0x05] & 0x20) + { + /* update $660009-$66000f data register */ + sram.sram[0x08] = (sram.sram[0x04] << 2) & 0xFC; + } + else + { + /* update $660001-$660003 data register */ + sram.sram[0x06] = (sram.sram[0x01] ^ (sram.sram[0x03] << 1)) & 0xFE; + } + } + } + + return data; + } + + default: /* 64xxxx-$65xxxx */ + { + return 0x00; + } + } +} + +/* + Realtec ROM bankswitch (Earth Defend, Balloon Boy & Funny World, Whac-A-Critter) + (Note: register usage is inverted in TascoDlx documentation) +*/ +static void mapper_realtec_w(uint32 address, uint32 data) +{ + switch (address) + { + case 0x402000: + { + /* number of mapped 64k blocks (the written value is a number of 128k blocks) */ + cart.hw.regs[2] = data << 1; + return; + } + + case 0x404000: + { + /* 00000xxx */ + cart.hw.regs[0] = data & 7; + return; + } + + case 0x400000: + { + /* 00000yy1 */ + cart.hw.regs[1] = data & 6; + + /* ensure mapped size is not null */ + if (cart.hw.regs[2]) + { + /* mapped start address is 00yy xxx0 0000 0000 0000 0000 */ + uint32 base = (cart.hw.regs[0] << 1) | (cart.hw.regs[1] << 3); + + /* selected blocks are mirrored into the whole cartridge area */ + int i; + for (i=0x00; i<0x40; i++) + { + m68k.memory_map[i].base = &cart.rom[(base + (i % cart.hw.regs[2])) << 16]; + } + } + return; + } + } +} + +/* Game no Kanzume Otokuyou ROM Mapper */ +static void mapper_seganet_w(uint32 address, uint32 data) +{ + if ((address & 0xff) == 0xf1) + { + int i; + if (data & 1) + { + /* ROM Write protected */ + for (i=0; i<0x40; i++) + { + m68k.memory_map[i].write8 = m68k_unused_8_w; + m68k.memory_map[i].write16 = m68k_unused_16_w; + zbank_memory_map[i].write = zbank_unused_w; + } + } + else + { + /* ROM Write enabled */ + for (i=0; i<0x40; i++) + { + m68k.memory_map[i].write8 = NULL; + m68k.memory_map[i].write16 = NULL; + zbank_memory_map[i].write = NULL; + } + } + } +} + +/* + Custom ROM Bankswitch used in Soul Edge VS Samurai Spirits, Top Fighter, Mulan, Pocket Monsters II, Lion King 3, Super King Kong 99, Pokemon Stadium +*/ +static void mapper_32k_w(uint32 data) +{ + int i; + + /* 64 x 32k banks */ + if (data) + { + for (i=0; i<0x10; i++) + { + /* Remap to unused ROM area */ + m68k.memory_map[i].base = &cart.rom[0x400000 + (i << 16)]; + + /* address = address OR (value << 15) */ + memcpy(m68k.memory_map[i].base, cart.rom + ((i << 16) | (data & 0x3f) << 15), 0x8000); + memcpy(m68k.memory_map[i].base + 0x8000, cart.rom + ((i << 16) | ((data | 1) & 0x3f) << 15), 0x8000); + } + } + else + { + /* reset default $000000-$0FFFFF mapping */ + for (i=0; i<16; i++) + { + m68k.memory_map[i].base = &cart.rom[i << 16]; + } + } +} + +/* + Custom ROM Bankswitch used in Chinese Fighter III +*/ +static void mapper_64k_w(uint32 data) +{ + int i; + + /* 16 x 64k banks */ + if (data) + { + /* bank is mapped at $000000-$0FFFFF */ + for (i=0; i<16; i++) + { + m68k.memory_map[i].base = &cart.rom[(data & 0xf) << 16]; + } + } + else + { + /* reset default $000000-$0FFFFF mapping */ + for (i=0; i<16; i++) + { + m68k.memory_map[i].base = &cart.rom[(i & 0xf) << 16]; + } + } +} + +/* + Custom ROM Bankswitch used in pirate "Multi-in-1" cartridges, A Bug's Life, King of Fighter 99, Pocket Monster, Rockman X3 + */ +static void mapper_64k_multi_w(uint32 address) +{ + int i; + + /* 64 x 64k banks */ + for (i=0; i<64; i++) + { + m68k.memory_map[i].base = &cart.rom[((address++) & 0x3f) << 16]; + } +} + +/* + Custom ROM Bankswitch used in RADICA cartridges +*/ +static uint32 mapper_radica_r(uint32 address) +{ + int i = 0; + address = (address >> 1); + + /* 64 x 64k banks */ + for (i = 0; i < 64; i++) + { + m68k.memory_map[i].base = &cart.rom[((address++)& 0x3f)<< 16]; + } + + return 0xffff; +} + + +/************************************************************ + default !TIME signal handler +*************************************************************/ + +static void default_time_w(uint32 address, uint32 data) +{ + if (address < 0xa13040) + { + /* unlicensed cartridges mapper (default) */ + mapper_64k_multi_w(address); + return; + } + + /* official cartridges mapper (default) */ + mapper_sega_w(data); +} + + +/************************************************************ + Internal register handlers +*************************************************************/ + +static uint32 default_regs_r(uint32 address) +{ + int i; + for (i=0; i<4; i++) + { + if ((address & cart.hw.mask[i]) == cart.hw.addr[i]) + { + return cart.hw.regs[i]; + } + } + return m68k_read_bus_8(address); +} + +static uint32 default_regs_r_16(uint32 address) +{ + int i; + for (i=0; i<4; i++) + { + if ((address & cart.hw.mask[i]) == cart.hw.addr[i]) + { + return (cart.hw.regs[i] << 8); + } + } + return m68k_read_bus_16(address); +} + +static void default_regs_w(uint32 address, uint32 data) +{ + int i; + for (i=0; i<4; i++) + { + if ((address & cart.hw.mask[i]) == cart.hw.addr[i]) + { + cart.hw.regs[i] = data; + return; + } + } + m68k_unused_8_w(address, data); +} + +/* basic register shifting hardware (Bug's Life, Pocket Monster) */ +static uint32 custom_regs_r(uint32 address) +{ + int i; + for (i=0; i<4; i++) + { + if ((address & cart.hw.mask[i]) == cart.hw.addr[i]) + { + return cart.hw.regs[i] >> 1; + } + } + + return m68k_read_bus_8(address); +} + +/* custom register hardware (Top Fighter, Lion King III, Super Donkey Kong 99, Mulan, Pocket Monsters II, Pokemon Stadium) */ +static void custom_regs_w(uint32 address, uint32 data) +{ + uint8 temp; + + /* ROM bankswitch */ + if ((address >> 16) > 0x6f) + { + mapper_32k_w(data); + return; + } + + /* write register */ + default_regs_w(address, data); + + /* bitswapping */ + temp = cart.hw.regs[0]; + switch (cart.hw.regs[1] & 3) + { + case 0: + cart.hw.regs[2] = (temp << 1); + break; + + case 1: + cart.hw.regs[2] = (temp >> 1); + return; + + case 2: + cart.hw.regs[2] = ((temp >> 4) | ((temp & 0x0F) << 4)); + return; + + default: + cart.hw.regs[2] = (((temp >> 7) & 0x01) | ((temp >> 5) & 0x02) | + ((temp >> 3) & 0x04) | ((temp >> 1) & 0x08) | + ((temp << 1) & 0x10) | ((temp << 3) & 0x20) | + ((temp << 5) & 0x40) | ((temp << 7) & 0x80)); + return; + } +} + +/* alternate custom register hardware (Chinese Fighters III) */ +static void custom_alt_regs_w(uint32 address, uint32 data) +{ + /* ROM bankswitch */ + if ((address >> 16) > 0x5f) + { + mapper_64k_w(data); + return; + } + + /* write regs */ + default_regs_w(address, data); +} + + +/* "Tekken 3 Special" custom register hardware */ +static uint32 tekken_regs_r(uint32 address) +{ + /* data output */ + if ((address & 0x0e) == 0x02) + { + /* maybe depends on mode bits ? */ + return (cart.hw.regs[0] - 1); + } + + return m68k_read_bus_16(address); +} + +static void tekken_regs_w(uint32 address, uint32 data) +{ + switch (address & 0x0e) + { + case 0x00: + { + /* data output reset ? (game writes $FF before & after protection check) */ + cart.hw.regs[0]= 0x00; + break; + } + + case 0x02: + { + /* read only ? */ + break; + } + + case 0x0c: + { + /* data output mode bit 0 ? (game writes $01) */ + break; + } + + case 0x0e: + { + /* data output mode bit 1 ? (never written by game) */ + break; + } + + default: + { + /* data input (only connected to D0 ?)*/ + if (data & 1) + { + /* 4-bit hardware register ($400004 corresponds to bit0, $400006 to bit1, etc) */ + cart.hw.regs[0] |= 1 << (((address - 0x04) >> 1) & 3); + } + break; + } + } +} + +/* "Top Shooter" arcade board hardware */ +static uint32 topshooter_r(uint32 address) +{ + if (address < 0x202000) + { + uint8 temp = 0xff; + + switch (address & 0xff) + { + case 0x43: + { + if (input.pad[0] & INPUT_A) temp &= ~0x80; /* Shoot */ + if (input.pad[0] & INPUT_B) temp &= ~0x10; /* Bet */ + if (input.pad[0] & INPUT_START) temp &= ~0x20; /* Start */ + break; + } + + case 0x45: /* ??? (DOWN) & Service Mode (UP) */ + { + if (input.pad[0] & INPUT_UP) temp &= ~0x08; /* Service Mode */ + if (input.pad[0] & INPUT_DOWN) temp &= ~0x10; /* ???, used in service menu to select next option */ + break; + } + + case 0x47: + { + if (input.pad[0] & INPUT_RIGHT) temp &= ~0x03; /* Insert 10 coins */ + break; + } + + case 0x49: + { + if (input.pad[0] & INPUT_LEFT) temp &= ~0x03; /* Clear coins */ + if (input.pad[0] & INPUT_C) temp &= ~0x01; /* Insert XXX coins */ + break; + } + + case 0x51: + { + temp = 0xA5; + break; + } + + default: + { + temp = m68k_read_bus_8(address); + break; + } + } + return temp; + } + + return READ_BYTE(sram.sram , address & 0xffff); +} + +static void topshooter_w(uint32 address, uint32 data) +{ + if (address >= 0x202000) + { + WRITE_BYTE(sram.sram , address & 0xffff, data); + return; + } + + m68k_unused_8_w(address, data); +} + + +/* Sega Channel hardware (not emulated) */ +/* + +$A13004: BUSY ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? + +Unused read16 00A13004 (00005B54) +Unused read16 00A13004 (00005B70) +Unused read16 00A13006 (00005B7C) + +Unused read16 00A13004 (00005BC4) +Unused read16 00A13004 (00005BDA) + +Unused write16 00A13032 = 0004 (00005706) +Unused write16 00A130F0 = 0000 (0000570E) + +Unused write16 00A130F0 = 0000 (0000463E) +Unused write16 00A130F2 = 0001 (00004646) +Unused write16 00A130F4 = 0002 (0000464E) +Unused write16 00A130F6 = 0003 (00004656) +Unused write16 00A130F8 = 0004 (0000465E) +Unused write16 00A130FA = 0005 (00004666) + +Unused write16 00A13032 = 0004 (00005706) +Unused write16 00A13032 = 0104 (0000579E) + +Unused write16 00380000 = ACDC (00005718) +Unused write16 00380002 = 0000 (00005722) +Unused read16 00380000 (0000572C) +Unused write16 00A13032 = 0104 (0000579E) +Unused write16 00300000 = ACDC (000057B2) +Unused write16 00380000 = 0000 (000057BC) +Unused read16 00300000 (000057C6) + +static uint32 sega_channel_r(uint32 address) +{ + return m68k_read_bus_16(address);; +} + +static void sega_channel_w(uint32 address, uint32 data) +{ + m68k_unused_16_w(address, data); +} +*/ diff --git a/waterbox/gpgx/core/cart_hw/svp/svp.c b/waterbox/gpgx/core/cart_hw/svp/svp.c index eee72c047d..b225c04650 100644 --- a/waterbox/gpgx/core/cart_hw/svp/svp.c +++ b/waterbox/gpgx/core/cart_hw/svp/svp.c @@ -1,49 +1,83 @@ -/* - basic, incomplete SSP160x (SSP1601?) interpreter - with SVP memory controller emu - - (c) Copyright 2008, Grazvydas "notaz" Ignotas - Free for non-commercial use. - - For commercial use, separate licencing terms must be obtained. - - Modified for Genesis Plus GX (Eke-Eke): added BIG ENDIAN support, fixed addr/code inversion -*/ - -#include "shared.h" - -svp_t *svp = NULL; - -void svp_init(void) -{ - svp = malloc(sizeof(svp_t)); - memset(svp, 0, sizeof(*svp)); -} - -void svp_reset(void) -{ - memcpy(svp->iram_rom + 0x800, cart.rom + 0x800, 0x20000 - 0x800); - ssp1601_reset(&svp->ssp1601); -} - -void svp_write_dram(uint32 address, uint32 data) -{ - *(uint16 *)(svp->dram + (address & 0x1fffe)) = data; - if ((address == 0x30fe06) && data) svp->ssp1601.emu_status &= ~SSP_WAIT_30FE06; - if ((address == 0x30fe08) && data) svp->ssp1601.emu_status &= ~SSP_WAIT_30FE08; -} - -uint32 svp_read_cell_1(uint32 address) -{ - address >>= 1; - address = (address & 0x7001) | ((address & 0x3e) << 6) | ((address & 0xfc0) >> 5); - return *(uint16 *)(svp->dram + (address & 0x1fffe)); -} - -uint32 svp_read_cell_2(uint32 address) -{ - address >>= 1; - address = (address & 0x7801) | ((address & 0x1e) << 6) | ((address & 0x7e0) >> 4); - return *(uint16 *)(svp->dram + (address & 0x1fffe)); -} - +/* +basic, incomplete SSP160x (SSP1601?) interpreter +with SVP memory controller emu +(c) Copyright 2008, Grazvydas "notaz" Ignotas +Free for non-commercial use. +For commercial use, separate licencing terms must be obtained. +Modified for Genesis Plus GX (Eke-Eke): added BIG ENDIAN support, fixed addr/code inversion +*/ + +#include "shared.h" + +svp_t *svp; + +static void svp_write_dram(uint32 address, uint32 data) +{ + *(uint16 *)(svp->dram + (address & 0x1fffe)) = data; + if (data) + { + if (address == 0x30fe06) + svp->ssp1601.emu_status &= ~SSP_WAIT_30FE06; + else if (address == 0x30fe08) + svp->ssp1601.emu_status &= ~SSP_WAIT_30FE08; + } +} + +static uint32 svp_read_cell_1(uint32 address) +{ + address = (address & 0xe002) | ((address & 0x7c) << 6) | ((address & 0x1f80) >> 5); + return *(uint16 *)(svp->dram + address); +} + +static uint32 svp_read_cell_2(uint32 address) +{ + address = (address & 0xf002) | ((address & 0x3c) << 6) | ((address & 0xfc0) >> 4); + return *(uint16 *)(svp->dram + address); +} + +static uint32 svp_read_cell_byte(uint32 address) +{ + uint16 data = m68k.memory_map[address >> 16].read16(address); + + if (address & 0x01) + { + return (data & 0xff); + } + + return (data >> 8); +} + +void svp_init(void) +{ + svp = malloc(sizeof(*svp)); + memset(svp, 0, sizeof(*svp)); + + m68k.memory_map[0x30].base = svp->dram; + m68k.memory_map[0x30].read8 = NULL; + m68k.memory_map[0x30].read16 = NULL; + m68k.memory_map[0x30].write8 = NULL; + m68k.memory_map[0x30].write16 = svp_write_dram; + zbank_memory_map[0x30].read = NULL; + zbank_memory_map[0x30].write = NULL; + + m68k.memory_map[0x31].base = svp->dram + 0x10000; + m68k.memory_map[0x31].read8 = NULL; + m68k.memory_map[0x31].read16 = NULL; + m68k.memory_map[0x31].write8 = NULL; + m68k.memory_map[0x31].write16 = NULL; + zbank_memory_map[0x31].read = NULL; + zbank_memory_map[0x31].write = NULL; + + m68k.memory_map[0x39].read8 = svp_read_cell_byte; + m68k.memory_map[0x39].read16 = svp_read_cell_1; + zbank_memory_map[0x39].read = svp_read_cell_byte; + m68k.memory_map[0x3a].read8 = svp_read_cell_byte; + m68k.memory_map[0x3a].read16 = svp_read_cell_2; + zbank_memory_map[0x3a].read = svp_read_cell_byte; +} + +void svp_reset(void) +{ + memcpy(svp->iram_rom + 0x800, cart.rom + 0x800, 0x20000 - 0x800); + ssp1601_reset(&svp->ssp1601); +} diff --git a/waterbox/gpgx/core/cart_hw/svp/svp.h b/waterbox/gpgx/core/cart_hw/svp/svp.h index 845cc027aa..a20d299a83 100644 --- a/waterbox/gpgx/core/cart_hw/svp/svp.h +++ b/waterbox/gpgx/core/cart_hw/svp/svp.h @@ -1,33 +1,30 @@ -/* - basic, incomplete SSP160x (SSP1601?) interpreter - with SVP memory controller emu - - (c) Copyright 2008, Grazvydas "notaz" Ignotas - Free for non-commercial use. - - For commercial use, separate licencing terms must be obtained. - - Modified for Genesis Plus GX (Eke-Eke): added BIG ENDIAN support, fixed addr/code inversion -*/ - -#ifndef _SVP_H_ -#define _SVP_H_ - -#include "shared.h" -#include "ssp16.h" - -typedef struct { - unsigned char iram_rom[0x20000]; /* IRAM (0-0x7ff) and program ROM (0x800-0x1ffff) */ - unsigned char dram[0x20000]; - ssp1601_t ssp1601; -} svp_t; - -extern svp_t *svp; - -extern void svp_init(void); -extern void svp_reset(void); -extern void svp_write_dram(uint32 address, uint32 data); -extern uint32 svp_read_cell_1(uint32 address); -extern uint32 svp_read_cell_2(uint32 address); - -#endif +/* + basic, incomplete SSP160x (SSP1601?) interpreter + with SVP memory controller emu + + (c) Copyright 2008, Grazvydas "notaz" Ignotas + Free for non-commercial use. + + For commercial use, separate licencing terms must be obtained. + + Modified for Genesis Plus GX (Eke-Eke): added BIG ENDIAN support, fixed addr/code inversion +*/ + +#ifndef _SVP_H_ +#define _SVP_H_ + +#include "shared.h" +#include "ssp16.h" + +typedef struct { + unsigned char iram_rom[0x20000]; /* IRAM (0-0x7ff) and program ROM (0x800-0x1ffff) */ + unsigned char dram[0x20000]; + ssp1601_t ssp1601; +} svp_t; + +extern svp_t *svp; + +extern void svp_init(void); +extern void svp_reset(void); + +#endif diff --git a/waterbox/gpgx/core/mem68k.c b/waterbox/gpgx/core/mem68k.c index ed90a0ae2c..56353cc3e8 100644 --- a/waterbox/gpgx/core/mem68k.c +++ b/waterbox/gpgx/core/mem68k.c @@ -1,1281 +1,1293 @@ -/*************************************************************************************** - * Genesis Plus - * Main 68k bus handlers - * - * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code) - * Copyright (C) 2007-2013 Eke-Eke (Genesis Plus GX) - * - * Redistribution and use of this code or any derivative works are permitted - * provided that the following conditions are met: - * - * - Redistributions may not be sold, nor may they be used in a commercial - * product or activity. - * - * - Redistributions that are modified from the original source must include the - * complete source code, including the source code for all components used by a - * binary built from the modified sources. However, as a special exception, the - * source code distributed need not include anything that is normally distributed - * (in either source or binary form) with the major components (compiler, kernel, - * and so on) of the operating system on which the executable runs, unless that - * component itself accompanies the executable. - * - * - Redistributions must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************************/ - -#include "shared.h" - -/*--------------------------------------------------------------------------*/ -/* Unused areas (return open bus data, i.e prefetched instruction word) */ -/*--------------------------------------------------------------------------*/ - -unsigned int m68k_read_bus_8(unsigned int address) -{ -#ifdef LOGERROR - error("Unused read8 %08X (%08X)\n", address, m68k_get_reg(M68K_REG_PC)); -#endif - address = m68k.pc | (address & 1); - return READ_BYTE(m68k.memory_map[((address)>>16)&0xff].base, (address) & 0xffff); -} - -unsigned int m68k_read_bus_16(unsigned int address) -{ -#ifdef LOGERROR - error("Unused read16 %08X (%08X)\n", address, m68k_get_reg(M68K_REG_PC)); -#endif - address = m68k.pc; - return *(uint16 *)(m68k.memory_map[((address)>>16)&0xff].base + ((address) & 0xffff)); -} - - -void m68k_unused_8_w(unsigned int address, unsigned int data) -{ -#ifdef LOGERROR - error("Unused write8 %08X = %02X (%08X)\n", address, data, m68k_get_reg(M68K_REG_PC)); -#endif -} - -void m68k_unused_16_w(unsigned int address, unsigned int data) -{ -#ifdef LOGERROR - error("Unused write16 %08X = %04X (%08X)\n", address, data, m68k_get_reg(M68K_REG_PC)); -#endif -} - - -/*--------------------------------------------------------------------------*/ -/* Illegal areas (cause system to lock-up since !DTACK is not returned) */ -/*--------------------------------------------------------------------------*/ - -void m68k_lockup_w_8 (unsigned int address, unsigned int data) -{ -#ifdef LOGERROR - error ("Lockup %08X = %02X (%08X)\n", address, data, m68k_get_reg(M68K_REG_PC)); -#endif - if (!config.force_dtack) - { - m68k_pulse_halt(); - m68k.cycles = m68k.cycle_end; - } -} - -void m68k_lockup_w_16 (unsigned int address, unsigned int data) -{ -#ifdef LOGERROR - error ("Lockup %08X = %04X (%08X)\n", address, data, m68k_get_reg(M68K_REG_PC)); -#endif - if (!config.force_dtack) - { - m68k_pulse_halt(); - m68k.cycles = m68k.cycle_end; - } -} - -unsigned int m68k_lockup_r_8 (unsigned int address) -{ -#ifdef LOGERROR - error ("Lockup %08X.b (%08X)\n", address, m68k_get_reg(M68K_REG_PC)); -#endif - if (!config.force_dtack) - { - m68k_pulse_halt(); - m68k.cycles = m68k.cycle_end; - } - address = m68k.pc | (address & 1); - return READ_BYTE(m68k.memory_map[((address)>>16)&0xff].base, (address) & 0xffff); -} - -unsigned int m68k_lockup_r_16 (unsigned int address) -{ -#ifdef LOGERROR - error ("Lockup %08X.w (%08X)\n", address, m68k_get_reg(M68K_REG_PC)); -#endif - if (!config.force_dtack) - { - m68k_pulse_halt(); - m68k.cycles = m68k.cycle_end; - } - address = m68k.pc; - return *(uint16 *)(m68k.memory_map[((address)>>16)&0xff].base + ((address) & 0xffff)); -} - - -/*--------------------------------------------------------------------------*/ -/* Z80 bus (accessed through I/O chip) */ -/*--------------------------------------------------------------------------*/ - -unsigned int z80_read_byte(unsigned int address) -{ - switch ((address >> 13) & 3) - { - case 2: /* YM2612 */ - { - return fm_read(m68k.cycles, address & 3); - } - - case 3: /* Misc */ - { - /* VDP (through 68k bus) */ - if ((address & 0xFF00) == 0x7F00) - { - return m68k_lockup_r_8(address); - } - return (m68k_read_bus_8(address) | 0xFF); - } - - default: /* ZRAM */ - { - return zram[address & 0x1FFF]; - } - } -} - -unsigned int z80_read_word(unsigned int address) -{ - unsigned int data = z80_read_byte(address); - return (data | (data << 8)); -} - -void z80_write_byte(unsigned int address, unsigned int data) -{ - switch ((address >> 13) & 3) - { - case 2: /* YM2612 */ - { - fm_write(m68k.cycles, address & 3, data); - return; - } - - case 3: - { - switch ((address >> 8) & 0x7F) - { - case 0x60: /* Bank register */ - { - gen_zbank_w(data & 1); - return; - } - - case 0x7F: /* VDP */ - { - m68k_lockup_w_8(address, data); - return; - } - - default: - { - m68k_unused_8_w(address, data); - return; - } - } - } - - default: /* ZRAM */ - { - zram[address & 0x1FFF] = data; - m68k.cycles += 8; /* ZRAM access latency (fixes Pacman 2: New Adventures) */ - return; - } - } -} - -void z80_write_word(unsigned int address, unsigned int data) -{ - z80_write_byte(address, data >> 8); -} - - -/*--------------------------------------------------------------------------*/ -/* I/O Control */ -/*--------------------------------------------------------------------------*/ - -static void m68k_poll_detect(unsigned int reg_mask) -{ - /* detect MAIN-CPU register polling */ - if (m68k.poll.detected & reg_mask) - { - if (m68k.cycles <= m68k.poll.cycle) - { - if (m68k.pc == m68k.poll.pc) - { - /* MAIN-CPU polling confirmed ? */ - if (m68k.poll.detected & 1) - { - /* idle MAIN-CPU until register is modified */ - m68k.cycles = m68k.cycle_end; - m68k.stopped = reg_mask; -#ifdef LOG_SCD - error("m68k stopped from %d cycles\n", m68k.cycles); -#endif - } - else - { - /* confirm MAIN-CPU polling */ - m68k.poll.detected |= 1; - m68k.poll.cycle = m68k.cycles + 840; - } - } - return; - } - } - else - { - /* set MAIN-CPU register access flag */ - m68k.poll.detected = reg_mask; - } - - /* reset MAIN-CPU polling detection */ - m68k.poll.cycle = m68k.cycles + 840; - m68k.poll.pc = m68k.pc; -} - -static void m68k_poll_sync(unsigned int reg_mask) -{ - /* relative SUB-CPU cycle counter */ - unsigned int cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE; - - /* sync SUB-CPU with MAIN-CPU */ - if (!s68k.stopped) - { - s68k_run(cycles); - } - - /* SUB-CPU idle on register polling ? */ - if (s68k.stopped & reg_mask) - { - /* sync SUB-CPU with MAIN-CPU */ - s68k.cycles = cycles; - - /* restart SUB-CPU */ - s68k.stopped = 0; -#ifdef LOG_SCD - error("s68k started from %d cycles\n", cycles); -#endif - } - - /* clear CPU register access flags */ - s68k.poll.detected &= ~reg_mask; - m68k.poll.detected &= ~reg_mask; -} - -unsigned int ctrl_io_read_byte(unsigned int address) -{ - switch ((address >> 8) & 0xFF) - { - case 0x00: /* I/O chip */ - { - if (!(address & 0xE0)) - { - return io_68k_read((address >> 1) & 0x0F); - } - return m68k_read_bus_8(address); - } - - case 0x11: /* Z80 BUSACK */ - { - if (!(address & 1)) - { - /* Unused bits return prefetched bus data (Time Killers) */ - address = m68k.pc; - - /* Check if bus has been requested and is not reseted */ - if (zstate == 3) - { - /* D0 is cleared */ - return (READ_BYTE(m68k.memory_map[((address)>>16)&0xff].base, (address) & 0xffff) & 0xFE); - } - - /* D0 is set */ - return (READ_BYTE(m68k.memory_map[((address)>>16)&0xff].base, (address) & 0xffff) | 0x01); - } - return m68k_read_bus_8(address); - } - - case 0x20: /* MEGA-CD */ - { -#ifdef LOG_SCD - error("[%d][%d]read byte CD register %X (%X)\n", v_counter, m68k.cycles, address, m68k.pc); -#endif - if (system_hw == SYSTEM_MCD) - { - /* register index ($A12000-A1203F mirrored up to $A120FF) */ - uint8 index = address & 0x3f; - - /* Memory Mode */ - if (index == 0x03) - { - m68k_poll_detect(1<<0x03); - return scd.regs[0x03>>1].byte.l; - } - - /* SUB-CPU communication flags */ - if (index == 0x0f) - { - if (!s68k.stopped) - { - /* relative SUB-CPU cycle counter */ - unsigned int cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE; - - /* sync SUB-CPU with MAIN-CPU (Dracula Unleashed w/ Sega CD Model 2 Boot ROM) */ - s68k_run(cycles); - } - - m68k_poll_detect(1<<0x0f); - return scd.regs[0x0f>>1].byte.l; - } - - /* default registers */ - if (index < 0x30) - { - /* SUB-CPU communication words */ - if (index >= 0x20) - { - m68k_poll_detect(1 << (index - 0x10)); - } - - /* register LSB */ - if (address & 1) - { - return scd.regs[index >> 1].byte.l; - } - - /* register MSB */ - return scd.regs[index >> 1].byte.h; - } - } - - return m68k_read_bus_8(address); - } - - case 0x30: /* TIME */ - { - if (cart.hw.time_r) - { - unsigned int data = cart.hw.time_r(address); - if (address & 1) - { - return (data & 0xFF); - } - return (data >> 8); - } - return m68k_read_bus_8(address); - } - - case 0x41: /* BOOT ROM */ - { - if ((config.bios & 1) && (address & 1)) - { - unsigned int data = gen_bankswitch_r() & 1; - - /* Unused bits return prefetched bus data */ - address = m68k.pc; - data |= (READ_BYTE(m68k.memory_map[((address)>>16)&0xff].base, (address) & 0xffff) & 0xFE); - return data; - } - return m68k_read_bus_8(address); - } - - case 0x10: /* MEMORY MODE */ - case 0x12: /* Z80 RESET */ - case 0x13: /* unknown */ - case 0x40: /* TMSS */ - case 0x44: /* RADICA */ - case 0x50: /* SVP */ - { - return m68k_read_bus_8(address); - } - - default: /* Invalid address */ - { - return m68k_lockup_r_8(address); - } - } -} - -unsigned int ctrl_io_read_word(unsigned int address) -{ - switch ((address >> 8) & 0xFF) - { - case 0x00: /* I/O chip */ - { - if (!(address & 0xE0)) - { - unsigned int data = io_68k_read((address >> 1) & 0x0F); - return (data << 8 | data); - } - return m68k_read_bus_16(address); - } - - case 0x11: /* Z80 BUSACK */ - { - /* Unused bits return prefetched bus data (Time Killers) */ - address = m68k.pc; - - /* Check if bus has been requested and is not reseted */ - if (zstate == 3) - { - /* D8 is cleared */ - return (*(uint16 *)(m68k.memory_map[((address)>>16)&0xff].base + ((address) & 0xffff)) & 0xFEFF); - } - - /* D8 is set */ - return (*(uint16 *)(m68k.memory_map[((address)>>16)&0xff].base + ((address) & 0xffff)) | 0x0100); - } - - case 0x20: /* MEGA-CD */ - { -#ifdef LOG_SCD - error("[%d][%d]read word CD register %X (%X)\n", v_counter, m68k.cycles, address, m68k.pc); -#endif - if (system_hw == SYSTEM_MCD) - { - /* register index ($A12000-A1203F mirrored up to $A120FF) */ - uint8 index = address & 0x3f; - - /* Memory Mode */ - if (index == 0x02) - { - m68k_poll_detect(1<<0x03); - return scd.regs[0x03>>1].w; - } - - /* CDC host data (word access only ?) */ - if (index == 0x08) - { - return cdc_host_r(); - } - - /* H-INT vector (word access only ?) */ - if (index == 0x06) - { - return *(uint16 *)(m68k.memory_map[0].base + 0x72); - } - - /* Stopwatch counter (word read access only ?) */ - if (index == 0x0c) - { - /* relative SUB-CPU cycle counter */ - unsigned int cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE; - - /* cycle-accurate counter value */ - return (scd.regs[0x0c>>1].w + ((cycles - scd.stopwatch) / TIMERS_SCYCLES_RATIO)) & 0xfff; - } - - /* default registers */ - if (index < 0x30) - { - /* SUB-CPU communication words */ - if (index >= 0x20) - { - if (!s68k.stopped) - { - /* relative SUB-CPU cycle counter */ - unsigned int cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE; - - /* sync SUB-CPU with MAIN-CPU (Soul Star) */ - s68k_run(cycles); - } - - m68k_poll_detect(3 << (index - 0x10)); - } - - return scd.regs[index >> 1].w; - } - } - - /* invalid address */ - return m68k_read_bus_16(address); - } - - case 0x30: /* TIME */ - { - if (cart.hw.time_r) - { - return cart.hw.time_r(address); - } - return m68k_read_bus_16(address); - } - - case 0x50: /* SVP */ - { - if ((address & 0xFD) == 0) - { - return svp->ssp1601.gr[SSP_XST].byte.h; - } - - if ((address & 0xFF) == 4) - { - unsigned int data = svp->ssp1601.gr[SSP_PM0].byte.h; - svp->ssp1601.gr[SSP_PM0].byte.h &= ~1; - return data; - } - - return m68k_read_bus_16(address); - } - - case 0x10: /* MEMORY MODE */ - case 0x12: /* Z80 RESET */ - case 0x13: /* unknown */ - case 0x40: /* TMSS */ - case 0x41: /* BOOT ROM */ - case 0x44: /* RADICA */ - { - return m68k_read_bus_16(address); - } - - default: /* Invalid address */ - { - return m68k_lockup_r_16(address); - } - } -} - -void ctrl_io_write_byte(unsigned int address, unsigned int data) -{ - switch ((address >> 8) & 0xFF) - { - case 0x00: /* I/O chip */ - { - if ((address & 0xE1) == 0x01) - { - /* get /LWR only */ - io_68k_write((address >> 1) & 0x0F, data); - return; - } - m68k_unused_8_w(address, data); - return; - } - - case 0x11: /* Z80 BUSREQ */ - { - if (!(address & 1)) - { - gen_zbusreq_w(data & 1, m68k.cycles); - return; - } - m68k_unused_8_w(address, data); - return; - } - - case 0x12: /* Z80 RESET */ - { - if (!(address & 1)) - { - gen_zreset_w(data & 1, m68k.cycles); - return; - } - m68k_unused_8_w(address, data); - return; - } - - case 0x20: /* MEGA-CD */ - { -#ifdef LOG_SCD - error("[%d][%d]write byte CD register %X -> 0x%02X (%X)\n", v_counter, m68k.cycles, address, data, m68k.pc); -#endif - if (system_hw == SYSTEM_MCD) - { - /* register index ($A12000-A1203F mirrored up to $A120FF) */ - switch (address & 0x3f) - { - case 0x00: /* SUB-CPU interrupt */ - { - /* IFL2 bit */ - if (data & 0x01) - { - /* level 2 interrupt enabled ? */ - if (scd.regs[0x32>>1].byte.l & 0x04) - { - if (!s68k.stopped) - { - /* relative SUB-CPU cycle counter */ - unsigned int cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE; - - /* sync SUB-CPU with MAIN-CPU (Earnest Evans, Fhey Area) */ - s68k_run(cycles); - } - - /* set IFL2 flag */ - scd.regs[0x00].byte.h |= 0x01; - - /* trigger level 2 interrupt */ - scd.pending |= (1 << 2); - - /* update IRQ level */ - s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1); - } - } - - /* writing 0 does nothing */ - return; - } - - case 0x01: /* SUB-CPU control */ - { - /* RESET bit */ - if (data & 0x01) - { - /* trigger reset on 0->1 transition */ - if (!(scd.regs[0x00].byte.l & 0x01)) - { - /* reset SUB-CPU */ - s68k_pulse_reset(); - } - - /* BUSREQ bit */ - if (data & 0x02) - { - /* SUB-CPU bus requested */ - s68k_pulse_halt(); - } - else - { - /* SUB-CPU bus released */ - s68k_clear_halt(); - } - } - else - { - /* SUB-CPU is halted while !RESET is asserted */ - s68k_pulse_halt(); - } - - scd.regs[0x00].byte.l = data; - return; - } - - case 0x02: /* PRG-RAM Write Protection */ - { - scd.regs[0x02>>1].byte.h = data; - return; - } - - case 0x03: /* Memory mode */ - { - m68k_poll_sync(1<<0x03); - - /* PRG-RAM 128k bank mapped to $020000-$03FFFF (resp. $420000-$43FFFF) */ - m68k.memory_map[scd.cartridge.boot + 0x02].base = scd.prg_ram + ((data & 0xc0) << 11); - m68k.memory_map[scd.cartridge.boot + 0x03].base = m68k.memory_map[scd.cartridge.boot + 0x02].base + 0x10000; - - /* check current mode */ - if (scd.regs[0x03>>1].byte.l & 0x04) - { - /* DMNA bit */ - if (data & 0x02) - { - /* writing 1 to DMNA in 1M mode will return Word-RAM to SUB-CPU in 2M mode */ - scd.dmna = 1; - } - else - { - /* writing 0 to DMNA in 1M mode actually set DMNA bit */ - data |= 0x02; - - /* update BK0-1 & DMNA bits */ - scd.regs[0x03>>1].byte.l = (scd.regs[0x03>>1].byte.l & ~0xc2) | (data & 0xc2); - return; - } - } - else - { - /* writing 0 in 2M mode does nothing */ - if (data & 0x02) - { - /* Word-RAM is assigned to SUB-CPU */ - scd.dmna = 1; - - /* clear RET bit */ - scd.regs[0x03>>1].byte.l = (scd.regs[0x03>>1].byte.l & ~0xc3) | (data & 0xc2); - return; - } - } - - /* update BK0-1 bits */ - scd.regs[0x03>>1].byte.l = (scd.regs[0x02>>1].byte.l & ~0xc0) | (data & 0xc0); - return; - } - - case 0x0e: /* MAIN-CPU communication flags */ - case 0x0f: /* !LWR is ignored (Space Ace, Dragon's Lair) */ - { - m68k_poll_sync(1<<0x0e); - scd.regs[0x0e>>1].byte.h = data; - return; - } - - default: - { - /* MAIN-CPU communication words */ - if ((address & 0x30) == 0x10) - { - m68k_poll_sync(1 << (address & 0x1f)); - - /* register LSB */ - if (address & 1) - { - scd.regs[(address >> 1) & 0xff].byte.l = data; - return; - } - - /* register MSB */ - scd.regs[(address >> 1) & 0xff].byte.h = data; - return; - } - - /* invalid address */ - m68k_unused_8_w(address, data); - return; - } - } - } - - m68k_unused_8_w(address, data); - return; - } - - case 0x30: /* TIME */ - { - cart.hw.time_w(address, data); - return; - } - - case 0x41: /* BOOT ROM */ - { - if ((config.bios & 1) && (address & 1)) - { - gen_bankswitch_w(data & 1); - return; - } - m68k_unused_8_w(address, data); - return; - } - - case 0x10: /* MEMORY MODE */ - case 0x13: /* unknown */ - case 0x40: /* TMSS */ - case 0x44: /* RADICA */ - case 0x50: /* SVP */ - { - m68k_unused_8_w(address, data); - return; - } - - default: /* Invalid address */ - { - m68k_lockup_w_8(address, data); - return; - } - } -} - -void ctrl_io_write_word(unsigned int address, unsigned int data) -{ - switch ((address >> 8) & 0xFF) - { - case 0x00: /* I/O chip */ - { - if (!(address & 0xE0)) - { - io_68k_write((address >> 1) & 0x0F, data & 0xFF); - return; - } - m68k_unused_16_w(address, data); - return; - } - - case 0x11: /* Z80 BUSREQ */ - { - gen_zbusreq_w((data >> 8) & 1, m68k.cycles); - return; - } - - case 0x12: /* Z80 RESET */ - { - gen_zreset_w((data >> 8) & 1, m68k.cycles); - return; - } - - case 0x20: /* MEGA-CD */ - { -#ifdef LOG_SCD - error("[%d][%d]write word CD register %X -> 0x%04X (%X)\n", v_counter, m68k.cycles, address, data, m68k.pc); -#endif - if (system_hw == SYSTEM_MCD) - { - /* register index ($A12000-A1203F mirrored up to $A120FF) */ - switch (address & 0x3e) - { - case 0x00: /* SUB-CPU interrupt & control */ - { - /* RESET bit */ - if (data & 0x01) - { - /* trigger reset on 0->1 transition */ - if (!(scd.regs[0x00].byte.l & 0x01)) - { - /* reset SUB-CPU */ - s68k_pulse_reset(); - } - - /* BUSREQ bit */ - if (data & 0x02) - { - /* SUB-CPU bus requested */ - s68k_pulse_halt(); - } - else - { - /* SUB-CPU bus released */ - s68k_clear_halt(); - } - } - else - { - /* SUB-CPU is halted while !RESET is asserted */ - s68k_pulse_halt(); - } - - /* IFL2 bit */ - if (data & 0x100) - { - /* level 2 interrupt enabled ? */ - if (scd.regs[0x32>>1].byte.l & 0x04) - { - /* set IFL2 flag */ - scd.regs[0x00].byte.h |= 0x01; - - /* trigger level 2 interrupt */ - scd.pending |= (1 << 2); - - /* update IRQ level */ - s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1); - } - } - - /* update LSB only */ - scd.regs[0x00].byte.l = data & 0xff; - return; - } - - case 0x02: /* Memory Mode */ - { - m68k_poll_sync(1<<0x03); - - /* PRG-RAM 128k bank mapped to $020000-$03FFFF (resp. $420000-$43FFFF) */ - m68k.memory_map[scd.cartridge.boot + 0x02].base = scd.prg_ram + ((data & 0xc0) << 11); - m68k.memory_map[scd.cartridge.boot + 0x03].base = m68k.memory_map[scd.cartridge.boot + 0x02].base + 0x10000; - - /* check current mode */ - if (scd.regs[0x03>>1].byte.l & 0x04) - { - /* DMNA bit */ - if (data & 0x02) - { - /* writing 1 to DMNA in 1M mode will return Word-RAM to SUB-CPU in 2M mode */ - scd.dmna = 1; - } - else - { - /* writing 0 to DMNA in 1M mode actually set DMNA bit */ - data |= 0x02; - - /* update WP0-7, BK0-1 & DMNA bits */ - scd.regs[0x02>>1].w = (scd.regs[0x02>>1].w & ~0xffc2) | (data & 0xffc2); - return; - } - } - else - { - /* writing 0 in 2M mode does nothing */ - if (data & 0x02) - { - /* Word-RAM is assigned to SUB-CPU */ - scd.dmna = 1; - - /* clear RET bit */ - scd.regs[0x02>>1].w = (scd.regs[0x02>>1].w & ~0xffc3) | (data & 0xffc2); - return; - } - } - - /* update WP0-7 & BK0-1 bits */ - scd.regs[0x02>>1].w = (scd.regs[0x02>>1].w & ~0xffc0) | (data & 0xffc0); - return; - } - - case 0x06: /* H-INT vector (word access only ?) */ - { - *(uint16 *)(m68k.memory_map[0].base + 0x72) = data; - return; - } - - case 0x0e: /* CPU communication flags */ - { - m68k_poll_sync(1<<0x0e); - - /* D8-D15 ignored -> only MAIN-CPU flags are updated (Mortal Kombat) */ - scd.regs[0x0e>>1].byte.h = data & 0xff; - return; - } - - default: - { - /* MAIN-CPU communication words */ - if ((address & 0x30) == 0x10) - { - m68k_poll_sync(3 << (address & 0x1e)); - scd.regs[(address >> 1) & 0xff].w = data; - return; - } - - /* invalid address */ - m68k_unused_16_w (address, data); - return; - } - } - } - - m68k_unused_16_w (address, data); - return; - } - - case 0x30: /* TIME */ - { - cart.hw.time_w(address, data); - return; - } - - case 0x40: /* TMSS */ - { - if (config.bios & 1) - { - gen_tmss_w(address & 3, data); - return; - } - m68k_unused_16_w(address, data); - return; - } - - case 0x50: /* SVP */ - { - if (!(address & 0xFD)) - { - svp->ssp1601.gr[SSP_XST].byte.h = data; - svp->ssp1601.gr[SSP_PM0].byte.h |= 2; - svp->ssp1601.emu_status &= ~SSP_WAIT_PM0; - return; - } - m68k_unused_16_w(address, data); - return; - } - - case 0x10: /* MEMORY MODE */ - case 0x13: /* unknown */ - case 0x41: /* BOOT ROM */ - case 0x44: /* RADICA */ - { - m68k_unused_16_w (address, data); - return; - } - - default: /* Invalid address */ - { - m68k_lockup_w_16 (address, data); - return; - } - } -} - - -/*--------------------------------------------------------------------------*/ -/* VDP */ -/*--------------------------------------------------------------------------*/ - -unsigned int vdp_read_byte(unsigned int address) -{ - switch (address & 0xFD) - { - case 0x00: /* DATA */ - { - return (vdp_68k_data_r() >> 8); - } - - case 0x01: /* DATA */ - { - return (vdp_68k_data_r() & 0xFF); - } - - case 0x04: /* CTRL */ - { - unsigned int data = (vdp_68k_ctrl_r(m68k.cycles) >> 8) & 3; - - /* Unused bits return prefetched bus data */ - address = m68k.pc; - data |= (READ_BYTE(m68k.memory_map[((address)>>16)&0xff].base, (address) & 0xffff) & 0xFC); - - return data; - } - - case 0x05: /* CTRL */ - { - return (vdp_68k_ctrl_r(m68k.cycles) & 0xFF); - } - - case 0x08: /* HVC */ - case 0x0C: - { - return (vdp_hvc_r(m68k.cycles) >> 8); - } - - case 0x09: /* HVC */ - case 0x0D: - { - return (vdp_hvc_r(m68k.cycles) & 0xFF); - } - - case 0x18: /* Unused */ - case 0x19: - case 0x1C: - case 0x1D: - { - return m68k_read_bus_8(address); - } - - default: /* Invalid address */ - { - return m68k_lockup_r_8(address); - } - } -} - -unsigned int vdp_read_word(unsigned int address) -{ - switch (address & 0xFC) - { - case 0x00: /* DATA */ - { - return vdp_68k_data_r(); - } - - case 0x04: /* CTRL */ - { - unsigned int data = vdp_68k_ctrl_r(m68k.cycles) & 0x3FF; - - /* Unused bits return prefetched bus data */ - address = m68k.pc; - data |= (*(uint16 *)(m68k.memory_map[((address)>>16)&0xff].base + ((address) & 0xffff)) & 0xFC00); - - return data; - } - - case 0x08: /* HVC */ - case 0x0C: - { - return vdp_hvc_r(m68k.cycles); - } - - case 0x18: /* Unused */ - case 0x1C: - { - return m68k_read_bus_16(address); - } - - default: /* Invalid address */ - { - return m68k_lockup_r_16(address); - } - } -} - -void vdp_write_byte(unsigned int address, unsigned int data) -{ - switch (address & 0xFC) - { - case 0x00: /* Data port */ - { - vdp_68k_data_w(data << 8 | data); - return; - } - - case 0x04: /* Control port */ - { - vdp_68k_ctrl_w(data << 8 | data); - return; - } - - case 0x10: /* PSG */ - case 0x14: - { - if (address & 1) - { - SN76489_Write(m68k.cycles, data); - return; - } - m68k_unused_8_w(address, data); - return; - } - - case 0x18: /* Unused */ - { - m68k_unused_8_w(address, data); - return; - } - - case 0x1C: /* TEST register */ - { - vdp_test_w(data << 8 | data); - return; - } - - default: /* Invalid address */ - { - m68k_lockup_w_8(address, data); - return; - } - } -} - -void vdp_write_word(unsigned int address, unsigned int data) -{ - switch (address & 0xFC) - { - case 0x00: /* DATA */ - { - vdp_68k_data_w(data); - return; - } - - case 0x04: /* CTRL */ - { - vdp_68k_ctrl_w(data); - return; - } - - case 0x10: /* PSG */ - case 0x14: - { - SN76489_Write(m68k.cycles, data & 0xFF); - return; - } - - case 0x18: /* Unused */ - { - m68k_unused_16_w(address, data); - return; - } - - case 0x1C: /* Test register */ - { - vdp_test_w(data); - return; - } - - default: /* Invalid address */ - { - m68k_lockup_w_16 (address, data); - return; - } - } -} - - -/*--------------------------------------------------------------------------*/ -/* PICO (incomplete) */ -/*--------------------------------------------------------------------------*/ - -unsigned int pico_read_byte(unsigned int address) -{ - switch (address & 0xFF) - { - case 0x01: /* VERSION register */ - { - return (region_code >> 1); - } - - case 0x03: /* IO register */ - { - return ~input.pad[0]; - } - - case 0x05: /* PEN X coordinate (MSB) */ - { - return (input.analog[0][0] >> 8); - } - - case 0x07: /* PEN X coordinate (LSB) */ - { - return (input.analog[0][0] & 0xFF); - } - - case 0x09: /* PEN Y coordinate (MSB) */ - { - return (input.analog[0][1] >> 8); - } - - case 0x0B: /* PEN Y coordinate (LSB) */ - { - return (input.analog[0][1] & 0xFF); - } - - case 0x0D: /* PAGE register */ - { - return (1 << pico_current) - 1; - } - - case 0x10: /* ADPCM data registers (TODO) */ - case 0x11: - { - return 0xff; - } - - case 0x12: /* ADPCM control registers (TODO) */ - { - return 0x80; - } - - default: - { - return m68k_read_bus_8(address); - } - } -} - -unsigned int pico_read_word(unsigned int address) -{ - return (pico_read_byte(address | 1) | (pico_read_byte(address) << 8)); -} +/*************************************************************************************** + * Genesis Plus + * Main 68k bus handlers + * + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code) + * Copyright (C) 2007-2013 Eke-Eke (Genesis Plus GX) + * + * Redistribution and use of this code or any derivative works are permitted + * provided that the following conditions are met: + * + * - Redistributions may not be sold, nor may they be used in a commercial + * product or activity. + * + * - Redistributions that are modified from the original source must include the + * complete source code, including the source code for all components used by a + * binary built from the modified sources. However, as a special exception, the + * source code distributed need not include anything that is normally distributed + * (in either source or binary form) with the major components (compiler, kernel, + * and so on) of the operating system on which the executable runs, unless that + * component itself accompanies the executable. + * + * - Redistributions must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************************/ + +#include "shared.h" + +/*--------------------------------------------------------------------------*/ +/* Unused areas (return open bus data, i.e prefetched instruction word) */ +/*--------------------------------------------------------------------------*/ + +unsigned int m68k_read_bus_8(unsigned int address) +{ +#ifdef LOGERROR + error("Unused read8 %08X (%08X)\n", address, m68k_get_reg(M68K_REG_PC)); +#endif + address = m68k.pc | (address & 1); + return READ_BYTE(m68k.memory_map[((address)>>16)&0xff].base, (address) & 0xffff); +} + +unsigned int m68k_read_bus_16(unsigned int address) +{ +#ifdef LOGERROR + error("Unused read16 %08X (%08X)\n", address, m68k_get_reg(M68K_REG_PC)); +#endif + address = m68k.pc; + return *(uint16 *)(m68k.memory_map[((address)>>16)&0xff].base + ((address) & 0xffff)); +} + + +void m68k_unused_8_w(unsigned int address, unsigned int data) +{ +#ifdef LOGERROR + error("Unused write8 %08X = %02X (%08X)\n", address, data, m68k_get_reg(M68K_REG_PC)); +#endif +} + +void m68k_unused_16_w(unsigned int address, unsigned int data) +{ +#ifdef LOGERROR + error("Unused write16 %08X = %04X (%08X)\n", address, data, m68k_get_reg(M68K_REG_PC)); +#endif +} + + +/*--------------------------------------------------------------------------*/ +/* Illegal areas (cause system to lock-up since !DTACK is not returned) */ +/*--------------------------------------------------------------------------*/ + +void m68k_lockup_w_8 (unsigned int address, unsigned int data) +{ +#ifdef LOGERROR + error ("Lockup %08X = %02X (%08X)\n", address, data, m68k_get_reg(M68K_REG_PC)); +#endif + if (!config.force_dtack) + { + m68k_pulse_halt(); + m68k.cycles = m68k.cycle_end; + } +} + +void m68k_lockup_w_16 (unsigned int address, unsigned int data) +{ +#ifdef LOGERROR + error ("Lockup %08X = %04X (%08X)\n", address, data, m68k_get_reg(M68K_REG_PC)); +#endif + if (!config.force_dtack) + { + m68k_pulse_halt(); + m68k.cycles = m68k.cycle_end; + } +} + +unsigned int m68k_lockup_r_8 (unsigned int address) +{ +#ifdef LOGERROR + error ("Lockup %08X.b (%08X)\n", address, m68k_get_reg(M68K_REG_PC)); +#endif + if (!config.force_dtack) + { + m68k_pulse_halt(); + m68k.cycles = m68k.cycle_end; + } + address = m68k.pc | (address & 1); + return READ_BYTE(m68k.memory_map[((address)>>16)&0xff].base, (address) & 0xffff); +} + +unsigned int m68k_lockup_r_16 (unsigned int address) +{ +#ifdef LOGERROR + error ("Lockup %08X.w (%08X)\n", address, m68k_get_reg(M68K_REG_PC)); +#endif + if (!config.force_dtack) + { + m68k_pulse_halt(); + m68k.cycles = m68k.cycle_end; + } + address = m68k.pc; + return *(uint16 *)(m68k.memory_map[((address)>>16)&0xff].base + ((address) & 0xffff)); +} + + +/*--------------------------------------------------------------------------*/ +/* Z80 bus (accessed through I/O chip) */ +/*--------------------------------------------------------------------------*/ + +unsigned int z80_read_byte(unsigned int address) +{ + switch ((address >> 13) & 3) + { + case 2: /* YM2612 */ + { + return fm_read(m68k.cycles, address & 3); + } + + case 3: /* Misc */ + { + /* VDP (through 68k bus) */ + if ((address & 0xFF00) == 0x7F00) + { + return m68k_lockup_r_8(address); + } + return (m68k_read_bus_8(address) | 0xFF); + } + + default: /* ZRAM */ + { + return zram[address & 0x1FFF]; + } + } +} + +unsigned int z80_read_word(unsigned int address) +{ + unsigned int data = z80_read_byte(address); + return (data | (data << 8)); +} + +void z80_write_byte(unsigned int address, unsigned int data) +{ + switch ((address >> 13) & 3) + { + case 2: /* YM2612 */ + { + fm_write(m68k.cycles, address & 3, data); + return; + } + + case 3: + { + switch ((address >> 8) & 0x7F) + { + case 0x60: /* Bank register */ + { + gen_zbank_w(data & 1); + return; + } + + case 0x7F: /* VDP */ + { + m68k_lockup_w_8(address, data); + return; + } + + default: + { + m68k_unused_8_w(address, data); + return; + } + } + } + + default: /* ZRAM */ + { + zram[address & 0x1FFF] = data; + m68k.cycles += 8; /* ZRAM access latency (fixes Pacman 2: New Adventures) */ + return; + } + } +} + +void z80_write_word(unsigned int address, unsigned int data) +{ + z80_write_byte(address, data >> 8); +} + + +/*--------------------------------------------------------------------------*/ +/* I/O Control */ +/*--------------------------------------------------------------------------*/ + +static void m68k_poll_detect(unsigned int reg_mask) +{ + /* detect MAIN-CPU register polling */ + if (m68k.poll.detected & reg_mask) + { + if (m68k.cycles <= m68k.poll.cycle) + { + if (m68k.pc == m68k.poll.pc) + { + /* MAIN-CPU polling confirmed ? */ + if (m68k.poll.detected & 1) + { + /* idle MAIN-CPU until register is modified */ + m68k.cycles = m68k.cycle_end; + m68k.stopped = reg_mask; +#ifdef LOG_SCD + error("m68k stopped from %d cycles\n", m68k.cycles); +#endif + } + else + { + /* confirm MAIN-CPU polling */ + m68k.poll.detected |= 1; + m68k.poll.cycle = m68k.cycles + 840; + } + } + return; + } + } + else + { + /* set MAIN-CPU register access flag */ + m68k.poll.detected = reg_mask; + } + + /* reset MAIN-CPU polling detection */ + m68k.poll.cycle = m68k.cycles + 840; + m68k.poll.pc = m68k.pc; +} + +static void m68k_poll_sync(unsigned int reg_mask) +{ + /* relative SUB-CPU cycle counter */ + unsigned int cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE; + + /* sync SUB-CPU with MAIN-CPU */ + if (!s68k.stopped) + { + s68k_run(cycles); + } + + /* SUB-CPU idle on register polling ? */ + if (s68k.stopped & reg_mask) + { + /* sync SUB-CPU with MAIN-CPU */ + s68k.cycles = cycles; + + /* restart SUB-CPU */ + s68k.stopped = 0; +#ifdef LOG_SCD + error("s68k started from %d cycles\n", cycles); +#endif + } + + /* clear CPU register access flags */ + s68k.poll.detected &= ~reg_mask; + m68k.poll.detected &= ~reg_mask; +} + +unsigned int ctrl_io_read_byte(unsigned int address) +{ + switch ((address >> 8) & 0xFF) + { + case 0x00: /* I/O chip */ + { + if (!(address & 0xE0)) + { + return io_68k_read((address >> 1) & 0x0F); + } + return m68k_read_bus_8(address); + } + + case 0x11: /* Z80 BUSACK */ + { + if (!(address & 1)) + { + /* Unused bits return prefetched bus data (Time Killers) */ + address = m68k.pc; + + /* Check if bus has been requested and is not reseted */ + if (zstate == 3) + { + /* D0 is cleared */ + return (READ_BYTE(m68k.memory_map[((address)>>16)&0xff].base, (address) & 0xffff) & 0xFE); + } + + /* D0 is set */ + return (READ_BYTE(m68k.memory_map[((address)>>16)&0xff].base, (address) & 0xffff) | 0x01); + } + return m68k_read_bus_8(address); + } + + case 0x20: /* MEGA-CD */ + { +#ifdef LOG_SCD + error("[%d][%d]read byte CD register %X (%X)\n", v_counter, m68k.cycles, address, m68k.pc); +#endif + if (system_hw == SYSTEM_MCD) + { + /* register index ($A12000-A1203F mirrored up to $A120FF) */ + uint8 index = address & 0x3f; + + /* Memory Mode */ + if (index == 0x03) + { + m68k_poll_detect(1<<0x03); + return scd.regs[0x03>>1].byte.l; + } + + /* SUB-CPU communication flags */ + if (index == 0x0f) + { + if (!s68k.stopped) + { + /* relative SUB-CPU cycle counter */ + unsigned int cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE; + + /* sync SUB-CPU with MAIN-CPU (Dracula Unleashed w/ Sega CD Model 2 Boot ROM) */ + s68k_run(cycles); + } + + m68k_poll_detect(1<<0x0f); + return scd.regs[0x0f>>1].byte.l; + } + + /* default registers */ + if (index < 0x30) + { + /* SUB-CPU communication words */ + if (index >= 0x20) + { + m68k_poll_detect(1 << (index - 0x10)); + } + + /* register LSB */ + if (address & 1) + { + return scd.regs[index >> 1].byte.l; + } + + /* register MSB */ + return scd.regs[index >> 1].byte.h; + } + } + + return m68k_read_bus_8(address); + } + + case 0x30: /* TIME */ + { + if (cart.hw.time_r) + { + unsigned int data = cart.hw.time_r(address); + if (address & 1) + { + return (data & 0xFF); + } + return (data >> 8); + } + return m68k_read_bus_8(address); + } + + case 0x41: /* BOOT ROM */ + { + if ((config.bios & 1) && (address & 1)) + { + unsigned int data = gen_bankswitch_r() & 1; + + /* Unused bits return prefetched bus data */ + address = m68k.pc; + data |= (READ_BYTE(m68k.memory_map[((address)>>16)&0xff].base, (address) & 0xffff) & 0xFE); + return data; + } + return m68k_read_bus_8(address); + } + + case 0x10: /* MEMORY MODE */ + case 0x12: /* Z80 RESET */ + case 0x13: /* unknown */ + case 0x40: /* TMSS */ + case 0x44: /* RADICA */ + case 0x50: /* SVP */ + { + if ((address & 0xFC) == 0x00) + { + unsigned int data = svp->ssp1601.gr[SSP_XST].byte.h; + return (address & 1) ? (data & 0xFF) : (data >> 8); + } + + if ((address & 0xFE) == 0x04) + { + unsigned int data = svp->ssp1601.gr[SSP_PM0].byte.h; + svp->ssp1601.gr[SSP_PM0].byte.h &= ~1; + return (address & 1) ? (data & 0xFF) : (data >> 8); + } + return m68k_read_bus_8(address); + } + + default: /* Invalid address */ + { + return m68k_lockup_r_8(address); + } + } +} + +unsigned int ctrl_io_read_word(unsigned int address) +{ + switch ((address >> 8) & 0xFF) + { + case 0x00: /* I/O chip */ + { + if (!(address & 0xE0)) + { + unsigned int data = io_68k_read((address >> 1) & 0x0F); + return (data << 8 | data); + } + return m68k_read_bus_16(address); + } + + case 0x11: /* Z80 BUSACK */ + { + /* Unused bits return prefetched bus data (Time Killers) */ + address = m68k.pc; + + /* Check if bus has been requested and is not reseted */ + if (zstate == 3) + { + /* D8 is cleared */ + return (*(uint16 *)(m68k.memory_map[((address)>>16)&0xff].base + ((address) & 0xffff)) & 0xFEFF); + } + + /* D8 is set */ + return (*(uint16 *)(m68k.memory_map[((address)>>16)&0xff].base + ((address) & 0xffff)) | 0x0100); + } + + case 0x20: /* MEGA-CD */ + { +#ifdef LOG_SCD + error("[%d][%d]read word CD register %X (%X)\n", v_counter, m68k.cycles, address, m68k.pc); +#endif + if (system_hw == SYSTEM_MCD) + { + /* register index ($A12000-A1203F mirrored up to $A120FF) */ + uint8 index = address & 0x3f; + + /* Memory Mode */ + if (index == 0x02) + { + m68k_poll_detect(1<<0x03); + return scd.regs[0x03>>1].w; + } + + /* CDC host data (word access only ?) */ + if (index == 0x08) + { + return cdc_host_r(); + } + + /* H-INT vector (word access only ?) */ + if (index == 0x06) + { + return *(uint16 *)(m68k.memory_map[0].base + 0x72); + } + + /* Stopwatch counter (word read access only ?) */ + if (index == 0x0c) + { + /* relative SUB-CPU cycle counter */ + unsigned int cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE; + + /* cycle-accurate counter value */ + return (scd.regs[0x0c>>1].w + ((cycles - scd.stopwatch) / TIMERS_SCYCLES_RATIO)) & 0xfff; + } + + /* default registers */ + if (index < 0x30) + { + /* SUB-CPU communication words */ + if (index >= 0x20) + { + if (!s68k.stopped) + { + /* relative SUB-CPU cycle counter */ + unsigned int cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE; + + /* sync SUB-CPU with MAIN-CPU (Soul Star) */ + s68k_run(cycles); + } + + m68k_poll_detect(3 << (index - 0x10)); + } + + return scd.regs[index >> 1].w; + } + } + + /* invalid address */ + return m68k_read_bus_16(address); + } + + case 0x30: /* TIME */ + { + if (cart.hw.time_r) + { + return cart.hw.time_r(address); + } + return m68k_read_bus_16(address); + } + + case 0x50: /* SVP */ + { + if ((address & 0xFC) == 0) + { + return svp->ssp1601.gr[SSP_XST].byte.h; + } + + if ((address & 0xFE) == 4) + { + unsigned int data = svp->ssp1601.gr[SSP_PM0].byte.h; + svp->ssp1601.gr[SSP_PM0].byte.h &= ~1; + return data; + } + + return m68k_read_bus_16(address); + } + + case 0x10: /* MEMORY MODE */ + case 0x12: /* Z80 RESET */ + case 0x13: /* unknown */ + case 0x40: /* TMSS */ + case 0x41: /* BOOT ROM */ + case 0x44: /* RADICA */ + { + return m68k_read_bus_16(address); + } + + default: /* Invalid address */ + { + return m68k_lockup_r_16(address); + } + } +} + +void ctrl_io_write_byte(unsigned int address, unsigned int data) +{ + switch ((address >> 8) & 0xFF) + { + case 0x00: /* I/O chip */ + { + if ((address & 0xE1) == 0x01) + { + /* get /LWR only */ + io_68k_write((address >> 1) & 0x0F, data); + return; + } + m68k_unused_8_w(address, data); + return; + } + + case 0x11: /* Z80 BUSREQ */ + { + if (!(address & 1)) + { + gen_zbusreq_w(data & 1, m68k.cycles); + return; + } + m68k_unused_8_w(address, data); + return; + } + + case 0x12: /* Z80 RESET */ + { + if (!(address & 1)) + { + gen_zreset_w(data & 1, m68k.cycles); + return; + } + m68k_unused_8_w(address, data); + return; + } + + case 0x20: /* MEGA-CD */ + { +#ifdef LOG_SCD + error("[%d][%d]write byte CD register %X -> 0x%02X (%X)\n", v_counter, m68k.cycles, address, data, m68k.pc); +#endif + if (system_hw == SYSTEM_MCD) + { + /* register index ($A12000-A1203F mirrored up to $A120FF) */ + switch (address & 0x3f) + { + case 0x00: /* SUB-CPU interrupt */ + { + /* IFL2 bit */ + if (data & 0x01) + { + /* level 2 interrupt enabled ? */ + if (scd.regs[0x32>>1].byte.l & 0x04) + { + if (!s68k.stopped) + { + /* relative SUB-CPU cycle counter */ + unsigned int cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE; + + /* sync SUB-CPU with MAIN-CPU (Earnest Evans, Fhey Area) */ + s68k_run(cycles); + } + + /* set IFL2 flag */ + scd.regs[0x00].byte.h |= 0x01; + + /* trigger level 2 interrupt */ + scd.pending |= (1 << 2); + + /* update IRQ level */ + s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1); + } + } + + /* writing 0 does nothing */ + return; + } + + case 0x01: /* SUB-CPU control */ + { + /* RESET bit */ + if (data & 0x01) + { + /* trigger reset on 0->1 transition */ + if (!(scd.regs[0x00].byte.l & 0x01)) + { + /* reset SUB-CPU */ + s68k_pulse_reset(); + } + + /* BUSREQ bit */ + if (data & 0x02) + { + /* SUB-CPU bus requested */ + s68k_pulse_halt(); + } + else + { + /* SUB-CPU bus released */ + s68k_clear_halt(); + } + } + else + { + /* SUB-CPU is halted while !RESET is asserted */ + s68k_pulse_halt(); + } + + scd.regs[0x00].byte.l = data; + return; + } + + case 0x02: /* PRG-RAM Write Protection */ + { + scd.regs[0x02>>1].byte.h = data; + return; + } + + case 0x03: /* Memory mode */ + { + m68k_poll_sync(1<<0x03); + + /* PRG-RAM 128k bank mapped to $020000-$03FFFF (resp. $420000-$43FFFF) */ + m68k.memory_map[scd.cartridge.boot + 0x02].base = scd.prg_ram + ((data & 0xc0) << 11); + m68k.memory_map[scd.cartridge.boot + 0x03].base = m68k.memory_map[scd.cartridge.boot + 0x02].base + 0x10000; + + /* check current mode */ + if (scd.regs[0x03>>1].byte.l & 0x04) + { + /* DMNA bit */ + if (data & 0x02) + { + /* writing 1 to DMNA in 1M mode will return Word-RAM to SUB-CPU in 2M mode */ + scd.dmna = 1; + } + else + { + /* writing 0 to DMNA in 1M mode actually set DMNA bit */ + data |= 0x02; + + /* update BK0-1 & DMNA bits */ + scd.regs[0x03>>1].byte.l = (scd.regs[0x03>>1].byte.l & ~0xc2) | (data & 0xc2); + return; + } + } + else + { + /* writing 0 in 2M mode does nothing */ + if (data & 0x02) + { + /* Word-RAM is assigned to SUB-CPU */ + scd.dmna = 1; + + /* clear RET bit */ + scd.regs[0x03>>1].byte.l = (scd.regs[0x03>>1].byte.l & ~0xc3) | (data & 0xc2); + return; + } + } + + /* update BK0-1 bits */ + scd.regs[0x03>>1].byte.l = (scd.regs[0x02>>1].byte.l & ~0xc0) | (data & 0xc0); + return; + } + + case 0x0e: /* MAIN-CPU communication flags */ + case 0x0f: /* !LWR is ignored (Space Ace, Dragon's Lair) */ + { + m68k_poll_sync(1<<0x0e); + scd.regs[0x0e>>1].byte.h = data; + return; + } + + default: + { + /* MAIN-CPU communication words */ + if ((address & 0x30) == 0x10) + { + m68k_poll_sync(1 << (address & 0x1f)); + + /* register LSB */ + if (address & 1) + { + scd.regs[(address >> 1) & 0xff].byte.l = data; + return; + } + + /* register MSB */ + scd.regs[(address >> 1) & 0xff].byte.h = data; + return; + } + + /* invalid address */ + m68k_unused_8_w(address, data); + return; + } + } + } + + m68k_unused_8_w(address, data); + return; + } + + case 0x30: /* TIME */ + { + cart.hw.time_w(address, data); + return; + } + + case 0x41: /* BOOT ROM */ + { + if ((config.bios & 1) && (address & 1)) + { + gen_bankswitch_w(data & 1); + return; + } + m68k_unused_8_w(address, data); + return; + } + + case 0x10: /* MEMORY MODE */ + case 0x13: /* unknown */ + case 0x40: /* TMSS */ + case 0x44: /* RADICA */ + case 0x50: /* SVP */ + { + m68k_unused_8_w(address, data); + return; + } + + default: /* Invalid address */ + { + m68k_lockup_w_8(address, data); + return; + } + } +} + +void ctrl_io_write_word(unsigned int address, unsigned int data) +{ + switch ((address >> 8) & 0xFF) + { + case 0x00: /* I/O chip */ + { + if (!(address & 0xE0)) + { + io_68k_write((address >> 1) & 0x0F, data & 0xFF); + return; + } + m68k_unused_16_w(address, data); + return; + } + + case 0x11: /* Z80 BUSREQ */ + { + gen_zbusreq_w((data >> 8) & 1, m68k.cycles); + return; + } + + case 0x12: /* Z80 RESET */ + { + gen_zreset_w((data >> 8) & 1, m68k.cycles); + return; + } + + case 0x20: /* MEGA-CD */ + { +#ifdef LOG_SCD + error("[%d][%d]write word CD register %X -> 0x%04X (%X)\n", v_counter, m68k.cycles, address, data, m68k.pc); +#endif + if (system_hw == SYSTEM_MCD) + { + /* register index ($A12000-A1203F mirrored up to $A120FF) */ + switch (address & 0x3e) + { + case 0x00: /* SUB-CPU interrupt & control */ + { + /* RESET bit */ + if (data & 0x01) + { + /* trigger reset on 0->1 transition */ + if (!(scd.regs[0x00].byte.l & 0x01)) + { + /* reset SUB-CPU */ + s68k_pulse_reset(); + } + + /* BUSREQ bit */ + if (data & 0x02) + { + /* SUB-CPU bus requested */ + s68k_pulse_halt(); + } + else + { + /* SUB-CPU bus released */ + s68k_clear_halt(); + } + } + else + { + /* SUB-CPU is halted while !RESET is asserted */ + s68k_pulse_halt(); + } + + /* IFL2 bit */ + if (data & 0x100) + { + /* level 2 interrupt enabled ? */ + if (scd.regs[0x32>>1].byte.l & 0x04) + { + /* set IFL2 flag */ + scd.regs[0x00].byte.h |= 0x01; + + /* trigger level 2 interrupt */ + scd.pending |= (1 << 2); + + /* update IRQ level */ + s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1); + } + } + + /* update LSB only */ + scd.regs[0x00].byte.l = data & 0xff; + return; + } + + case 0x02: /* Memory Mode */ + { + m68k_poll_sync(1<<0x03); + + /* PRG-RAM 128k bank mapped to $020000-$03FFFF (resp. $420000-$43FFFF) */ + m68k.memory_map[scd.cartridge.boot + 0x02].base = scd.prg_ram + ((data & 0xc0) << 11); + m68k.memory_map[scd.cartridge.boot + 0x03].base = m68k.memory_map[scd.cartridge.boot + 0x02].base + 0x10000; + + /* check current mode */ + if (scd.regs[0x03>>1].byte.l & 0x04) + { + /* DMNA bit */ + if (data & 0x02) + { + /* writing 1 to DMNA in 1M mode will return Word-RAM to SUB-CPU in 2M mode */ + scd.dmna = 1; + } + else + { + /* writing 0 to DMNA in 1M mode actually set DMNA bit */ + data |= 0x02; + + /* update WP0-7, BK0-1 & DMNA bits */ + scd.regs[0x02>>1].w = (scd.regs[0x02>>1].w & ~0xffc2) | (data & 0xffc2); + return; + } + } + else + { + /* writing 0 in 2M mode does nothing */ + if (data & 0x02) + { + /* Word-RAM is assigned to SUB-CPU */ + scd.dmna = 1; + + /* clear RET bit */ + scd.regs[0x02>>1].w = (scd.regs[0x02>>1].w & ~0xffc3) | (data & 0xffc2); + return; + } + } + + /* update WP0-7 & BK0-1 bits */ + scd.regs[0x02>>1].w = (scd.regs[0x02>>1].w & ~0xffc0) | (data & 0xffc0); + return; + } + + case 0x06: /* H-INT vector (word access only ?) */ + { + *(uint16 *)(m68k.memory_map[0].base + 0x72) = data; + return; + } + + case 0x0e: /* CPU communication flags */ + { + m68k_poll_sync(1<<0x0e); + + /* D8-D15 ignored -> only MAIN-CPU flags are updated (Mortal Kombat) */ + scd.regs[0x0e>>1].byte.h = data & 0xff; + return; + } + + default: + { + /* MAIN-CPU communication words */ + if ((address & 0x30) == 0x10) + { + m68k_poll_sync(3 << (address & 0x1e)); + scd.regs[(address >> 1) & 0xff].w = data; + return; + } + + /* invalid address */ + m68k_unused_16_w (address, data); + return; + } + } + } + + m68k_unused_16_w (address, data); + return; + } + + case 0x30: /* TIME */ + { + cart.hw.time_w(address, data); + return; + } + + case 0x40: /* TMSS */ + { + if (config.bios & 1) + { + gen_tmss_w(address & 3, data); + return; + } + m68k_unused_16_w(address, data); + return; + } + + case 0x50: /* SVP */ + { + if (!(address & 0xFD)) + { + svp->ssp1601.gr[SSP_XST].byte.h = data; + svp->ssp1601.gr[SSP_PM0].byte.h |= 2; + svp->ssp1601.emu_status &= ~SSP_WAIT_PM0; + return; + } + m68k_unused_16_w(address, data); + return; + } + + case 0x10: /* MEMORY MODE */ + case 0x13: /* unknown */ + case 0x41: /* BOOT ROM */ + case 0x44: /* RADICA */ + { + m68k_unused_16_w (address, data); + return; + } + + default: /* Invalid address */ + { + m68k_lockup_w_16 (address, data); + return; + } + } +} + + +/*--------------------------------------------------------------------------*/ +/* VDP */ +/*--------------------------------------------------------------------------*/ + +unsigned int vdp_read_byte(unsigned int address) +{ + switch (address & 0xFD) + { + case 0x00: /* DATA */ + { + return (vdp_68k_data_r() >> 8); + } + + case 0x01: /* DATA */ + { + return (vdp_68k_data_r() & 0xFF); + } + + case 0x04: /* CTRL */ + { + unsigned int data = (vdp_68k_ctrl_r(m68k.cycles) >> 8) & 3; + + /* Unused bits return prefetched bus data */ + address = m68k.pc; + data |= (READ_BYTE(m68k.memory_map[((address)>>16)&0xff].base, (address) & 0xffff) & 0xFC); + + return data; + } + + case 0x05: /* CTRL */ + { + return (vdp_68k_ctrl_r(m68k.cycles) & 0xFF); + } + + case 0x08: /* HVC */ + case 0x0C: + { + return (vdp_hvc_r(m68k.cycles) >> 8); + } + + case 0x09: /* HVC */ + case 0x0D: + { + return (vdp_hvc_r(m68k.cycles) & 0xFF); + } + + case 0x18: /* Unused */ + case 0x19: + case 0x1C: + case 0x1D: + { + return m68k_read_bus_8(address); + } + + default: /* Invalid address */ + { + return m68k_lockup_r_8(address); + } + } +} + +unsigned int vdp_read_word(unsigned int address) +{ + switch (address & 0xFC) + { + case 0x00: /* DATA */ + { + return vdp_68k_data_r(); + } + + case 0x04: /* CTRL */ + { + unsigned int data = vdp_68k_ctrl_r(m68k.cycles) & 0x3FF; + + /* Unused bits return prefetched bus data */ + address = m68k.pc; + data |= (*(uint16 *)(m68k.memory_map[((address)>>16)&0xff].base + ((address) & 0xffff)) & 0xFC00); + + return data; + } + + case 0x08: /* HVC */ + case 0x0C: + { + return vdp_hvc_r(m68k.cycles); + } + + case 0x18: /* Unused */ + case 0x1C: + { + return m68k_read_bus_16(address); + } + + default: /* Invalid address */ + { + return m68k_lockup_r_16(address); + } + } +} + +void vdp_write_byte(unsigned int address, unsigned int data) +{ + switch (address & 0xFC) + { + case 0x00: /* Data port */ + { + vdp_68k_data_w(data << 8 | data); + return; + } + + case 0x04: /* Control port */ + { + vdp_68k_ctrl_w(data << 8 | data); + return; + } + + case 0x10: /* PSG */ + case 0x14: + { + if (address & 1) + { + SN76489_Write(m68k.cycles, data); + return; + } + m68k_unused_8_w(address, data); + return; + } + + case 0x18: /* Unused */ + { + m68k_unused_8_w(address, data); + return; + } + + case 0x1C: /* TEST register */ + { + vdp_test_w(data << 8 | data); + return; + } + + default: /* Invalid address */ + { + m68k_lockup_w_8(address, data); + return; + } + } +} + +void vdp_write_word(unsigned int address, unsigned int data) +{ + switch (address & 0xFC) + { + case 0x00: /* DATA */ + { + vdp_68k_data_w(data); + return; + } + + case 0x04: /* CTRL */ + { + vdp_68k_ctrl_w(data); + return; + } + + case 0x10: /* PSG */ + case 0x14: + { + SN76489_Write(m68k.cycles, data & 0xFF); + return; + } + + case 0x18: /* Unused */ + { + m68k_unused_16_w(address, data); + return; + } + + case 0x1C: /* Test register */ + { + vdp_test_w(data); + return; + } + + default: /* Invalid address */ + { + m68k_lockup_w_16 (address, data); + return; + } + } +} + + +/*--------------------------------------------------------------------------*/ +/* PICO (incomplete) */ +/*--------------------------------------------------------------------------*/ + +unsigned int pico_read_byte(unsigned int address) +{ + switch (address & 0xFF) + { + case 0x01: /* VERSION register */ + { + return (region_code >> 1); + } + + case 0x03: /* IO register */ + { + return ~input.pad[0]; + } + + case 0x05: /* PEN X coordinate (MSB) */ + { + return (input.analog[0][0] >> 8); + } + + case 0x07: /* PEN X coordinate (LSB) */ + { + return (input.analog[0][0] & 0xFF); + } + + case 0x09: /* PEN Y coordinate (MSB) */ + { + return (input.analog[0][1] >> 8); + } + + case 0x0B: /* PEN Y coordinate (LSB) */ + { + return (input.analog[0][1] & 0xFF); + } + + case 0x0D: /* PAGE register */ + { + return (1 << pico_current) - 1; + } + + case 0x10: /* ADPCM data registers (TODO) */ + case 0x11: + { + return 0xff; + } + + case 0x12: /* ADPCM control registers (TODO) */ + { + return 0x80; + } + + default: + { + return m68k_read_bus_8(address); + } + } +} + +unsigned int pico_read_word(unsigned int address) +{ + return (pico_read_byte(address | 1) | (pico_read_byte(address) << 8)); +}