diff --git a/hash/megadriv.xml b/hash/megadriv.xml index 28f26b8f1f917..374e275741919 100644 --- a/hash/megadriv.xml +++ b/hash/megadriv.xml @@ -1156,7 +1156,8 @@ The three available regions are PAL, NTSC-U and NTSC-J or a combination such as 1993 Electronic Arts - + + @@ -1781,13 +1782,10 @@ The three available regions are PAL, NTSC-U and NTSC-J or a combination such as - + College Slam (USA) 1996 Acclaim Entertainment - @@ -3657,11 +3655,12 @@ Crashes with NTSC machines after EOA logo (verify) 1990 Sega - + + @@ -4651,6 +4650,7 @@ Moans about [Sega Mega Modem] not hooked up, punts to a red screen 1992 Electronic Arts + @@ -6206,19 +6206,15 @@ Unsupported [Menacer] peripheral - + NFL Quarterback Club (World) 1994 Acclaim Entertainment - - - + @@ -8200,7 +8196,7 @@ Unemulated HeartBeat peripheral - + @@ -10650,7 +10646,7 @@ https://tcrf.net/World_Championship_Soccer_(Genesis) Doesn't accept any input ]]> - + @@ -10719,7 +10715,7 @@ Doesn't accept any input - + @@ -10882,7 +10878,7 @@ but dumps still have to be confirmed. Shíliù Zhāng Májiàng II (China) - 199? + 1993? City Man @@ -10899,11 +10895,12 @@ but dumps still have to be confirmed. 199? <unknown> + - + @@ -10913,11 +10910,12 @@ Only Flashback portion is present in the dump, the other two entries and menu ar 199? <unknown> + - + @@ -11500,6 +11498,21 @@ Black screen after starting a game, access $be1040-3 for a 0x524e4302 value (?) + + RockHeaven (hack of Alex Kidd Tenkuu Majou) + 199? + <unlicensed> + + + + + + + + + Alien³ (Europe, USA, rev. A) 1993 @@ -11633,7 +11646,7 @@ Black screen after starting a game, access $be1040-3 for a 0x524e4302 value (?) - Ā Q Liánhuán Pào (Taiwan) + Ā Q Liánhuán Pào (Taiwan, unprotected) 1995 C&E @@ -12512,12 +12525,15 @@ No sound (btanb?) - + Barkley Shut Up and Jam! 2 (USA) 1995 Accolade + - + @@ -12709,6 +12725,7 @@ https://bootleggames.fandom.com/wiki/Barver_Battle_Saga:_Tai_Kong_Zhan_Shi Creaton Softech + @@ -13646,8 +13663,10 @@ No [VDP] sprites 1995 Codemasters + + - + @@ -13657,30 +13676,37 @@ No [VDP] sprites 1995 Codemasters + - + Brian Lara Cricket 96 (Europe, 199604) 1996 Codemasters + - + - + Brian Lara Cricket 96 (Europe, 199603) 1996 Codemasters + - + @@ -14998,10 +15024,10 @@ No [VDP] sprites - Chāojí Dà Fùwēng (Taiwan) + Chāojí Dà Fùwēng (Taiwan, unprotected) 1994? - Gametec + Gamtec @@ -15330,7 +15356,7 @@ https://bootleggames.fandom.com/wiki/Chaoji_Dafuweng - + College Football USA 96 (prototype 19950621) 1995 @@ -16488,7 +16514,7 @@ https://bootleggames.fandom.com/wiki/Chaoji_Dafuweng - + CutThroat Island (prototype) 1995 @@ -16572,7 +16598,7 @@ https://bootleggames.fandom.com/wiki/Chaoji_Dafuweng - + Danny Sullivan's Indy Heat (prototype) (pirate) 1992 @@ -16620,6 +16646,7 @@ https://bootleggames.fandom.com/wiki/Chaoji_Dafuweng + Dashin' Desperadoes (USA) 1993 @@ -16866,8 +16893,10 @@ https://bootleggames.fandom.com/wiki/Chaoji_Dafuweng - - + + + + @@ -16924,8 +16953,10 @@ https://bootleggames.fandom.com/wiki/Chaoji_Dafuweng - - + + + + @@ -16942,8 +16973,10 @@ https://bootleggames.fandom.com/wiki/Chaoji_Dafuweng - - + + + + @@ -18736,7 +18769,7 @@ No sound in intro opening (verify) Fēngkuáng Táohuāyuán (Taiwan) - 199? + 1998? Creaton Softech - Fēngshén Yīngjié Chuán (Taiwan) + Fēngshén Yīngjié Chuán (Taiwan, unprotected) 1996 Chuanpu Technologies @@ -19165,13 +19199,10 @@ https://segaretro.org/Feng_Shen_Ying_Jie_Chuan - + Frank Thomas Big Hurt Baseball (Europe, USA) 1995 Acclaim Entertainment - @@ -19324,6 +19355,7 @@ https://segaretro.org/Feng_Shen_Ying_Jie_Chuan 1995 Sega + @@ -19892,6 +19924,23 @@ Unemulated [Sega Mega Modem] features + + Gunfight 3 in 1 (Taiwan) + 1998? + <unlicensed> + + + + + + + + + + + Gynoug (Japan) 1991 @@ -19982,9 +20031,12 @@ Unemulated [Sega Mega Modem] features - Hei Tao 2 - Super Big 2 (Taiwan) + Hei Tao 2 - Super Big 2 (Taiwan, unprotected) 199? King Tec + @@ -20773,10 +20825,28 @@ Unemulated [Sega Mega Modem] features - - Jiu Ji Ma Jiang II - Ye Yan Bian (China) + + Ju Ji Ma Jiang II - Ye Yan Bian (China, protected) + 199? + Sun Green + + + + + + + + + + + + + Jiu Ji Ma Jiang II - Ye Yan Bian (China, unprotected) 199? <unlicensed> + @@ -20814,6 +20884,7 @@ Unemulated [Sega Mega Modem] features 1992 Electronic Arts + @@ -22644,6 +22715,7 @@ Needs [megadriv_z80_z80_bank_w] workaround to work (emulator copy protection?) + @@ -22878,9 +22950,12 @@ Needs [megadriv_z80_z80_bank_w] workaround to work (emulator copy protection?) 1993 FCI? + + + @@ -24954,7 +25029,7 @@ Unemulated [Sega Mega Modem] features - + @@ -24966,6 +25041,7 @@ Unemulated [Sega Mega Modem] features 1991 Sega + @@ -25072,6 +25148,28 @@ Unemulated [Sega Mega Modem] features + + Nyuushi Chokuzen Check Nanmon Kimon Kiki Kaikai (Japan, Sega Channel) + 1995 + We Net + + + + + + + + + + Old Towers (v1.2) 2019 @@ -25756,7 +25854,7 @@ Black screen at intro 1994 Codemasters - + @@ -25768,7 +25866,7 @@ Black screen at intro 1994 Codemasters - + @@ -26429,6 +26527,28 @@ Black screen + + Planet Message Quiz (Japan, Sega Channel) + 1995 + We Net + + + + + + + + + + Pocahontas (USA) 1996 @@ -26443,7 +26563,7 @@ Black screen Pocket Monsters - 199? + 1999? <unlicensed> @@ -26455,7 +26575,7 @@ Black screen Pocket Monsters (alt protection) - 199? + 1999? <unlicensed> @@ -28150,13 +28270,14 @@ Red screen Sānguózhì V (Taiwan) - 199? + 1999? SKOB + @@ -28436,11 +28557,15 @@ Throws "this game is [...] european megadrive system" even with megadriv system - - Shane Warne Cricket (Aus) + + Shane Warne Cricket (Australia) 1997 Codemasters + + @@ -28800,7 +28925,7 @@ https://segaretro.org/Shi_Jie_Zhi_Bang_Zheng_Ba_Zhan:_World_Pro_Baseball_94 - Shuǐhǔ - Fēngyún Chuán (Taiwan) + Shuǐhǔ - Fēngyún Chuán (Taiwan, unprotected) 1999 Never Ending Soft Team - Shuǐhǔ Zhuàn (China) + Shuǐhǔ Zhuàn (China, unprotected) 1996 Chuanpu Technologies + @@ -29263,7 +29391,7 @@ https://bootleggames.fandom.com/wiki/Shui_Hu_Feng_Yun_Zhuan - + @@ -29277,7 +29405,7 @@ https://bootleggames.fandom.com/wiki/Shui_Hu_Feng_Yun_Zhuan - + @@ -29720,7 +29848,7 @@ Original scene release which was altered to include a cracktro and bypass the co - + @@ -29743,7 +29871,7 @@ Original scene release which was altered to include a cracktro and bypass the co - + @@ -29758,7 +29886,7 @@ Original scene release which was altered to include a cracktro and bypass the co - + @@ -30118,13 +30246,10 @@ Original scene release which was altered to include a cracktro and bypass the co 1997 Tec Toy + @@ -31395,6 +31520,7 @@ Freezes at the start of any in-game mode 1995 Codemasters + @@ -31406,6 +31532,8 @@ Freezes at the start of any in-game mode 1995 Codemasters + + @@ -32213,7 +32341,7 @@ No BGMs Tekken Special - 199? + 1997? <unlicensed> @@ -32223,8 +32351,9 @@ No BGMs - - Tekken 3 Special + + + Tekken 3 Special (unprotected) 199? <unlicensed> @@ -33044,6 +33173,7 @@ No BGMs <unlicensed> + @@ -33052,10 +33182,11 @@ No BGMs Tūnshí Tiāndì III (China) - 199? + 1997? SKOB + @@ -33885,6 +34016,22 @@ Has missing sound samples (i.e. tire screech, "time bonus" on checkpoints) + + RockWorld (hack of Wani Wani World) + 199? + <unlicensed> + + + + + + + + + + Wardner (USA) 1991 @@ -35504,18 +35651,22 @@ Black screen - - + + + - + Wùkōng Wàizhuàn (China) 1996 Ming + @@ -35878,13 +36029,16 @@ Black screen - + Beggar Prince (rev 1) (Europe, USA) 2006 Super Fighter Team + - + @@ -35932,10 +36086,14 @@ Black screen - + Yàsè Chuánshuō (China) 1995 Ming + @@ -35963,9 +36121,12 @@ Black screen - Yīmén Yīngliè - Yángjiā Jiāng (China) + Yīmén Yīngliè - Yángjiā Jiāng (China, unprotected) 199? <unlicensed> + @@ -36400,14 +36561,31 @@ Jumps to unmapped area at PC=0xffd004e8 - - 12 in 1 (incomplete dump) + + 12 in 1 (pirate) 199? <unlicensed> - - + + + + + + + + + + 1800 in 1 (China, pirate) + 199? + <unlicensed> + + + + + @@ -36425,7 +36603,7 @@ Jumps to unmapped area at PC=0xffd004e8 - A Bug's Life + A Bug's Life (bootleg?) 2000 <unlicensed> @@ -36448,8 +36626,9 @@ Jumps to unmapped area at PC=0xffd004e8 + Tenchi wo Kurau III - Sanguo Wai Chuan - Chinese Fighter (China) - 199? + 1996? <unlicensed> - Golden 10 in 1 (Incomplete Dump) + Golden 10 in 1 (pirate) 199? <unlicensed> - - + + + + + + + + + + + Golden Mega 250 in 1 (pirate) + 199? + <unlicensed> + + + + @@ -36565,8 +36759,9 @@ Crashes during attract or in character select, copy protection + Líng Huàn Dàoshi - Super Magician (China) - 199? + 1994? Ming @@ -36606,7 +36801,7 @@ Crashes during attract or in character select, copy protection Jī Májiàng - Zhī Májiàng Qíngrén (China) - 199? + 1995? <unlicensed> @@ -36619,7 +36814,7 @@ Crashes during attract or in character select, copy protection Jī Májiàng - Zhī Májiàng Qíngrén (China, alt) - 199? + 1995? <unlicensed> @@ -36630,9 +36825,27 @@ Crashes during attract or in character select, copy protection + + Shísān Zhāng Májiàng - Zhong Guo Měi Nv Pian (Taiwan) + 1993 + <unlicensed> + + + + + + + + + + + Pokemon Stadium - 199? + 2000? + <unlicensed> @@ -36660,7 +36873,7 @@ https://segaretro.org/Rockman_X3_(Mega_Drive) Soul Blade - 199? + 1997? <unlicensed> @@ -36716,8 +36929,9 @@ https://bootleggames.fandom.com/wiki/Squirrel_King <unknown> - - + + + @@ -36870,19 +37084,19 @@ https://bootleggames.fandom.com/wiki/Super_Bubble_Bobble_MD Top Fighter 2000 MK VIII - 199? - <unlicensed> + 1999 + X Boy - + - - Top Fighter 2005 - 199? + + Top Fighter 2005 (China, unprotected) + 2005? <unlicensed> @@ -36895,6 +37109,11 @@ https://bootleggames.fandom.com/wiki/Super_Bubble_Bobble_MD Whac-a-Critter (USA) 1993 Realtec + + @@ -37003,19 +37222,6 @@ https://bootleggames.fandom.com/wiki/Super_Bubble_Bobble_MD - - Ju Ji Ma Jiang II - 199? - Sun Green - - - - - - - - - Truco '96 (Argentina, unprotected) @@ -37045,8 +37251,8 @@ https://bootleggames.fandom.com/wiki/Super_Bubble_Bobble_MD TC 2000 (Argentina, unprotected) - 199? - <unlicensed> + 1995? + Miky @@ -37056,8 +37262,8 @@ https://bootleggames.fandom.com/wiki/Super_Bubble_Bobble_MD TC 2000 (Argentina, protected) - 199? - <unlicensed> + 1995? + Miky @@ -37123,7 +37329,7 @@ https://bootleggames.fandom.com/wiki/Super_Bubble_Bobble_MD Magic Bubble 1993 C&E - + @@ -37135,7 +37341,7 @@ https://bootleggames.fandom.com/wiki/Super_Bubble_Bobble_MD Magic Bubble (alt) 1993 C&E - + @@ -37450,9 +37656,13 @@ Unsupported lightgun or mouse? - Dragon Ball Final Bout (China?) + Dragon Ball Final Bout (Taiwan, unprotected) 1998 - <unknown> + DVS Electronic + @@ -37862,8 +38072,9 @@ BGM sometimes goes silent (does several [YM2612] 68k writes without bus) - Mighty Morphin Power Rangers - The Fighting Edition (Russia) - 199? + + Mighty Morphin Power Rangers - The Fighting Edition (Russia, unprotected) + 1997? <unknown> @@ -38214,6 +38425,8 @@ https://bootleggames.fandom.com/wiki/SpongeBob_SquarePants <unknown> + + @@ -38328,6 +38541,7 @@ https://segaretro.org/Action_Replay_(Mega_Drive) Needs own slot type with mountable carts ]]> + @@ -38657,4 +38871,21 @@ Crashes at startup with megadriv (verify) + + SSF Extended test (v2) + 2014 + krikzz + + + + + + + + + + diff --git a/hash/supracan.xml b/hash/supracan.xml index 0791bcfa6ee56..5521786a133b4 100644 --- a/hash/supracan.xml +++ b/hash/supracan.xml @@ -97,7 +97,7 @@ Broken [video] during intro, uses bitmap mode with ROZ layer Super Taiwanese Baseball League ~ Chao Ji Zhong Hua Zhi Bang Lian Meng 1995 - C&E Soft + C&E clock(), megadrive_cart_options, nullptr).set_must_be_loaded(false); +} + +void megadrive_action_replay_device::device_start() +{ + megadrive_rom_device::device_start(); +} + +void megadrive_action_replay_device::device_reset() +{ + megadrive_rom_device::device_reset(); + m_ar_view.select(0); +} + +void megadrive_action_replay_device::unlock_cart_w(offs_t offset, u16 data, u16 mem_mask) +{ + if (data == 0xffff) + { + m_ar_view.disable(); + } +} + +void megadrive_action_replay_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x7f'ffff).rw(m_lockon_cart, FUNC(megadrive_cart_slot_device::base_r), FUNC(megadrive_cart_slot_device::base_w)); + map(0x00'0000, 0x01'ffff).view(m_ar_view); + m_ar_view[0](0x00'0000, 0x00'7fff).mirror(0x00'8000).bankr(m_rom); + m_ar_view[0](0x01'0006, 0x01'0007).w(FUNC(megadrive_action_replay_device::unlock_cart_w)); +} + +void megadrive_action_replay_device::time_io_map(address_map &map) +{ + map(0x00, 0xff).rw(m_lockon_cart, FUNC(megadrive_cart_slot_device::time_r), FUNC(megadrive_cart_slot_device::time_w)); +} diff --git a/src/devices/bus/megadrive/cart/action_replay.h b/src/devices/bus/megadrive/cart/action_replay.h new file mode 100644 index 0000000000000..889d623ff9e3b --- /dev/null +++ b/src/devices/bus/megadrive/cart/action_replay.h @@ -0,0 +1,37 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese + +#ifndef MAME_BUS_MEGADRIVE_CART_ACTION_REPLAY_H +#define MAME_BUS_MEGADRIVE_CART_ACTION_REPLAY_H + +#pragma once + +#include "rom.h" +#include "slot.h" + +class megadrive_action_replay_device : public megadrive_rom_device +{ +public: + megadrive_action_replay_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; + virtual void time_io_map(address_map &map) override ATTR_COLD; + +protected: + megadrive_action_replay_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; + + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + + required_device m_lockon_cart; + memory_view m_ar_view; + + void unlock_cart_w(offs_t offset, u16 data, u16 mem_mask); +}; + +DECLARE_DEVICE_TYPE(MEGADRIVE_ACTION_REPLAY, megadrive_action_replay_device) + + +#endif // MAME_BUS_MEGADRIVE_CART_ACTION_REPLAY_H diff --git a/src/devices/bus/megadrive/cart/avartisan.cpp b/src/devices/bus/megadrive/cart/avartisan.cpp new file mode 100644 index 0000000000000..d585ce74ef755 --- /dev/null +++ b/src/devices/bus/megadrive/cart/avartisan.cpp @@ -0,0 +1,74 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese +/************************************************************************************************** + +AV Artisan/Realtec cart mappers + +Goofy banking scheme. Maps every bank with $7e000 page at startup, remaps in $20000 chunks +depending on masked values between $404000 and $402000 then locks the mapper. + +Practically only funnywld sets these to non-zero values, everything else just writes 0 to both +regs. + +**************************************************************************************************/ + +#include "emu.h" +#include "avartisan.h" + +#include "bus/generic/slot.h" + +DEFINE_DEVICE_TYPE(MEGADRIVE_UNL_AVARTISAN, megadrive_unl_avartisan_device, "megadrive_unl_avartisan", "Megadrive AV Artisan cart") + +megadrive_unl_avartisan_device::megadrive_unl_avartisan_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, MEGADRIVE_UNL_AVARTISAN, tag, owner, clock) + , device_megadrive_cart_interface( mconfig, *this ) + , m_rom_bank(*this, "rom_bank_%u", 0U) +{ +} + +void megadrive_unl_avartisan_device::device_start() +{ + memory_region *const romregion(cart_rom_region()); + const u32 page_size = 0x00'2000; + device_generic_cart_interface::map_non_power_of_two( + unsigned(romregion->bytes() / page_size), + [this, base = &romregion->as_u8()] (unsigned entry, unsigned page) + { + for (int i = 0; i < 0x40; i++) + m_rom_bank[i]->configure_entry(entry, &base[page * page_size]); + }); +} + +void megadrive_unl_avartisan_device::device_reset() +{ + // TODO: default + // GPGX uses /VRES to bypass TMSS with a read at $100, is it even possible? + for (int i = 0; i < 0x40; i++) + m_rom_bank[i]->set_entry(0x3f); + m_lock_config = false; +} + +void megadrive_unl_avartisan_device::cart_map(address_map &map) +{ + for (int i = 0; i < 0x40; i++) + map(0x00'0000 | (i * 0x2000), 0x00'1fff | (i * 0x2000)).mirror(0x380000).bankr(m_rom_bank[i]); + map(0x40'2000, 0x40'2000).lw8(NAME([this] (offs_t offset, u8 data) { m_bank_size = (data & 3) << 4; })); + map(0x40'4000, 0x40'4000).lw8(NAME([this] (offs_t offset, u8 data) { m_bank_sel = (data & 3) << 4; })); + map(0x40'0000, 0x40'0000).lw8( + NAME([this] (offs_t offset, u8 data) { + // 0 -> 1 transitions + if (!m_lock_config && BIT(data, 0)) + { + logerror("size %02x sel %02x (%02x)\n", m_bank_size, m_bank_sel, ~m_bank_size); + u8 bank_base = m_bank_sel & m_bank_size; + for (int i = 0; i < 0x40; i++) + { + m_rom_bank[i]->set_entry(((i & ~m_bank_size) | bank_base) & 0x3f); + } + + m_lock_config = !!BIT(data, 0); + } + }) + ); +} + diff --git a/src/devices/bus/megadrive/cart/avartisan.h b/src/devices/bus/megadrive/cart/avartisan.h new file mode 100644 index 0000000000000..00de874f935c0 --- /dev/null +++ b/src/devices/bus/megadrive/cart/avartisan.h @@ -0,0 +1,33 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese + +#ifndef MAME_BUS_MEGADRIVE_CART_AVARTISAN_H +#define MAME_BUS_MEGADRIVE_CART_AVARTISAN_H + +#pragma once + +#include "rom.h" +#include "slot.h" + +class megadrive_unl_avartisan_device : public device_t, + public device_megadrive_cart_interface +{ +public: + megadrive_unl_avartisan_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; + +protected: + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + + memory_bank_array_creator<0x40> m_rom_bank; + u8 m_bank_size; + u8 m_bank_sel; + bool m_lock_config; +}; + +DECLARE_DEVICE_TYPE(MEGADRIVE_UNL_AVARTISAN, megadrive_unl_avartisan_device) + + +#endif // MAME_BUS_MEGADRIVE_CART_AVARTISAN_H diff --git a/src/devices/bus/megadrive/cart/eeprom.cpp b/src/devices/bus/megadrive/cart/eeprom.cpp new file mode 100644 index 0000000000000..2f23abe875a8d --- /dev/null +++ b/src/devices/bus/megadrive/cart/eeprom.cpp @@ -0,0 +1,261 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese +/************************************************************************************************** + +Megadrive ROM + I2C EEPROM + +**************************************************************************************************/ + +#include "emu.h" +#include "eeprom.h" + +/* + * evander Evander Holyfield Boxing + * ddanpei Honoo no Toukyuuji - Dodge Danpei + * gameto Game Toshokan + * ghw/ghwj/ghwu Greatest Heavyweights + * ninjab Ninja Burai Densetsu + * megaman/rockman1 Megaman The Wily Wars + * sporttbb Sports Talk Baseball + * wboymw/wboy5 Wonder Boy in Monster World + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_EEPROM, megadrive_eeprom_device, "megadrive_eeprom", "Megadrive ROM + I2C EEPROM cart") + +megadrive_eeprom_device::megadrive_eeprom_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, type, tag, owner, clock) + , m_i2cmem(*this, "i2cmem") +{ +} + +megadrive_eeprom_device::megadrive_eeprom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_eeprom_device(mconfig, MEGADRIVE_EEPROM, tag, owner, clock) +{ +} + +void megadrive_eeprom_device::device_add_mconfig(machine_config &config) +{ + I2C_X24C01(config, m_i2cmem); +} + +void megadrive_eeprom_device::cart_map(address_map &map) +{ + map(0x00'0000, m_rom_mask).mirror(m_rom_mirror).bankr(m_rom); + map(0x20'0001, 0x20'0001).lrw8( + NAME([this] (offs_t offset) { + return m_i2cmem->read_sda(); + }), + NAME([this] (offs_t offset, u8 data) { + m_i2cmem->write_scl(BIT(data, 1)); + m_i2cmem->write_sda(BIT(data, 0)); + }) + ); +} + +/* + * nbajam/nbajam1/nbajamj NBA Jam + * + * Uses a 24C02, otherwise same as Sega handling + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_EEPROM_NBAJAM, megadrive_eeprom_nbajam_device, "megadrive_eeprom_nbajam", "Megadrive NBA Jam cart") + + +megadrive_eeprom_nbajam_device::megadrive_eeprom_nbajam_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_eeprom_device(mconfig, MEGADRIVE_EEPROM_NBAJAM, tag, owner, clock) +{ +} + +void megadrive_eeprom_nbajam_device::device_add_mconfig(machine_config &config) +{ + I2C_24C02(config, m_i2cmem); +} + +/* + * nbajamte NBA Jam TE (MD and 32x versions) + * nflqb NFL Quarterback Club + * blockb Blockbuster World Video Game Championship II + * + * Uses a 24C02, moves SCL to $200000 + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_EEPROM_NBAJAMTE, megadrive_eeprom_nbajamte_device, "megadrive_eeprom_nbajamte", "Megadrive NBA Jam TE cart") + +megadrive_eeprom_nbajamte_device::megadrive_eeprom_nbajamte_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : megadrive_eeprom_device(mconfig, type, tag, owner, clock) +{ +} + +megadrive_eeprom_nbajamte_device::megadrive_eeprom_nbajamte_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_eeprom_nbajamte_device(mconfig, MEGADRIVE_EEPROM_NBAJAMTE, tag, owner, clock) +{ +} + +void megadrive_eeprom_nbajamte_device::device_add_mconfig(machine_config &config) +{ + // nflqb uses a 24LC02B + I2C_24C02(config, m_i2cmem); +} + +void megadrive_eeprom_nbajamte_device::cart_map(address_map &map) +{ + map(0x00'0000, m_rom_mask).mirror(m_rom_mirror).bankr(m_rom); + map(0x20'0000, 0x20'0000).lw8( + NAME([this] (offs_t offset, u8 data) { + m_i2cmem->write_scl(BIT(data, 0)); + }) + ); + map(0x20'0001, 0x20'0001).lrw8( + NAME([this] (offs_t offset) { + return m_i2cmem->read_sda(); + }), + NAME([this] (offs_t offset, u8 data) { + m_i2cmem->write_sda(BIT(data, 0)); + }) + ); +} + +/* + * nflqb96 NFL Quarterback Club 96 + * + * Same as NBA Jam TE with a '16 in place of the '02 + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_EEPROM_NFLQB96, megadrive_eeprom_nflqb96_device, "megadrive_eeprom_nflqb96", "Megadrive NFL Quarterback Club 96 cart") + +megadrive_eeprom_nflqb96_device::megadrive_eeprom_nflqb96_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_eeprom_nbajamte_device(mconfig, MEGADRIVE_EEPROM_NFLQB96, tag, owner, clock) +{ +} + +void megadrive_eeprom_nflqb96_device::device_add_mconfig(machine_config &config) +{ + I2C_24C16(config, m_i2cmem); +} + +/* + * collslam College Slam + * bighurt Frank Thomas Big Hurt Baseball + * + * Bump of nflqb96 with a '65 in place of the '16 + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_EEPROM_COLLSLAM, megadrive_eeprom_collslam_device, "megadrive_eeprom_collslam", "Megadrive College Slam cart") + +megadrive_eeprom_collslam_device::megadrive_eeprom_collslam_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_eeprom_nbajamte_device(mconfig, MEGADRIVE_EEPROM_COLLSLAM, tag, owner, clock) +{ +} + +void megadrive_eeprom_collslam_device::device_add_mconfig(machine_config &config) +{ + I2C_24C65(config, m_i2cmem); +} + +/* + * nhlpa93 NHLPA Hockey 93 + * ringspow Rings of Power + * + * '01 at bits 7-6 of $200001 + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_EEPROM_NHLPA, megadrive_eeprom_nhlpa_device, "megadrive_eeprom_nhlpa", "Megadrive NHLPA Hockey 93 cart") + +megadrive_eeprom_nhlpa_device::megadrive_eeprom_nhlpa_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_eeprom_device(mconfig, MEGADRIVE_EEPROM_NHLPA, tag, owner, clock) +{ +} + +void megadrive_eeprom_nhlpa_device::device_add_mconfig(machine_config &config) +{ + I2C_24C01(config, m_i2cmem); +} + +void megadrive_eeprom_nhlpa_device::cart_map(address_map &map) +{ + map(0x00'0000, m_rom_mask).mirror(m_rom_mirror).bankr(m_rom); + map(0x20'0001, 0x20'0001).lrw8( + NAME([this] (offs_t offset) { + return m_i2cmem->read_sda() << 7; + }), + NAME([this] (offs_t offset, u8 data) { + m_i2cmem->write_sda(BIT(data, 7)); + m_i2cmem->write_scl(BIT(data, 6)); + }) + ); +} + + + +/* + * brianlar Brian Lara Cricket + * + * Same as Codemasters J-Cart I2C implementation + * + * Guru I2C hookup notes: + * 1,2,3,4,7 GND + * 5 to LS244 pin 17 + * 6 to PAL pin 15 + * Output of 244 pin 17 is pin 3 which goes to ROM pin 29. It's a 42 pin ROM so pin 29 is D7 + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_EEPROM_BLARA95, megadrive_eeprom_blara95_device, "megadrive_eeprom_blara95", "Megadrive Brian Lara Cricket 95 cart") + +megadrive_eeprom_blara95_device::megadrive_eeprom_blara95_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : megadrive_eeprom_device(mconfig, type, tag, owner, clock) +{ +} + +megadrive_eeprom_blara95_device::megadrive_eeprom_blara95_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_eeprom_blara95_device(mconfig, MEGADRIVE_EEPROM_BLARA95, tag, owner, clock) +{ +} + +void megadrive_eeprom_blara95_device::device_add_mconfig(machine_config &config) +{ + I2C_24C08(config, m_i2cmem); +} + +void megadrive_eeprom_blara95_device::cart_map(address_map &map) +{ + map(0x00'0000, m_rom_mask).mirror(m_rom_mirror).bankr(m_rom); + map(0x30'0000, 0x30'0000).lw8( + NAME([this] (offs_t offset, u8 data) { + m_i2cmem->write_scl(BIT(data, 1)); + m_i2cmem->write_sda(BIT(data, 0)); + }) + ); + map(0x38'0001, 0x38'0001).lr8( + NAME([this] (offs_t offset) { + return m_i2cmem->read_sda() << 7; + }) + ); +} + +/* + * brianl96 Brian Lara Cricket 96 + * shanewar Shane Warne Cricket + * + * Same as Brian Lara 95, with a '65 here + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_EEPROM_BLARA96, megadrive_eeprom_blara96_device, "megadrive_eeprom_blara96", "Megadrive Brian Lara Cricket 96 cart") + +megadrive_eeprom_blara96_device::megadrive_eeprom_blara96_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_eeprom_blara95_device(mconfig, MEGADRIVE_EEPROM_BLARA96, tag, owner, clock) +{ +} + +void megadrive_eeprom_blara96_device::device_add_mconfig(machine_config &config) +{ + I2C_24C65(config, m_i2cmem); +} + diff --git a/src/devices/bus/megadrive/cart/eeprom.h b/src/devices/bus/megadrive/cart/eeprom.h new file mode 100644 index 0000000000000..dc8af787b9a44 --- /dev/null +++ b/src/devices/bus/megadrive/cart/eeprom.h @@ -0,0 +1,113 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese + +#ifndef MAME_BUS_MEGADRIVE_CART_EEPROM_H +#define MAME_BUS_MEGADRIVE_CART_EEPROM_H + +#pragma once + +#include "machine/i2cmem.h" + +#include "rom.h" +#include "slot.h" + +class megadrive_eeprom_device : public megadrive_rom_device +{ +public: + megadrive_eeprom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; +protected: + megadrive_eeprom_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; + + required_device m_i2cmem; +}; + +class megadrive_eeprom_nbajam_device : public megadrive_eeprom_device +{ +public: + megadrive_eeprom_nbajam_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; +}; + +class megadrive_eeprom_nbajamte_device : public megadrive_eeprom_device +{ +public: + megadrive_eeprom_nbajamte_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; +protected: + megadrive_eeprom_nbajamte_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; +}; + +class megadrive_eeprom_nflqb96_device : public megadrive_eeprom_nbajamte_device +{ +public: + megadrive_eeprom_nflqb96_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; +}; + +class megadrive_eeprom_collslam_device : public megadrive_eeprom_nbajamte_device +{ +public: + megadrive_eeprom_collslam_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; +}; + +class megadrive_eeprom_nhlpa_device : public megadrive_eeprom_device +{ +public: + megadrive_eeprom_nhlpa_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; +protected: + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; +}; + + + +class megadrive_eeprom_blara95_device : public megadrive_eeprom_device +{ +public: + megadrive_eeprom_blara95_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; +protected: + megadrive_eeprom_blara95_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; +}; + +class megadrive_eeprom_blara96_device : public megadrive_eeprom_blara95_device +{ +public: + megadrive_eeprom_blara96_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; +}; + + + + +DECLARE_DEVICE_TYPE(MEGADRIVE_EEPROM, megadrive_eeprom_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_EEPROM_NBAJAM, megadrive_eeprom_nbajam_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_EEPROM_NBAJAMTE, megadrive_eeprom_nbajamte_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_EEPROM_NFLQB96, megadrive_eeprom_nflqb96_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_EEPROM_COLLSLAM, megadrive_eeprom_collslam_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_EEPROM_NHLPA, megadrive_eeprom_nhlpa_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_EEPROM_BLARA95, megadrive_eeprom_blara95_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_EEPROM_BLARA96, megadrive_eeprom_blara96_device) + + +#endif // MAME_BUS_MEGADRIVE_CART_EEPROM_H diff --git a/src/devices/bus/megadrive/cart/everdrive.cpp b/src/devices/bus/megadrive/cart/everdrive.cpp new file mode 100644 index 0000000000000..810333c2d40b6 --- /dev/null +++ b/src/devices/bus/megadrive/cart/everdrive.cpp @@ -0,0 +1,235 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese +/************************************************************************************************** + +Everdrive-MD (first gen) + +TODO: +- avoid phantom cart slot loading (does nothing, we load BIOS from here); +- ST_M29W640FT core is incomplete (spurious unhandled writes); +- SPI comms dislikes receiving a SS signal when full speed is selected +\- goes 0 -> 1 -> 0, throwing a "SEL ERROR 120" if we don't guard against it; +- Add remaining cfg_w flags; +- Currently bases on HW spec 1.1 firmware v3, anything below that not yet supported; +- Overlay for ROM patching (Game Genie based); +- Reserved OS loading (A+B+C at power on, +UP for earlier carts) does nothing; +- Understand and implement module options; +- JTAG interface; + +**************************************************************************************************/ + +#include "emu.h" +#include "everdrive.h" + +#include "bus/generic/slot.h" + +DEFINE_DEVICE_TYPE(MEGADRIVE_HB_EVERDRIVE, megadrive_hb_everdrive_device, "everdrive_md", "Megadrive Krikzz Everdrive-MD cart") + +megadrive_hb_everdrive_device::megadrive_hb_everdrive_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, MEGADRIVE_HB_EVERDRIVE, tag, owner, clock) + , device_megadrive_cart_interface( mconfig, *this ) + , m_flash(*this, "flash") + , m_sdcard(*this, "sdcard") + , m_game_mode(*this, "game_mode") +{ +} + +void megadrive_hb_everdrive_device::device_add_mconfig(machine_config &config) +{ + // exact type is guessed by photo manipulation + ST_M29W640FT(config, m_flash); + + SPI_SDCARD(config, m_sdcard, 0); + m_sdcard->set_prefer_sdhc(); + m_sdcard->spi_miso_callback().set([this](int state) { m_in_bit = state; }); +} + +// 0x00000 bootloader +// 0x10000 OS +// 0x20000 reserve OS copy +// 0x30000 settings +// 0x40000-0xfffff module ROM area +// NOTE: bootloader stores boot flags (?) at $d0000 +ROM_START( everdrive_md ) + ROM_REGION16_BE(0x800000, "flash", ROMREGION_ERASE00) + ROM_LOAD16_WORD_SWAP("v35.bin", 0x00000, 0x20000, CRC(161b4d2e) SHA1(fe71de7dd1f2117409b158ccd45c68b1d6781a9c) ) + +// ROM_LOAD16_WORD_SWAP("game.bin", 0x400000, 0x3e0000, CRC(1) SHA1(1) ) +// ROM_LOAD16_WORD_SWAP("mdos_v2.bin", 0x10000, 0x20000, CRC(b777ef96) SHA1(8efe2ec873fa4fcaddf08a2c156e540ba4a05b57) ) +// ROM_LOAD16_WORD_SWAP("os-v36.bin", 0x10000, 0x10000, CRC(ff915066) SHA1(977a8cca44ce9fa0765001f535f19390a7d8ff16) ) +// ROM_LOAD16_WORD_SWAP("os-v22.bin", 0x10000, 0x10000, CRC(22bcd1c7) SHA1(a23916e6bc1e8d8681704b774a3cbc745065d21e) ) +ROM_END + + + +const tiny_rom_entry *megadrive_hb_everdrive_device::device_rom_region() const +{ + return ROM_NAME( everdrive_md ); +} + + +void megadrive_hb_everdrive_device::device_start() +{ + m_spi_clock = timer_alloc(FUNC(megadrive_hb_everdrive_device::spi_clock_cb), this); + + save_item(NAME(m_spi_clock_state)); + save_item(NAME(m_spi_full_speed)); + save_item(NAME(m_spi_clock_cycles)); + save_item(NAME(m_in_bit)); + save_item(NAME(m_in_latch)); + save_item(NAME(m_out_latch)); + + save_item(NAME(m_vblv)); +} + +void megadrive_hb_everdrive_device::device_reset() +{ + m_vblv = 0; + m_rom_map_port = 0; + m_spi_clock->adjust(attotime::never); + m_spi_clock_cycles = 0; + m_spi_clock_state = false; + m_sdcard->spi_ss_w(0); + + m_game_mode.select(0); +} + +void megadrive_hb_everdrive_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x3f'ffff).view(m_game_mode); + m_game_mode[0](0x00'0000, 0x3f'ffff).lrw16( + NAME([this] (offs_t offset) { + return m_flash->read(offset | m_rom_map_port); + }), + NAME([this] (offs_t offset, u16 data, u16 mem_mask) { + m_flash->write(offset | m_rom_map_port, data); + }) + ); + m_game_mode[1](0x00'0000, 0x3f'ffff).lr16( + NAME([this] (offs_t offset) { + return m_flash->read(offset | 0x20'0000); + }) + ); + + // vblank redirection (for cheating), in OS mode (so at copy time) +// m_vbl_catch[0](0x00'0078, 0x00'0079).lr16(NAME([] () { return 0xff; })); +// m_vbl_catch[0](0x00'007a, 0x00'007b).lr16(NAME([this] () { return m_vblv; })); +} + +// TODO: OS range /TIME inaccessible when in game_mode +void megadrive_hb_everdrive_device::time_io_map(address_map &map) +{ + map(0x00, 0x01).rw(FUNC(megadrive_hb_everdrive_device::spi_data_r), FUNC(megadrive_hb_everdrive_device::spi_data_w)); + map(0x02, 0x03).rw(FUNC(megadrive_hb_everdrive_device::state_r), FUNC(megadrive_hb_everdrive_device::cfg_w)); + map(0x04, 0x05).lw16(NAME([this] (offs_t offset, u16 data, u16 mem_mask) { COMBINE_DATA(&m_vblv); })); + // 0x06, 0x07 SRAMB, bank select for SRAM saving + // VER, unverified, makes an 'M' to appear on bottom right (for software controlled MEGAKEY?) + map(0x08, 0x09).lr16(NAME([] () { return 13; })); + map(0x0a, 0x0b).lw16(NAME([this] (offs_t offset, u16 data, u16 mem_mask) { + if (ACCESSING_BITS_0_7) + m_rom_map_port = BIT(data, 0) ? (0x40'0000 >> 1) : 0; + })); + + // TODO: assume cloning 315-5709 for RAM_MODE_1 and SSF2_MODE +} + +u16 megadrive_hb_everdrive_device::spi_data_r(offs_t offset, u16 mem_mask) +{ + const u16 mask = m_spi_16 ? 0xffff : 0xff; + return m_in_latch & mask; +} + +void megadrive_hb_everdrive_device::spi_data_w(offs_t offset, u16 data, u16 mem_mask) +{ + COMBINE_DATA(&m_out_latch); + const u16 mask = m_spi_16 ? 0xffff : 0xff; + m_out_latch &= mask; + + m_spi_clock_cycles = m_spi_16 ? 16 : 8; + m_spi_clock_state = false; + + // Timings reported are per single byte, estimated. + // This will score a "time 1/10 sec: 96" / "speed kb/s: 105" in krikzz's benchmark + const int ticks = (m_spi_full_speed ? 16 : 128) >> 3; + m_spi_clock->adjust(attotime::from_ticks(ticks, this->clock()), 0, attotime::from_ticks(ticks, this->clock())); +} + + +u16 megadrive_hb_everdrive_device::state_r(offs_t offset, u16 mem_mask) +{ + const u8 spi_ready = m_spi_clock_cycles == 0; + return (m_sdcard->get_card_present() << 3) + // SMS key pressed if '1' + | (0 << 2) + | (m_flash->is_ready() << 1) + | spi_ready; +} + +void megadrive_hb_everdrive_device::cfg_w(offs_t offset, u16 data, u16 mem_mask) +{ + if (ACCESSING_BITS_0_7) + { + m_spi_full_speed = BIT(data, 1); + // assume negated by using #SS nomenclature + // HACK: don't change SS line if full speed is selected + if (!m_spi_full_speed) + m_sdcard->spi_ss_w(BIT(~data, 0)); + // used on dir listing onward + m_spi_16 = BIT(data, 2); + //printf("SS %d full_speed %d\n", BIT(data, 0), m_spi_full_speed); + + // guess + m_spi_clock->adjust(attotime::never); + m_spi_clock_cycles = 0; + + m_game_mode.select(BIT(data, 3)); + + // m_sms_mode = BIT(data, 4); + // m_hard_reset = BIT(data, 5); + // m_ram_mode_1 = BIT(data, 6); + // m_ram_on = BIT(data, 7); + // m_vbl_catch.select(BIT(data, 8)); + // m_megakey_on = BIT(data, 9); + // m_megakey_region_1 = BIT(data, 10); + // m_ssf2_mode = BIT(data, 11); + // m_ram_fs = BIT(data, 12); + // following is for Mega CD BIOS loading + // m_cart = BIT(data, 13); + } +} + +TIMER_CALLBACK_MEMBER(megadrive_hb_everdrive_device::spi_clock_cb) +{ + if (m_spi_clock_cycles > 0) + { + //m_sdcard->spi_ss_w(1); + + if (m_spi_clock_state) + { + m_in_latch <<= 1; + m_in_latch &= ~0x01; + m_in_latch |= m_in_bit; + + m_sdcard->spi_clock_w(1); + + m_spi_clock_cycles--; + } + else + { + m_sdcard->spi_mosi_w(BIT(m_out_latch, m_spi_16 ? 15 : 7)); + m_sdcard->spi_clock_w(0); + + m_out_latch <<= 1; + } + + m_spi_clock_state = !m_spi_clock_state; + } + else + { + //m_sdcard->spi_ss_w(0); + + m_spi_clock_state = false; + m_spi_clock->adjust(attotime::never); + } +} + diff --git a/src/devices/bus/megadrive/cart/everdrive.h b/src/devices/bus/megadrive/cart/everdrive.h new file mode 100644 index 0000000000000..7dc8f4b19f2aa --- /dev/null +++ b/src/devices/bus/megadrive/cart/everdrive.h @@ -0,0 +1,58 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese + +#ifndef MAME_BUS_MEGADRIVE_CART_EVERDRIVE_H +#define MAME_BUS_MEGADRIVE_CART_EVERDRIVE_H + +#pragma once + +#include "machine/intelfsh.h" +#include "machine/spi_sdcard.h" + +#include "slot.h" + +class megadrive_hb_everdrive_device : public device_t, + public device_megadrive_cart_interface +{ +public: + megadrive_hb_everdrive_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + static constexpr feature_type imperfect_features() { return feature::MEDIA; } + + virtual void cart_map(address_map &map) override ATTR_COLD; + virtual void time_io_map(address_map &map) override ATTR_COLD; + +protected: + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; + + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + + virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD; +private: + required_device m_flash; + required_device m_sdcard; + memory_view m_game_mode; + + TIMER_CALLBACK_MEMBER(spi_clock_cb); + u16 spi_data_r(offs_t offset, u16 mem_mask = ~0); + void spi_data_w(offs_t offset, u16 data, u16 mem_mask = ~0); + u16 state_r(offs_t offset, u16 mem_mask = ~0); + void cfg_w(offs_t offset, u16 data, u16 mem_mask = ~0); + + emu_timer *m_spi_clock; + bool m_spi_clock_state; + bool m_spi_full_speed; + int m_spi_clock_cycles; + int m_in_bit; + u16 m_in_latch; + u16 m_out_latch; + bool m_spi_16; + + u32 m_rom_map_port; + u16 m_vblv; +}; + +DECLARE_DEVICE_TYPE(MEGADRIVE_HB_EVERDRIVE, megadrive_hb_everdrive_device) + +#endif // MAME_BUS_MEGADRIVE_CART_DEV_H diff --git a/src/devices/bus/megadrive/cart/gamtec.cpp b/src/devices/bus/megadrive/cart/gamtec.cpp new file mode 100644 index 0000000000000..0a00910f1ffac --- /dev/null +++ b/src/devices/bus/megadrive/cart/gamtec.cpp @@ -0,0 +1,475 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese +/************************************************************************************************** + +Gamtec/Chuanpu/Never Ending Soft cart mappers + +Using a fixed data (discrete?) chip at $40'0000 as protection device + +**************************************************************************************************/ + +#include "emu.h" +#include "gamtec.h" + +#include "bus/generic/slot.h" + + +/* + * 16 Zhang Mahjong II + * https://segaretro.org/16_Zhang_Mahjong_II + * + * TODO: + * - unknown purpose for ports $400002 and $400006 (spotted thru DASM code analysis) + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_UNL_TILESMJ2, megadrive_unl_tilesmj2_device, "megadrive_unl_tilesmj2", "Megadrive 16 Zhang Mahjong II cart") + +megadrive_unl_tilesmj2_device::megadrive_unl_tilesmj2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, MEGADRIVE_UNL_TILESMJ2, tag, owner, clock) +{ +} + +void megadrive_unl_tilesmj2_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x3f'ffff).bankr(m_rom); +// map(0x40'0000, 0x40'0000) unused? + map(0x40'0002, 0x40'0002).lr8(NAME([] () { return 0x98; })); // PC=193c, + map(0x40'0004, 0x40'0004).lr8(NAME([] () { return 0xc9; })); // PC=3ec, startup + map(0x40'0006, 0x40'0006).lr8(NAME([] () { return 0x18; })); // PC=1626, attract +} + +/* + * Líng Huàn Dàoshi - Super Magician + * https://segaretro.org/Ling_Huan_Daoshi + * + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_UNL_ELFWOR, megadrive_unl_elfwor_device, "megadrive_unl_elfwor", "Megadrive Ling Huan Daoshi Super Magician cart") + +megadrive_unl_elfwor_device::megadrive_unl_elfwor_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, MEGADRIVE_UNL_ELFWOR, tag, owner, clock) +{ +} + +void megadrive_unl_elfwor_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x3f'ffff).bankr(m_rom); + map(0x40'0000, 0x40'0000).lr8(NAME([] () { return 0x55; })); + map(0x40'0002, 0x40'0002).lr8(NAME([] () { return 0x0f; })); + map(0x40'0004, 0x40'0004).lr8(NAME([] () { return 0xc9; })); + map(0x40'0006, 0x40'0006).lr8(NAME([] () { return 0x18; })); +} + +/* + * Huan Le Tao Qi Shu: Smart Mouse (huanle original set, not the Piko Interactive 2017 re-release) + * https://segaretro.org/Huan_Le_Tao_Qi_Shu:_Smart_Mouse + * + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_UNL_SMOUSE, megadrive_unl_smouse_device, "megadrive_unl_smouse", "Megadrive Huan Le Tao Qi Shu Smart Mouse cart") + +megadrive_unl_smouse_device::megadrive_unl_smouse_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, MEGADRIVE_UNL_SMOUSE, tag, owner, clock) +{ +} + +void megadrive_unl_smouse_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x3f'ffff).bankr(m_rom); + map(0x40'0000, 0x40'0000).lr8(NAME([] () { return 0x55; })); + map(0x40'0002, 0x40'0002).lr8(NAME([] () { return 0x0f; })); + map(0x40'0004, 0x40'0004).lr8(NAME([] () { return 0xaa; })); + map(0x40'0006, 0x40'0006).lr8(NAME([] () { return 0xf0; })); +} + +/* + * Ya Se Chuan Shuo / Wu Kong Wai Zhuan + * https://segaretro.org/Ya_Se_Chuan_Shuo + * https://segaretro.org/Wu_Kong_Wai_Zhuan + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_UNL_YASECH, megadrive_unl_yasech_device, "megadrive_unl_yasech", "Megadrive Ya Se Chuan Shuo cart") + +megadrive_unl_yasech_device::megadrive_unl_yasech_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, MEGADRIVE_UNL_YASECH, tag, owner, clock) + , m_nvram(*this, "nvram") +{ +} + +void megadrive_unl_yasech_device::device_add_mconfig(machine_config &config) +{ + // init doesn't really matter: game specifically looks for a specific header pattern at tail + // (0x06, 0x09, 0x01, 0x08) in both banks, flushing to 0 if not found. + NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_1); +} + +void megadrive_unl_yasech_device::device_start() +{ + megadrive_rom_device::device_start(); + const u32 nvram_size = 0x1000; + m_nvram_ptr = std::make_unique(nvram_size); + m_nvram->set_base(m_nvram_ptr.get(), nvram_size); + + save_pointer(NAME(m_nvram_ptr), nvram_size); +} + +u16 megadrive_unl_yasech_device::nvram_r(offs_t offset) +{ + const u32 nvram_offset = offset & 0xfff; + return 0xff00 | m_nvram_ptr[nvram_offset]; +} + +void megadrive_unl_yasech_device::nvram_w(offs_t offset, u16 data, u16 mem_mask) +{ + if (ACCESSING_BITS_0_7) + { + const u32 nvram_offset = offset & 0xfff; + m_nvram_ptr[nvram_offset] = data & 0xff; + } +} + + +void megadrive_unl_yasech_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x3f'ffff).bankr(m_rom); + map(0x20'0000, 0x20'1fff).rw(FUNC(megadrive_unl_yasech_device::nvram_r), FUNC(megadrive_unl_yasech_device::nvram_w)); + map(0x40'0000, 0x40'0000).lr8(NAME([] () { return 0x63; })); + map(0x40'0002, 0x40'0002).lr8(NAME([] () { return 0x98; })); + map(0x40'0004, 0x40'0004).lr8(NAME([] () { return 0xc9; })); + map(0x40'0006, 0x40'0006).lr8(NAME([] () { return 0x18; })); +} + +/* + * Meng Huan Shui Guo Pan: 777 Casino + * https://segaretro.org/Meng_Huan_Shui_Guo_Pan:_777_Casino + * + * Protection check here is subtle: it's done from Z80 space when new game is selected. + * If fails, going in a parlor and talk with a cashier twice will crash the game by Z80 trashing + * work RAM. + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_UNL_777CASINO, megadrive_unl_777casino_device, "megadrive_unl_777casino", "Megadrive 777 Casino cart") + +megadrive_unl_777casino_device::megadrive_unl_777casino_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, MEGADRIVE_UNL_777CASINO, tag, owner, clock) +{ +} + +void megadrive_unl_777casino_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x3f'ffff).bankr(m_rom); + // TODO: unconfirmed values (carried over from GPGX) + map(0x40'0000, 0x40'0000).lr8(NAME([] () { return 0x63; })); + map(0x40'0002, 0x40'0002).lr8(NAME([] () { return 0x98; })); + map(0x40'0004, 0x40'0004).lr8(NAME([] () { return 0xc9; })); + map(0x40'0006, 0x40'0006).lr8(NAME([] () { return 0x18; })); +} + +/* + * Soul Blade + * https://segaretro.org/Soul_Blade + * + * Game also implements self-modifying code at PC=28026 .. PC=28066, presumably against copiers + * + * Shi San Zhang Ma Jiang: Zhong Guo Mei Nv Pian + * (assumed, only $40'0004 checked on title to gameplay transition) + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_UNL_SOULBLADE, megadrive_unl_soulblade_device, "megadrive_unl_soulblade", "Megadrive Soul Blade cart") + +megadrive_unl_soulblade_device::megadrive_unl_soulblade_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, MEGADRIVE_UNL_SOULBLADE, tag, owner, clock) +{ +} + +void megadrive_unl_soulblade_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x3f'ffff).bankr(m_rom); + // unknown, assuming same as other entries + map(0x40'0000, 0x40'0000).lr8(NAME([] () { return 0x63; })); + // alt value on fight startup (PC=28B62 #-$68), unused? + map(0x40'0002, 0x40'0002).lr8(NAME([] () { return 0x98; })); + // after set amount of blocks/damage during fights (PC=2844C #-$56 or #-$37), causes GFX garbage + map(0x40'0004, 0x40'0004).lr8(NAME([] () { return 0xc9; })); + // on fight startup, twice (PC=28B58 #-$10), locks up if unhappy + map(0x40'0006, 0x40'0006).lr8(NAME([] () { return 0xf0; })); +} + +/* + * Super Bubble Bobble MD + * https://segaretro.org/Super_Bubble_Bobble_MD + * https://bootleggames.fandom.com/wiki/Super_Bubble_Bobble_MD + * + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_UNL_SUPRBUBL, megadrive_unl_suprbubl_device, "megadrive_unl_suprbubl", "Megadrive Super Bubble Bobble cart") + +megadrive_unl_suprbubl_device::megadrive_unl_suprbubl_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, MEGADRIVE_UNL_SUPRBUBL, tag, owner, clock) +{ +} + +void megadrive_unl_suprbubl_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x3f'ffff).bankr(m_rom); + // just checked once, on startup + map(0x40'0000, 0x40'0000).lr8(NAME([] () { return 0x55; })); + map(0x40'0002, 0x40'0002).lr8(NAME([] () { return 0x0f; })); +} + +/* + * Chao Ji Mahjong Club + * https://segaretro.org/Chao_Ji_Mahjong_Club + * + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_UNL_CJMJCLUB, megadrive_unl_cjmjclub_device, "megadrive_unl_cjmjclub", "Megadrive Chao Ji Mahjong Club cart") + +megadrive_unl_cjmjclub_device::megadrive_unl_cjmjclub_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, MEGADRIVE_UNL_CJMJCLUB, tag, owner, clock) +{ +} + +void megadrive_unl_cjmjclub_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x3f'ffff).bankr(m_rom); + // at startup, passed as dword to $ffff08 + map(0x40'0000, 0x40'0000).lr8(NAME([] () { return 0x90; })); + map(0x40'0002, 0x40'0002).lr8(NAME([] () { return 0xd3; })); +} + +/* + * Creaton Softech published games (beyond the one above) + * + * majianqr https://segaretro.org/Ma_Jiang_Qing_Ren:_Ji_Ma_Jiang_Zhi + * fengkuan https://segaretro.org/Feng_Kuang_Tao_Hua_Yuan + * mhpoker https://segaretro.org/Du_Shen_Zhi_Meng_Huan_Poker + * btlchess https://segaretro.org/Zhan_Qi_Chinese_Battle_Chess + * + * Uses $400000, $401000 instead of the usual linear mapping (just hooked up differently?) + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_UNL_MJLOV, megadrive_unl_mjlov_device, "megadrive_unl_mjlov", "Megadrive Creaton Softec cart") + +megadrive_unl_mjlov_device::megadrive_unl_mjlov_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, MEGADRIVE_UNL_MJLOV, tag, owner, clock) +{ +} + +void megadrive_unl_mjlov_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x3f'ffff).bankr(m_rom); + map(0x40'0000, 0x40'0000).lr8(NAME([] () { return 0x90; })); + map(0x40'1000, 0x40'1000).lr8(NAME([] () { return 0xd3; })); +} + +/* + * San Guo Yan Yi: Huo Shao Chi Bi / The Battle of Red Cliffs + * https://segaretro.org/San_Guo_Yan_Yi:_Huo_Shao_Chi_Bi + * + * Slight ROM encryption + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_UNL_REDCLIFF, megadrive_unl_redcliff_device, "megadrive_unl_redcliff", "Megadrive Battle of Red Cliffs cart") + + +megadrive_unl_redcliff_device::megadrive_unl_redcliff_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, MEGADRIVE_UNL_REDCLIFF, tag, owner, clock) + , device_megadrive_cart_interface( mconfig, *this ) + , m_rom(*this, "rom") +{ +} + +void megadrive_unl_redcliff_device::device_start() +{ + memory_region *const romregion(cart_rom_region()); + m_decrypted_rom.resize(0x40'0000); + + auto enc = &romregion->as_u8(); + int i; + + std::fill(m_decrypted_rom.begin(), m_decrypted_rom.end(), 0xff ^ 0x40); + + // NOTE: dump is oversized, original in .mdx format? + for (i = 4; i < romregion->bytes(); i++) + m_decrypted_rom[i - 4] = enc[i] ^ 0x40; + + m_rom->configure_entry(0, &m_decrypted_rom[0]); +} + +void megadrive_unl_redcliff_device::device_reset() +{ +} + +void megadrive_unl_redcliff_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x3f'ffff).bankr(m_rom); + // NOTE: may not even use the same "chip" described in this file + // gameplay + map(0x40'0000, 0x40'0000).lr8(NAME([] () { return 0x55; })); + // startup + map(0x40'0004, 0x40'0004).lr8(NAME([] () { return 0xaa; })); +} + +/* + * Squirrel King + * https://segaretro.org/Squirrel_King + * + * Uses area $400000-$400006 as r/w latch + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_UNL_SQUIRRELK, megadrive_unl_squirrelk_device, "megadrive_unl_squirrelk", "Megadrive Squirrel King cart") + +megadrive_unl_squirrelk_device::megadrive_unl_squirrelk_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, MEGADRIVE_UNL_SQUIRRELK, tag, owner, clock) +{ +} + +void megadrive_unl_squirrelk_device::device_start() +{ + megadrive_rom_device::device_start(); + save_item(NAME(m_latch)); +} + +void megadrive_unl_squirrelk_device::device_reset() +{ + megadrive_rom_device::device_reset(); + // irrelevant, initialized at startup + m_latch = 0xff; +} + +void megadrive_unl_squirrelk_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x3f'ffff).bankr(m_rom); + map(0x40'0000, 0x40'0000).select(6).lrw8( + NAME([this] (offs_t offset) { + return m_latch; + }), + NAME([this] (offs_t offset, u8 data) { + m_latch = data; + }) + ); +} + +/* + * The Lion King II + * https://segaretro.org/The_Lion_King_II + * + * Similar to above except two latches instead of one + * Game also implements self-modifying code at PC=808DA .. PC=8095A, presumably against copiers + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_UNL_LIONKING2, megadrive_unl_lionking2_device, "megadrive_unl_lionking2", "Megadrive The Lion King II cart") + +megadrive_unl_lionking2_device::megadrive_unl_lionking2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, MEGADRIVE_UNL_LIONKING2, tag, owner, clock) +{ +} + +void megadrive_unl_lionking2_device::device_start() +{ + megadrive_rom_device::device_start(); + save_pointer(NAME(m_latch), 2); +} + +void megadrive_unl_lionking2_device::device_reset() +{ + megadrive_rom_device::device_reset(); + // irrelevant, initialized at startup + m_latch[0] = m_latch[1] = 0xff; +} + +void megadrive_unl_lionking2_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x3f'ffff).bankr(m_rom); + map(0x40'0000, 0x40'0000).select(4).lw8( + NAME([this] (offs_t offset, u8 data) { + m_latch[offset] = data; + }) + ); + map(0x40'0002, 0x40'0002).select(4).lr8( + NAME([this] (offs_t offset, u8 data) { + return m_latch[offset]; + }) + ); +} + +/* + * Tenchi o Kurau III: Sangoku Gaiden / Tun Shi Tian Di 3: San Guo Wai Chuan / Chinese Fighter III + * https://segaretro.org/Tenchi_o_Kurau_III:_Sangoku_Gaiden + * + * Pseudo-banking scheme looks similar to Top Fighter, otherwise using Squirrel King latching + * obfuscated by address lanes. + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_UNL_CHINF3, megadrive_unl_chinf3_device, "megadrive_unl_chinf3", "Megadrive Chinese Fighter III cart") + +megadrive_unl_chinf3_device::megadrive_unl_chinf3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, MEGADRIVE_UNL_CHINF3, tag, owner, clock) + , m_page_rom(*this, "page_rom") + , m_page_view(*this, "page_view") +{ +} + +void megadrive_unl_chinf3_device::device_start() +{ + megadrive_rom_device::device_start(); + memory_region *const romregion(cart_rom_region()); + const u32 page_size = 0x01'0000; + device_generic_cart_interface::map_non_power_of_two( + unsigned(romregion->bytes() / page_size), + [this, base = &romregion->as_u8()] (unsigned entry, unsigned page) + { + m_page_rom->configure_entry(entry, &base[page * page_size]); + }); + + save_pointer(NAME(m_prot_latch), 4); +} + +void megadrive_unl_chinf3_device::device_reset() +{ + megadrive_rom_device::device_reset(); + m_page_view.select(0); + std::fill_n(&m_prot_latch[0], 4, 0xff); +} + +void megadrive_unl_chinf3_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x1f'ffff).view(m_page_view); + m_page_view[0](0x00'0000, 0x1f'ffff).bankr(m_rom); + m_page_view[1](0x00'0000, 0x00'ffff).mirror(0x1f'0000).bankr(m_page_rom); + map(0x40'0000, 0x40'0000).select(0xc).mirror(0x0f'fff3).lrw8( + NAME([this] (offs_t offset) { + return m_prot_latch[offset >> 2]; + }), + NAME([this] (offs_t offset, u8 data) { + m_prot_latch[offset >> 2] = data; + }) + ); + map(0x60'0000, 0x60'0000).mirror(0x0f'ffff).lw8( + NAME([this] (offs_t offset, u8 data) { + if (data) + { + m_page_rom->set_entry(data & 0xf); + m_page_view.select(1); + } + else + { + m_page_view.select(0); + } + }) + ); +} diff --git a/src/devices/bus/megadrive/cart/gamtec.h b/src/devices/bus/megadrive/cart/gamtec.h new file mode 100644 index 0000000000000..05219bc868f1d --- /dev/null +++ b/src/devices/bus/megadrive/cart/gamtec.h @@ -0,0 +1,171 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese + +#ifndef MAME_BUS_MEGADRIVE_CART_GAMTEC_H +#define MAME_BUS_MEGADRIVE_CART_GAMTEC_H + +#pragma once + +#include "machine/nvram.h" + +#include "rom.h" +#include "slot.h" + +class megadrive_unl_tilesmj2_device : public megadrive_rom_device +{ +public: + megadrive_unl_tilesmj2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; +}; + +class megadrive_unl_elfwor_device : public megadrive_rom_device +{ +public: + megadrive_unl_elfwor_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; +}; + +class megadrive_unl_smouse_device : public megadrive_rom_device +{ +public: + megadrive_unl_smouse_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; +}; + +class megadrive_unl_yasech_device : public megadrive_rom_device +{ +public: + megadrive_unl_yasech_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; + +protected: + virtual void device_start() override ATTR_COLD; + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; + + u16 nvram_r(offs_t offset); + void nvram_w(offs_t offset, u16 data, u16 mem_mask); + +private: + required_device m_nvram; + std::unique_ptr m_nvram_ptr; + +}; + +class megadrive_unl_777casino_device : public megadrive_rom_device +{ +public: + megadrive_unl_777casino_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; +}; + +class megadrive_unl_soulblade_device : public megadrive_rom_device +{ +public: + megadrive_unl_soulblade_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; +}; + +class megadrive_unl_suprbubl_device : public megadrive_rom_device +{ +public: + megadrive_unl_suprbubl_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; +}; + +class megadrive_unl_cjmjclub_device : public megadrive_rom_device +{ +public: + megadrive_unl_cjmjclub_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; +}; + +class megadrive_unl_mjlov_device : public megadrive_rom_device +{ +public: + megadrive_unl_mjlov_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; +}; + +class megadrive_unl_redcliff_device : public device_t, + public device_megadrive_cart_interface +{ +public: + megadrive_unl_redcliff_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; +protected: + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + +// bool check_rom(std::string &message) ATTR_COLD; + memory_bank_creator m_rom; + std::vector m_decrypted_rom; +}; + +class megadrive_unl_squirrelk_device : public megadrive_rom_device +{ +public: + megadrive_unl_squirrelk_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; +protected: + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; +private: + u8 m_latch; +}; + +class megadrive_unl_lionking2_device : public megadrive_rom_device +{ +public: + megadrive_unl_lionking2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; +protected: + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; +private: + u8 m_latch[2]; +}; + +class megadrive_unl_chinf3_device : public megadrive_rom_device +{ +public: + megadrive_unl_chinf3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; +protected: + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; +private: + memory_bank_creator m_page_rom; + memory_view m_page_view; + + u8 m_prot_latch[4]; +}; + + +DECLARE_DEVICE_TYPE(MEGADRIVE_UNL_TILESMJ2, megadrive_unl_tilesmj2_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_UNL_ELFWOR, megadrive_unl_elfwor_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_UNL_SMOUSE, megadrive_unl_smouse_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_UNL_YASECH, megadrive_unl_yasech_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_UNL_777CASINO, megadrive_unl_777casino_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_UNL_SOULBLADE, megadrive_unl_soulblade_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_UNL_SUPRBUBL, megadrive_unl_suprbubl_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_UNL_CJMJCLUB, megadrive_unl_cjmjclub_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_UNL_MJLOV, megadrive_unl_mjlov_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_UNL_REDCLIFF, megadrive_unl_redcliff_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_UNL_SQUIRRELK, megadrive_unl_squirrelk_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_UNL_LIONKING2, megadrive_unl_lionking2_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_UNL_CHINF3, megadrive_unl_chinf3_device) + +#endif // MAME_BUS_MEGADRIVE_CART_GAMTEC_H diff --git a/src/devices/bus/megadrive/cart/jcart.cpp b/src/devices/bus/megadrive/cart/jcart.cpp new file mode 100644 index 0000000000000..4a0b42ba30566 --- /dev/null +++ b/src/devices/bus/megadrive/cart/jcart.cpp @@ -0,0 +1,177 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese, Fabio Priuli +/************************************************************************************************** + +Codemasters J-Cart + +Two extra ports mounted on cart + +TODO: +- Starting at 3 with control ports doesn't work well for Teradrive (will map to P5/P6, before + system ports) + +**************************************************************************************************/ + +#include "emu.h" +#include "jcart.h" + +#include "bus/sms_ctrl/controllers.h" + +/* + * Pete Sampras Tennis + * + * Maps J-Cart to 0x3f'fffe in place of 0x38'fffe of all the others. + * sampras set will hang, sampras1/sampras2 won't but still won't give 4p option + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_ROM_JCART_SAMPRAS, megadrive_rom_jcart_sampras_device, "megadrive_rom_jcart_sampras", "Megadrive J-Cart Pete Sampras Tennis cart") + +megadrive_rom_jcart_sampras_device::megadrive_rom_jcart_sampras_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, type, tag, owner, clock) + , m_ctrl_ports(*this, "control%u", 3U) +{ +} + +megadrive_rom_jcart_sampras_device::megadrive_rom_jcart_sampras_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_jcart_sampras_device(mconfig, MEGADRIVE_ROM_JCART_SAMPRAS, tag, owner, clock) +{ +} + +void megadrive_rom_jcart_sampras_device::device_add_mconfig(machine_config &config) +{ + SMS_CONTROL_PORT(config, m_ctrl_ports[0], sms_control_port_devices, SMS_CTRL_OPTION_MD_PAD); + m_ctrl_ports[0]->th_handler().set(FUNC(megadrive_rom_jcart_sampras_device::th_in<0>)); + + SMS_CONTROL_PORT(config, m_ctrl_ports[1], sms_control_port_devices, SMS_CTRL_OPTION_MD_PAD); + m_ctrl_ports[1]->th_handler().set(FUNC(megadrive_rom_jcart_sampras_device::th_in<1>)); +} + + +void megadrive_rom_jcart_sampras_device::device_start() +{ + megadrive_rom_device::device_start(); + save_item(NAME(m_th_in)); + save_item(NAME(m_th_out)); +} + +void megadrive_rom_jcart_sampras_device::device_reset() +{ + megadrive_rom_device::device_reset(); + m_th_in[0] = m_th_in[1] = 0x40; + m_th_out = 0x40; +} + +template +void megadrive_rom_jcart_sampras_device::th_in(int state) +{ + m_th_in[N] = state ? 0x40 : 0x00; +} + +u16 megadrive_rom_jcart_sampras_device::jcart_r(offs_t offset, u16 mem_mask) +{ + u8 const ctrl3 = (m_ctrl_ports[0]->in_r() & 0x3f) | (m_th_in[0] & m_th_out) | 0x80; + u8 const ctrl4 = (m_ctrl_ports[1]->in_r() & 0x3f) | (m_th_in[1] & m_th_out) | 0x80; + return ctrl3 | (ctrl4 << 8); +} + +void megadrive_rom_jcart_sampras_device::jcart_w(offs_t offset, u16 data, u16 mem_mask) +{ + // assume TH only actively driven low + m_th_out = BIT(data, 0) << 6; + m_ctrl_ports[0]->out_w(m_th_out | 0x3f, ~m_th_out & 0x40); + m_ctrl_ports[1]->out_w(m_th_out | 0x3f, ~m_th_out & 0x40); +} + +void megadrive_rom_jcart_sampras_device::cart_map(address_map &map) +{ + map(0x00'0000, m_rom_mask).mirror(m_rom_mirror).bankr(m_rom); + map(0x3f'fffe, 0x3f'ffff).rw(FUNC(megadrive_rom_jcart_sampras_device::jcart_r), FUNC(megadrive_rom_jcart_sampras_device::jcart_w)); +} + +/* + * Super Skidmarks / Pete Sampras Tennis '96 + * + * Relocated J-Cart position + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_ROM_JCART_SSKID, megadrive_rom_jcart_sskid_device, "megadrive_rom_jcart_sskid", "Megadrive J-Cart Super Skidmarks cart") + +megadrive_rom_jcart_sskid_device::megadrive_rom_jcart_sskid_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_jcart_sampras_device(mconfig, MEGADRIVE_ROM_JCART_SSKID, tag, owner, clock) +{ +} + +void megadrive_rom_jcart_sskid_device::cart_map(address_map &map) +{ + map(0x00'0000, m_rom_mask).mirror(m_rom_mirror).bankr(m_rom); + map(0x38'fffe, 0x38'ffff).rw(FUNC(megadrive_rom_jcart_sskid_device::jcart_r), FUNC(megadrive_rom_jcart_sskid_device::jcart_w)); +} + +/* + * Micro Machines 2 / Micro Machines Military + * + * Adds an I2C to the bus + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_ROM_JCART_MICROMAC2, megadrive_rom_jcart_micromac2_device, "megadrive_rom_jcart_micromac2", "Megadrive J-Cart Micro Machines 2 cart") + +megadrive_rom_jcart_micromac2_device::megadrive_rom_jcart_micromac2_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_jcart_sampras_device(mconfig, type, tag, owner, clock) + , m_i2cmem(*this, "i2cmem") +{ +} + +megadrive_rom_jcart_micromac2_device::megadrive_rom_jcart_micromac2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_jcart_micromac2_device(mconfig, MEGADRIVE_ROM_JCART_MICROMAC2, tag, owner, clock) +{ +} + + +void megadrive_rom_jcart_micromac2_device::device_add_mconfig(machine_config &config) +{ + megadrive_rom_jcart_sampras_device::device_add_mconfig(config); + + I2C_24C08(config, m_i2cmem); +} + +void megadrive_rom_jcart_micromac2_device::cart_map(address_map &map) +{ + map(0x00'0000, m_rom_mask).mirror(m_rom_mirror).bankr(m_rom); + map(0x30'0000, 0x30'0000).lw8( + NAME([this] (offs_t offset, u8 data) { + m_i2cmem->write_scl(BIT(data, 1)); + m_i2cmem->write_sda(BIT(data, 0)); + }) + ); + map(0x38'0001, 0x38'0001).lr8( + NAME([this] (offs_t offset) { + return m_i2cmem->read_sda() << 7; + }) + ); + map(0x38'fffe, 0x38'ffff).rw(FUNC(megadrive_rom_jcart_micromac2_device::jcart_r), FUNC(megadrive_rom_jcart_micromac2_device::jcart_w)); +} + +/* + * Micro Machines Turbo Tournament 96 + * + * Bumps I2C, otherwise same as 2 + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_ROM_JCART_MICROMAC96, megadrive_rom_jcart_micromac96_device, "megadrive_rom_jcart_micromac96", "Megadrive J-Cart Micro Machines 96 cart") + +megadrive_rom_jcart_micromac96_device::megadrive_rom_jcart_micromac96_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_jcart_micromac2_device(mconfig, MEGADRIVE_ROM_JCART_MICROMAC96, tag, owner, clock) +{ +} + +void megadrive_rom_jcart_micromac96_device::device_add_mconfig(machine_config &config) +{ + megadrive_rom_jcart_micromac2_device::device_add_mconfig(config); + + I2C_24C16(config.replace(), m_i2cmem); +} + diff --git a/src/devices/bus/megadrive/cart/jcart.h b/src/devices/bus/megadrive/cart/jcart.h new file mode 100644 index 0000000000000..8cc91320a37a9 --- /dev/null +++ b/src/devices/bus/megadrive/cart/jcart.h @@ -0,0 +1,79 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese, Fabio Priuli + +#ifndef MAME_BUS_MEGADRIVE_CART_JCART_H +#define MAME_BUS_MEGADRIVE_CART_JCART_H + +#pragma once + +#include "bus/sms_ctrl/smsctrl.h" +#include "machine/i2cmem.h" + +#include "rom.h" +#include "slot.h" + +class megadrive_rom_jcart_sampras_device : public megadrive_rom_device +{ +public: + megadrive_rom_jcart_sampras_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; +protected: + megadrive_rom_jcart_sampras_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; + + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + + u16 jcart_r(offs_t offset, u16 mem_mask = ~0); + void jcart_w(offs_t offset, u16 data, u16 mem_mask = ~0); + +private: + template void th_in(int state); + + required_device_array m_ctrl_ports; + uint8_t m_th_in[2]; + uint8_t m_th_out; +}; + +class megadrive_rom_jcart_sskid_device : public megadrive_rom_jcart_sampras_device +{ +public: + megadrive_rom_jcart_sskid_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; +}; + +class megadrive_rom_jcart_micromac2_device : public megadrive_rom_jcart_sampras_device +{ +public: + megadrive_rom_jcart_micromac2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; + +protected: + megadrive_rom_jcart_micromac2_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; + + required_device m_i2cmem; +}; + +class megadrive_rom_jcart_micromac96_device : public megadrive_rom_jcart_micromac2_device +{ +public: + megadrive_rom_jcart_micromac96_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; +}; + + +DECLARE_DEVICE_TYPE(MEGADRIVE_ROM_JCART_SAMPRAS, megadrive_rom_jcart_sampras_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_ROM_JCART_SSKID, megadrive_rom_jcart_sskid_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_ROM_JCART_MICROMAC2, megadrive_rom_jcart_micromac2_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_ROM_JCART_MICROMAC96, megadrive_rom_jcart_micromac96_device) + + +#endif // MAME_BUS_MEGADRIVE_CART_JCART_H diff --git a/src/devices/bus/megadrive/cart/mcpirate.cpp b/src/devices/bus/megadrive/cart/mcpirate.cpp new file mode 100644 index 0000000000000..57f902286fa2b --- /dev/null +++ b/src/devices/bus/megadrive/cart/mcpirate.cpp @@ -0,0 +1,225 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese +/************************************************************************************************** + +X-in-1 pirate multigame handling (with actual menu vs. /VRES in multigame) + +https://segaretro.org/Mega_Drive_unlicensed_multi-carts_(S_series) + +TODO: +- wisdomtc may use a single mapper bank granularity of $80000 + +**************************************************************************************************/ + +#include "emu.h" +#include "mcpirate.h" + +#include "bus/generic/slot.h" + +DEFINE_DEVICE_TYPE(MEGADRIVE_MCPIRATE, megadrive_mcpirate_device, "megadrive_mcpirate", "Megadrive multigame pirate cart") + +megadrive_mcpirate_device::megadrive_mcpirate_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, MEGADRIVE_MCPIRATE, tag, owner, clock) + , device_megadrive_cart_interface( mconfig, *this ) + , m_rom_bank(*this, "rom_bank_%u", 0U) +{ +} + +void megadrive_mcpirate_device::device_start() +{ + memory_region *const romregion(cart_rom_region()); + const u32 page_size = 0x02'0000; + m_bank_mask = device_generic_cart_interface::map_non_power_of_two( + unsigned(romregion->bytes() / page_size), + [this, base = &romregion->as_u8()] (unsigned entry, unsigned page) + { + for (int i = 0; i < 4; i++) + m_rom_bank[i]->configure_entry(entry, &base[page * page_size]); + }); + logerror("Bank mask %02x\n", m_bank_mask); +} + +void megadrive_mcpirate_device::device_reset() +{ + for (int i = 0; i < 4; i++) + m_rom_bank[i]->set_entry(i); +} + +void megadrive_mcpirate_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x01'ffff).mirror(0x38'0000).bankr(m_rom_bank[0]); + map(0x02'0000, 0x03'ffff).mirror(0x38'0000).bankr(m_rom_bank[1]); + map(0x04'0000, 0x05'ffff).mirror(0x38'0000).bankr(m_rom_bank[2]); + map(0x06'0000, 0x07'ffff).mirror(0x38'0000).bankr(m_rom_bank[3]); +} + + +void megadrive_mcpirate_device::time_io_map(address_map &map) +{ + map(0x00, 0x00).select(0x3e).lw8( + NAME([this] (offs_t offset, u8 data) { + (void)data; + const u8 page_sel = offset >> 1; + logerror("Bank select %02x\n", page_sel); + for (int i = 0; i < 4; i++) + m_rom_bank[i]->set_entry((page_sel + i) & m_bank_mask); + }) + ); +} + +/* + * 1800-in-1 mapper + * + * https://segaretro.org/Mega_Drive_unlicensed_multi-carts_(unsorted;_9_in_1)#9_in_1 + * + * Changes bank on strobe reads, shuffled. + * All Sega references looks either skipped or patched. + * + * Mapping (from 9-in-1 menu): + * | gamename | log | phy | + * | 0001 RABO III | 18 | 02 | + * | 0002 SPACE INVADERS | 00 | 00 | + * | 0003 SUPPER VOLLEY BALL | 1c | 06 | + * | 0004 KLAX | 0a | 08 | + * | 0005 PACMANIA | 1a | 0a | + * | 0006 TECMO WORLD CAP 92 | 0e | 0c | + * | 0007 DOUBLE CLUTCH | 04 | 04 | + * | 0008 COLUMNS | 1e | 0e | + * | 0009 BLOCK OUT | 7e | 0f | + * + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_18KIN1, megadrive_18kin1_device, "megadrive_18kin1", "Megadrive 1800-in-1 pirate cart") + +megadrive_18kin1_device::megadrive_18kin1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, MEGADRIVE_18KIN1, tag, owner, clock) + , device_megadrive_cart_interface( mconfig, *this ) + , m_rom_bank(*this, "rom_bank_%u", 0U) + , m_config(*this, "CONFIG") +{ +} + +void megadrive_18kin1_device::device_start() +{ + memory_region *const romregion(cart_rom_region()); + const u32 page_size = 0x02'0000; + m_bank_mask = device_generic_cart_interface::map_non_power_of_two( + unsigned(romregion->bytes() / page_size), + [this, base = &romregion->as_u8()] (unsigned entry, unsigned page) + { + for (int i = 0; i < 4; i++) + m_rom_bank[i]->configure_entry(entry, &base[page * page_size]); + }); + logerror("Bank mask %02x\n", m_bank_mask); +} + +void megadrive_18kin1_device::device_reset() +{ + for (int i = 0; i < 4; i++) + m_rom_bank[i]->set_entry(i); +} + +INPUT_PORTS_START( _18kin1 ) + // Menu reads /time register contents for number of entries displayed. + // This doesn't change the number of actual games. + // TODO: dips or jumpers? + PORT_START("CONFIG") + PORT_CONFNAME(0x03, 0x03, "Menu title") + PORT_CONFSETTING( 0x00, "9 in 1") + PORT_CONFSETTING( 0x01, "190 in 1") + PORT_CONFSETTING( 0x02, "888 in 1") + PORT_CONFSETTING( 0x03, "1800 in 1") +INPUT_PORTS_END + +ioport_constructor megadrive_18kin1_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( _18kin1 ); +} + +void megadrive_18kin1_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x01'ffff).mirror(0x38'0000).bankr(m_rom_bank[0]); + map(0x02'0000, 0x03'ffff).mirror(0x38'0000).bankr(m_rom_bank[1]); + map(0x04'0000, 0x05'ffff).mirror(0x38'0000).bankr(m_rom_bank[2]); + map(0x06'0000, 0x07'ffff).mirror(0x38'0000).bankr(m_rom_bank[3]); +} + +void megadrive_18kin1_device::time_io_map(address_map &map) +{ + map(0x01, 0x01).select(0x7e).lr8( + NAME([this] (offs_t offset) { + const u8 page_sel = bitswap<4>(offset, 1, 2, 4, 5); + logerror("Bank select log: %02x phy: %02x & %02x\n", offset, page_sel, m_bank_mask); + if (!machine().side_effects_disabled()) + { + for (int i = 0; i < 4; i++) + m_rom_bank[i]->set_entry((page_sel + i) & m_bank_mask); + } + return m_config->read() & 3; + }) + ); +} + +/* + * Golden Mega 250-in-1 + * + * Sonic 2, Alex Kidd, Trampoline Terror and Tecmo Cup Football Game (the Captain Tsubasa prototype) + * mixed in 250 variants ... + * + * | gamename | log | phy | + * | 001. SONIC 2 | 11 | 04 | + * | 013. TECMO CUP SOCCER IV | a0 | 02 | + * | 030. ALEX KIDD | 40 | 01 | + * | 063. TRAMPOLINE TERROR | 00 | 00 | + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_GOLDM250, megadrive_goldm250_device, "megadrive_goldm250", "Megadrive Golden Mega 250-in-1 pirate cart") + +megadrive_goldm250_device::megadrive_goldm250_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, MEGADRIVE_GOLDM250, tag, owner, clock) + , device_megadrive_cart_interface( mconfig, *this ) + , m_rom_bank(*this, "rom_bank_%u", 0U) +{ +} + +void megadrive_goldm250_device::device_start() +{ + memory_region *const romregion(cart_rom_region()); + const u32 page_size = 0x04'0000; + m_bank_mask = device_generic_cart_interface::map_non_power_of_two( + unsigned(romregion->bytes() / page_size), + [this, base = &romregion->as_u8()] (unsigned entry, unsigned page) + { + for (int i = 0; i < 4; i++) + m_rom_bank[i]->configure_entry(entry, &base[page * page_size]); + }); + logerror("Bank mask %02x\n", m_bank_mask); +} + +void megadrive_goldm250_device::device_reset() +{ + for (int i = 0; i < 4; i++) + m_rom_bank[i]->set_entry(i); +} + +void megadrive_goldm250_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x03'ffff).mirror(0x30'0000).bankr(m_rom_bank[0]); + map(0x04'0000, 0x07'ffff).mirror(0x30'0000).bankr(m_rom_bank[1]); + map(0x08'0000, 0x0b'ffff).mirror(0x30'0000).bankr(m_rom_bank[2]); + map(0x0c'0000, 0x0f'ffff).mirror(0x30'0000).bankr(m_rom_bank[3]); + map(0x08'9000, 0x08'9001).lw16(NAME([this] (offs_t offset, u16 data, u16 mem_mask) { + // writes in word units + if (ACCESSING_BITS_0_7) + { + const u8 page_sel = bitswap<3>(data, 0, 7, 6); + logerror("Bank select log: %02x phy: %02x & %02x\n", data, page_sel, m_bank_mask); + for (int i = 0; i < 4; i++) + m_rom_bank[i]->set_entry((page_sel + i) & m_bank_mask); + } + })); +} + + diff --git a/src/devices/bus/megadrive/cart/mcpirate.h b/src/devices/bus/megadrive/cart/mcpirate.h new file mode 100644 index 0000000000000..b0766b8f0955c --- /dev/null +++ b/src/devices/bus/megadrive/cart/mcpirate.h @@ -0,0 +1,75 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese + +#ifndef MAME_BUS_MEGADRIVE_CART_MCPIRATE_H +#define MAME_BUS_MEGADRIVE_CART_MCPIRATE_H + +#pragma once + +#include "slot.h" + +class megadrive_mcpirate_device : public device_t, + public device_megadrive_cart_interface +{ +public: + megadrive_mcpirate_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; + virtual void time_io_map(address_map &map) override ATTR_COLD; + +protected: + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + +private: + memory_bank_array_creator<4> m_rom_bank; + + u8 m_bank_mask; +}; + +class megadrive_18kin1_device : public device_t, + public device_megadrive_cart_interface +{ +public: + megadrive_18kin1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; + virtual void time_io_map(address_map &map) override ATTR_COLD; + +protected: + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + virtual ioport_constructor device_input_ports() const override ATTR_COLD; + +private: + memory_bank_array_creator<4> m_rom_bank; + required_ioport m_config; + + u8 m_bank_mask; +}; + +class megadrive_goldm250_device : public device_t, + public device_megadrive_cart_interface +{ +public: + megadrive_goldm250_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; + +protected: + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + +private: + memory_bank_array_creator<4> m_rom_bank; + + u8 m_bank_mask; +}; + + +DECLARE_DEVICE_TYPE(MEGADRIVE_MCPIRATE, megadrive_mcpirate_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_18KIN1, megadrive_18kin1_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_GOLDM250, megadrive_goldm250_device) + + +#endif // MAME_BUS_MEGADRIVE_CART_MCPIRATE_H diff --git a/src/devices/bus/megadrive/cart/miky.cpp b/src/devices/bus/megadrive/cart/miky.cpp new file mode 100644 index 0000000000000..941a46032f486 --- /dev/null +++ b/src/devices/bus/megadrive/cart/miky.cpp @@ -0,0 +1,88 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese +/************************************************************************************************** + +https://segaretro.org/TC_2000 +https://segaretro.org/Truco_%2796 + +Unknown protection chip, simple strobe write then read + +**************************************************************************************************/ + +#include "emu.h" +#include "miky.h" + +DEFINE_DEVICE_TYPE(MEGADRIVE_UNL_TC2000, megadrive_unl_tc2000_device, "megadrive_unl_tc2000", "Megadrive TC2000 cart") + +megadrive_unl_tc2000_device::megadrive_unl_tc2000_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, MEGADRIVE_UNL_TC2000, tag, owner, clock) +{ +} + +void megadrive_unl_tc2000_device::device_start() +{ + megadrive_rom_device::device_start(); + save_item(NAME(m_prot_latch)); +} + +void megadrive_unl_tc2000_device::device_reset() +{ + megadrive_rom_device::device_reset(); + // undefined, initialized by game anyway + m_prot_latch = 0; +} + + +void megadrive_unl_tc2000_device::cart_map(address_map &map) +{ + // writes often in ROM space, buggy? + map(0x00'0000, 0x0f'ffff).bankr(m_rom).nopw(); + map(0x10'0000, 0x10'0000).mirror(0x0f'fffe).lr8(NAME([this] () { return m_prot_latch; })); + // truco96a + map(0x10'0000, 0x10'0000).mirror(0x0f'fff0).lw8(NAME([this] (offs_t offset, u8 data) { (void)data; m_prot_latch = 0x00; })); + // tc2000 + map(0x10'0008, 0x10'0008).mirror(0x0f'fff0).lw8(NAME([this] (offs_t offset, u8 data) { (void)data; m_prot_latch = 0x50; })); + map(0x10'000c, 0x10'000c).mirror(0x0f'fff0).lw8(NAME([this] (offs_t offset, u8 data) { (void)data; m_prot_latch = 0xa0; })); +} + +/* + * Futbol Argentino 96 + * https://segaretro.org/J.League_Pro_Striker_2/Bootlegs + * + * Unlike jlps2 saving a league doesn't really work without playing at least one match first. + * Is this is based on an undumped earlier rev? (No protection access on that) + * + * TODO: + * - protection not really understood (game does a very small use of it, just expects the read + * values to always return fixed values) + * + */ + + DEFINE_DEVICE_TYPE(MEGADRIVE_UNL_FUTBOL_ARG96, megadrive_unl_futbol_arg96_device, "megadrive_unl_futbol_arg96", "Megadrive Futbol Argentino 96 cart") + +megadrive_unl_futbol_arg96_device::megadrive_unl_futbol_arg96_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_tplay96_device(mconfig, MEGADRIVE_UNL_FUTBOL_ARG96, tag, owner, clock) +{ +} + +u16 megadrive_unl_futbol_arg96_device::get_nvram_length() +{ + return 0x2000; +} + +void megadrive_unl_futbol_arg96_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x1f'ffff).mirror(0x20'0000).bankr(m_rom); + map(0x20'0000, 0x20'3fff).rw(FUNC(megadrive_unl_futbol_arg96_device::nvram_r), FUNC(megadrive_unl_futbol_arg96_device::nvram_w)); + // writes (in this order, always 0): + // 4c'6000 x1 + // 4c'6400 x1 + // 4c'6800 x2 + // 4c'6c00 x3 + // 4c'7000 x4 + map(0x4c'6201, 0x4c'6201).lr8(NAME([] () { return 0xa; })); + map(0x4c'6601, 0x4c'6601).lr8(NAME([] () { return 0x9; })); + map(0x4c'6a01, 0x4c'6a01).lr8(NAME([] () { return 0x7; })); +} + + diff --git a/src/devices/bus/megadrive/cart/miky.h b/src/devices/bus/megadrive/cart/miky.h new file mode 100644 index 0000000000000..600e72d474d23 --- /dev/null +++ b/src/devices/bus/megadrive/cart/miky.h @@ -0,0 +1,43 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese + +#ifndef MAME_BUS_MEGADRIVE_CART_MIKY_H +#define MAME_BUS_MEGADRIVE_CART_MIKY_H + +#pragma once + +#include "rom.h" +#include "sram.h" +#include "slot.h" + +class megadrive_unl_tc2000_device : public megadrive_rom_device +{ +public: + megadrive_unl_tc2000_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; +protected: + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; +private: + u8 m_prot_latch; +}; + +class megadrive_unl_futbol_arg96_device : public megadrive_rom_tplay96_device +{ +public: + megadrive_unl_futbol_arg96_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; + +protected: + virtual u16 get_nvram_length() override ATTR_COLD; + +}; + + +DECLARE_DEVICE_TYPE(MEGADRIVE_UNL_TC2000, megadrive_unl_tc2000_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_UNL_FUTBOL_ARG96, megadrive_unl_futbol_arg96_device) + + +#endif // MAME_BUS_MEGADRIVE_CART_TEKKENSP_H diff --git a/src/devices/bus/megadrive/cart/multigame.cpp b/src/devices/bus/megadrive/cart/multigame.cpp new file mode 100644 index 0000000000000..50775670b225b --- /dev/null +++ b/src/devices/bus/megadrive/cart/multigame.cpp @@ -0,0 +1,183 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese +/************************************************************************************************** + +Multigame cart mappers, with CMOS latching on power/reset + +TODO: +- sportg mirroring is unconfirmed (may just rotate starting address instead); + +**************************************************************************************************/ + +#include "emu.h" +#include "multigame.h" + +#include "bus/generic/slot.h" + +/* + * TecToy Sport Games + * https://segaretro.org/Sport_Games + * + * Sega MPR-19945-MX ROM with a 74HC74N and a 74HC00N attached. + * Games bankswitch also changes with power switch according to manual, + * for simplicity we just use /VRES only. + * + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_TECTOY_SPORTS, megadrive_tectoy_sports_device, "megadrive_tectoy_sports", "Megadrive TecToy Sport Games cart") + +megadrive_tectoy_sports_device::megadrive_tectoy_sports_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, MEGADRIVE_TECTOY_SPORTS, tag, owner, clock) + , device_megadrive_cart_interface( mconfig, *this ) + , m_rom(*this, "rom") +{ +} + +void megadrive_tectoy_sports_device::device_start() +{ + memory_region *const romregion(cart_rom_region()); + const u32 page_size = 0x10'0000; + device_generic_cart_interface::map_non_power_of_two( + unsigned(romregion->bytes() / page_size), + [this, base = &romregion->as_u8()] (unsigned entry, unsigned page) + { + m_rom->configure_entry(entry, &base[page * page_size]); + }); + // m_rom_mirror = 0x30'0000; + + // No info about what is the default game on cold boot, assume Super Volley Ball + m_game_sel = 2; + save_item(NAME(m_game_sel)); +} + +void megadrive_tectoy_sports_device::device_reset() +{ + m_game_sel ++; + m_game_sel %= 3; + + const std::string game_names[] = { "Super Volley Ball", "World Championship Soccer II", "Super Real Basketball" }; + + logerror("Game mounted: %s\n", game_names[m_game_sel]); + m_rom->set_entry(m_game_sel); +} + +void megadrive_tectoy_sports_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x0f'ffff).mirror(0x30'0000).bankr(m_rom); +} + +/* + * Codemasters 2-in-1 + * https://segaretro.org/2_Games_on_One_Cart:_Fantastic_Dizzy_and_Cosmic_Spacehead + * https://segaretro.org/Double_Hits:_Micro_Machines_/_Psycho_Pinball + * + * "One of the games will begin: for example Cosmic Spacehead", again suggesting that cold boot + * may still have preserved (static) state. + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_CM2IN1, megadrive_cm2in1_device, "megadrive_cm2in1", "Megadrive Codemasters 2 games on 1 cart") + +megadrive_cm2in1_device::megadrive_cm2in1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, MEGADRIVE_CM2IN1, tag, owner, clock) + , device_megadrive_cart_interface( mconfig, *this ) + , m_rom(*this, "rom") +{ +} + +void megadrive_cm2in1_device::device_start() +{ + memory_region *const romregion(cart_rom_region()); + const u32 page_size = 0x20'0000; + device_generic_cart_interface::map_non_power_of_two( + unsigned(romregion->bytes() / page_size), + [this, base = &romregion->as_u8()] (unsigned entry, unsigned page) + { + m_rom->configure_entry(entry, &base[page * page_size]); + }); + + // start in a predictable manner + m_game_sel = 1; + save_item(NAME(m_game_sel)); +} + +void megadrive_cm2in1_device::device_reset() +{ + m_game_sel ++; + m_game_sel &= 1; + + m_rom->set_entry(m_game_sel); +} + +void megadrive_cm2in1_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x1f'ffff).mirror(0x20'0000).bankr(m_rom); +} + +/* + * 3 in 1 Flashback - World Championship Soccer - Tecmo World Cup 92 + * 3 in 1 Road Rash - Ms. Pac-Man - Block Out + * + * Unknown source (pirate but with copyright text on back cover!?) + * + * Uneven bank scheme, the two soccer games lies at $18'0000 and $1c'0000 so we simplify with a + * memory_view. Road Rash cart is half total size/page size, so we need to capture ROM length at + * init time. + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_3IN1FWT, megadrive_3in1fwt_device, "megadrive_3in1fwt", "Megadrive Flashback 3-in-1 cart") + +megadrive_3in1fwt_device::megadrive_3in1fwt_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, MEGADRIVE_3IN1FWT, tag, owner, clock) + , m_rom_bank(*this, "rom_bank") + , m_rom_view(*this, "rom_view") +{ +} + +void megadrive_3in1fwt_device::device_start() +{ + megadrive_rom_device::device_start(); + memory_region *const romregion(cart_rom_region()); + + m_rom_mask = romregion->bytes() - 1; + const u32 page_size = romregion->bytes() / 8; + device_generic_cart_interface::map_non_power_of_two( + unsigned(romregion->bytes() / page_size), + [this, base = &romregion->as_u8(), pg_mult = page_size] (unsigned entry, unsigned page) + { + m_rom_bank->configure_entry(entry, &base[page * pg_mult]); + }); + + m_page_mask = page_size - 1; + + // start in a predictable manner + m_game_sel = 2; + save_item(NAME(m_game_sel)); +} + +void megadrive_3in1fwt_device::device_reset() +{ + megadrive_rom_device::device_reset(); + m_game_sel ++; + m_game_sel %= 3; + + m_rom_view.select(m_game_sel); + // unknown order + if (m_game_sel != 0) + { + u8 page_sel = 6 + ((m_game_sel & 1) ^ 1); + logerror("Page selection %02x\n", page_sel); + m_rom_bank->set_entry(page_sel); + } +} + +void megadrive_3in1fwt_device::cart_map(address_map &map) +{ + map(0x00'0000, m_rom_mask).view(m_rom_view); + m_rom_view[0](0x00'0000, m_rom_mask ).bankr(m_rom); + m_rom_view[1](0x00'0000, m_page_mask).bankr(m_rom_bank); + m_rom_view[2](0x00'0000, m_page_mask).bankr(m_rom_bank); +} + diff --git a/src/devices/bus/megadrive/cart/multigame.h b/src/devices/bus/megadrive/cart/multigame.h new file mode 100644 index 0000000000000..e42f5b0390bce --- /dev/null +++ b/src/devices/bus/megadrive/cart/multigame.h @@ -0,0 +1,69 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese + +#ifndef MAME_BUS_MEGADRIVE_CART_MULTIGAME_H +#define MAME_BUS_MEGADRIVE_CART_MULTIGAME_H + +#pragma once + +#include "rom.h" +#include "slot.h" + +class megadrive_tectoy_sports_device : public device_t, + public device_megadrive_cart_interface +{ +public: + megadrive_tectoy_sports_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; + +protected: + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + + memory_bank_creator m_rom; + u8 m_game_sel; +}; + +class megadrive_cm2in1_device : public device_t, + public device_megadrive_cart_interface +{ +public: + megadrive_cm2in1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; + +protected: + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + +private: + memory_bank_creator m_rom; + u8 m_game_sel; +}; + +class megadrive_3in1fwt_device : public megadrive_rom_device +{ +public: + megadrive_3in1fwt_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; + +protected: + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + + memory_bank_creator m_rom_bank; + memory_view m_rom_view; + u8 m_game_sel; + u32 m_rom_mask; + u32 m_page_mask; +}; + + +DECLARE_DEVICE_TYPE(MEGADRIVE_TECTOY_SPORTS, megadrive_tectoy_sports_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_CM2IN1, megadrive_cm2in1_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_3IN1FWT, megadrive_3in1fwt_device) + + +#endif // MAME_BUS_MEGADRIVE_CART_MULTIGAME_H diff --git a/src/devices/bus/megadrive/cart/options.cpp b/src/devices/bus/megadrive/cart/options.cpp new file mode 100644 index 0000000000000..51abff8278ccd --- /dev/null +++ b/src/devices/bus/megadrive/cart/options.cpp @@ -0,0 +1,215 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese + +#include "emu.h" +#include "options.h" + +#include "action_replay.h" +#include "avartisan.h" +#include "eeprom.h" +#include "everdrive.h" +#include "gamtec.h" +#include "jcart.h" +#include "mcpirate.h" +#include "miky.h" +#include "multigame.h" +#include "rockworld.h" +#include "rom.h" +#include "seganet.h" +#include "sfteam.h" +#include "sram.h" +#include "smb.h" +#include "smw64.h" +#include "ssf.h" +#include "t5740.h" +#include "tekkensp.h" +#include "xboy.h" + + +namespace bus::megadrive::slotoptions { + +char const *const MD_STD = "rom"; +char const *const MD_SSF2 = "rom_ssf2"; +char const *const HB_SSF = "rom_titan"; // TODO: rename +char const *const HB_SSF_SRAM = "ssf_sram"; +char const *const HB_SSF_EX = "ssf_ex"; +char const *const HB_EVERDRIVE = "everdrive"; +char const *const MD_SRAM = "rom_sram"; +char const *const MD_SONIC3 = "rom_fram"; // TODO: change string +char const *const MD_TPLAY96 = "rom_tplay96"; +char const *const MD_HARDBALL95 = "rom_hardbl95"; +char const *const MD_BARKLEY2 = "barkley2"; +char const *const MD_EEPROM = "rom_eeprom_mode1"; +char const *const MD_EEPROM_NBAJAM = "rom_nbajam_alt"; +char const *const MD_EEPROM_NBAJAMTE = "rom_nbajamte"; +char const *const MD_EEPROM_NFLQB96 = "rom_nflqb96"; +char const *const MD_EEPROM_COLLSLAM = "rom_cslam"; +char const *const MD_EEPROM_NHLPA = "rom_nhlpa"; +char const *const MD_EEPROM_BLARA95 = "rom_blara95"; +char const *const MD_EEPROM_BLARA96 = "rom_blara96"; + +char const *const MD_CM2IN1 = "rom_cm2in1"; +char const *const MD_JCART_SAMPRAS = "rom_jcart_sampras"; +char const *const MD_JCART_SSKID = "rom_jcart"; +char const *const MD_JCART_MICROMAC2 = "rom_codemast"; +char const *const MD_JCART_MICROMAC96 = "rom_mm96"; +char const *const MD_SEGANET = "seganet"; +char const *const MD_TECTOY_SPORTS = "tectoy_sports"; +char const *const MD_3IN1_FWT = "3in1fwt"; +char const *const MC_PIRATE = "rom_mcpir"; // TODO: rename, what even MC stands for? +char const *const MC_18KIN1 = "18kin1"; +char const *const MC_GOLDM250 = "goldm250"; +char const *const UNL_XINQIG = "rom_xinqig"; +char const *const HB_BEGGARP = "rom_sf001"; +char const *const HB_BEGGARP1 = "rom_sf001_beggarp1"; +char const *const HB_WUKONG = "rom_sf002"; +char const *const HB_STARODYS = "rom_sf004"; +char const *const UNL_TILESMJ2 = "rom_16mj2"; +char const *const UNL_ELFWOR = "rom_elfwor"; +char const *const UNL_SMOUSE = "rom_smouse"; +char const *const UNL_YASECH = "rom_yasech"; +char const *const UNL_777CASINO = "rom_777casino"; +char const *const UNL_SOULBLADE = "rom_soulb"; +char const *const UNL_SUPRBUBL = "rom_sbubl"; +char const *const UNL_CJMJCLUB = "rom_cjmjclub"; +char const *const UNL_MJLOV = "rom_mjlov"; +char const *const UNL_REDCLIFF = "rom_redcl"; +char const *const UNL_SQUIRRELK = "rom_squir"; +char const *const UNL_LIONKING2 = "rom_lion2"; +char const *const UNL_KOF98 = "rom_kof98"; +char const *const UNL_BUGSLIFE = "rom_bugs"; +char const *const UNL_POKEMONA = "rom_pokea"; +char const *const UNL_KOF99 = "rom_kof99"; +char const *const UNL_SMB = "rom_smb"; +char const *const UNL_SMB2 = "rom_smb2"; +char const *const UNL_ROCKMANX3 = "rom_rx3"; +char const *const UNL_SANGUO5 = "rom_sanguo5"; +char const *const UNL_AVARTISAN = "rom_realtec"; +char const *const UNL_TEKKENSP = "rom_tekkensp"; +char const *const UNL_TC2000 = "rom_tc2000"; +char const *const UNL_FUTBOL_ARG96 = "rom_sram_arg96"; +char const *const UNL_TOPF = "rom_lion3"; +char const *const UNL_POKESTAD = "rom_pokestad"; // TODO: alias of above, probably unneeded +char const *const UNL_CHINF3 = "rom_chinf3"; +char const *const UNL_SMW64 = "rom_smw64"; +char const *const UNL_ROCKWORLD = "rockworld"; +char const *const UNL_ROCKHEAVEN = "rockheaven"; +char const *const HB_PSOLAR = "rom_stm95"; // TODO: rename + +char const *const ACTION_REPLAY = "ar"; + +} // namespace bus::megadrive::slotoptions + + +void megadrive_cart_options(device_slot_interface &device) +{ + using namespace bus::megadrive; + + // normal + device.option_add_internal(slotoptions::MD_STD, MEGADRIVE_ROM); + device.option_add_internal(slotoptions::MD_SSF2, MEGADRIVE_ROM_SSF2); + + // SRAM + device.option_add_internal(slotoptions::MD_SRAM, MEGADRIVE_ROM_SRAM); + device.option_add_internal(slotoptions::MD_SONIC3, MEGADRIVE_ROM_SONIC3); + device.option_add_internal(slotoptions::MD_TPLAY96, MEGADRIVE_ROM_TPLAY96); + device.option_add_internal(slotoptions::MD_HARDBALL95, MEGADRIVE_ROM_HARDBALL95); + device.option_add_internal(slotoptions::MD_BARKLEY2, MEGADRIVE_ROM_BARKLEY2); + device.option_add_internal(slotoptions::UNL_SANGUO5, MEGADRIVE_UNL_SANGUO5); + + // EEPROM + device.option_add_internal(slotoptions::MD_EEPROM, MEGADRIVE_EEPROM); + device.option_add_internal(slotoptions::MD_EEPROM_NBAJAM, MEGADRIVE_EEPROM_NBAJAM); + device.option_add_internal(slotoptions::MD_EEPROM_NBAJAMTE, MEGADRIVE_EEPROM_NBAJAMTE); + device.option_add_internal(slotoptions::MD_EEPROM_NFLQB96, MEGADRIVE_EEPROM_NFLQB96); + device.option_add_internal(slotoptions::MD_EEPROM_COLLSLAM, MEGADRIVE_EEPROM_COLLSLAM); + device.option_add_internal(slotoptions::MD_EEPROM_NHLPA, MEGADRIVE_EEPROM_NHLPA); + device.option_add_internal(slotoptions::MD_EEPROM_BLARA95, MEGADRIVE_EEPROM_BLARA95); + device.option_add_internal(slotoptions::MD_EEPROM_BLARA96, MEGADRIVE_EEPROM_BLARA96); + + // J-Cart + device.option_add_internal(slotoptions::MD_JCART_SAMPRAS, MEGADRIVE_ROM_JCART_SAMPRAS); + device.option_add_internal(slotoptions::MD_JCART_SSKID, MEGADRIVE_ROM_JCART_SSKID); + device.option_add_internal(slotoptions::MD_JCART_MICROMAC2, MEGADRIVE_ROM_JCART_MICROMAC2); + device.option_add_internal(slotoptions::MD_JCART_MICROMAC96, MEGADRIVE_ROM_JCART_MICROMAC96); + + // reset based multigames + device.option_add_internal(slotoptions::MD_CM2IN1, MEGADRIVE_CM2IN1); + device.option_add_internal(slotoptions::MD_TECTOY_SPORTS, MEGADRIVE_TECTOY_SPORTS); + device.option_add_internal(slotoptions::MD_3IN1_FWT, MEGADRIVE_3IN1FWT); + + // menu based multigames + device.option_add_internal(slotoptions::MD_SEGANET, MEGADRIVE_SEGANET); + device.option_add_internal(slotoptions::MC_PIRATE, MEGADRIVE_MCPIRATE); + device.option_add_internal(slotoptions::MC_18KIN1, MEGADRIVE_18KIN1); + device.option_add_internal(slotoptions::MC_GOLDM250, MEGADRIVE_GOLDM250); + + // unlicensed + // Gamtec + device.option_add_internal(slotoptions::UNL_TILESMJ2, MEGADRIVE_UNL_TILESMJ2); + device.option_add_internal(slotoptions::UNL_ELFWOR, MEGADRIVE_UNL_ELFWOR); + device.option_add_internal(slotoptions::UNL_SMOUSE, MEGADRIVE_UNL_SMOUSE); + device.option_add_internal(slotoptions::UNL_YASECH, MEGADRIVE_UNL_YASECH); + device.option_add_internal(slotoptions::UNL_777CASINO, MEGADRIVE_UNL_777CASINO); + device.option_add_internal(slotoptions::UNL_SOULBLADE, MEGADRIVE_UNL_SOULBLADE); + device.option_add_internal(slotoptions::UNL_SUPRBUBL, MEGADRIVE_UNL_SUPRBUBL); + device.option_add_internal(slotoptions::UNL_CJMJCLUB, MEGADRIVE_UNL_CJMJCLUB); + device.option_add_internal(slotoptions::UNL_MJLOV, MEGADRIVE_UNL_MJLOV); + device.option_add_internal(slotoptions::UNL_REDCLIFF, MEGADRIVE_UNL_REDCLIFF); + device.option_add_internal(slotoptions::UNL_SQUIRRELK, MEGADRIVE_UNL_SQUIRRELK); + device.option_add_internal(slotoptions::UNL_LIONKING2, MEGADRIVE_UNL_LIONKING2); + + // X Boy + device.option_add_internal(slotoptions::UNL_KOF98, MEGADRIVE_UNL_KOF98); + device.option_add_internal(slotoptions::UNL_BUGSLIFE, MEGADRIVE_UNL_BUGSLIFE); + device.option_add_internal(slotoptions::UNL_POKEMONA, MEGADRIVE_UNL_POKEMONA); + device.option_add_internal(slotoptions::UNL_KOF99, MEGADRIVE_UNL_KOF99); + device.option_add_internal(slotoptions::UNL_POKESTAD, MEGADRIVE_UNL_TOPF); + device.option_add_internal(slotoptions::UNL_TOPF, MEGADRIVE_UNL_TOPF); + device.option_add_internal(slotoptions::UNL_CHINF3, MEGADRIVE_UNL_CHINF3); + + // Super Mario Bros + device.option_add_internal(slotoptions::UNL_SMB, MEGADRIVE_UNL_SMB); + device.option_add_internal(slotoptions::UNL_SMB2, MEGADRIVE_UNL_SMB2); + device.option_add_internal(slotoptions::UNL_ROCKMANX3, MEGADRIVE_UNL_ROCKMANX3); + + // Super Mario World 64 + device.option_add_internal(slotoptions::UNL_SMW64, MEGADRIVE_UNL_SMW64); + + // AV Artisan + device.option_add_internal(slotoptions::UNL_AVARTISAN, MEGADRIVE_UNL_AVARTISAN); + + // Taiwanese carts + device.option_add_internal(slotoptions::UNL_TEKKENSP, MEGADRIVE_UNL_TEKKENSP); + + // Miky + device.option_add_internal(slotoptions::UNL_TC2000, MEGADRIVE_UNL_TC2000); + device.option_add_internal(slotoptions::UNL_FUTBOL_ARG96, MEGADRIVE_UNL_FUTBOL_ARG96); + + // Rock Heaven / Rock World + device.option_add_internal(slotoptions::UNL_ROCKHEAVEN, MEGADRIVE_UNL_ROCKHEAVEN); + device.option_add_internal(slotoptions::UNL_ROCKWORLD, MEGADRIVE_UNL_ROCKWORLD); + + // Action Replay + device.option_add_internal(slotoptions::ACTION_REPLAY, MEGADRIVE_ACTION_REPLAY); + + // Homebrew + // Super Fighter Team + device.option_add_internal(slotoptions::UNL_XINQIG, MEGADRIVE_UNL_XINQIG); + device.option_add_internal(slotoptions::HB_BEGGARP, MEGADRIVE_HB_BEGGARP); + device.option_add_internal(slotoptions::HB_BEGGARP1, MEGADRIVE_HB_BEGGARP1); + device.option_add_internal(slotoptions::HB_WUKONG, MEGADRIVE_HB_WUKONG); + device.option_add_internal(slotoptions::HB_STARODYS, MEGADRIVE_HB_STARODYS); + + // krikzz "SEGA SSF" + device.option_add_internal(slotoptions::HB_SSF, MEGADRIVE_HB_SSF); + device.option_add_internal(slotoptions::HB_SSF_SRAM, MEGADRIVE_HB_SSF_SRAM); + device.option_add_internal(slotoptions::HB_SSF_EX, MEGADRIVE_HB_SSF_EX); + + // Everdrive based carts + device.option_add(slotoptions::HB_EVERDRIVE, MEGADRIVE_HB_EVERDRIVE); + + // WaterMelon + device.option_add_internal(slotoptions::HB_PSOLAR, MEGADRIVE_HB_PSOLAR); + +} diff --git a/src/devices/bus/megadrive/cart/options.h b/src/devices/bus/megadrive/cart/options.h new file mode 100644 index 0000000000000..a5fffd6fa2cba --- /dev/null +++ b/src/devices/bus/megadrive/cart/options.h @@ -0,0 +1,83 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese + +#ifndef MAME_BUS_MEGADRIVE_CART_OPTIONS_H +#define MAME_BUS_MEGADRIVE_CART_OPTIONS_H + +#pragma once + +void megadrive_cart_options(device_slot_interface &device); + +namespace bus::megadrive::slotoptions { + + extern char const *const MD_STD; + extern char const *const MD_SSF2; + extern char const *const MD_SRAM; + extern char const *const MD_SONIC3; + extern char const *const MD_TPLAY96; + extern char const *const MD_HARDBALL95; + + extern char const *const MD_EEPROM; + extern char const *const MD_EEPROM_NBAJAM; + extern char const *const MD_EEPROM_NBAJAMTE; + extern char const *const MD_EEPROM_NFLQB96; + extern char const *const MD_EEPROM_COLLSLAM; + extern char const *const MD_EEPROM_NHLPA; + + extern char const *const MD_CM2IN1; + extern char const *const MD_TECTOY_SPORTS; + extern char const *const MD_GAME_KANZUME; + + extern char const *const MD_JCART_SAMPRAS; + extern char const *const MD_JCART_SSKID; + extern char const *const MD_JCART_MICROMAC2; + extern char const *const MD_JCART_MICROMAC96; + + extern char const *const MC_PIRATE; + extern char const *const MC_18KIN1; + extern char const *const MC_GOLDM250; + + extern char const *const UNL_XINQIG; + extern char const *const HB_BEGGARP; + extern char const *const HB_BEGGARP1; + extern char const *const HB_WUKONG; + extern char const *const HB_STARODYS; + + extern char const *const UNL_TILESMJ2; + extern char const *const UNL_ELFWOR; + extern char const *const UNL_SMOUSE; + extern char const *const UNL_YASECH; + extern char const *const UNL_777CASINO; + extern char const *const UNL_SOULBLADE; + extern char const *const UNL_SUPRBUBL; + extern char const *const UNL_CJMJCLUB; + extern char const *const UNL_MJLOV; + extern char const *const UNL_REDCLIFF; + extern char const *const UNL_LIONKING2; + extern char const *const UNL_KOF98; + extern char const *const UNL_BUGSLIFE; + extern char const *const UNL_POKEMONA; + extern char const *const UNL_KOF99; + extern char const *const UNL_SMB; + extern char const *const UNL_SMB2; + extern char const *const UNL_ROCKMANX3; + extern char const *const UNL_TEKKENSP; + extern char const *const UNL_TC2000; + + extern char const *const UNL_POKESTAD; + extern char const *const UNL_TOPF; + extern char const *const UNL_CHINF3; + extern char const *const UNL_SMW64; + extern char const *const UNL_ROCKWORLD; + extern char const *const UNL_ROCKHEAVEN; + + extern char const *const UNL_SANGUO5; + + extern char const *const ACTION_REPLAY; + + extern char const *const HB_SSF; + +} // namespace bus::megadrive::slotoptions + + +#endif // MAME_BUS_MEGADRIVE_CART_OPTIONS_H diff --git a/src/devices/bus/megadrive/cart/rockworld.cpp b/src/devices/bus/megadrive/cart/rockworld.cpp new file mode 100644 index 0000000000000..bbeab560511ce --- /dev/null +++ b/src/devices/bus/megadrive/cart/rockworld.cpp @@ -0,0 +1,40 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese +/************************************************************************************************** + +RockHeaven / RockWorld mapper + + +**************************************************************************************************/ + +#include "emu.h" +#include "rockworld.h" + +DEFINE_DEVICE_TYPE(MEGADRIVE_UNL_ROCKHEAVEN, megadrive_unl_rockheaven_device, "megadrive_unl_rockheaven", "Megadrive Rock Heaven cart") + +megadrive_unl_rockheaven_device::megadrive_unl_rockheaven_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, MEGADRIVE_UNL_ROCKHEAVEN, tag, owner, clock) +{ +} + +void megadrive_unl_rockheaven_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x3f'ffff).bankr(m_rom); + map(0x50'0008, 0x50'0009).lr16(NAME([] () { return 0x5082; })); +} + +DEFINE_DEVICE_TYPE(MEGADRIVE_UNL_ROCKWORLD, megadrive_unl_rockworld_device, "megadrive_unl_rockworld", "Megadrive Rock World cart") + +megadrive_unl_rockworld_device::megadrive_unl_rockworld_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, MEGADRIVE_UNL_ROCKWORLD, tag, owner, clock) +{ +} + +void megadrive_unl_rockworld_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x3f'ffff).bankr(m_rom); + map(0x50'0008, 0x50'0009).lr16(NAME([] () { return 0x4000; })); + map(0x50'0208, 0x50'0209).lr16(NAME([] () { return 0xa000; })); +} + + diff --git a/src/devices/bus/megadrive/cart/rockworld.h b/src/devices/bus/megadrive/cart/rockworld.h new file mode 100644 index 0000000000000..f1008e1625cd1 --- /dev/null +++ b/src/devices/bus/megadrive/cart/rockworld.h @@ -0,0 +1,31 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese + +#ifndef MAME_BUS_MEGADRIVE_CART_ROCKWORLD_H +#define MAME_BUS_MEGADRIVE_CART_ROCKWORLD_H + +#pragma once + +#include "rom.h" +#include "slot.h" + +class megadrive_unl_rockheaven_device : public megadrive_rom_device +{ +public: + megadrive_unl_rockheaven_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; +}; + +class megadrive_unl_rockworld_device : public megadrive_rom_device +{ +public: + megadrive_unl_rockworld_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; +}; + +DECLARE_DEVICE_TYPE(MEGADRIVE_UNL_ROCKHEAVEN, megadrive_unl_rockheaven_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_UNL_ROCKWORLD, megadrive_unl_rockworld_device) + +#endif // MAME_BUS_MEGADRIVE_CART_ROCKWORLD_H diff --git a/src/devices/bus/megadrive/cart/rom.cpp b/src/devices/bus/megadrive/cart/rom.cpp new file mode 100644 index 0000000000000..a2f84a2dd9233 --- /dev/null +++ b/src/devices/bus/megadrive/cart/rom.cpp @@ -0,0 +1,127 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese +/************************************************************************************************** + +Megadrive generic ROM cart emulation + +**************************************************************************************************/ + +#include "emu.h" +#include "rom.h" + +#include "bus/generic/slot.h" + +DEFINE_DEVICE_TYPE(MEGADRIVE_ROM, megadrive_rom_device, "megadrive_rom", "Megadrive ROM cart") + +megadrive_rom_device::megadrive_rom_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, type, tag, owner, clock) + , device_megadrive_cart_interface( mconfig, *this ) + , m_rom(*this, "rom") +{ +} + +megadrive_rom_device::megadrive_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, MEGADRIVE_ROM, tag, owner, clock) +{ +} + +void megadrive_rom_device::device_start() +{ + memory_region *const romregion(cart_rom_region()); + m_rom_mask = device_generic_cart_interface::map_non_power_of_two( + unsigned(romregion->bytes()), + [this, base = &romregion->as_u8()] (unsigned entry, unsigned page) + { + m_rom->configure_entry(0, &base[0]); + }); + m_rom_mirror = 0x3f'ffff ^ m_rom_mask; + logerror("Map linear rom with mask: %08x mirror: %08x\n", m_rom_mask, m_rom_mirror); +} + +void megadrive_rom_device::device_reset() +{ +} + +void megadrive_rom_device::cart_map(address_map &map) +{ + map(0x00'0000, m_rom_mask).mirror(m_rom_mirror).bankr(m_rom); +} + +/* + * Super Street Fighter II + * + * Sega 315-5709 or 315-5779 mapper + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_ROM_SSF2, megadrive_rom_ssf2_device, "megadrive_rom_ssf2", "Megadrive SSF2 ROM cart") + +megadrive_rom_ssf2_device::megadrive_rom_ssf2_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, type, tag, owner, clock) + , device_megadrive_cart_interface( mconfig, *this ) + , m_rom_bank(*this, "rom_bank_%u", 0U) + , m_sram_view(*this, "sram_view") +{ +} + +megadrive_rom_ssf2_device::megadrive_rom_ssf2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_ssf2_device(mconfig, MEGADRIVE_ROM_SSF2, tag, owner, clock) +{ +} + +void megadrive_rom_ssf2_device::device_start() +{ + memory_region *const romregion(cart_rom_region()); + const u32 page_size = 0x08'0000; + device_generic_cart_interface::map_non_power_of_two( + unsigned(romregion->bytes() / page_size), + [this, base = &romregion->as_u8()] (unsigned entry, unsigned page) + { + for (int i = 0; i < 8; i++) + m_rom_bank[i]->configure_entry(entry, &base[page * page_size]); + }); +} + +void megadrive_rom_ssf2_device::device_reset() +{ + for (int i = 0; i < 8; i++) + m_rom_bank[i]->set_entry(i); + // Starts in SRAM disabled mode, thru /VRES connected + // (game initializes $f1 after checking memory banks at $30'0000) + m_sram_view.disable(); +} + +// need this for subclassing ("A memory_view can be present in only one address map") +void megadrive_rom_ssf2_device::cart_bank_map(address_map &map) +{ + for (int i = 0; i < 8; i++) + { + const u32 page_size = 0x08'0000; + + map(0x00'0000 | (page_size * i), 0x07'ffff | (page_size * i)).bankr(m_rom_bank[i]); + } +} + +void megadrive_rom_ssf2_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x3f'ffff).m(*this, FUNC(megadrive_rom_ssf2_device::cart_bank_map)); + map(0x20'0000, 0x3f'ffff).view(m_sram_view); + m_sram_view[0](0x20'0000, 0x3f'ffff).unmaprw(); +} + +void megadrive_rom_ssf2_device::time_io_map(address_map &map) +{ + map(0xf1, 0xf1).lw8(NAME([this] (offs_t offset, u8 data) { + if (BIT(data, 1)) + m_sram_view.disable(); + else + m_sram_view.select(0); + })); + map(0xf3, 0xf3).lw8(NAME([this] (offs_t offset, u8 data) { m_rom_bank[1]->set_entry(data & 0xf); })); + map(0xf5, 0xf5).lw8(NAME([this] (offs_t offset, u8 data) { m_rom_bank[2]->set_entry(data & 0xf); })); + map(0xf7, 0xf7).lw8(NAME([this] (offs_t offset, u8 data) { m_rom_bank[3]->set_entry(data & 0xf); })); + map(0xf9, 0xf9).lw8(NAME([this] (offs_t offset, u8 data) { m_rom_bank[4]->set_entry(data & 0xf); })); + map(0xfb, 0xfb).lw8(NAME([this] (offs_t offset, u8 data) { m_rom_bank[5]->set_entry(data & 0xf); })); + map(0xfd, 0xfd).lw8(NAME([this] (offs_t offset, u8 data) { m_rom_bank[6]->set_entry(data & 0xf); })); + map(0xff, 0xff).lw8(NAME([this] (offs_t offset, u8 data) { m_rom_bank[7]->set_entry(data & 0xf); })); +} diff --git a/src/devices/bus/megadrive/cart/rom.h b/src/devices/bus/megadrive/cart/rom.h new file mode 100644 index 0000000000000..c632dd33f137c --- /dev/null +++ b/src/devices/bus/megadrive/cart/rom.h @@ -0,0 +1,58 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese + +#ifndef MAME_BUS_MEGADRIVE_CART_ROM_H +#define MAME_BUS_MEGADRIVE_CART_ROM_H + +#pragma once + +#include "slot.h" +//#include "machine/nvram.h" + +class megadrive_rom_device : public device_t, + public device_megadrive_cart_interface +{ +public: + megadrive_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; + +protected: + megadrive_rom_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + +// bool check_rom(std::string &message) ATTR_COLD; + memory_bank_creator m_rom; + + u32 m_rom_mask; + u32 m_rom_mirror; + +// void install_rom() ATTR_COLD; +}; + +class megadrive_rom_ssf2_device : public device_t, + public device_megadrive_cart_interface +{ +public: + megadrive_rom_ssf2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; + virtual void time_io_map(address_map &map) override ATTR_COLD; + + void cart_bank_map(address_map &map); +protected: + megadrive_rom_ssf2_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + + memory_bank_array_creator<8> m_rom_bank; + memory_view m_sram_view; +}; + +DECLARE_DEVICE_TYPE(MEGADRIVE_ROM, megadrive_rom_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_ROM_SSF2, megadrive_rom_ssf2_device) + +#endif // MAME_BUS_MEGADRIVE_CART_ROM_H diff --git a/src/devices/bus/megadrive/cart/seganet.cpp b/src/devices/bus/megadrive/cart/seganet.cpp new file mode 100644 index 0000000000000..9a8dffe1ba612 --- /dev/null +++ b/src/devices/bus/megadrive/cart/seganet.cpp @@ -0,0 +1,70 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese +/************************************************************************************************** + +Sega Channel Game no Kanzume "digest" RAM cart, developed by CRI + +https://segaretro.org/Game_no_Kanzume_Otokuyou + +TODO: +- some unknowns, needs PCB picture + +**************************************************************************************************/ + +#include "emu.h" +#include "seganet.h" + +#include "bus/generic/slot.h" + +DEFINE_DEVICE_TYPE(MEGADRIVE_SEGANET, megadrive_seganet_device, "megadrive_seganet", "Megadrive Seganet Game no Kanzume RAM cart") + + +megadrive_seganet_device::megadrive_seganet_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, MEGADRIVE_SEGANET, tag, owner, clock) + , device_megadrive_cart_interface( mconfig, *this ) + , m_rom(*this, "rom") + , m_ram_view(*this, "ram_view") +{ +} + +void megadrive_seganet_device::device_start() +{ + memory_region *const romregion(cart_rom_region()); + device_generic_cart_interface::map_non_power_of_two( + unsigned(romregion->bytes()), + [this, base = &romregion->as_u8()] (unsigned entry, unsigned page) + { + m_rom->configure_entry(0, &base[0]); + }); +} + +void megadrive_seganet_device::device_reset() +{ + m_ram_view.disable(); +} + +void megadrive_seganet_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x2f'ffff).bankr(m_rom); + // NOTE: menu system writes extra couple writes at $40000, + // programming mistake? + map(0x00'0000, 0x03'ffff).view(m_ram_view); + m_ram_view[0](0x00'0000, 0x03'ffff).ram(); +} + +void megadrive_seganet_device::time_io_map(address_map &map) +{ +// map(0x01, 0x01) unknown, used in tandem with 0xf1 writes, ram bank select? + map(0xf1, 0xf1).lw8( + NAME([this] (offs_t offset, u8 data) { + // assumed, bclr #$1 at PC=5e282 + if (BIT(data, 1)) + m_ram_view.disable(); + else + m_ram_view.select(0); + // bit 0: write protect as per SSF2 mapper? + if (data & 0xfd) + popmessage("megadrive_seganet: unhandled $f1 write %02x", data); + }) + ); +} diff --git a/src/devices/bus/megadrive/cart/seganet.h b/src/devices/bus/megadrive/cart/seganet.h new file mode 100644 index 0000000000000..ae43e121d0f99 --- /dev/null +++ b/src/devices/bus/megadrive/cart/seganet.h @@ -0,0 +1,31 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese + +#ifndef MAME_BUS_MEGADRIVE_CART_SEGANET_H +#define MAME_BUS_MEGADRIVE_CART_SEGANET_H + +#pragma once + +#include "slot.h" + +class megadrive_seganet_device : public device_t, + public device_megadrive_cart_interface +{ +public: + megadrive_seganet_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; + virtual void time_io_map(address_map &map) override ATTR_COLD; + +protected: + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + + memory_bank_creator m_rom; + memory_view m_ram_view; +}; + +DECLARE_DEVICE_TYPE(MEGADRIVE_SEGANET, megadrive_seganet_device) + + +#endif // MAME_BUS_MEGADRIVE_CART_SEGANET_H diff --git a/src/devices/bus/megadrive/cart/sfteam.cpp b/src/devices/bus/megadrive/cart/sfteam.cpp new file mode 100644 index 0000000000000..62f7e31d21f0b --- /dev/null +++ b/src/devices/bus/megadrive/cart/sfteam.cpp @@ -0,0 +1,353 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese +/************************************************************************************************** + +Super Fighter Team protected mappers + +**************************************************************************************************/ + +#include "emu.h" +#include "sfteam.h" + +#include "bus/generic/slot.h" + + +/* + * Xin Qi Gai Wang Zi + * + * NVRAM at $40'0000 + * Some writes in ROM space at startup, PC=B4BEA (at least) tests that $100-$102 + * returns SW vectors 0x46fc2700 and resets if unhappy, presumably against copiers. + * + * NOTES: + * - xinqig doesn't work on Teradrive TMSS, no SEGA at $100. Cursory testing was performed. + * - To quickly check saving: start a new game, skip intro with start button then go to the + * bottom-right house, enter into the aura circle and press start to bring inventory, select the + * left diary with pen icon (normally disabled). + * - beggarp (below) reuses aforementioned copier check, expects the original bank to live at $0. + * To trigger: after intro, go all the way down then first house on the left (player PoV). + * Character will stumble on key shaped tile, go forward a bit then exit the house + * (bp b4bea to be sure it's triggering) + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_UNL_XINQIG, megadrive_unl_xinqig_device, "megadrive_unl_xinqig", "Megadrive Xin Qi Gai Wang Zi cart") + +megadrive_unl_xinqig_device::megadrive_unl_xinqig_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_tplay96_device(mconfig, type, tag, owner, clock) +{ +} + +megadrive_unl_xinqig_device::megadrive_unl_xinqig_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_unl_xinqig_device(mconfig, MEGADRIVE_UNL_XINQIG, tag, owner, clock) +{ +} + +u16 megadrive_unl_xinqig_device::get_nvram_length() +{ + return 0x4000; +} + +void megadrive_unl_xinqig_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x3f'ffff).bankr(m_rom); + map(0x40'0000, 0x40'7fff).rw(FUNC(megadrive_unl_xinqig_device::nvram_r), FUNC(megadrive_unl_xinqig_device::nvram_w)); +} + +/* + * beggarp Beggar Prince + * + * Super Fighter Team rerelease of xinqig + * + * Reuses the original C&E mapper with an extra $e00 write handler. + * + * $3c'0030 contains a lengthy message explaining why this is protected to begin with. + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_HB_BEGGARP, megadrive_hb_beggarp_device, "megadrive_hb_beggarp", "Megadrive Beggar Prince cart") + +megadrive_hb_beggarp_device::megadrive_hb_beggarp_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : megadrive_unl_xinqig_device(mconfig, type, tag, owner, clock) + , m_sf_rom_bank(*this, "sf_rom_bank") + , m_sf_rom_view(*this, "sf_rom_view") + , m_sram_view(*this, "sram_view") +{ +} + +megadrive_hb_beggarp_device::megadrive_hb_beggarp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_hb_beggarp_device(mconfig, MEGADRIVE_HB_BEGGARP, tag, owner, clock) +{ +} + +void megadrive_hb_beggarp_device::device_start() +{ + megadrive_unl_xinqig_device::device_start(); + memory_region *const romregion(cart_rom_region()); + const u32 page_size = 0x04'0000; + device_generic_cart_interface::map_non_power_of_two( + unsigned(romregion->bytes() / page_size), + [this, base = &romregion->as_u8()] (unsigned entry, unsigned page) + { + m_sf_rom_bank->configure_entry(entry, &base[page * page_size]); + }); +} + + +void megadrive_hb_beggarp_device::device_reset() +{ + megadrive_unl_xinqig_device::device_reset(); + m_sram_view.disable(); + m_sf_rom_view.disable(); + // remaps 0x38'0000 to 0 + m_sf_rom_bank->set_entry(0x0e); + m_bank_write_lock = false; +} + +void megadrive_hb_beggarp_device::bank_write_w(offs_t offset, u16 data, u16 mem_mask) +{ + // Writes 0xa0a0 after the Super Fighter Team logo, that unlocks the NVRAM + logerror("bank_write_w: %04x & %04x (%d)\n", data, mem_mask, m_bank_write_lock); + if (ACCESSING_BITS_0_7) + { + if (m_bank_write_lock) + return; + if (BIT(data, 7)) + { + m_sram_view.select(0); + m_sf_rom_view.select(0); + } + else + { + m_sram_view.disable(); + m_sf_rom_view.disable(); + } + + // TODO: is the game actually using this at all? + if (BIT(data, 6)) + popmessage("megadrive_hb_beggarp_device: cart locked! %04x & %04x", data, mem_mask); + + // once enabled this lock needs an hard reset to lift + m_bank_write_lock = !!(BIT(data, 5)); + } +} + +void megadrive_hb_beggarp_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x3f'ffff).bankr(m_rom); + map(0x00'0000, 0x03'ffff).view(m_sf_rom_view); + m_sf_rom_view[0](0x00'0000, 0x03'ffff).bankr(m_sf_rom_bank); + map(0x00'0e00, 0x00'0e01).w(FUNC(megadrive_hb_beggarp_device::bank_write_w)); + map(0x40'0000, 0x40'7fff).view(m_sram_view); + m_sram_view[0](0x40'0000, 0x40'7fff).rw(FUNC(megadrive_hb_beggarp_device::nvram_r), FUNC(megadrive_hb_beggarp_device::nvram_w)); +} + + + +/* + * beggarp1 Beggar Prince rev 1 + * + * Relocates NVRAM, probably to make game compatible with an expansion attached. + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_HB_BEGGARP1, megadrive_hb_beggarp1_device, "megadrive_hb_beggarp1", "Megadrive Beggar Prince rev 1 cart") + +megadrive_hb_beggarp1_device::megadrive_hb_beggarp1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_hb_beggarp_device(mconfig, MEGADRIVE_HB_BEGGARP1, tag, owner, clock) +{ +} + +void megadrive_hb_beggarp1_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x3f'ffff).bankr(m_rom); + map(0x00'0000, 0x03'ffff).view(m_sf_rom_view); + m_sf_rom_view[0](0x00'0000, 0x03'ffff).bankr(m_sf_rom_bank); + map(0x00'0e00, 0x00'0e01).w(FUNC(megadrive_hb_beggarp1_device::bank_write_w)); + map(0x3c'0000, 0x3f'ffff).view(m_sram_view); + m_sram_view[0](0x3c'0000, 0x3c'7fff).mirror(0x03'8000).rw(FUNC(megadrive_hb_beggarp1_device::nvram_r), FUNC(megadrive_hb_beggarp1_device::nvram_w)); +} + +/* + * wukong Legend of Wukong + * + * More $e00 style writes. Swaps the two halves around. + * + * TODO: + * - technically should derive from megadrive_unl_yasech_device + * + */ + + +DEFINE_DEVICE_TYPE(MEGADRIVE_HB_WUKONG, megadrive_hb_wukong_device, "megadrive_hb_wukong", "Megadrive Legend of Wukong cart") + +megadrive_hb_wukong_device::megadrive_hb_wukong_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_tplay96_device(mconfig, MEGADRIVE_HB_WUKONG, tag, owner, clock) + , m_sf_rom_bank(*this, "sf_rom_bank") + , m_sram_view(*this, "sram_view") +{ +} + +void megadrive_hb_wukong_device::device_start() +{ + megadrive_rom_tplay96_device::device_start(); + memory_region *const romregion(cart_rom_region()); + const u32 page_size = 0x20'0000; + device_generic_cart_interface::map_non_power_of_two( + unsigned(romregion->bytes() / page_size), + [this, base = &romregion->as_u8()] (unsigned entry, unsigned page) + { + m_sf_rom_bank->configure_entry(entry, &base[page * page_size]); + }); + +} + +void megadrive_hb_wukong_device::device_reset() +{ + megadrive_rom_tplay96_device::device_reset(); + m_sram_view.disable(); + m_sf_rom_bank->set_entry(1); +} + +u16 megadrive_hb_wukong_device::get_nvram_length() +{ + // unverified, game just use up to $3c'095f (0x800) + return 0x2000; +} + +void megadrive_hb_wukong_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x1f'ffff).bankr(m_rom); + map(0x20'0000, 0x3f'ffff).bankr(m_sf_rom_bank); + map(0x00'0e00, 0x00'0e01).lw16( + NAME([this] (offs_t offset, u16 data, u16 mem_mask) { + // 0x00 on Super Fighter Team logo + // 0x81 afterwards (where it checks that SRAM works) + logerror("bank_write_w: %04x & %04x\n", data, mem_mask); + if (ACCESSING_BITS_0_7) + { + m_sf_rom_bank->set_entry(!BIT(data, 7)); + if (BIT(data, 0)) + m_sram_view.select(0); + else + m_sram_view.disable(); + } + }) + ); + map(0x3c'0000, 0x3f'ffff).view(m_sram_view); + m_sram_view[0](0x3c'0000, 0x3c'3fff).mirror(0x03'c000).rw(FUNC(megadrive_hb_wukong_device::nvram_r), FUNC(megadrive_hb_wukong_device::nvram_w)); +} + +/* + * starodys Star Odyssey + * https://segaretro.org/Star_Odyssey_(Super_Fighter_Team) + * + * + * + */ + + +DEFINE_DEVICE_TYPE(MEGADRIVE_HB_STARODYS, megadrive_hb_starodys_device, "megadrive_hb_starodys", "Megadrive Star Odyssey cart") + +megadrive_hb_starodys_device::megadrive_hb_starodys_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_tplay96_device(mconfig, MEGADRIVE_HB_STARODYS, tag, owner, clock) + , m_sf_rom_bank(*this, "sf_rom_bank_%u", 0U) + , m_sf_rom_view(*this, "sf_rom_view") + , m_sram_view(*this, "sram_view") +{ +} + +void megadrive_hb_starodys_device::device_start() +{ + megadrive_rom_tplay96_device::device_start(); + memory_region *const romregion(cart_rom_region()); + const u32 page_size = 0x04'0000; + device_generic_cart_interface::map_non_power_of_two( + unsigned(romregion->bytes() / page_size), + [this, base = &romregion->as_u8()] (unsigned entry, unsigned page) + { + for (int i = 0; i < 5; i++) + m_sf_rom_bank[i]->configure_entry(entry, &base[page * page_size]); + }); +} + +void megadrive_hb_starodys_device::device_reset() +{ + megadrive_rom_tplay96_device::device_reset(); + m_sram_view.disable(); + for (int i = 0; i < 5; i++) + m_sf_rom_bank[i]->set_entry(i); + m_sf_rom_view.select(0); + m_bank_num = 0; + m_bank_write_lock = false; +} + +u16 megadrive_hb_starodys_device::get_nvram_length() +{ + // checks up to $20'3fff + return 0x8000; +} + +void megadrive_hb_starodys_device::cart_map(address_map &map) +{ + //map(0x00'0000, 0x1f'ffff).mirror(0x20'0000).bankr(m_rom); + map(0x00'0000, 0x1f'ffff).view(m_sf_rom_view); + m_sf_rom_view[0](0x00'0000, 0x03'ffff).mirror(0x1c'0000).bankr(m_sf_rom_bank[0]); + m_sf_rom_view[1](0x00'0000, 0x03'ffff).bankr(m_sf_rom_bank[0]); + m_sf_rom_view[1](0x04'0000, 0x07'ffff).bankr(m_sf_rom_bank[1]); + m_sf_rom_view[1](0x08'0000, 0x0b'ffff).bankr(m_sf_rom_bank[2]); + m_sf_rom_view[1](0x0c'0000, 0x0f'ffff).bankr(m_sf_rom_bank[3]); + m_sf_rom_view[1](0x10'0000, 0x13'ffff).bankr(m_sf_rom_bank[4]); + map(0x00'0d00, 0x00'0d01).lw16( + NAME([this] (offs_t offset, u16 data, u16 mem_mask) + { + logerror("$d00: %04x & %04x (%d)\n", data, mem_mask, m_bank_write_lock); + if (m_bank_write_lock) + return; + + if (BIT(data, 7)) + m_sram_view.select(0); + else + m_sram_view.disable(); + }) + ); + map(0x00'0e00, 0x00'0e01).lw16( + NAME([this] (offs_t offset, u16 data, u16 mem_mask) + { + logerror("$e00: %04x & %04x (%d)\n", data, mem_mask, m_bank_write_lock); + if (m_bank_write_lock) + return; + + m_bank_write_lock = !!(BIT(~data, 7)); + m_sf_rom_view.select(BIT(data, 6)); + // TODO: is the game actually using this at all? + if (BIT(data, 5)) + popmessage("megadrive_hb_starodys_device: cart locked! %04x & %04x", data, mem_mask); + }) + ); + map(0x00'0f00, 0x00'0f01).lw16( + NAME([this] (offs_t offset, u16 data, u16 mem_mask) + { + logerror("$e00: %04x & %04x (%d)\n", data, mem_mask, m_bank_write_lock); + if (m_bank_write_lock) + return; + + m_bank_num = (data >> 4) & 7; + for (int i = 0; i < 5; i++) + m_sf_rom_bank[i]->set_entry((m_bank_num + i) & 7); + }) + ); + map(0x20'0000, 0x2f'ffff).view(m_sram_view); + m_sram_view[0](0x20'0000, 0x2f'ffff).rw(FUNC(megadrive_hb_starodys_device::nvram_r), FUNC(megadrive_hb_starodys_device::nvram_w)); +} + +void megadrive_hb_starodys_device::time_io_map(address_map &map) +{ + // $a13'001, $a13'005, $a13'009 checked at startup + // $a13'00f after loading a game + map(0x01, 0x01).mirror(0xfe).lr8( + NAME([this] (offs_t offset) { + return m_bank_num << 4; + }) + ); +} diff --git a/src/devices/bus/megadrive/cart/sfteam.h b/src/devices/bus/megadrive/cart/sfteam.h new file mode 100644 index 0000000000000..bd4c48fe9aa06 --- /dev/null +++ b/src/devices/bus/megadrive/cart/sfteam.h @@ -0,0 +1,102 @@ + +// license: BSD-3-Clause +// copyright-holders: Angelo Salese + +#ifndef MAME_BUS_MEGADRIVE_CART_SFTEAM_H +#define MAME_BUS_MEGADRIVE_CART_SFTEAM_H + +#pragma once + +#include "machine/nvram.h" + +#include "rom.h" +#include "sram.h" +#include "slot.h" + + +class megadrive_unl_xinqig_device : public megadrive_rom_tplay96_device +{ +public: + megadrive_unl_xinqig_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; +protected: + megadrive_unl_xinqig_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + virtual u16 get_nvram_length() override ATTR_COLD; +}; + +class megadrive_hb_beggarp_device : public megadrive_unl_xinqig_device +{ +public: + megadrive_hb_beggarp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; + +protected: + megadrive_hb_beggarp_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + memory_bank_creator m_sf_rom_bank; + memory_view m_sf_rom_view; + memory_view m_sram_view; + + void bank_write_w(offs_t offset, u16 data, u16 mem_mask); +private: + bool m_bank_write_lock; +}; + +class megadrive_hb_beggarp1_device : public megadrive_hb_beggarp_device +{ +public: + megadrive_hb_beggarp1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; +}; + +class megadrive_hb_wukong_device : public megadrive_rom_tplay96_device +{ +public: + megadrive_hb_wukong_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; +protected: + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + + virtual u16 get_nvram_length() override ATTR_COLD; +private: + memory_bank_creator m_sf_rom_bank; + memory_view m_sram_view; +}; + +class megadrive_hb_starodys_device : public megadrive_rom_tplay96_device +{ +public: + megadrive_hb_starodys_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; + virtual void time_io_map(address_map &map) override ATTR_COLD; +protected: + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + + virtual u16 get_nvram_length() override ATTR_COLD; +private: + memory_bank_array_creator<5> m_sf_rom_bank; + memory_view m_sf_rom_view; + memory_view m_sram_view; + + u8 m_bank_num; + bool m_bank_write_lock; +}; + + +DECLARE_DEVICE_TYPE(MEGADRIVE_UNL_XINQIG, megadrive_unl_xinqig_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_HB_BEGGARP, megadrive_hb_beggarp_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_HB_BEGGARP1, megadrive_hb_beggarp1_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_HB_WUKONG, megadrive_hb_wukong_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_HB_STARODYS, megadrive_hb_starodys_device) + +#endif // MAME_BUS_MEGADRIVE_CART_SFTEAM_H + diff --git a/src/devices/bus/megadrive/cart/slot.cpp b/src/devices/bus/megadrive/cart/slot.cpp new file mode 100644 index 0000000000000..71fa2d8b83b58 --- /dev/null +++ b/src/devices/bus/megadrive/cart/slot.cpp @@ -0,0 +1,342 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese + +#include "emu.h" +#include "slot.h" + +#include "options.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +DEFINE_DEVICE_TYPE(MEGADRIVE_CART_SLOT, megadrive_cart_slot_device, "megadrive_cart_slot", "MegaDrive Cartridge Slot") + +device_megadrive_cart_interface::device_megadrive_cart_interface(const machine_config &mconfig, device_t &device) + : device_interface(device, "megadrive_cart") + , m_slot(dynamic_cast(device.owner())) +{ +} + +device_megadrive_cart_interface::~device_megadrive_cart_interface() +{ +} + +void device_megadrive_cart_interface::interface_pre_start() +{ + if (!m_slot->started()) + throw device_missing_dependencies(); +} + +void device_megadrive_cart_interface::interface_post_start() +{ + m_slot->m_space_mem->install_device(0x000000, 0xdfffff, *this, &device_megadrive_cart_interface::cart_map); + m_slot->m_space_io->install_device(0x00, 0xff, *this, &device_megadrive_cart_interface::time_io_map); +} + +void device_megadrive_cart_interface::cart_map(address_map &map) +{ + // NOTE: is host responsibility to handle open bus access +// map(0x000000, 0x3fffff).unmaprw(); +} + +// $a13000 base +void device_megadrive_cart_interface::time_io_map(address_map &map) +{ +// map(0x00, 0xff).unmaprw(); +} + + +//void device_megadrive_cart_interface::rom_alloc(size_t size) +//{ +// if (m_rom == nullptr) +// { +// m_rom = (uint16_t *)device().machine().memory().region_alloc(device().subtag("^cart:rom"), size, 2, ENDIANNESS_BIG)->base(); +// m_rom_size = size; +// m_rom_mask = size - 1; +// } +//} + + +megadrive_cart_slot_device::megadrive_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, MEGADRIVE_CART_SLOT, tag, owner, clock) + , device_memory_interface(mconfig, *this) + , device_cartrom_image_interface(mconfig, *this) + , device_single_card_slot_interface(mconfig, *this) + , m_cart(nullptr) + , m_space_mem_config("cart_mem", ENDIANNESS_BIG, 16, 24, 0, address_map_constructor()) + , m_space_io_config("time_io", ENDIANNESS_BIG, 16, 8, 0, address_map_constructor()) +{ +} + +megadrive_cart_slot_device::~megadrive_cart_slot_device() +{ +} + +device_memory_interface::space_config_vector megadrive_cart_slot_device::memory_space_config() const +{ + return space_config_vector{ + std::make_pair(AS_PROGRAM, &m_space_mem_config), + std::make_pair(AS_IO, &m_space_io_config) + }; +} + +void megadrive_cart_slot_device::device_start() +{ + m_cart = get_card_device(); + m_space_mem = &space(AS_PROGRAM); + m_space_io = &space(AS_IO); +} + +const char *megadrive_cart_slot_device::get_cart_type(const uint8_t *ROM, uint32_t len) +{ + using namespace bus::megadrive; + +// int type = slotoptions::MD_STD; + // TODO: not caring about loose detection for now + return slotoptions::MD_STD; +} + +//static int md_get_pcb_id(const char *slot) +//{ +// for (auto & elem : slot_list) +// { +// if (!strcmp(elem.slot_option, slot)) +// return elem.pcb_id; +// } +// +// return MD_STD; +//} + +//static const char *md_get_slot(int type) +//{ +// for (auto & elem : slot_list) +// { +// if (elem.pcb_id == type) +// return elem.slot_option; +// } +// +// return "rom"; +//} + +std::pair megadrive_cart_slot_device::call_load() +{ + if (m_cart) + { + std::error_condition err; + + if (loaded_through_softlist()) + { + err = load_swlist(); + } + else + { + err = load_loose(); + } + + if (err) + return std::make_pair(err ? err : std::errc::io_error, "Error loading detection"); + } + + return std::make_pair(std::error_condition(), std::string()); +} + +std::error_condition megadrive_cart_slot_device::load_swlist() +{ + using namespace bus::megadrive; + +// uint16_t *ROM; +// uint32_t length = get_software_region_length("rom"); + const char *slot_name; +// +// // if cart size is not (2^n * 64K), the system will see anyway that size so we need to alloc a bit more space +// length = m_cart->get_padded_size(length); +// +// memory_region *const romregion = machine().memory().region_alloc(subtag("rom"), length, 2, ENDIANNESS_BIG); +// auto const [err, actual] = read_at(file, offset, romregion->base(), len); +// if (err || (len != actual)) +// return std::make_pair(err ? err : std::errc::io_error, "Error reading ROM data from cartridge file"); +// +//// m_cart->rom_alloc(length); +//// ROM = m_cart->get_rom_base(); +// memcpy(romregion, get_software_region("rom"), get_software_region_length("rom")); +// +// // if we allocated a ROM larger that the file (e.g. due to uneven cart size), set remaining space to 0xff +// if (length > get_software_region_length("rom")) +// memset(romregion + get_software_region_length("rom")/2, 0xffff, (length - get_software_region_length("rom"))/2); +// + slot_name = get_feature("slot"); + if (slot_name == nullptr) + slot_name = slotoptions::MD_STD; + +// printf("%s\n", slot_name); + return std::error_condition(m_cart->load()); +} + +std::error_condition megadrive_cart_slot_device::load_loose() +{ + return std::error_condition(); + +// unsigned char *ROM; +// bool is_smd, is_md; +// uint32_t tmplen = length(), offset, len; +// std::vector tmpROM(tmplen); +// +// // STEP 1: store a (possibly headered) copy of the file and determine its type (SMD? MD? BIN?) +// fread(&tmpROM[0], tmplen); +// is_smd = false; //genesis_is_SMD(&tmpROM[0x200], tmplen - 0x200); +// is_md = (tmpROM[0x80] == 'E') && (tmpROM[0x81] == 'A') && (tmpROM[0x82] == 'M' || tmpROM[0x82] == 'G'); +// +// // take header into account, if any +// offset = is_smd ? 0x200 : 0; +// +// // STEP 2: allocate space for the real copy of the game +// // if cart size is not (2^n * 64K), the system will see anyway that size so we need to alloc a bit more space +// len = m_cart->get_padded_size(tmplen - offset); +// +// // this contains an hack for SSF2: its current bankswitch code needs larger ROM space to work +// // m_cart->rom_alloc((len == 0x500000) ? 0x900000 : len); +// +// // STEP 3: copy the game data in the appropriate way +// ROM = (unsigned char *)m_cart->get_rom_base(); +// +// if (is_smd) +// { +// osd_printf_debug("SMD!\n"); +// +// for (int ptr = 0; ptr < (tmplen - 0x200) / 0x2000; ptr += 2) +// { +// for (int x = 0; x < 0x2000; x++) +// { +// ROM[ptr * 0x2000 + x * 2 + 0] = tmpROM[0x200 + ((ptr + 1) * 0x2000) + x]; +// ROM[ptr * 0x2000 + x * 2 + 1] = tmpROM[0x200 + ((ptr + 0) * 0x2000) + x]; +// } +// } +// } +// else if (is_md) +// { +// osd_printf_debug("MD!\n"); +// +// for (int ptr = 0; ptr < tmplen; ptr += 2) +// { +// ROM[ptr] = tmpROM[(tmplen >> 1) + (ptr >> 1)]; +// ROM[ptr + 1] = tmpROM[(ptr >> 1)]; +// } +// } +// else +// { +// osd_printf_debug("BIN!\n"); +// +// fseek(0, SEEK_SET); +// fread(ROM, len); +// } +// +// // if we allocated a ROM larger that the file (e.g. due to uneven cart size), set remaining space to 0xff +// //if (len > (tmplen - offset)) +// // memset(m_cart->get_rom_base() + (tmplen - offset)/2, 0xffff, (len - tmplen + offset)/2); +// +// // STEP 4: determine the cart type (to deal with sram/eeprom & pirate mappers) +// // m_type = get_cart_type(ROM, tmplen - offset); +// +//// CPU needs to access ROM as a ROM_REGION16_BE, so we need to compensate on LE machines +//#ifdef LSB_FIRST +// unsigned char fliptemp; +// for (int ptr = 0; ptr < len; ptr += 2) +// { +// fliptemp = ROM[ptr]; +// ROM[ptr] = ROM[ptr+1]; +// ROM[ptr+1] = fliptemp; +// } +//#endif +// +// return std::error_condition(); +} + + +std::string megadrive_cart_slot_device::get_default_card_software(get_default_card_software_hook &hook) const +{ + using namespace bus::megadrive; + + if (hook.image_file()) + { + uint64_t len; + + if (hook.image_file()->length(len)) + { + osd_printf_warning("[%s] Error getting cartridge ROM length - defaulting to linear ROM type\n", tag()); + return slotoptions::MD_STD; + } + + std::vector rom(len); + + // FIXME: check error return or read returning short + util::read(*hook.image_file(), &rom[0], len); + + uint32_t const offset = 0; // genesis_is_SMD(&rom[0x200], len - 0x200) ? 0x200 : 0; + +// int const type = get_cart_type(&rom[offset], len - offset); + char const *const slot_string = get_cart_type(&rom[offset], len - offset); + + return std::string(slot_string); + } + else + { + return software_get_default_slot(slotoptions::MD_STD); + } +} + + +uint32_t device_megadrive_cart_interface::get_padded_size(uint32_t size) +{ + uint32_t pad_size = 0x10000; + while (size > pad_size) + pad_size <<= 1; + + if (pad_size < 0x800000 && size < pad_size) + return pad_size; + else + return size; +} + + +void megadrive_cart_slot_device::call_unload() +{ + if (m_cart) + m_cart->unload(); +// if (m_cart && m_cart->get_nvram_base() && m_cart->get_nvram_size()) +// battery_save(m_cart->get_nvram_base(), m_cart->get_nvram_size()); +} + +// 0x000000-0x3fffff +// shift << 1 here and not in memory constructor for two reasons: +// 1. cart has no A0 connected +// 2. memory_views would get confused by the shift with +// "A memory_view must be installed at its configuration address." +u16 megadrive_cart_slot_device::base_r(offs_t offset, u16 mem_mask) +{ + return m_space_mem->read_word(offset << 1, mem_mask); +} + +void megadrive_cart_slot_device::base_w(offs_t offset, u16 data, u16 mem_mask) +{ + m_space_mem->write_word(offset << 1, data, mem_mask); +} + +u16 megadrive_cart_slot_device::time_r(offs_t offset, u16 mem_mask) +{ + return m_space_io->read_word(offset << 1, mem_mask); +} + +void megadrive_cart_slot_device::time_w(offs_t offset, u16 data, u16 mem_mask) +{ + m_space_io->write_word(offset << 1, data, mem_mask); +} + diff --git a/src/devices/bus/megadrive/cart/slot.h b/src/devices/bus/megadrive/cart/slot.h new file mode 100644 index 0000000000000..8a7da94fc086c --- /dev/null +++ b/src/devices/bus/megadrive/cart/slot.h @@ -0,0 +1,106 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese + +#ifndef MAME_BUS_MEGADRIVE_CART_SLOT_H +#define MAME_BUS_MEGADRIVE_CART_SLOT_H + +#pragma once + +#include "imagedev/cartrom.h" + +class device_megadrive_cart_interface; + +class megadrive_cart_slot_device : public device_t, + public device_memory_interface, + public device_cartrom_image_interface, + public device_single_card_slot_interface +{ +public: + // construction/destruction + template + megadrive_cart_slot_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, T &&opts, char const *dflt) + : megadrive_cart_slot_device(mconfig, tag, owner, clock) + { + option_reset(); + opts(*this); + set_default_option(dflt); + set_fixed(false); + } + megadrive_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + virtual ~megadrive_cart_slot_device(); + + // TODO: should be false for megapc + virtual bool is_reset_on_load() const noexcept override { return true; } + virtual const char *image_interface() const noexcept override { return "megadriv_cart"; } + virtual const char *file_extensions() const noexcept override { return "smd,bin,md,gen"; } + + u16 base_r(offs_t offset, u16 mem_mask); + void base_w(offs_t offset, u16 data, u16 mem_mask); + + u16 time_r(offs_t offset, u16 mem_mask); + void time_w(offs_t offset, u16 data, u16 mem_mask); + + virtual std::pair call_load() override; + virtual void call_unload() override; + +protected: + virtual void device_start() override ATTR_COLD; + virtual space_config_vector memory_space_config() const override; + + virtual std::string get_default_card_software(get_default_card_software_hook &hook) const override; + static const char *get_cart_type(const uint8_t *ROM, uint32_t len); +private: + device_megadrive_cart_interface *m_cart; + + friend class device_megadrive_cart_interface; + + address_space_config m_space_mem_config; + address_space_config m_space_io_config; + + address_space *m_space_mem; + address_space *m_space_io; + + std::error_condition load_swlist(); + std::error_condition load_loose(); +}; + +class device_megadrive_cart_interface : public device_interface +{ +public: + // construction/destruction + virtual ~device_megadrive_cart_interface(); + + uint32_t get_padded_size(uint32_t size); + + bool loaded_through_softlist() const { return m_slot && m_slot->loaded_through_softlist(); } + char const *get_feature(std::string_view feature_name) const { return m_slot ? m_slot->get_feature(feature_name) : nullptr; } + + memory_region *cart_rom_region() { return m_slot ? m_slot->memregion("rom") : nullptr; } + memory_region *cart_sram_region() { return m_slot ? m_slot->memregion("sram") : nullptr; } + + void battery_load(void *buffer, int length, int fill) { assert(m_slot); m_slot->battery_load(buffer, length, fill); } + void battery_load(void *buffer, int length, void *def_buffer) { assert(m_slot); m_slot->battery_load(buffer, length, def_buffer); } + void battery_save(void const *buffer, int length) { assert(m_slot); m_slot->battery_save(buffer, length); } + + virtual std::error_condition load() ATTR_COLD { return std::error_condition(); }; + virtual void unload() ATTR_COLD { }; + +protected: + device_megadrive_cart_interface(const machine_config &mconfig, device_t &device); + + virtual void interface_pre_start() override; + virtual void interface_post_start() override; + megadrive_cart_slot_device *const m_slot; + + virtual void cart_map(address_map &map) ATTR_COLD; + virtual void time_io_map(address_map &map) ATTR_COLD; + + // device_start, /MRES B2 + // device_reset, /VRES B27 +}; + + +DECLARE_DEVICE_TYPE(MEGADRIVE_CART_SLOT, megadrive_cart_slot_device) + + +#endif // MAME_BUS_MEGADRIVE_CART_SLOT_H diff --git a/src/devices/bus/megadrive/cart/smb.cpp b/src/devices/bus/megadrive/cart/smb.cpp new file mode 100644 index 0000000000000..b14c661fa97e3 --- /dev/null +++ b/src/devices/bus/megadrive/cart/smb.cpp @@ -0,0 +1,79 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese +/************************************************************************************************** + +Super Mario Bros cart mappers + +"decode error" printed if protection fails + +TODO: +- are these really hacked versions? Rockman X3 does a few Gamtec style checks, ignored by the code + +**************************************************************************************************/ + +#include "emu.h" +#include "smb.h" + +/* + * Super Mario World / Super Mario Bros. + * https://segaretro.org/Super_Mario_World + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_UNL_SMB, megadrive_unl_smb_device, "megadrive_unl_smb", "Megadrive Super Mario World cart") + +megadrive_unl_smb_device::megadrive_unl_smb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, MEGADRIVE_UNL_SMB, tag, owner, clock) +{ +} + +void megadrive_unl_smb_device::time_io_map(address_map &map) +{ + map(0x00, 0x01).lr16(NAME([] () { return 0x001c; })); +} + +/* + * Super Mario Bros. 2 + * https://segaretro.org/Super_Mario_2_1998 + * + */ + + +DEFINE_DEVICE_TYPE(MEGADRIVE_UNL_SMB2, megadrive_unl_smb2_device, "megadrive_unl_smb2", "Megadrive Super Mario Bros 2 cart") + +megadrive_unl_smb2_device::megadrive_unl_smb2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, MEGADRIVE_UNL_SMB2, tag, owner, clock) +{ +} + +void megadrive_unl_smb2_device::time_io_map(address_map &map) +{ + map(0x00, 0x01).lr16(NAME([] () { return 0x000a; })); +} + +/* + * Rockman X3 + * https://segaretro.org/Rockman_X3_(Mega_Drive) + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_UNL_ROCKMANX3, megadrive_unl_rockmanx3_device, "megadrive_unl_rockmanx3", "Megadrive Rockman X3 cart") + +megadrive_unl_rockmanx3_device::megadrive_unl_rockmanx3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, MEGADRIVE_UNL_ROCKMANX3, tag, owner, clock) +{ +} + +void megadrive_unl_rockmanx3_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x3f'ffff).bankr(m_rom); + map(0x40'0004, 0x40'0004).lr8(NAME([] () { return 0xc9; })); // PC=a9d2, startup, anded with 0x9c + map(0x40'0006, 0x40'0006).lr8(NAME([] () { return 0xf0; })); // PC=12e0, start of level + +} + +void megadrive_unl_rockmanx3_device::time_io_map(address_map &map) +{ + map(0x00, 0x01).lr16(NAME([] () { return 0x000c; })); +} + diff --git a/src/devices/bus/megadrive/cart/smb.h b/src/devices/bus/megadrive/cart/smb.h new file mode 100644 index 0000000000000..581e5c9da2f4c --- /dev/null +++ b/src/devices/bus/megadrive/cart/smb.h @@ -0,0 +1,44 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese + +#ifndef MAME_BUS_MEGADRIVE_CART_SMB_H +#define MAME_BUS_MEGADRIVE_CART_SMB_H + +#pragma once + +#include "rom.h" +#include "slot.h" + +class megadrive_unl_smb_device : public megadrive_rom_device +{ +public: + megadrive_unl_smb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void time_io_map(address_map &map) override ATTR_COLD; +}; + +class megadrive_unl_smb2_device : public megadrive_rom_device +{ +public: + megadrive_unl_smb2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void time_io_map(address_map &map) override ATTR_COLD; +}; + +class megadrive_unl_rockmanx3_device : public megadrive_rom_device +{ +public: + megadrive_unl_rockmanx3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; + virtual void time_io_map(address_map &map) override ATTR_COLD; +}; + + + +DECLARE_DEVICE_TYPE(MEGADRIVE_UNL_SMB, megadrive_unl_smb_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_UNL_SMB2, megadrive_unl_smb2_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_UNL_ROCKMANX3, megadrive_unl_rockmanx3_device) + + +#endif // MAME_BUS_MEGADRIVE_CART_SMB_H diff --git a/src/devices/bus/megadrive/cart/smw64.cpp b/src/devices/bus/megadrive/cart/smw64.cpp new file mode 100644 index 0000000000000..5e66a2dbe8ded --- /dev/null +++ b/src/devices/bus/megadrive/cart/smw64.cpp @@ -0,0 +1,141 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese +/************************************************************************************************** + +Super Mario World 64 cart mappers + +https://segaretro.org/Super_Mario_World_64 + +Looks its own thing compared to anything else + +TODO: +- some blanks, sound can crash after a while (which looks the main thing they bothered to protect); + +**************************************************************************************************/ + +#include "emu.h" +#include "smw64.h" + +#include "bus/generic/slot.h" + +DEFINE_DEVICE_TYPE(MEGADRIVE_UNL_SMW64, megadrive_unl_smw64_device, "megadrive_unl_smw64", "Megadrive Super Mario World 64 cart") + +megadrive_unl_smw64_device::megadrive_unl_smw64_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, MEGADRIVE_UNL_SMW64, tag, owner, clock) + , m_page_rom(*this, "page_rom_%u", 0U) +{ +} + +void megadrive_unl_smw64_device::device_start() +{ + megadrive_rom_device::device_start(); + memory_region *const romregion(cart_rom_region()); + const u32 page_size = 0x01'0000; + device_generic_cart_interface::map_non_power_of_two( + unsigned(romregion->bytes() / page_size), + [this, base = &romregion->as_u8()] (unsigned entry, unsigned page) + { + m_page_rom[0]->configure_entry(entry, &base[page * page_size]); + m_page_rom[1]->configure_entry(entry, &base[page * page_size]); + }); + + save_pointer(NAME(m_latch), 3); + save_pointer(NAME(m_ctrl), 2); + save_pointer(NAME(m_data), 2); + save_item(NAME(m_page_67)); +} + +void megadrive_unl_smw64_device::device_reset() +{ + megadrive_rom_device::device_reset(); + + m_page_rom[0]->set_entry(8); + m_page_rom[1]->set_entry(8); +} + +void megadrive_unl_smw64_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x07'ffff).mirror(0x08'0000).bankr(m_rom); + map(0x60'0000, 0x60'ffff).mirror(0x08'0000).bankr(m_page_rom[0]); + map(0x61'0000, 0x61'ffff).mirror(0x08'0000).bankr(m_page_rom[1]); + map(0x60'0001, 0x60'0001).lw8( + NAME([this] (offs_t offset, u8 data) { + m_ctrl[0] = data; + }) + ); + map(0x60'0003, 0x60'0003).lw8( + NAME([this] (offs_t offset, u8 data) { + switch(m_ctrl[0] & 7) + { + case 0: m_latch[0] = ((m_latch[0] ^ m_data[0]) ^ data) & 0xfe; break; + case 1: m_latch[1] = data & 0xfe; break; + // often, unknown purpose + case 6: break; + case 7: m_page_rom[1]->set_entry(8 + ((data & 0x1c) >> 2)); break; + default: + logerror("$60'0003 unknown mode %02x\n", m_ctrl[0]); + break; + } + m_data[0] = data; + }) + ); + map(0x61'0003, 0x61'0003).lw8( + NAME([this] (offs_t offset, u8 data) { + m_page_61 = data; + }) + ); + map(0x64'0001, 0x64'0001).lw8( + NAME([this] (offs_t offset, u8 data) { + m_ctrl[1] = data; + }) + ); + // 0x64'0003 rmw at startup (& 0xc0 ^ 0x55) + map(0x64'0003, 0x64'0003).lw8( + NAME([this] (offs_t offset, u8 data) { + m_data[1] = data; + }) + ); + // unknown writes, in tandem with mode 6 in $60'0003 + map(0x66'0000, 0x66'0001).nopw(); + map(0x66'0001, 0x66'0001).lr8(NAME([this] () { return m_latch[0]; })); + map(0x66'0003, 0x66'0003).lr8(NAME([this] () { return m_latch[0] + 1; })); + map(0x66'0005, 0x66'0005).lr8(NAME([this] () { return m_latch[1]; })); + map(0x66'0007, 0x66'0007).lr8(NAME([this] () { return m_latch[1] + 1; })); + map(0x66'0009, 0x66'0009).lr8(NAME([this] () { return m_latch[2]; })); + map(0x66'000b, 0x66'000b).lr8(NAME([this] () { return m_latch[2] + 1; })); + map(0x66'000d, 0x66'000d).lr8(NAME([this] () { return m_latch[2] + 2; })); + map(0x66'000f, 0x66'000f).lr8(NAME([this] () { return m_latch[2] + 3; })); + + map(0x67'0001, 0x67'0001).select(2).lr8( + NAME([this] (offs_t offset) { + u8 res = 0; + if (BIT(m_page_61, 7)) + { + if (BIT(m_page_67, 6)) + res = m_ctrl[1] & m_data[1]; + else + res = m_ctrl[1] ^ 0xff; + } + + if (BIT(offset, 1)) + res &= 0x7f; + else if (!machine().side_effects_disabled() && BIT(m_page_67, 7)) + { + if (BIT(m_page_67, 5)) + m_latch[2] = (m_data[1] << 2) & 0xfc; + else + m_latch[0] = (m_data[0] ^ (m_ctrl[1] << 1)) & 0xfe; + } + + return res; + }) + ); + map(0x67'0001, 0x67'0001).lw8( + NAME([this] (offs_t offset, u8 data) { + m_page_67 = data; + if (BIT(m_page_61, 7)) + m_page_rom[0]->set_entry(8 + ((data & 0x1c) >> 2)); + }) + ); + +} diff --git a/src/devices/bus/megadrive/cart/smw64.h b/src/devices/bus/megadrive/cart/smw64.h new file mode 100644 index 0000000000000..c5e615beeb41e --- /dev/null +++ b/src/devices/bus/megadrive/cart/smw64.h @@ -0,0 +1,37 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese + +#ifndef MAME_BUS_MEGADRIVE_CART_SMW64_H +#define MAME_BUS_MEGADRIVE_CART_SMW64_H + +#pragma once + +#include "rom.h" +#include "slot.h" + +class megadrive_unl_smw64_device : public megadrive_rom_device +{ +public: + megadrive_unl_smw64_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + static constexpr feature_type imperfect_features() { return feature::PROTECTION; } + + virtual void cart_map(address_map &map) override ATTR_COLD; +protected: + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; +private: + memory_bank_array_creator<2> m_page_rom; + + u8 m_ctrl[2]; + u8 m_data[2]; + u8 m_latch[3]; + u8 m_page_61, m_page_67; +}; + + + +DECLARE_DEVICE_TYPE(MEGADRIVE_UNL_SMW64, megadrive_unl_smw64_device) + + +#endif // MAME_BUS_MEGADRIVE_CART_SMW64_H diff --git a/src/devices/bus/megadrive/cart/sram.cpp b/src/devices/bus/megadrive/cart/sram.cpp new file mode 100644 index 0000000000000..e20e968acc409 --- /dev/null +++ b/src/devices/bus/megadrive/cart/sram.cpp @@ -0,0 +1,296 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese + +#include "emu.h" +#include "sram.h" + +/* + * Generic ROM + SRAM (Sega style) + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_ROM_SRAM, megadrive_rom_sram_device, "megadrive_rom_sram", "Megadrive Sega ROM + SRAM cart") + +megadrive_rom_sram_device::megadrive_rom_sram_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, type, tag, owner, clock) + , m_sram_view(*this, "sram_view") +{ +} + +megadrive_rom_sram_device::megadrive_rom_sram_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_sram_device(mconfig, MEGADRIVE_ROM_SRAM, tag, owner, clock) +{ +} + + +std::error_condition megadrive_rom_sram_device::load() +{ + memory_region *const nvramregion(cart_sram_region()); + + if (nvramregion) + { + m_nvram_base = reinterpret_cast(nvramregion->base()); + m_nvram_size = nvramregion->bytes(); + m_nvram_mask = m_nvram_size - 1; + + if (m_nvram_size & m_nvram_mask) + return image_error::BADSOFTWARE; + + save_pointer(NAME(m_nvram_base), m_nvram_size); + battery_load(m_nvram_base, m_nvram_size, nullptr); + } + else + { + osd_printf_error("sram region not found\n"); + return image_error::BADSOFTWARE; + } + + return std::error_condition(); +} + + +void megadrive_rom_sram_device::unload() +{ + memory_region *const nvramregion(this->cart_sram_region()); + if (nvramregion && nvramregion->bytes()) + this->battery_save(nvramregion->base(), nvramregion->bytes()); +} + +void megadrive_rom_sram_device::device_start() +{ + megadrive_rom_device::device_start(); + memory_region *const nvramregion(cart_sram_region()); + // FIXME: initialize this thru load fn + if (!nvramregion) + throw emu_fatalerror("Missing SRAM region, cannot initialize\n"); + m_nvram_size = nvramregion->bytes(); + m_nvram_mask = m_nvram_size - 1; + save_item(NAME(m_nvram_write_protect)); +} + +void megadrive_rom_sram_device::device_reset() +{ + megadrive_rom_device::device_reset(); + m_nvram_write_protect = false; + m_sram_view.select(0); +} + + +void megadrive_rom_sram_device::cart_map(address_map &map) +{ + megadrive_rom_device::cart_map(map); + // TODO: most if not all of them really uses 8-bit interface + map(0x20'0000, 0x20'0001 | m_nvram_mask).view(m_sram_view); + m_sram_view[0](0x20'0000, 0x20'0001 | m_nvram_mask).lrw8( + NAME([this] (offs_t offset) { + return m_nvram_base[offset]; + }), + NAME([this] (offs_t offset, u8 data) { + if (!m_nvram_write_protect) + m_nvram_base[offset] = data; + }) + ); +} + +void megadrive_rom_sram_device::time_io_map(address_map &map) +{ + // TODO: does all Sega games have this? + // there must be a threshold where this is a thing vs. where is not ... + map(0xf1, 0xf1).lw8(NAME([this] (offs_t offset, u8 data) { + if (BIT(data, 1)) + m_sram_view.disable(); + else + m_sram_view.select(0); + m_nvram_write_protect = !!BIT(data, 0); + })); +} + +/* + * Sonic 3 + * Uses it's own (earlier?) version where bit 0 is the view select, swapped, and no write protect + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_ROM_SONIC3, megadrive_rom_sonic3_device, "megadrive_rom_sonic3", "Megadrive Sonic 3 ROM + SRAM cart") + +megadrive_rom_sonic3_device::megadrive_rom_sonic3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_sram_device(mconfig, MEGADRIVE_ROM_SONIC3, tag, owner, clock) +{ +} + +void megadrive_rom_sonic3_device::time_io_map(address_map &map) +{ + map(0xf1, 0xf1).lw8(NAME([this] (offs_t offset, u8 data) { + if (BIT(data, 0)) + m_sram_view.select(0); + else + m_sram_view.disable(); + })); +} + +/* + * Triple Play '96 + * + * 8-bit NVRAM with NO write protection control lanes + * At title screen hold A+B+C then press start, SFX plays, release all to get prompted for NVRAM + * reinitialize. + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_ROM_TPLAY96, megadrive_rom_tplay96_device, "megadrive_rom_tplay96", "Megadrive Triple Play '96 cart") + +megadrive_rom_tplay96_device::megadrive_rom_tplay96_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, type, tag, owner, clock) + , m_nvram(*this, "nvram") +{ +} + +megadrive_rom_tplay96_device::megadrive_rom_tplay96_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_tplay96_device(mconfig, MEGADRIVE_ROM_TPLAY96, tag, owner, clock) +{ +} + + +void megadrive_rom_tplay96_device::device_add_mconfig(machine_config &config) +{ + NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_1); +} + +u16 megadrive_rom_tplay96_device::get_nvram_length() +{ + return 0x8000; +} + +void megadrive_rom_tplay96_device::device_start() +{ + megadrive_rom_device::device_start(); + const u32 nvram_size = get_nvram_length(); + m_nvram_ptr = std::make_unique(nvram_size); + m_nvram->set_base(m_nvram_ptr.get(), nvram_size); + + save_pointer(NAME(m_nvram_ptr), nvram_size); + m_nvram_mask = nvram_size - 1; +} + +u16 megadrive_rom_tplay96_device::nvram_r(offs_t offset) +{ + const u32 nvram_offset = offset & m_nvram_mask; + return 0xff00 | m_nvram_ptr[nvram_offset]; +} + +void megadrive_rom_tplay96_device::nvram_w(offs_t offset, u16 data, u16 mem_mask) +{ + if (ACCESSING_BITS_0_7) + { + const u32 nvram_offset = offset & m_nvram_mask; + m_nvram_ptr[nvram_offset] = data & 0xff; + } +} + +void megadrive_rom_tplay96_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x3f'ffff).bankr(m_rom); + map(0x20'0000, 0x20'ffff).rw(FUNC(megadrive_rom_tplay96_device::nvram_r), FUNC(megadrive_rom_tplay96_device::nvram_w)); +} + +/* + * Hardball '95 + * Relocated NVRAM + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_ROM_HARDBALL95, megadrive_rom_hardball95_device, "megadrive_rom_hardball95", "Megadrive Hardball '95 cart") + +megadrive_rom_hardball95_device::megadrive_rom_hardball95_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_tplay96_device(mconfig, MEGADRIVE_ROM_HARDBALL95, tag, owner, clock) +{ +} + +void megadrive_rom_hardball95_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x3f'ffff).bankr(m_rom); + map(0x30'0000, 0x30'ffff).rw(FUNC(megadrive_rom_hardball95_device::nvram_r), FUNC(megadrive_rom_hardball95_device::nvram_w)); +} + +/* + * Barkley Shut Up and Jam 2 + * header indicates $20'0001 - $20'0fff as SRAM but in-game it uses a mirror at $23'xxxx + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_ROM_BARKLEY2, megadrive_rom_barkley2_device, "megadrive_rom_barkley2", "Megadrive Barkley Shut Up and Jam 2 cart") + +megadrive_rom_barkley2_device::megadrive_rom_barkley2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_tplay96_device(mconfig, MEGADRIVE_ROM_BARKLEY2, tag, owner, clock) +{ +} + +u16 megadrive_rom_barkley2_device::get_nvram_length() +{ + return 0x800; +} + +void megadrive_rom_barkley2_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x1f'ffff).bankr(m_rom); + map(0x20'0000, 0x3f'ffff).rw(FUNC(megadrive_rom_barkley2_device::nvram_r), FUNC(megadrive_rom_barkley2_device::nvram_w)); +} + + + +/* + * San Guo Zhi V / Tun Shi Tian Di III + * + * sanguo5 https://segaretro.org/San_Guo_Zhi_V + * tunshi / tunshi1 https://segaretro.org/Tun_Shi_Tian_Di_III + * + * SKOB published games with invalid header and SRAM at $20'0000 + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_UNL_SANGUO5, megadrive_unl_sanguo5_device, "megadrive_unl_sanguo5", "Megadrive San Guo Zhi V cart") + + +megadrive_unl_sanguo5_device::megadrive_unl_sanguo5_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, MEGADRIVE_UNL_SANGUO5, tag, owner, clock) + , m_nvram(*this, "nvram") +{ +} + +void megadrive_unl_sanguo5_device::device_add_mconfig(machine_config &config) +{ + NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_1); +} + +void megadrive_unl_sanguo5_device::device_start() +{ + megadrive_rom_device::device_start(); + const u32 nvram_size = 0x2000; + m_nvram_ptr = std::make_unique(nvram_size); + m_nvram->set_base(m_nvram_ptr.get(), nvram_size); + + save_pointer(NAME(m_nvram_ptr), nvram_size); +} + +u16 megadrive_unl_sanguo5_device::nvram_r(offs_t offset) +{ + const u32 nvram_offset = offset & 0x1fff; + return 0xff00 | m_nvram_ptr[nvram_offset]; +} + +void megadrive_unl_sanguo5_device::nvram_w(offs_t offset, u16 data, u16 mem_mask) +{ + if (ACCESSING_BITS_0_7) + { + const u32 nvram_offset = offset & 0x1fff; + m_nvram_ptr[nvram_offset] = data & 0xff; + } +} + +void megadrive_unl_sanguo5_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x3f'ffff).bankr(m_rom); + map(0x20'0000, 0x20'3fff).rw(FUNC(megadrive_unl_sanguo5_device::nvram_r), FUNC(megadrive_unl_sanguo5_device::nvram_w)); +} + + diff --git a/src/devices/bus/megadrive/cart/sram.h b/src/devices/bus/megadrive/cart/sram.h new file mode 100644 index 0000000000000..a9b9b75002de7 --- /dev/null +++ b/src/devices/bus/megadrive/cart/sram.h @@ -0,0 +1,115 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese + +#ifndef MAME_BUS_MEGADRIVE_CART_SRAM_H +#define MAME_BUS_MEGADRIVE_CART_SRAM_H + +#pragma once + +#include "machine/nvram.h" + +#include "rom.h" +#include "slot.h" + +class megadrive_rom_sram_device : public megadrive_rom_device +{ +public: + megadrive_rom_sram_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; + virtual void time_io_map(address_map &map) override ATTR_COLD; + +protected: + megadrive_rom_sram_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + + virtual std::error_condition load() override ATTR_COLD; + virtual void unload() override ATTR_COLD; + + memory_view m_sram_view; +private: + u8 *m_nvram_base; + u32 m_nvram_size, m_nvram_mask; + + bool m_nvram_write_protect; +}; + +class megadrive_rom_sonic3_device : public megadrive_rom_sram_device +{ +public: + megadrive_rom_sonic3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void time_io_map(address_map &map) override ATTR_COLD; +}; + +class megadrive_rom_tplay96_device : public megadrive_rom_device +{ +public: + megadrive_rom_tplay96_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; + +protected: + megadrive_rom_tplay96_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + virtual void device_start() override ATTR_COLD; + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; + + virtual u16 get_nvram_length() ATTR_COLD; + + u16 nvram_r(offs_t offset); + void nvram_w(offs_t offset, u16 data, u16 mem_mask); + +private: + required_device m_nvram; + std::unique_ptr m_nvram_ptr; + u16 m_nvram_mask; +}; + +class megadrive_rom_hardball95_device : public megadrive_rom_tplay96_device +{ +public: + megadrive_rom_hardball95_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; +}; + +class megadrive_rom_barkley2_device : public megadrive_rom_tplay96_device +{ +public: + megadrive_rom_barkley2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; +protected: + virtual u16 get_nvram_length() override ATTR_COLD; +}; + +class megadrive_unl_sanguo5_device : public megadrive_rom_device +{ +public: + megadrive_unl_sanguo5_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; +protected: + virtual void device_start() override ATTR_COLD; + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; + + u16 nvram_r(offs_t offset); + void nvram_w(offs_t offset, u16 data, u16 mem_mask); + +private: + required_device m_nvram; + std::unique_ptr m_nvram_ptr; +}; + + +DECLARE_DEVICE_TYPE(MEGADRIVE_ROM_SRAM, megadrive_rom_sram_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_ROM_SONIC3, megadrive_rom_sonic3_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_ROM_TPLAY96, megadrive_rom_tplay96_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_ROM_HARDBALL95, megadrive_rom_hardball95_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_ROM_BARKLEY2, megadrive_rom_barkley2_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_UNL_SANGUO5, megadrive_unl_sanguo5_device) + +#endif // MAME_BUS_MEGADRIVE_CART_SRAM_H diff --git a/src/devices/bus/megadrive/cart/ssf.cpp b/src/devices/bus/megadrive/cart/ssf.cpp new file mode 100644 index 0000000000000..c62ae6c5a83f5 --- /dev/null +++ b/src/devices/bus/megadrive/cart/ssf.cpp @@ -0,0 +1,223 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese +/************************************************************************************************** + +Krikzz "SEGA SSF" mapper + +https://krikzz.com/pub/support/mega-everdrive/v1/dev/extended_ssf-v2.txt + +**************************************************************************************************/ + +#include "emu.h" +#include "ssf.h" + +DEFINE_DEVICE_TYPE(MEGADRIVE_HB_SSF, megadrive_hb_ssf_device, "megadrive_hb_ssf", "Megadrive Krikzz Sega SSF cart") + +megadrive_hb_ssf_device::megadrive_hb_ssf_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_ssf2_device(mconfig, type, tag, owner, clock) +{ +} + +megadrive_hb_ssf_device::megadrive_hb_ssf_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_hb_ssf_device(mconfig, MEGADRIVE_HB_SSF, tag, owner, clock) +{ +} + +// NOTE: same as Sega mapper (Demons of Asteborg wants it this way) +void megadrive_hb_ssf_device::time_f0_w(offs_t offset, u16 data, u16 mem_mask) +{ + if (BIT(data, 1)) + m_sram_view.disable(); + else + m_sram_view.select(0); + m_nvram_write_protect = !!BIT(data, 0); +} + + +void megadrive_hb_ssf_device::time_io_map(address_map &map) +{ + map(0xf0, 0xf1).w(FUNC(megadrive_hb_ssf_device::time_f0_w)); + map(0xf3, 0xf3).lw8(NAME([this] (offs_t offset, u8 data) { m_rom_bank[1]->set_entry(data & 0x1f); })); + map(0xf5, 0xf5).lw8(NAME([this] (offs_t offset, u8 data) { m_rom_bank[2]->set_entry(data & 0x1f); })); + map(0xf7, 0xf7).lw8(NAME([this] (offs_t offset, u8 data) { m_rom_bank[3]->set_entry(data & 0x1f); })); + map(0xf9, 0xf9).lw8(NAME([this] (offs_t offset, u8 data) { m_rom_bank[4]->set_entry(data & 0x1f); })); + map(0xfb, 0xfb).lw8(NAME([this] (offs_t offset, u8 data) { m_rom_bank[5]->set_entry(data & 0x1f); })); + map(0xfd, 0xfd).lw8(NAME([this] (offs_t offset, u8 data) { m_rom_bank[6]->set_entry(data & 0x1f); })); + map(0xff, 0xff).lw8(NAME([this] (offs_t offset, u8 data) { m_rom_bank[7]->set_entry(data & 0x1f); })); +} + +/* + * Demons of Asteborg + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_HB_SSF_SRAM, megadrive_hb_ssf_sram_device, "megadrive_hb_ssf_sram", "Megadrive Krikzz Sega SSF + SRAM cart") + +megadrive_hb_ssf_sram_device::megadrive_hb_ssf_sram_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_hb_ssf_device(mconfig, MEGADRIVE_HB_SSF_SRAM, tag, owner, clock) + , m_nvram(*this, "nvram") +{ +} + +void megadrive_hb_ssf_sram_device::device_add_mconfig(machine_config &config) +{ + NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_1); +} + +void megadrive_hb_ssf_sram_device::device_start() +{ + megadrive_hb_ssf_device::device_start(); + const u32 nvram_size = 0x8000; + m_nvram_ptr = std::make_unique(nvram_size); + m_nvram->set_base(m_nvram_ptr.get(), nvram_size); + + save_pointer(NAME(m_nvram_ptr), nvram_size); +} + +u16 megadrive_hb_ssf_sram_device::nvram_r(offs_t offset) +{ + const u32 nvram_offset = offset & 0xffff; + return 0xff00 | m_nvram_ptr[nvram_offset]; +} + +void megadrive_hb_ssf_sram_device::nvram_w(offs_t offset, u16 data, u16 mem_mask) +{ + if (ACCESSING_BITS_0_7) + { + const u32 nvram_offset = offset & 0xffff; + m_nvram_ptr[nvram_offset] = data & 0xff; + } +} + +void megadrive_hb_ssf_sram_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x3f'ffff).m(*this, FUNC(megadrive_hb_ssf_sram_device::cart_bank_map)); + map(0x20'0000, 0x20'ffff).view(m_sram_view); + m_sram_view[0](0x20'0000, 0x20'ffff).rw(FUNC(megadrive_hb_ssf_sram_device::nvram_r), FUNC(megadrive_hb_ssf_sram_device::nvram_w)); +} + +/* + * krikzz SSF actual extended SSF + * + * TODO: + * - SD card; + * - USB (2.0?); + * - LED; + * - is math unit signed or unsigned? Sample ROM doesn't seem to care; + * - what "support 16-bit or 32-bit" really mean? Are args reset after use? Sample ROM doesn't care + * again; + * - division by zero actual values; + * + */ + + +DEFINE_DEVICE_TYPE(MEGADRIVE_HB_SSF_EX, megadrive_hb_ssf_ex_device, "megadrive_hb_ssf_ex", "Megadrive Krikzz Sega SSF Extended cart") + +megadrive_hb_ssf_ex_device::megadrive_hb_ssf_ex_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_hb_ssf_device(mconfig, MEGADRIVE_HB_SSF_EX, tag, owner, clock) +{ +} + +void megadrive_hb_ssf_ex_device::device_start() +{ + megadrive_hb_ssf_device::device_start(); + save_pointer(STRUCT_MEMBER(m_math, arg), 2); + save_pointer(STRUCT_MEMBER(m_math, mul), 2); + save_pointer(STRUCT_MEMBER(m_math, div), 2); +} + +void megadrive_hb_ssf_ex_device::device_reset() +{ + megadrive_hb_ssf_device::device_reset(); + m_sram_view.select(0); + // undefined at /VRES + for (int i = 0; i < 2; i++) + { + m_math[i].arg = 0xffff; + m_math[i].mul = 0xffff; + m_math[i].div = 0xffff; + } +} + +/* + * needs to be a word write + * 1--- ---- ---- ---- unlock writes to this register + * -x-- ---- ---- ---- 32X mode + * --x- ---- ---- ---- ROM memory write protect + * ---x ---- ---- ---- LED + * ---- ---- ---x xxxx ROM bank [0] + */ +void megadrive_hb_ssf_ex_device::time_f0_w(offs_t offset, u16 data, u16 mem_mask) + { + logerror("time_f0_w %04x & %04x (%s)\n", data, mem_mask, BIT(data, 15) ? "valid" : "ignored"); + if (BIT(data, 15)) + { + m_sram_view.select(BIT(data, 13)); + + // m_led_output = BIT(data, 12); + + m_rom_bank[0]->set_entry(data & 0x1f); + } +} + +void megadrive_hb_ssf_ex_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x3f'ffff).view(m_sram_view); + m_sram_view[0](0x00'0000, 0x3f'ffff).m(*this, FUNC(megadrive_hb_ssf_ex_device::cart_bank_map)); + for (int i = 0; i < 8; i++) + { + const u32 page_size = 0x08'0000; + + m_sram_view[1](0x00'0000 | (page_size * i), 0x07'ffff | (page_size * i)).bankrw(m_rom_bank[i]); + } +} + +void megadrive_hb_ssf_ex_device::time_io_map(address_map &map) +{ + megadrive_hb_ssf_device::time_io_map(map); + map(0xd0, 0xd3).lrw16( + NAME([this] (offs_t offset) { + return m_math[offset].arg; + }), + NAME([this] (offs_t offset, u16 data, u16 mem_mask) { + COMBINE_DATA(&m_math[offset].arg); + }) + ); + map(0xd4, 0xd7).lw16( + NAME([this] (offs_t offset, u16 data, u16 mem_mask) { + COMBINE_DATA(&m_math[offset].mul); + if (offset) + { + const u32 arg = (m_math[0].arg << 16) | m_math[1].arg; + const u32 mul = (m_math[0].mul << 16) | m_math[1].mul; + const u32 res = arg * mul; + m_math[0].arg = res >> 16; + m_math[1].arg = res & 0xffff; + logerror("mul unit: %08x * %08x = %08x\n", arg, mul, res); + } + }) + ); + map(0xd8, 0xdb).lw16( + NAME([this] (offs_t offset, u16 data, u16 mem_mask) { + COMBINE_DATA(&m_math[offset].div); + if (offset) + { + const u32 arg = (m_math[0].arg << 16) | m_math[1].arg; + const u32 div = (m_math[0].div << 16) | m_math[1].div; + const u32 res = div ? arg / div : 0xffff'ffff; + m_math[0].arg = res >> 16; + m_math[1].arg = res & 0xffff; + logerror("div unit: %08x / %08x = %08x\n", arg, div, res); + } + }) + ); +// map(0xe0, 0xe1).rw SD card data +// map(0xe2, 0xe3).rw USB data (8-bit) +// map(0xe4, 0xe5).r (14) SPI controller ready +// (2) USB FIFO write ready +// (1) USB FIFO read ready +// (0) SPI controller ready +// map(0xe6, 0xe7).w (2) SPI auto read (16-bits only) +// (1) 16bit SPI mode +// (0) SD card chip select +} diff --git a/src/devices/bus/megadrive/cart/ssf.h b/src/devices/bus/megadrive/cart/ssf.h new file mode 100644 index 0000000000000..acb85748c2279 --- /dev/null +++ b/src/devices/bus/megadrive/cart/ssf.h @@ -0,0 +1,79 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese + +#ifndef MAME_BUS_MEGADRIVE_CART_SSF_H +#define MAME_BUS_MEGADRIVE_CART_SSF_H + +#pragma once + +#include "machine/nvram.h" + +#include "rom.h" +#include "slot.h" + +class megadrive_hb_ssf_device : public megadrive_rom_ssf2_device +{ +public: + megadrive_hb_ssf_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void time_io_map(address_map &map) override ATTR_COLD; +protected: + megadrive_hb_ssf_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + virtual void time_f0_w(offs_t offset, u16 data, u16 mem_mask); + + bool m_nvram_write_protect; +}; + +class megadrive_hb_ssf_sram_device : public megadrive_hb_ssf_device +{ +public: + megadrive_hb_ssf_sram_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; + +protected: + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; + + virtual void device_start() override ATTR_COLD; + + u16 nvram_r(offs_t offset); + void nvram_w(offs_t offset, u16 data, u16 mem_mask); +private: + required_device m_nvram; + std::unique_ptr m_nvram_ptr; +}; + +class megadrive_hb_ssf_ex_device : public megadrive_hb_ssf_device +{ +public: + megadrive_hb_ssf_ex_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + static constexpr feature_type unemulated_features() { return feature::MEDIA | feature::DISK; } + + virtual void cart_map(address_map &map) override ATTR_COLD; + virtual void time_io_map(address_map &map) override ATTR_COLD; +protected: +// virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; + + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + + virtual void time_f0_w(offs_t offset, u16 data, u16 mem_mask) override; +private: + struct math_unit_t { + u16 arg; + u16 mul; + u16 div; + }; + + math_unit_t m_math[2]; +}; + + + +DECLARE_DEVICE_TYPE(MEGADRIVE_HB_SSF, megadrive_hb_ssf_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_HB_SSF_SRAM, megadrive_hb_ssf_sram_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_HB_SSF_EX, megadrive_hb_ssf_ex_device) + +#endif // MAME_BUS_MEGADRIVE_CART_SSF_H diff --git a/src/devices/bus/megadrive/cart/t5740.cpp b/src/devices/bus/megadrive/cart/t5740.cpp new file mode 100644 index 0000000000000..33819a34a7683 --- /dev/null +++ b/src/devices/bus/megadrive/cart/t5740.cpp @@ -0,0 +1,102 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese +/************************************************************************************************** + +WaterMelon T-5740 + +https://segaretro.org/Pier_Solar_and_the_Great_Architects + +TODO: +- several unknowns in TIME io range; + +**************************************************************************************************/ + +#include "emu.h" +#include "t5740.h" + +#include "bus/generic/slot.h" + +DEFINE_DEVICE_TYPE(MEGADRIVE_HB_PSOLAR, megadrive_hb_psolar_device, "megadrive_hb_psolar", "Megadrive Pier Solar T-5740 cart") + +megadrive_hb_psolar_device::megadrive_hb_psolar_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, MEGADRIVE_HB_PSOLAR, tag, owner, clock) + , device_megadrive_cart_interface( mconfig, *this ) + , m_rom_bank(*this, "rom_bank_%u", 0U) + , m_spi_eeprom(*this, "spi_eeprom") +{ +} + +void megadrive_hb_psolar_device::device_add_mconfig(machine_config &config) +{ + M95320_EEPROM(config, m_spi_eeprom, 0); +} + +void megadrive_hb_psolar_device::device_start() +{ + memory_region *const romregion(cart_rom_region()); + const u32 page_size = 0x08'0000; + device_generic_cart_interface::map_non_power_of_two( + unsigned(romregion->bytes() / page_size), + [this, base = &romregion->as_u8()] (unsigned entry, unsigned page) + { + for (int i = 0; i < 8; i++) + m_rom_bank[i]->configure_entry(entry, &base[page * page_size]); + }); +} + +void megadrive_hb_psolar_device::device_reset() +{ + for (int i = 0; i < 8; i++) + m_rom_bank[i]->set_entry(i); +} + +void megadrive_hb_psolar_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x07'ffff).bankr(m_rom_bank[0]); + // HACK: protection workaround + // At startup each bank is 32K mirrored, and an unspecified condition unlocks the + // full bank. PC=15e6 reads it 3 times, with byte accesses, expecting to read the cart header + // otherwise will crash during the "not endorsed by Sega" screen. + map(0x01'8100, 0x01'81ff).lr16(NAME([this] (offs_t offset, u16 mem_mask) { + const auto base = reinterpret_cast(m_rom_bank[0]->base()); + const u32 rom_address = 0x1'8100 + (offset << 1); + if (mem_mask != 0xffff) + { + return base[(rom_address & 0x7fff) >> 1]; + } + return base[rom_address >> 1]; + })); + map(0x08'0000, 0x0f'ffff).bankr(m_rom_bank[1]); + map(0x10'0000, 0x17'ffff).bankr(m_rom_bank[2]); + map(0x18'0000, 0x1f'ffff).bankr(m_rom_bank[3]); + map(0x20'0000, 0x27'ffff).bankr(m_rom_bank[4]); + map(0x28'0000, 0x2f'ffff).bankr(m_rom_bank[5]); + map(0x30'0000, 0x37'ffff).bankr(m_rom_bank[6]); + map(0x38'0000, 0x3f'ffff).bankr(m_rom_bank[7]); +} + +void megadrive_hb_psolar_device::time_io_map(address_map &map) +{ + map(0x01, 0x01).lw8(NAME([] (offs_t offset, u8 data) { + //logerror("Mode %02x\n", data); + // x--- enable SPI bus? + // --x- enable bankswitch addresses? + // ---x always on + })); + map(0x03, 0x03).lw8(NAME([this] (offs_t offset, u8 data) { m_rom_bank[5]->set_entry(data & 0xf); })); + map(0x05, 0x05).lw8(NAME([this] (offs_t offset, u8 data) { m_rom_bank[6]->set_entry(data & 0xf); })); + map(0x07, 0x07).lw8(NAME([this] (offs_t offset, u8 data) { m_rom_bank[7]->set_entry(data & 0xf); })); + map(0x09, 0x09).lw8( + NAME([this] (offs_t offset, u8 data) { + m_spi_eeprom->set_si_line(BIT(data, 0)); + m_spi_eeprom->set_sck_line(BIT(data, 1)); + m_spi_eeprom->set_halt_line(BIT(data, 2)); + m_spi_eeprom->set_cs_line(BIT(data, 3)); + }) + ); + map(0x0b, 0x0b).lr8( + NAME([this] (offs_t offset) { + return m_spi_eeprom->get_so_line() & 1; + }) + ); +} diff --git a/src/devices/bus/megadrive/cart/t5740.h b/src/devices/bus/megadrive/cart/t5740.h new file mode 100644 index 0000000000000..0259e3fa49b66 --- /dev/null +++ b/src/devices/bus/megadrive/cart/t5740.h @@ -0,0 +1,34 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese + +#ifndef MAME_BUS_MEGADRIVE_CART_T5740_H +#define MAME_BUS_MEGADRIVE_CART_T5740_H + +#pragma once + +#include "machine/m95320.h" + +#include "slot.h" + +class megadrive_hb_psolar_device : public device_t + , public device_megadrive_cart_interface +{ +public: + megadrive_hb_psolar_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; + virtual void time_io_map(address_map &map) override ATTR_COLD; +protected: + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; + + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; +private: + memory_bank_array_creator<8> m_rom_bank; + required_device m_spi_eeprom; +}; + +DECLARE_DEVICE_TYPE(MEGADRIVE_HB_PSOLAR, megadrive_hb_psolar_device) + + +#endif // MAME_BUS_MEGADRIVE_CART_T5740_H diff --git a/src/devices/bus/megadrive/cart/tekkensp.cpp b/src/devices/bus/megadrive/cart/tekkensp.cpp new file mode 100644 index 0000000000000..6a1697df336aa --- /dev/null +++ b/src/devices/bus/megadrive/cart/tekkensp.cpp @@ -0,0 +1,64 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese +/************************************************************************************************** + +https://segaretro.org/Tekken_Special + +Unidentified protection chip, developer not known + +TODO: +- identify and verify on HW all the unused combinations; +- chip mirror, if any; + +**************************************************************************************************/ + +#include "emu.h" +#include "tekkensp.h" + +DEFINE_DEVICE_TYPE(MEGADRIVE_UNL_TEKKENSP, megadrive_unl_tekkensp_device, "megadrive_unl_tekkensp", "Megadrive Tekken Special cart") + +megadrive_unl_tekkensp_device::megadrive_unl_tekkensp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, MEGADRIVE_UNL_TEKKENSP, tag, owner, clock) +{ +} + +void megadrive_unl_tekkensp_device::device_start() +{ + megadrive_rom_device::device_start(); + save_item(NAME(m_prot_latch)); +} + +void megadrive_unl_tekkensp_device::device_reset() +{ + megadrive_rom_device::device_reset(); + // undefined, initialized by game anyway + m_prot_latch = 0; +} + +template void megadrive_unl_tekkensp_device::prot_shift_w(u8 data) +{ + if (BIT(data, 0)) + { + m_prot_latch |= (1 << N); + } +} + +void megadrive_unl_tekkensp_device::cart_map(address_map &map) +{ + map(0x00'0000, m_rom_mask).mirror(m_rom_mirror).bankr(m_rom); + // reset? + map(0x40'0000, 0x40'0000).lw8(NAME([this] (offs_t offset, u8 data) { (void)data; m_prot_latch = 0; })); + // -1 is likely coming from the mode + map(0x40'0002, 0x40'0002).lr8(NAME([this] (offs_t offset) { return m_prot_latch - 1; })); + map(0x40'0004, 0x40'0004).w(FUNC(megadrive_unl_tekkensp_device::prot_shift_w<0>)); + map(0x40'0006, 0x40'0006).w(FUNC(megadrive_unl_tekkensp_device::prot_shift_w<1>)); + map(0x40'0008, 0x40'0008).w(FUNC(megadrive_unl_tekkensp_device::prot_shift_w<2>)); + map(0x40'000a, 0x40'000a).w(FUNC(megadrive_unl_tekkensp_device::prot_shift_w<3>)); + map(0x40'000c, 0x40'000c).lw8(NAME([this] (offs_t offset, u8 data) { + if (!BIT(data, 0)) + popmessage("tekkensp.cpp: data output mode bit 0 == 0"); + })); + map(0x40'000e, 0x40'000e).lw8(NAME([this] (offs_t offset, u8 data) { + popmessage("tekkensp.cpp: data output mode bit 1 == %d", BIT(data, 0)); + })); +} diff --git a/src/devices/bus/megadrive/cart/tekkensp.h b/src/devices/bus/megadrive/cart/tekkensp.h new file mode 100644 index 0000000000000..4dd80310cdfd0 --- /dev/null +++ b/src/devices/bus/megadrive/cart/tekkensp.h @@ -0,0 +1,29 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese + +#ifndef MAME_BUS_MEGADRIVE_CART_TEKKENSP_H +#define MAME_BUS_MEGADRIVE_CART_TEKKENSP_H + +#pragma once + +#include "rom.h" +#include "slot.h" + +class megadrive_unl_tekkensp_device : public megadrive_rom_device +{ +public: + megadrive_unl_tekkensp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; +protected: + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; +private: + template void prot_shift_w(u8 data); + u8 m_prot_latch; +}; + +DECLARE_DEVICE_TYPE(MEGADRIVE_UNL_TEKKENSP, megadrive_unl_tekkensp_device) + + +#endif // MAME_BUS_MEGADRIVE_CART_TEKKENSP_H diff --git a/src/devices/bus/megadrive/cart/xboy.cpp b/src/devices/bus/megadrive/cart/xboy.cpp new file mode 100644 index 0000000000000..389eeb848f9f2 --- /dev/null +++ b/src/devices/bus/megadrive/cart/xboy.cpp @@ -0,0 +1,216 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese +/************************************************************************************************** + +X Boy published/developed cart mappers + +**************************************************************************************************/ + + +#include "emu.h" +#include "xboy.h" + +#include "bus/generic/slot.h" + + +/* + * The King of Fighters '99 + * https://segaretro.org/King_of_Fighters_98%27 + * + * Earlier protection variant + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_UNL_KOF98, megadrive_unl_kof98_device, "megadrive_unl_kof98", "Megadrive The King of Fighters '98 cart") + +megadrive_unl_kof98_device::megadrive_unl_kof98_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, MEGADRIVE_UNL_KOF98, tag, owner, clock) +{ +} + +void megadrive_unl_kof98_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x3f'ffff).bankr(m_rom); + // everytime, trashes stack otherwise + map(0x48'0000, 0x4b'ffff).lr16(NAME([] () { return 0xaa00; })); + // when selecting Arcade or VS., pointer to reach above + map(0x4c'0000, 0x4f'ffff).lr16(NAME([] () { return 0xf000; })); +} + + +/* + * A Bug's Life + * https://segaretro.org/A_Bug%27s_Life_(Mega_Drive) + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_UNL_BUGSLIFE, megadrive_unl_bugslife_device, "megadrive_unl_bugslife", "Megadrive A Bug's Life cart") + +megadrive_unl_bugslife_device::megadrive_unl_bugslife_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, MEGADRIVE_UNL_BUGSLIFE, tag, owner, clock) +{ +} + +void megadrive_unl_bugslife_device::time_io_map(address_map &map) +{ + map(0x00, 0x01).lr16(NAME([] () { return 0x28; })); + // those two are patched by SW + map(0x02, 0x03).lr16(NAME([] () { return 0x01; })); + map(0x3e, 0x3f).lr16(NAME([] () { return 0x1f; })); +} + +/* + * Pokemon Monster + * https://segaretro.org/Pocket_Monster + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_UNL_POKEMONA, megadrive_unl_pokemona_device, "megadrive_unl_pokemona", "Megadrive Pokemon Monster alt cart") + +megadrive_unl_pokemona_device::megadrive_unl_pokemona_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, MEGADRIVE_UNL_POKEMONA, tag, owner, clock) +{ +} + +void megadrive_unl_pokemona_device::time_io_map(address_map &map) +{ + map(0x00, 0x01).lr16(NAME([] () { return 0x14; })); + // those two are patched by SW + map(0x02, 0x03).lr16(NAME([] () { return 0x01; })); + map(0x3e, 0x3f).lr16(NAME([] () { return 0x1f; })); +} + +/* + * The King of Fighters '99 + * https://segaretro.org/The_King_of_Fighters_%2799_(Mega_Drive) + * + * Writes "Secondary memory access failure" if $a13000 returns & 0xf != 0 + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_UNL_KOF99, megadrive_unl_kof99_device, "megadrive_unl_kof99", "Megadrive The King of Fighters '99 cart") + +megadrive_unl_kof99_device::megadrive_unl_kof99_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, MEGADRIVE_UNL_KOF99, tag, owner, clock) +{ +} + +void megadrive_unl_kof99_device::time_io_map(address_map &map) +{ + map(0x00, 0x01).lr16(NAME([] () { return 0x00; })); + map(0x02, 0x03).lr16(NAME([] () { return 0x01; })); + map(0x3e, 0x3f).lr16(NAME([] () { return 0x1f; })); +} + +/* + * pokestad Pokemon Stadium + * https://segaretro.org/Pokemon_Stadium + * + * lionkin3 Lion King 3 + * mulan Hua Mu Lan - Mulan + * pokemon2 Pocket Monsters 2 + * souledge Soul Edge vs Samurai Spirits + * sdkong99/skkong99 Super Donkey Kong 99 + * topf Top Fighter 2000 MK VIII + * https://segaretro.org/Top_Fighter_2000_MK_VIII + * + * gunfight Gunfight 3 in 1 + * https://segaretro.org/Gunfight_3_in_1 + * + * Obfuscated bankswitch mechanism + a bitswap based protection device. + * + * TODO: + * - pokestad is the only game that doesn't access protection, verify on HW if it has it anyway. + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_UNL_TOPF, megadrive_unl_topf_device, "megadrive_unl_topf", "Megadrive Top Fighter cart") + +megadrive_unl_topf_device::megadrive_unl_topf_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, MEGADRIVE_UNL_TOPF, tag, owner, clock) + , m_rom_bank(*this, "rom_bank_%u", 0U) + , m_rom_view(*this, "rom_view") +{ +} + +void megadrive_unl_topf_device::device_start() +{ + megadrive_rom_device::device_start(); + memory_region *const romregion(cart_rom_region()); + const u32 page_size = 0x00'8000; + device_generic_cart_interface::map_non_power_of_two( + unsigned(romregion->bytes() / page_size), + [this, base = &romregion->as_u8()] (unsigned entry, unsigned page) + { + for (int i = 0; i < 32; i++) + m_rom_bank[i]->configure_entry(entry, &base[page * page_size]); + }); + + + save_item(NAME(m_prot_latch)); + save_item(NAME(m_prot_mode)); +} + +void megadrive_unl_topf_device::device_reset() +{ + m_prot_latch = 0; + m_prot_mode = 0; + m_rom_view.select(0); +} + +void megadrive_unl_topf_device::prot_latch_w(u8 data) +{ + m_prot_latch = data; +} + +void megadrive_unl_topf_device::prot_mode_w(u8 data) +{ + m_prot_mode = data & 3; +} + +u8 megadrive_unl_topf_device::prot_data_r() +{ + u8 res = 0; + switch(m_prot_mode) + { + case 0: res = (m_prot_latch << 1); break; + case 1: res = (m_prot_latch >> 1); break; + case 2: res = bitswap<8>(m_prot_latch, 3, 2, 1, 0, 7, 6, 5, 4); break; + case 3: res = bitswap<8>(m_prot_latch, 0, 1, 2, 3, 4, 5, 6, 7); break; + } + + return res; +} + +void megadrive_unl_topf_device::cart_map(address_map &map) +{ + // TODO: just 0x0f'ffff ? + map(0x00'0000, 0x1f'ffff).view(m_rom_view); + m_rom_view[0](0x00'0000, 0x1f'ffff).bankr(m_rom); + for (int bank = 0; bank < 16; bank++) + { + u32 bank_base = bank * 0x1'0000; + m_rom_view[1](0x00'0000 | bank_base, 0x00'7fff | bank_base).bankr(m_rom_bank[bank * 2 + 0]); + m_rom_view[1](0x00'8000 | bank_base, 0x00'ffff | bank_base).bankr(m_rom_bank[bank * 2 + 1]); + } + + map(0x60'0001, 0x60'0001).mirror(0x0f'fff8).w(FUNC(megadrive_unl_topf_device::prot_latch_w)); + map(0x60'0003, 0x60'0003).mirror(0x0f'fff8).w(FUNC(megadrive_unl_topf_device::prot_mode_w)); + map(0x60'0005, 0x60'0005).mirror(0x0f'fff8).r(FUNC(megadrive_unl_topf_device::prot_data_r)); + + map(0x70'0000, 0x70'0000).mirror(0x0f'ffff).lw8(NAME([this] (u8 data) { + if (data) + { + m_rom_view.select(1); + for (int i = 0; i < 16; i++) + { + m_rom_bank[i * 2 + 0]->set_entry((i * 2 | data) & 0x3f); + m_rom_bank[i * 2 + 1]->set_entry((i * 2 | (data | 1)) & 0x3f); + } + } + else + { + m_rom_view.select(0); + } + })); +} diff --git a/src/devices/bus/megadrive/cart/xboy.h b/src/devices/bus/megadrive/cart/xboy.h new file mode 100644 index 0000000000000..7788ad757c1c4 --- /dev/null +++ b/src/devices/bus/megadrive/cart/xboy.h @@ -0,0 +1,73 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese + +#ifndef MAME_BUS_MEGADRIVE_CART_XBOY_H +#define MAME_BUS_MEGADRIVE_CART_XBOY_H + +#pragma once + +#include "rom.h" +#include "slot.h" + +class megadrive_unl_kof98_device : public megadrive_rom_device +{ +public: + megadrive_unl_kof98_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; +}; + + +class megadrive_unl_bugslife_device : public megadrive_rom_device +{ +public: + megadrive_unl_bugslife_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void time_io_map(address_map &map) override ATTR_COLD; +}; + +class megadrive_unl_pokemona_device : public megadrive_rom_device +{ +public: + megadrive_unl_pokemona_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void time_io_map(address_map &map) override ATTR_COLD; +}; + +class megadrive_unl_kof99_device : public megadrive_rom_device +{ +public: + megadrive_unl_kof99_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void time_io_map(address_map &map) override ATTR_COLD; +}; + +class megadrive_unl_topf_device : public megadrive_rom_device +{ +public: + megadrive_unl_topf_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void cart_map(address_map &map) override ATTR_COLD; +protected: + virtual void device_start() override; + virtual void device_reset() override; + + void prot_latch_w(u8 data); + void prot_mode_w(u8 data); + u8 prot_data_r(); +private: + memory_bank_array_creator<32> m_rom_bank; + memory_view m_rom_view; + + u8 m_prot_latch; + u8 m_prot_mode; +}; + +DECLARE_DEVICE_TYPE(MEGADRIVE_UNL_KOF98, megadrive_unl_kof98_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_UNL_BUGSLIFE, megadrive_unl_bugslife_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_UNL_POKEMONA, megadrive_unl_pokemona_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_UNL_KOF99, megadrive_unl_kof99_device) +DECLARE_DEVICE_TYPE(MEGADRIVE_UNL_TOPF, megadrive_unl_topf_device) + + +#endif // MAME_BUS_MEGADRIVE_CART_XBOY_H diff --git a/src/devices/bus/megadrive/eeprom.cpp b/src/devices/bus/megadrive/eeprom.cpp index 23005b8999828..0af843ea4d378 100644 --- a/src/devices/bus/megadrive/eeprom.cpp +++ b/src/devices/bus/megadrive/eeprom.cpp @@ -32,7 +32,7 @@ Micro Machines Military | 0x380001-7 | 0x300000-0*| 0x300000-1*| 0x03ff (24C08) | 0x0f | Yes | Micro Machines 96 | 0x380001-7 | 0x300000-0*| 0x300000-1*| 0x07ff (24C16) | 0x0f | Yes | Brian Lara Cricket 96 | 0x380001-7 | 0x300000-0*| 0x300000-1*| 0x1fff (24C64) | 0x??* | | - Shame Warne Cricket | 0x380001-7 | 0x300000-0*| 0x300000-1*| 0x1fff (24C64) | 0x??* | | + Shane Warne Cricket | 0x380001-7 | 0x300000-0*| 0x300000-1*| 0x1fff (24C64) | 0x??* | | ----------------------------------|------------|------------|------------|----------------|-----------|-------| * Not specified in Eke-Eke's document @@ -132,7 +132,7 @@ void md_eeprom_nbajamte_device::device_add_mconfig(machine_config &config) void md_eeprom_cslam_device::device_add_mconfig(machine_config &config) { - I2C_24C64(config, m_i2cmem); + I2C_24C65(config, m_i2cmem); } void md_eeprom_nflqb96_device::device_add_mconfig(machine_config &config) @@ -147,7 +147,7 @@ void md_eeprom_nhlpa_device::device_add_mconfig(machine_config &config) void md_eeprom_blara_device::device_add_mconfig(machine_config &config) { - I2C_24C64(config, m_i2cmem); + I2C_24C65(config, m_i2cmem); } void md_eeprom_mode1_device::device_add_mconfig(machine_config &config) diff --git a/src/devices/bus/megadrive/jcart.cpp b/src/devices/bus/megadrive/jcart.cpp index d8cad677e5278..115cf4eb8f7a8 100644 --- a/src/devices/bus/megadrive/jcart.cpp +++ b/src/devices/bus/megadrive/jcart.cpp @@ -34,7 +34,7 @@ DEFINE_DEVICE_TYPE(MD_JCART, md_jcart_device, "md_jcart", "MD J-Cart games") DEFINE_DEVICE_TYPE(MD_SEPROM_CODEMAST, md_seprom_codemast_device, "md_seprom_codemast", "MD J-Cart games + SEPROM") -DEFINE_DEVICE_TYPE(MD_SEPROM_MM96, md_seprom_mm96_device, "md_seprom_mm96", "MD Micro Machine 96") +DEFINE_DEVICE_TYPE(MD_SEPROM_MM96, md_seprom_mm96_device, "md_seprom_mm96", "MD Micro Machines 96") // Sampras, Super Skidmarks? md_jcart_device::md_jcart_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) diff --git a/src/devices/bus/megadrive/md_carts.cpp b/src/devices/bus/megadrive/md_carts.cpp index f63112fdfab0f..f6f9e1a6bb3cb 100644 --- a/src/devices/bus/megadrive/md_carts.cpp +++ b/src/devices/bus/megadrive/md_carts.cpp @@ -41,11 +41,13 @@ void md_cart(device_slot_interface &device) device.option_add_internal("rom_nflqb96", MD_EEPROM_NFLQB96); device.option_add_internal("rom_cslam", MD_EEPROM_CSLAM); device.option_add_internal("rom_nhlpa", MD_EEPROM_NHLPA); - device.option_add_internal("rom_blara", MD_EEPROM_BLARA); + device.option_add_internal("rom_blara95", MD_EEPROM_BLARA); + device.option_add_internal("rom_blara96", MD_EEPROM_BLARA); device.option_add_internal("rom_eeprom_mode1", MD_EEPROM_MODE1); // J-Cart controller (Sampras Tennis) + device.option_add_internal("rom_jcart_sampras", MD_JCART); device.option_add_internal("rom_jcart", MD_JCART); -// J-Cart controller + EEPROM handling (not supported fully yet) + // J-Cart controller + EEPROM handling (not supported fully yet) device.option_add_internal("rom_codemast", MD_SEPROM_CODEMAST); device.option_add_internal("rom_mm96", MD_SEPROM_MM96); // STM95 EEPROM @@ -56,7 +58,6 @@ void md_cart(device_slot_interface &device) device.option_add_internal("rom_ggenie", MD_ROM_GAMEGENIE); // unique bankswitch device.option_add_internal("rom_ssf2", MD_ROM_SSF2); - device.option_add_internal("rom_radica", MD_ROM_RADICA); // pirate mappers (protection and/or bankswitch) device.option_add_internal("rom_16mj2", MD_ROM_16MJ2); device.option_add_internal("rom_bugs", MD_ROM_BUGSLIFE); @@ -85,7 +86,6 @@ void md_cart(device_slot_interface &device) device.option_add_internal("rom_sram_arg96", MD_ROM_SRAM_ARG96); device.option_add_internal("rom_tc2000", MD_ROM_TC2000); device.option_add_internal("rom_tekkensp", MD_ROM_TEKKENSP); - device.option_add_internal("rom_topf", MD_ROM_TOPF); device.option_add_internal("rom_titan", MD_ROM_TITAN); diff --git a/src/devices/bus/megadrive/md_slot.cpp b/src/devices/bus/megadrive/md_slot.cpp index 856b48759bf93..c06c988584e5e 100644 --- a/src/devices/bus/megadrive/md_slot.cpp +++ b/src/devices/bus/megadrive/md_slot.cpp @@ -242,7 +242,6 @@ static const md_slot slot_list[] = { SSF2, "rom_ssf2" }, { CM_2IN1, "rom_cm2in1" }, - { RADICA, "rom_radica" }, // { GAME_KANDUME, "rom_gkand" }, // what's needed by this? { TILESMJ2, "rom_16mj2" }, @@ -625,7 +624,7 @@ void base_md_cart_slot_device::setup_nvram() break; case SEGA_FRAM: m_cart->m_nvram_start = 0x200000; - m_cart->m_nvram_end = m_cart->m_nvram_start + get_software_region_length("fram") - 1; + m_cart->m_nvram_end = m_cart->m_nvram_start + get_software_region_length("sram") - 1; m_cart->nvram_alloc(m_cart->m_nvram_end - m_cart->m_nvram_start + 1); m_cart->m_nvram_active = 1; m_cart->m_nvram_handlers_installed = 1; @@ -695,7 +694,7 @@ int base_md_cart_slot_device::get_cart_type(const uint8_t *ROM, uint32_t len) kof98_sig[] = { 0x9b, 0xfc, 0x00, 0x00, 0x4a, 0x00 }, s15in1_sig[] = { 0x22, 0x3c, 0x00, 0xa1, 0x30, 0x00 }, kof99_sig[] = { 0x20, 0x3c, 0x30, 0x00, 0x00, 0xa1 }, // move.l #$300000A1,d0 - radica_sig[] = { 0x4e, 0xd0, 0x30, 0x39, 0x00, 0xa1 }, // jmp (a0) move.w ($a130xx),d0 +// radica_sig[] = { 0x4e, 0xd0, 0x30, 0x39, 0x00, 0xa1 }, // jmp (a0) move.w ($a130xx),d0 soulb_sig[] = { 0x33, 0xfc, 0x00, 0x0c, 0x00, 0xff }, // move.w #$C,($FF020A).l (what happens if check fails) s19in1_sig[] = { 0x13, 0xc0, 0x00, 0xa1, 0x30, 0x38 }, rockman_sig[] = { 0xea, 0x80 }; @@ -834,9 +833,9 @@ int base_md_cart_slot_device::get_cart_type(const uint8_t *ROM, uint32_t len) break; case 0x400000: - if (!memcmp(&ROM[0x3c031c], radica_sig, sizeof(radica_sig)) || - !memcmp(&ROM[0x3f031c], radica_sig, sizeof(radica_sig))) // ssf+gng + radica vol1 - type = RADICA; + //if (!memcmp(&ROM[0x3c031c], radica_sig, sizeof(radica_sig)) || + // !memcmp(&ROM[0x3f031c], radica_sig, sizeof(radica_sig))) // ssf+gng + radica vol1 + // type = RADICA; if (!memcmp(&ROM[0x028460], soulb_sig, sizeof(soulb_sig))) type = SOULBLAD; diff --git a/src/devices/bus/megadrive/md_slot.h b/src/devices/bus/megadrive/md_slot.h index dc75d97b6d6a1..71cf4d6774b87 100644 --- a/src/devices/bus/megadrive/md_slot.h +++ b/src/devices/bus/megadrive/md_slot.h @@ -52,7 +52,7 @@ enum SSF2, /* Super Street Fighter 2 */ CM_2IN1, /* CodeMasters 2in1 : Psycho Pinball + Micro Machines */ GAME_KANDUME, /* Game no Kandume Otokuyou */ - RADICA, /* Radica TV games.. these probably should be a separate driver since they are a separate 'console' */ +// RADICA, /* Radica TV games, handled in sega/megadriv_rad.cpp */ TILESMJ2, /* 16 Mahjong Tiles II */ BUGSLIFE, /* A Bug's Life */ diff --git a/src/devices/bus/megadrive/rom.cpp b/src/devices/bus/megadrive/rom.cpp index e87128d0017a5..5a09214526faa 100644 --- a/src/devices/bus/megadrive/rom.cpp +++ b/src/devices/bus/megadrive/rom.cpp @@ -59,8 +59,6 @@ DEFINE_DEVICE_TYPE(MD_ROM_REDCL, md_rom_redcl_device, "md_rom_redcl", " DEFINE_DEVICE_TYPE(MD_ROM_SQUIR, md_rom_squir_device, "md_rom_squir", "MD Squirrel King") DEFINE_DEVICE_TYPE(MD_ROM_TC2000, md_rom_tc2000_device, "md_rom_tc2000", "MD TC2000") DEFINE_DEVICE_TYPE(MD_ROM_TEKKENSP, md_rom_tekkensp_device, "md_rom_tekkensp", "MD Tekken Special") -DEFINE_DEVICE_TYPE(MD_ROM_TOPF, md_rom_topf_device, "md_rom_topf", "MD Top Fighter") -DEFINE_DEVICE_TYPE(MD_ROM_RADICA, md_rom_radica_device, "md_rom_radica", "MD Radica TV games") DEFINE_DEVICE_TYPE(MD_ROM_BEGGARP, md_rom_beggarp_device, "md_rom_beggarp", "MD Beggar Prince") DEFINE_DEVICE_TYPE(MD_ROM_WUKONG, md_rom_wukong_device, "md_rom_wukong", "MD Legend of Wukong") DEFINE_DEVICE_TYPE(MD_ROM_STARODYS, md_rom_starodys_device, "md_rom_starodys", "MD Star Odyssey") @@ -239,16 +237,6 @@ md_rom_tekkensp_device::md_rom_tekkensp_device(const machine_config &mconfig, co { } -md_rom_topf_device::md_rom_topf_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : md_std_rom_device(mconfig, MD_ROM_TOPF, tag, owner, clock), m_latch(0) -{ -} - -md_rom_radica_device::md_rom_radica_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : md_std_rom_device(mconfig, MD_ROM_RADICA, tag, owner, clock), m_bank(0) -{ -} - md_rom_beggarp_device::md_rom_beggarp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : md_std_rom_device(mconfig, MD_ROM_BEGGARP, tag, owner, clock), m_mode(0), m_lock(0) { @@ -401,28 +389,6 @@ void md_rom_tekkensp_device::device_reset() m_reg = 0; } -void md_rom_topf_device::device_start() -{ - save_item(NAME(m_latch)); - save_item(NAME(m_bank)); -} - -void md_rom_topf_device::device_reset() -{ - m_latch = 0; - m_bank[0] = m_bank[1] = m_bank[2] = 0; -} - -void md_rom_radica_device::device_start() -{ - save_item(NAME(m_bank)); -} - -void md_rom_radica_device::device_reset() -{ - m_bank = 0; -} - void md_rom_beggarp_device::device_start() { save_item(NAME(m_mode)); @@ -527,7 +493,7 @@ uint16_t md_rom_fram_device::read(offs_t offset) void md_rom_fram_device::write(offs_t offset, uint16_t data, uint16_t mem_mask) { if (offset >= m_nvram_start/2 && offset <= m_nvram_end/2 && m_nvram_active) - m_nvram[offset - m_nvram_start/2] = data; + m_nvram[offset - m_nvram_start/2] = data; } void md_rom_fram_device::write_a13(offs_t offset, uint16_t data) @@ -1344,102 +1310,6 @@ void md_rom_tekkensp_device::write(offs_t offset, uint16_t data, uint16_t mem_ma } } -/*------------------------------------------------- - TOP FIGHTER - -------------------------------------------------*/ - -uint16_t md_rom_topf_device::read(offs_t offset) -{ - //cpu #0 (PC=0004CBAE): unmapped program memory word read from 006A35D4 & 00FF -- wants regD7 - if (offset == 0x645b44/2) - { - //cpu #0 (PC=0004DE00): unmapped program memory word write to 00689B80 = 004A & 00FF - //cpu #0 (PC=0004DE08): unmapped program memory word write to 00 = 00B5 & 00FF - //cpu #0 (PC=0004DE0C): unmapped program memory word read from 00645B44 & 00FF - - return 0x9f;//0x25; - } - if (offset == 0x6bd294/2) - { - /* - cpu #0 (PC=00177192): unmapped program memory word write to 006BD240 = 00A8 & 00FF - cpu #0 (PC=0017719A): unmapped program memory word write to 006BD2D2 = 0098 & 00FF - cpu #0 (PC=001771A2): unmapped program memory word read from 006BD294 & 00FF - */ - - if (machine().device("maincpu")->pc()==0x1771a2) return 0x50; - else - { - m_latch++; - logerror("%06x topfig_6BD294_r %04x\n",machine().device("maincpu")->pc(), m_latch); - return m_latch; - } - } - if (offset == 0x6f5344/2) - { - if (machine().device("maincpu")->pc()==0x4C94E) - return machine().device("maincpu")->state_int((M68K_D0)) & 0xff; - else - { - m_latch++; - logerror("%06x topfig_6F5344_r %04x\n", machine().device("maincpu")->pc(), m_latch); - return m_latch; - } - } - - if (offset >= 0x20000/2 && offset < 0x28000/2) - return m_rom[offset + (m_bank[0] * 0x188000)/2]; - - if (offset >= 0x58000/2 && offset < 0x60000/2) - return m_rom[offset + (m_bank[1] * 0x20000)/2]; - - if (offset >= 0x60000/2 && offset < 0x68000/2) - return m_rom[offset + (m_bank[2] * 0x110000)/2]; - - // non-protection accesses - if (offset < 0x400000/2) - return m_rom[MD_ADDR(offset)]; - else - return 0xffff; -} - -void md_rom_topf_device::write(offs_t offset, uint16_t data, uint16_t mem_mask) -{ - if (offset >= 0x700000/2 && offset < 0x800000/2) - { - if (data == 0x002a) - m_bank[2] = 1; // == 0x2e*0x8000?! - else if (data==0x0035) // characters ingame - m_bank[0] = 1; // == 0x35*0x8000 - else if (data==0x000f) // special moves - m_bank[1] = 1; // == 0xf*0x8000 - else if (data==0x0000) - { - m_bank[0] = 0; - m_bank[1] = 0; - m_bank[2] = 0; - } - else - logerror("%06x offset %06x, data %04x\n", machine().device("maincpu")->pc(), offset, data); - } -} - -/*------------------------------------------------- - RADICA TV GAMES [to be split...] - -------------------------------------------------*/ - -uint16_t md_rom_radica_device::read(offs_t offset) -{ - return m_rom[(((m_bank * 0x10000) + (offset << 1)) & (m_rom_size - 1))/2]; -} - -uint16_t md_rom_radica_device::read_a13(offs_t offset) -{ - if (offset < 0x80) - m_bank = offset & 0x3f; - return 0; -} - /*------------------------------------------------- BEGGAR PRINCE This game uses cart which is the same as SEGA_SRAM diff --git a/src/devices/bus/megadrive/rom.h b/src/devices/bus/megadrive/rom.h index b98469d3155e3..e9151b9f235ce 100644 --- a/src/devices/bus/megadrive/rom.h +++ b/src/devices/bus/megadrive/rom.h @@ -526,49 +526,6 @@ class md_rom_tekkensp_device : public md_std_rom_device uint16_t m_reg; }; -// ======================> md_rom_topf_device - -class md_rom_topf_device : public md_std_rom_device -{ -public: - // construction/destruction - md_rom_topf_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - - // reading and writing - virtual uint16_t read(offs_t offset) override; - virtual void write(offs_t offset, uint16_t data, uint16_t mem_mask = ~0) override; - -protected: - // device-level overrides - virtual void device_start() override ATTR_COLD; - virtual void device_reset() override ATTR_COLD; - -private: - uint16_t m_latch; - uint8_t m_bank[3]; -}; - -// ======================> md_rom_radica_device - -class md_rom_radica_device : public md_std_rom_device -{ -public: - // construction/destruction - md_rom_radica_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - - // reading and writing - virtual uint16_t read(offs_t offset) override; - virtual uint16_t read_a13(offs_t offset) override; - -protected: - // device-level overrides - virtual void device_start() override ATTR_COLD; - virtual void device_reset() override ATTR_COLD; - -private: - uint8_t m_bank; -}; - // ======================> md_rom_beggarp_device class md_rom_beggarp_device : public md_std_rom_device @@ -671,8 +628,6 @@ DECLARE_DEVICE_TYPE(MD_ROM_SQUIR, md_rom_squir_device) DECLARE_DEVICE_TYPE(MD_ROM_SRAM_ARG96, md_rom_sram_arg96_device) DECLARE_DEVICE_TYPE(MD_ROM_TC2000, md_rom_tc2000_device) DECLARE_DEVICE_TYPE(MD_ROM_TEKKENSP, md_rom_tekkensp_device) -DECLARE_DEVICE_TYPE(MD_ROM_TOPF, md_rom_topf_device) -DECLARE_DEVICE_TYPE(MD_ROM_RADICA, md_rom_radica_device) DECLARE_DEVICE_TYPE(MD_ROM_BEGGARP, md_rom_beggarp_device) DECLARE_DEVICE_TYPE(MD_ROM_WUKONG, md_rom_wukong_device) DECLARE_DEVICE_TYPE(MD_ROM_STARODYS, md_rom_starodys_device) diff --git a/src/devices/machine/i2cmem.cpp b/src/devices/machine/i2cmem.cpp index 12e8cb88d803b..b856cd862a1fc 100644 --- a/src/devices/machine/i2cmem.cpp +++ b/src/devices/machine/i2cmem.cpp @@ -65,6 +65,7 @@ DEFINE_DEVICE_TYPE(I2C_X2404P, i2c_x2404p_device, "x2404p", "X2404P I2C Memor DEFINE_DEVICE_TYPE(I2C_24C08, i2c_24c08_device, "24c08", "24C08 I2C Memory") DEFINE_DEVICE_TYPE(I2C_24C16, i2c_24c16_device, "24c16", "24C16 I2C Memory") DEFINE_DEVICE_TYPE(I2C_24C64, i2c_24c64_device, "24c64", "24C64 I2C Memory") +DEFINE_DEVICE_TYPE(I2C_24C65, i2c_24c65_device, "24c65", "24C65 I2C Memory") DEFINE_DEVICE_TYPE(I2C_24C128, i2c_24c128_device, "24c128", "24C128 I2C Memory") DEFINE_DEVICE_TYPE(I2C_24C256, i2c_24c256_device, "24c256", "24C256 I2C Memory") DEFINE_DEVICE_TYPE(I2C_24C512, i2c_24c512_device, "24c512", "24C512 I2C Memory") @@ -175,6 +176,12 @@ i2c_24c64_device::i2c_24c64_device(const machine_config &mconfig, const char *ta { } +// TODO: write protection differs too compared to '64 +i2c_24c65_device::i2c_24c65_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + i2cmem_device(mconfig, I2C_24C65, tag, owner, clock, 0, 64, 0x2000) +{ +} + i2c_24c128_device::i2c_24c128_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : i2cmem_device(mconfig, I2C_24C128, tag, owner, clock, 0, 64, 0x4000) { diff --git a/src/devices/machine/i2cmem.h b/src/devices/machine/i2cmem.h index dc4bb5f7f4fb4..9d9b6648f6ed5 100644 --- a/src/devices/machine/i2cmem.h +++ b/src/devices/machine/i2cmem.h @@ -115,6 +115,7 @@ DECLARE_I2C_DEVICE(x2404p); DECLARE_I2C_DEVICE(24c08); DECLARE_I2C_DEVICE(24c16); DECLARE_I2C_DEVICE(24c64); +DECLARE_I2C_DEVICE(24c65); DECLARE_I2C_DEVICE(24c128); DECLARE_I2C_DEVICE(24c256); DECLARE_I2C_DEVICE(24c512); @@ -132,6 +133,7 @@ DECLARE_DEVICE_TYPE(I2C_X2404P, i2c_x2404p_device) DECLARE_DEVICE_TYPE(I2C_24C08, i2c_24c08_device) DECLARE_DEVICE_TYPE(I2C_24C16, i2c_24c16_device) DECLARE_DEVICE_TYPE(I2C_24C64, i2c_24c64_device) +DECLARE_DEVICE_TYPE(I2C_24C65, i2c_24c65_device) DECLARE_DEVICE_TYPE(I2C_24C128, i2c_24c128_device) DECLARE_DEVICE_TYPE(I2C_24C256, i2c_24c256_device) DECLARE_DEVICE_TYPE(I2C_24C512, i2c_24c512_device) diff --git a/src/devices/machine/intelfsh.cpp b/src/devices/machine/intelfsh.cpp index e303dd4533d8c..630469944a74c 100644 --- a/src/devices/machine/intelfsh.cpp +++ b/src/devices/machine/intelfsh.cpp @@ -109,6 +109,7 @@ DEFINE_DEVICE_TYPE(MACRONIX_29F1610MC_16BIT, macronix_29f1610mc_16bit_device, "m DEFINE_DEVICE_TYPE(MACRONIX_29L001MC, macronix_29l001mc_device, "macronix_29l001mc", "Macronix 29L001MC Flash") DEFINE_DEVICE_TYPE(MACRONIX_29LV160TMC, macronix_29lv160tmc_device, "macronix_29lv160tmc", "Macronix 29LV160TMC Flash") DEFINE_DEVICE_TYPE(ST_M29W640GB, st_m29w640gb_device, "st_m29w640gb", "ST M29W640GB Flash") +DEFINE_DEVICE_TYPE(ST_M29W640FT, st_m29w640ft_device, "st_m29w640ft", "ST M29W640FT Flash") DEFINE_DEVICE_TYPE(TMS_29F040, tms_29f040_device, "tms_29f040", "Texas Instruments 29F040 Flash") DEFINE_DEVICE_TYPE(PANASONIC_MN63F805MNP, panasonic_mn63f805mnp_device, "panasonic_mn63f805mnp", "Panasonic MN63F805MNP Flash") @@ -264,6 +265,9 @@ macronix_29lv160tmc_device::macronix_29lv160tmc_device(const machine_config &mco st_m29w640gb_device::st_m29w640gb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : intelfsh8_device(mconfig, ST_M29W640GB, tag, owner, clock, 0x800000, MFG_ST, 0x227e) { m_bot_boot_sector = true; m_device_id2 = 0x2210; m_device_id3 = 0x2200; } +st_m29w640ft_device::st_m29w640ft_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : intelfsh16_device(mconfig, ST_M29W640FT, tag, owner, clock, 0x800000, MFG_ST, 0x22ed) { m_bot_boot_sector = true; m_device_id2 = 0x2210; m_device_id3 = 0x2200; } + panasonic_mn63f805mnp_device::panasonic_mn63f805mnp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : intelfsh8_device(mconfig, PANASONIC_MN63F805MNP, tag, owner, clock, 0x10000, MFG_PANASONIC, 0x1b) { m_sector_is_4k = true; } @@ -603,7 +607,8 @@ void intelfsh_device::write_full(uint32_t address, uint32_t data) m_flash_mode = FM_NORMAL; break; case 0x90: - if ( m_fast_mode && m_maker_id == MFG_FUJITSU ) // reset from fast mode (when fast mode is enabled) + // TODO: W640GB also needs this path + if ( m_fast_mode && (m_maker_id == MFG_FUJITSU || (m_maker_id == MFG_ST && (m_device_id == 0x22ed || m_device_id == 0x227e))) ) // reset from fast mode (when fast mode is enabled) m_flash_mode = FM_FAST_RESET; else // read ID m_flash_mode = FM_READID; @@ -626,8 +631,16 @@ void intelfsh_device::write_full(uint32_t address, uint32_t data) case 0x20: // block erase if (m_maker_id == MFG_SST && m_device_id == 0x61) logerror("Unknown flash mode byte %x\n", data & 0xff); + else if (m_maker_id == MFG_ST && (m_device_id == 0x22ed || m_device_id == 0x227e)) + { + // unlock bypass + m_flash_mode = FM_NORMAL; + m_fast_mode = true; + } else + { m_flash_mode = FM_CLEARPART1; + } break; case 0x60: // set master lock m_flash_mode = FM_SETMASTER; @@ -636,8 +649,10 @@ void intelfsh_device::write_full(uint32_t address, uint32_t data) m_flash_mode = FM_READSTATUS; break; case 0xa0: // fast program (fast mode must be enabled) - if ( m_fast_mode && m_maker_id == MFG_FUJITSU ) + if ( m_fast_mode && (m_maker_id == MFG_FUJITSU || (m_maker_id == MFG_ST && (m_device_id == 0x22ed || m_device_id == 0x227e))) ) + { m_flash_mode = FM_BYTEPROGRAM; + } else logerror( "%s: Unknown flash mode byte %x\n", machine().describe_context(), data & 0xff ); break; @@ -958,7 +973,9 @@ void intelfsh_device::write_full(uint32_t address, uint32_t data) m_data[address] &= data; } else + { m_data[address] = data; + } break; case 16: // senbbs test mode requires this, note, flash type is guessed there based on manufacturer + device ident as markings were erased m_data[address*2] = data >> 8; diff --git a/src/devices/machine/intelfsh.h b/src/devices/machine/intelfsh.h index 7f81f25a15d04..c2da4d31644e2 100644 --- a/src/devices/machine/intelfsh.h +++ b/src/devices/machine/intelfsh.h @@ -223,12 +223,19 @@ class macronix_29lv160tmc_device : public intelfsh8_device macronix_29lv160tmc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); }; +// TODO: both m29w640 can be either 8 or 16 bit interface class st_m29w640gb_device : public intelfsh8_device { public: st_m29w640gb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); }; +class st_m29w640ft_device : public intelfsh16_device +{ +public: + st_m29w640ft_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); +}; + class panasonic_mn63f805mnp_device : public intelfsh8_device { public: @@ -425,6 +432,7 @@ DECLARE_DEVICE_TYPE(MACRONIX_29F1610MC_16BIT,macronix_29f1610mc_16bit_device) DECLARE_DEVICE_TYPE(MACRONIX_29L001MC, macronix_29l001mc_device) DECLARE_DEVICE_TYPE(MACRONIX_29LV160TMC, macronix_29lv160tmc_device) DECLARE_DEVICE_TYPE(ST_M29W640GB, st_m29w640gb_device) +DECLARE_DEVICE_TYPE(ST_M29W640FT, st_m29w640ft_device) DECLARE_DEVICE_TYPE(TMS_29F040, tms_29f040_device) DECLARE_DEVICE_TYPE(PANASONIC_MN63F805MNP, panasonic_mn63f805mnp_device) diff --git a/src/devices/machine/m95320.cpp b/src/devices/machine/m95320.cpp new file mode 100644 index 0000000000000..97dfc32c13cc7 --- /dev/null +++ b/src/devices/machine/m95320.cpp @@ -0,0 +1,202 @@ +// license: BSD-3-Clause +// copyright-holders: Fabio Priuli, MetalliC +/************************************************************************************************** + +M95320-W M95320-R M95320-DF +32-Kbit serial SPI bus EEPROM with high-speed clock + +TODO: +- direct converted from original stm95 for megadriv:psolar; +- Actual SPI bus connection; +- M95320-D variant (has extra instructions); +- M95640 (same base instruction set, double size); + +**************************************************************************************************/ + +#include "emu.h" +#include "m95320.h" + +DEFINE_DEVICE_TYPE(M95320_EEPROM, m95320_eeprom_device, "m95320_eeprom", "STM95320 SPI bus EEPROM") + +m95320_eeprom_device::m95320_eeprom_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, type, tag, owner, clock) + , device_nvram_interface(mconfig, *this) +{ +} + +m95320_eeprom_device::m95320_eeprom_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : m95320_eeprom_device(mconfig, M95320_EEPROM, tag, owner, clock) +{ +} + + +void m95320_eeprom_device::device_start() +{ + m_eeprom_data = std::make_unique(m_size); + + save_pointer(NAME(m_eeprom_data), m_size); + save_item(NAME(m_latch)); + save_item(NAME(m_reset_line)); + save_item(NAME(m_sck_line)); + save_item(NAME(m_wel)); + save_item(NAME(m_stream_pos)); + save_item(NAME(m_stream_data)); + save_item(NAME(m_eeprom_addr)); +} + +void m95320_eeprom_device::nvram_default() +{ +} + + +bool m95320_eeprom_device::nvram_read(util::read_stream &file) +{ + auto const [err, actual] = util::read(file, m_eeprom_data.get(), m_size); + return !err && (actual == m_size); +} + +bool m95320_eeprom_device::nvram_write(util::write_stream &file) +{ + auto const [err, actual] = util::write(file, m_eeprom_data.get(), m_size); + return !err; +} + + +void m95320_eeprom_device::set_cs_line(int state) +{ + m_reset_line = state; + if (m_reset_line != CLEAR_LINE) + { + m_stream_pos = 0; + m_internal_state = IDLE; + } +} + +void m95320_eeprom_device::set_si_line(int state) +{ + m_latch = state; +} + +int m95320_eeprom_device::get_so_line(void) +{ + if (m_internal_state == READING || m_internal_state == CMD_RDSR) + return (m_stream_data >> 8) & 1; + else + return 0; +} + +void m95320_eeprom_device::set_sck_line(int state) +{ + if (m_reset_line == CLEAR_LINE) + { + if (state == ASSERT_LINE && m_sck_line == CLEAR_LINE) + { + switch (m_internal_state) + { + case IDLE: + m_stream_data = (m_stream_data << 1) | (m_latch ? 1 : 0); + m_stream_pos++; + if (m_stream_pos == 8) + { + m_stream_pos = 0; + //printf("STM95 EEPROM: got cmd %02X\n", m_stream_data&0xff); + switch(m_stream_data & 0xff) + { + case 0x01: // write status register + if (m_wel != 0) + m_internal_state = CMD_WRSR; + m_wel = 0; + break; + case 0x02: // write + if (m_wel != 0) + m_internal_state = CMD_WRITE; + m_stream_data = 0; + m_wel = 0; + break; + case 0x03: // read + m_internal_state = CMD_READ; + m_stream_data = 0; + break; + case 0x04: // write disable + m_wel = 0; + break; + case 0x05: // read status register + m_internal_state = CMD_RDSR; + // TODO: SRWD / BP1 / BP0 and WIP bits + m_stream_data = m_wel << 1; + break; + case 0x06: // write enable + m_wel = 1; + break; + default: + logerror("unknown cmd %02X\n", m_stream_data&0xff); + } + } + break; + case CMD_WRSR: + m_stream_pos++; // just skip, don't care block protection + if (m_stream_pos == 8) + { + m_internal_state = IDLE; + m_stream_pos = 0; + } + break; + case CMD_RDSR: + m_stream_data = m_stream_data << 1; + m_stream_pos++; + if (m_stream_pos == 8) + { + m_internal_state = IDLE; + m_stream_pos = 0; + } + break; + case CMD_READ: + m_stream_data = (m_stream_data << 1) | (m_latch ? 1 : 0); + m_stream_pos++; + if (m_stream_pos == 16) + { + m_eeprom_addr = m_stream_data & (m_size - 1); + m_stream_data = m_eeprom_data[m_eeprom_addr]; + m_internal_state = READING; + m_stream_pos = 0; + } + break; + case READING: + m_stream_data = m_stream_data<<1; + m_stream_pos++; + if (m_stream_pos == 8) + { + if (++m_eeprom_addr == m_size) + m_eeprom_addr = 0; + m_stream_data |= m_eeprom_data[m_eeprom_addr]; + m_stream_pos = 0; + } + break; + case CMD_WRITE: + m_stream_data = (m_stream_data << 1) | (m_latch ? 1 : 0); + m_stream_pos++; + if (m_stream_pos == 16) + { + m_eeprom_addr = m_stream_data & (m_size - 1); + m_internal_state = WRITING; + m_stream_pos = 0; + } + break; + case WRITING: + m_stream_data = (m_stream_data << 1) | (m_latch ? 1 : 0); + m_stream_pos++; + if (m_stream_pos == 8) + { + m_eeprom_data[m_eeprom_addr] = m_stream_data; + if (++m_eeprom_addr == m_size) + m_eeprom_addr = 0; + m_stream_pos = 0; + } + break; + } + } + } + m_sck_line = state; +} + + diff --git a/src/devices/machine/m95320.h b/src/devices/machine/m95320.h new file mode 100644 index 0000000000000..18505f490deb8 --- /dev/null +++ b/src/devices/machine/m95320.h @@ -0,0 +1,59 @@ +// license: BSD-3-Clause +// copyright-holders: Fabio Priuli, MetalliC + +#ifndef MAME_MACHINE_M95320_H +#define MAME_MACHINE_M95320_H + +#pragma once + +#include "machine/eeprom.h" + +class m95320_eeprom_device : public device_t, public device_nvram_interface +{ +public: + m95320_eeprom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); + + void set_cs_line(int); + void set_halt_line(int state) {}; // TODO: not implemented + void set_si_line(int); + void set_sck_line(int state); + int get_so_line(void); + +protected: + m95320_eeprom_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock = 0); + + virtual void device_start() override ATTR_COLD; + + virtual void nvram_default() override; + virtual bool nvram_read(util::read_stream &file) override; + virtual bool nvram_write(util::write_stream &file) override; +private: + enum stmstate_t + { + IDLE = 0, + CMD_WRSR, + CMD_RDSR, + CMD_READ, + CMD_WRITE, + READING, + WRITING + }; + static constexpr unsigned m_size = 0x1000; + + int m_latch; + int m_reset_line; + int m_sck_line; + int m_wel; + + stmstate_t m_internal_state; + int m_stream_pos; + int m_stream_data; + int m_eeprom_addr; + std::unique_ptr m_eeprom_data; + +}; + +DECLARE_DEVICE_TYPE(M95320_EEPROM, m95320_eeprom_device) + + +#endif // MAME_MACHINE_M95320_H diff --git a/src/devices/machine/w83977tf.cpp b/src/devices/machine/w83977tf.cpp index 2a5131210e53a..8585d20a7a003 100644 --- a/src/devices/machine/w83977tf.cpp +++ b/src/devices/machine/w83977tf.cpp @@ -11,6 +11,7 @@ Winbond W83977TF status only three times (and port $61 is claimed by PIIX4 for PCI SERR# read only) - DRQ (savquest enables DRQ3 for LPT) - Hookup LPT modes; +- subclass for megadrive magistr16 system (uses w83977f/w83977af) **************************************************************************************************/ diff --git a/src/devices/video/ym7101.cpp b/src/devices/video/ym7101.cpp index c1d79248cff20..e1e908b9eaba0 100644 --- a/src/devices/video/ym7101.cpp +++ b/src/devices/video/ym7101.cpp @@ -124,6 +124,8 @@ void ym7101_device::device_start() save_item(NAME(m_hscroll_address)); save_item(NAME(m_hsz)); save_item(NAME(m_vsz)); + save_item(NAME(m_hpage)); + save_item(NAME(m_vpage)); save_item(NAME(m_auto_increment)); save_item(NAME(m_plane_a_name_table)); save_item(NAME(m_window_name_table)); @@ -483,6 +485,53 @@ void ym7101_device::vsram_map(address_map &map) static const char *const size_names[] = { "256 pixels/32 cells", "512 pixels/64 cells", "", "1024 pixels/128 cells" }; +void ym7101_device::calculate_plane_sizes() +{ + const u16 page_masks[] = { 32, 64, 1, 128 }; + + m_hpage = page_masks[m_hsz]; + m_vpage = page_masks[m_vsz]; + + // https://gendev.spritesmind.net/forum/viewtopic.php?p=31307#p31307 + // Triggering 1x settings that aren't 11x00 or 00x11 trigger various forms of overrides ... + if (m_hsz & 2 || m_vsz & 2) + { + if (m_hsz == 2) + { + // forces 32x1 regardless of VSZ + m_hpage = 32; + m_vpage = 1; + LOG("Prohibited plane setting HSZ 2 VSZ %d (forced to 32x1)\n", m_vsz); + } + else if (m_hsz == 3) + { + // forces 128x32 regardless of VSZ + m_vpage = 32; + if (m_vsz) + LOG("Prohibited plane setting HSZ 3 VSZ %d (forced to 128x32)\n", m_vsz); + } + else if (m_vsz == 2) + { + if (m_hsz == 0) + popmessage("ym7101.cpp: prohibited plane setting HSZ 0 VSZ 2 (mirroring?)"); + else + { + // forces NNx32, H untouched + // hulk uses HSZ=1 VSZ=2 on title screen + m_vpage = 32; + LOG("Prohibited plane setting HSZ %d VSZ 2 (forced to V32)\n", m_hsz); + } + } + else if (m_vsz == 3 && m_hsz == 1) + { + // forces 64x64 + m_hpage = 64; + m_vpage = 64; + LOG("Prohibited plane setting HSZ 1 VSZ 3 (forced to 64x64)\n"); + } + } +} + // https://plutiedev.com/vdp-registers // https://segaretro.org/Sega_Mega_Drive/VDP_registers // NOTE: in decimal units, classic Yamaha @@ -640,8 +689,8 @@ void ym7101_device::regs_map(address_map &map) , m_vsz , size_names[m_vsz] ); - if (m_hsz == 2 || m_vsz == 2 || (m_vsz == 3 && m_hsz != 0) || (m_hsz == 3 && m_vsz != 0)) - popmessage("ym7101.cpp: illegal plane size set %d %d", m_hsz, m_vsz); + + calculate_plane_sizes(); })); map(17, 17).lw8(NAME([this] (u8 data) { m_rigt = !!BIT(data, 7); @@ -853,10 +902,8 @@ void ym7101_device::prepare_tile_line(int scanline) const u16 tile_mask = 0x7ff; //const u16 page_mask[] = { 0x7ff, 0x1fff, 0x1fff, 0x1fff }; - const u16 page_masks[] = { 32, 64, 1, 128 }; - - const u16 h_page = page_masks[m_hsz]; - const u16 v_page = page_masks[m_vsz]; +// const u16 m_hpage = page_masks[m_hsz]; +// const u16 m_vpage = page_masks[m_vsz]; // AV Artisan games will set plane B base with 0x18000 const u32 plane_a_name_base = (m_plane_a_name_table & m_vram_mask) >> 1; @@ -928,8 +975,8 @@ void ym7101_device::prepare_tile_line(int scanline) { const u16 scrollx_a = m_vram[(m_hscroll_address >> 1) + scroll_x_base]; const u16 scrolly_a = m_vsram[x & scroll_y_mask]; - const u16 vcolumn_a = (scrolly_a + scanline) & ((v_page * 8) - 1); - const u32 tile_offset_a = ((x - (scrollx_a >> 3)) & ((h_page * 1) - 1)) + ((vcolumn_a >> 3) * (h_page >> 0)); + const u16 vcolumn_a = (scrolly_a + scanline) & ((m_vpage * 8) - 1); + const u32 tile_offset_a = ((x - (scrollx_a >> 3)) & ((m_hpage * 1) - 1)) + ((vcolumn_a >> 3) * (m_hpage >> 0)); scrolly_a_frac = scrolly_a & 7; scrollx_a_frac = scrollx_a & 7; @@ -945,8 +992,8 @@ void ym7101_device::prepare_tile_line(int scanline) const u16 scrollx_b_frac = scrollx_b & 7; const u16 scrolly_b = m_vsram[(x & scroll_y_mask) + 1]; const u16 scrolly_b_frac = scrolly_b & 7; - const u16 vcolumn_b = (scrolly_b + scanline) & ((v_page * 8) - 1); - const u32 tile_offset_b = ((x - (scrollx_b >> 3)) & ((h_page * 1) - 1)) + ((vcolumn_b >> 3) * (h_page >> 0)); + const u16 vcolumn_b = (scrolly_b + scanline) & ((m_vpage * 8) - 1); + const u32 tile_offset_b = ((x - (scrollx_b >> 3)) & ((m_hpage * 1) - 1)) + ((vcolumn_b >> 3) * (m_hpage >> 0)); const u16 id_flags_b = m_vram[(plane_b_name_base + tile_offset_b) & m_vram_mask]; const u16 tile_b = id_flags_b & tile_mask; const u8 flipx_b = BIT(id_flags_b, 11) ? 4 : 3; diff --git a/src/devices/video/ym7101.h b/src/devices/video/ym7101.h index 736e690cd1d72..61ce49cd839bb 100644 --- a/src/devices/video/ym7101.h +++ b/src/devices/video/ym7101.h @@ -183,6 +183,8 @@ class ym7101_device : public device_t, u16 m_hvcounter_latch; u32 m_vram_mask; bool m_sprite_collision, m_sprite_overflow; + u16 m_hpage, m_vpage; + void calculate_plane_sizes(); bitmap_rgb32 m_bitmap; bool render_line(int scanline); diff --git a/src/mame/pc/teradrive.cpp b/src/mame/pc/teradrive.cpp index 02ae194fd5684..4663d63eb5dcc 100644 --- a/src/mame/pc/teradrive.cpp +++ b/src/mame/pc/teradrive.cpp @@ -1,6 +1,6 @@ // license:BSD-3-Clause // copyright-holders: Angelo Salese -// thanks-to: Mask of Destiny, Nemesis, Sik +// thanks-to: Mask of Destiny, Nemesis, Sik, ICEknight /************************************************************************************************** Sega Teradrive @@ -20,6 +20,7 @@ References (generic MD): - https://segaretro.org/Sega_Mega_Drive/VDP_general_usage - https://segaretro.org/Sega_Mega_Drive/Technical_specifications - https://gendev.spritesmind.net/forum/viewtopic.php?p=37011#p37011 +- https://github.com/jsgroth/jgenesis/wiki/Tricky%E2%80%90to%E2%80%90Emulate-Games#genesis NOTES (PC side): - F1 at POST will bring a setup menu; @@ -33,6 +34,7 @@ NOTES (MD side): - has discrete YM3438 in place of YM2612 - Mega CD expansion port working with DIY extension cable, 32x needs at least a passive cart adapter - focus 3 in debugger is the current default for MD side +- bp ff0122,1,{fill 0xff8100,4,"SEGA";g} to bypass TMSS loading for games without a valid header - MAME inability of handling differing refresh rates causes visible tearing in MD screen (cfr. koteteik intro). A partial workaround is to use Video mode = composite, so that VGA will downclock to ~60 Hz instead. @@ -42,21 +44,29 @@ NOTES (MD side): - Quadtel EMM driver fails recognizing WD76C10 chipset with drv4; - Cannot HDD format with floppy insthdd.bat, cannot boot from HDD (needs floppy first). Attached disk is a WDL-330PS with no geometry info available; -- MD side cart slot, expansion bay and VDP rewrites (WIP); - TMSS unlock and respective x86<->MD bus grants are sketchy; - SEGA TERADRIVE テラドライブ ユーザーズマニュアル known to exist (not scanned yet) - "TIMER FAIL" when exiting from F1 setup menu (keyboard? reset from chipset?); +- dual boot not yet handled; + +TODO (MD side): +- some games (orunnersj, timekillu, rhythmld and late SGDK games) fails on Z80 bus request stuff; +- dashdes: is a flickerfest during gameplay; +- sonic2/combatca: no interlace support in 2-players mode; +- dheadj: scrolling issues in stage 4-1 (blocks overflowing with ); +- shangon/skitchin: one line off during gameplay; +- caesar: no sound; +- gynougj: stray tile on top-left of title screen; **************************************************************************************************/ #include "emu.h" -#include "bus/generic/carts.h" -#include "bus/generic/slot.h" - #include "bus/isa/isa.h" #include "bus/isa/isa_cards.h" #include "bus/isa/svga_paradise.h" +#include "bus/megadrive/cart/options.h" +#include "bus/megadrive/cart/slot.h" #include "bus/pc_kbd/keyboards.h" #include "bus/pc_kbd/pc_kbdc.h" #include "bus/sms_ctrl/controllers.h" @@ -465,7 +475,7 @@ class teradrive_state : public driver_device required_device m_mdscreen; required_memory_bank m_tmss_bank; memory_view m_tmss_view; - required_device m_md_cart; + required_device m_md_cart; required_device m_md_vdp; required_device m_opn; memory_view m_md_68k_sound_view; @@ -536,7 +546,8 @@ void teradrive_state::md_68k_map(address_map &map) // m_cart_view[1](0x400000, 0x400fff).view(m_tmss_view); // m_tmss_view[0](0x400000, 0x400fff).rom().region("tmss", 0); - map(0x000000, 0x3fffff).r(m_md_cart, FUNC(generic_slot_device::read_rom)); + // TODO: implement bus conflict for 0x40'0000,0x7f'ffff area (if expansion port attached) + map(0x000000, 0x7fffff).rw(m_md_cart, FUNC(megadrive_cart_slot_device::base_r), FUNC(megadrive_cart_slot_device::base_w)); map(0x000000, 0x000fff).view(m_tmss_view); m_tmss_view[0](0x000000, 0x000fff).bankr(m_tmss_bank); @@ -598,7 +609,7 @@ void teradrive_state::md_68k_map(address_map &map) // map(0xa11400, 0xa1dfff) (no DTACK generation, freezes machine without additional HW) // map(0xa12000, 0xa120ff).m(m_exp, FUNC(...::fdc_map)); -// map(0xa13000, 0xa130ff).m(m_cart, FUNC(...::time_map)); + map(0xa13000, 0xa130ff).rw(m_md_cart, FUNC(megadrive_cart_slot_device::time_r), FUNC(megadrive_cart_slot_device::time_w)); // map(0xa14000, 0xa14003) TMSS lock // map(0xa15100, 0xa153ff) 32X registers if present, otherwise // map(0xae0000, 0xae0003) Teradrive bus switch registers @@ -1026,11 +1037,7 @@ void teradrive_state::teradrive(machine_config &config) m_md_ioports[N]->set_out_handler(m_md_ctrl_ports[N], FUNC(sms_control_port_device::out_w)); } - // TODO: vestigial - GENERIC_CARTSLOT(config, m_md_cart, generic_plain_slot, "megadriv_cart"); - m_md_cart->set_width(GENERIC_ROM16_WIDTH); - // TODO: generic_cartslot has issues with softlisted endianness (use loose for now) - m_md_cart->set_endian(ENDIANNESS_BIG); + MEGADRIVE_CART_SLOT(config, m_md_cart, md_master_xtal / 7, megadrive_cart_options, nullptr).set_must_be_loaded(false); SPEAKER(config, "md_speaker", 2).front(); diff --git a/src/mame/sega/megadriv.cpp b/src/mame/sega/megadriv.cpp index 2af1094e64c35..36b9a4e3d8697 100644 --- a/src/mame/sega/megadriv.cpp +++ b/src/mame/sega/megadriv.cpp @@ -45,12 +45,6 @@ Known Non-Issues (confirmed on Real Genesis) void md_base_state::megadriv_z80_bank_w(uint16_t data) { - // TODO: menghu crashes here - // Tries to setup a bank of 0xff0000 from z80 side (PC=1131) after you talk with the cashier twice. - // Without a guard over it game will trash 68k memory causing a crash, works on real HW with everdrive - // so not coming from a cart copy protection. - // Update: it breaks cfodder BGM on character select at least, therefore we current don't guard against it - // Apparently reading 68k RAM from z80 is not recommended by Sega, so *writing* isn't possible lacking bus grant? m_genz80.z80_bank_addr = ((m_genz80.z80_bank_addr >> 1) | (data << 23)) & 0xff8000; }