diff --git a/src/mess/drivers/sms.c b/src/mess/drivers/sms.c index fa029b6782f..a79a855aef4 100644 --- a/src/mess/drivers/sms.c +++ b/src/mess/drivers/sms.c @@ -540,6 +540,17 @@ static const sn76496_config psg_intf = static SLOT_INTERFACE_START(sms_cart) + SLOT_INTERFACE_INTERNAL("rom", SEGA8_ROM_STD) + SLOT_INTERFACE_INTERNAL("codemasters", SEGA8_ROM_CODEMASTERS) + SLOT_INTERFACE_INTERNAL("4pak", SEGA8_ROM_4PAK) + SLOT_INTERFACE_INTERNAL("zemina", SEGA8_ROM_ZEMINA) + SLOT_INTERFACE_INTERNAL("nemesis", SEGA8_ROM_NEMESIS) + SLOT_INTERFACE_INTERNAL("janggun", SEGA8_ROM_JANGGUN) + SLOT_INTERFACE_INTERNAL("korean", SEGA8_ROM_KOREAN) + SLOT_INTERFACE_INTERNAL("korean_nb", SEGA8_ROM_KOREAN_NB) +SLOT_INTERFACE_END + +static SLOT_INTERFACE_START(sg1000mk3_cart) SLOT_INTERFACE_INTERNAL("rom", SEGA8_ROM_STD) SLOT_INTERFACE_INTERNAL("terebi", SEGA8_ROM_TEREBI) SLOT_INTERFACE_INTERNAL("codemasters", SEGA8_ROM_CODEMASTERS) @@ -549,6 +560,12 @@ static SLOT_INTERFACE_START(sms_cart) SLOT_INTERFACE_INTERNAL("janggun", SEGA8_ROM_JANGGUN) SLOT_INTERFACE_INTERNAL("korean", SEGA8_ROM_KOREAN) SLOT_INTERFACE_INTERNAL("korean_nb", SEGA8_ROM_KOREAN_NB) + SLOT_INTERFACE_INTERNAL("castle", SEGA8_ROM_CASTLE) + SLOT_INTERFACE_INTERNAL("dahjee_typea", SEGA8_ROM_DAHJEE_TYPEA) + SLOT_INTERFACE_INTERNAL("dahjee_typeb", SEGA8_ROM_DAHJEE_TYPEB) +// are these SC-3000 carts below actually compatible or not? remove if not! + SLOT_INTERFACE_INTERNAL("level3", SEGA8_ROM_BASIC_L3) + SLOT_INTERFACE_INTERNAL("music_editor", SEGA8_ROM_MUSIC_EDITOR) SLOT_INTERFACE_END static SLOT_INTERFACE_START(gg_cart) @@ -793,7 +810,7 @@ static MACHINE_CONFIG_DERIVED( sg1000m3, sms_fm ) MCFG_CPU_IO_MAP(sms_no3e3f_io) MCFG_DEVICE_REMOVE("slot") - MCFG_SG1000MK3_CARTRIDGE_ADD("slot", sms_cart, NULL, NULL) + MCFG_SG1000MK3_CARTRIDGE_ADD("slot", sg1000mk3_cart, NULL, NULL) MACHINE_CONFIG_END static MACHINE_CONFIG_DERIVED( sms2_fm, sms2_ntsc ) diff --git a/src/mess/machine/sega8_rom.c b/src/mess/machine/sega8_rom.c index 8fa631f560f..99dd69bdf8d 100644 --- a/src/mess/machine/sega8_rom.c +++ b/src/mess/machine/sega8_rom.c @@ -15,9 +15,20 @@ // constructors //------------------------------------------------- +// Base cart type shared across SG-1000, SG-1000 Mark II, SG-1000 Mark III, SMS, GG +// even if in sg1000 rom banks are never changed and ram is never enabled const device_type SEGA8_ROM_STD = &device_creator; -const device_type SEGA8_ROM_EEPROM = &device_creator; + +// Specific SG-1000 MkI - MkII cart types +const device_type SEGA8_ROM_CASTLE = &device_creator; +const device_type SEGA8_ROM_BASIC_L3 = &device_creator; +const device_type SEGA8_ROM_MUSIC_EDITOR = &device_creator; const device_type SEGA8_ROM_TEREBI = &device_creator; +const device_type SEGA8_ROM_DAHJEE_TYPEA = &device_creator; +const device_type SEGA8_ROM_DAHJEE_TYPEB = &device_creator; + +// Specific SG-1000 MkIII - SMS - GG cart types +const device_type SEGA8_ROM_EEPROM = &device_creator; const device_type SEGA8_ROM_CODEMASTERS = &device_creator; const device_type SEGA8_ROM_4PAK = &device_creator; const device_type SEGA8_ROM_ZEMINA = &device_creator; @@ -27,6 +38,7 @@ const device_type SEGA8_ROM_KOREAN = &device_creator; const device_type SEGA8_ROM_KOREAN_NB = &device_creator; + sega8_rom_device::sega8_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : device_t(mconfig, type, name, tag, owner, clock, shortname, source), device_sega8_cart_interface( mconfig, *this ) @@ -34,22 +46,34 @@ sega8_rom_device::sega8_rom_device(const machine_config &mconfig, device_type ty } sega8_rom_device::sega8_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : device_t(mconfig, SEGA8_ROM_STD, "SMS Carts", tag, owner, clock, "sega8_rom", __FILE__), + : device_t(mconfig, SEGA8_ROM_STD, "Mark III, SMS & GG Carts", tag, owner, clock, "sega8_rom", __FILE__), device_sega8_cart_interface( mconfig, *this ) { } -sega8_eeprom_device::sega8_eeprom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : device_t(mconfig, SEGA8_ROM_EEPROM, "SMS EEPROM Carts", tag, owner, clock, "sega8_eeprom", __FILE__), - device_sega8_cart_interface( mconfig, *this ), - m_eeprom(*this, "eeprom") + + +sega8_castle_device::sega8_castle_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sega8_rom_device(mconfig, SEGA8_ROM_CASTLE, "SG-1000 The Castle Cart", tag, owner, clock, "sega8_castle", __FILE__) +{ +} + + +sega8_basic_l3_device::sega8_basic_l3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sega8_rom_device(mconfig, SEGA8_ROM_BASIC_L3, "SC-3000 BASIC Level III Cart", tag, owner, clock, "sega8_basicl3", __FILE__) +{ +} + + +sega8_music_editor_device::sega8_music_editor_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sega8_rom_device(mconfig, SEGA8_ROM_MUSIC_EDITOR, "SC-3000 Music Editor Cart", tag, owner, clock, "sega8_music", __FILE__) { } sega8_terebi_device::sega8_terebi_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : sega8_rom_device(mconfig, SEGA8_ROM_TEREBI, "SMS Terebi Oekaki Cart", tag, owner, clock, "sega8_terebi", __FILE__), + : sega8_rom_device(mconfig, SEGA8_ROM_TEREBI, "SG-1000 Terebi Oekaki Cart", tag, owner, clock, "sega8_terebi", __FILE__), m_tvdraw_x(*this, "TVDRAW_X"), m_tvdraw_y(*this, "TVDRAW_Y"), m_tvdraw_pen(*this, "TVDRAW_PEN") @@ -57,8 +81,30 @@ sega8_terebi_device::sega8_terebi_device(const machine_config &mconfig, const ch } +sega8_dahjee_typea_device::sega8_dahjee_typea_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sega8_rom_device(mconfig, SEGA8_ROM_DAHJEE_TYPEA, "SG-1000 Dahjee RAM expansion + Cart (Type A)", tag, owner, clock, "sega8_dahjeea", __FILE__) +{ +} + + +sega8_dahjee_typeb_device::sega8_dahjee_typeb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sega8_rom_device(mconfig, SEGA8_ROM_DAHJEE_TYPEB, "SG-1000 Dahjee RAM expansion + Cart (Type B)", tag, owner, clock, "sega8_dahjeeb", __FILE__) +{ +} + + + + +sega8_eeprom_device::sega8_eeprom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SEGA8_ROM_EEPROM, "GG Carts + EEPROM", tag, owner, clock, "sega8_eeprom", __FILE__), + device_sega8_cart_interface( mconfig, *this ), + m_eeprom(*this, "eeprom") +{ +} + + sega8_codemasters_device::sega8_codemasters_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : device_t(mconfig, SEGA8_ROM_CODEMASTERS, "SMS Codemasters Carts", tag, owner, clock, "sega8_codemasters", __FILE__), + : device_t(mconfig, SEGA8_ROM_CODEMASTERS, "Mark III, SMS & GG Codemasters Carts", tag, owner, clock, "sega8_codemasters", __FILE__), device_sega8_cart_interface( mconfig, *this ) { } @@ -122,6 +168,21 @@ void sega8_rom_device::device_reset() } + +void sega8_terebi_device::device_start() +{ + save_item(NAME(m_rom_bank_base)); + save_item(NAME(m_tvdraw_data)); +} + +void sega8_terebi_device::device_reset() +{ + m_tvdraw_data = 0; +} + + + + void sega8_eeprom_device::device_start() { save_item(NAME(m_rom_bank_base)); @@ -136,17 +197,6 @@ void sega8_eeprom_device::device_reset() } -void sega8_terebi_device::device_start() -{ - save_item(NAME(m_rom_bank_base)); - save_item(NAME(m_tvdraw_data)); -} - -void sega8_terebi_device::device_reset() -{ - m_tvdraw_data = 0; -} - void sega8_codemasters_device::device_start() { save_item(NAME(m_rom_bank_base)); @@ -186,12 +236,6 @@ void sega8_zemina_device::device_reset() } -void sega8_janggun_device::device_start() -{ - save_item(NAME(m_rom_bank_base)); -} - - // initial bank setup needs to know how many 16K banks are available, so it needs to be called during cart loading... void sega8_rom_device::late_bank_setup() @@ -254,7 +298,6 @@ void sega8_korean_device::late_bank_setup() } - /*------------------------------------------------- mapper specific handlers -------------------------------------------------*/ @@ -262,6 +305,7 @@ void sega8_korean_device::late_bank_setup() /*------------------------------------------------- Base Sega 8bit carts, possibly with bankswitch + (only used by Mark III, SMS and GG games) -------------------------------------------------*/ @@ -312,6 +356,242 @@ WRITE8_MEMBER(sega8_rom_device::write_mapper) } } +/*------------------------------------------------- + + The Castle is a SG-1000 game featuring 8K of + oncart RAM, mapped at 0x8000-0x9fff + + -------------------------------------------------*/ + +READ8_MEMBER(sega8_castle_device::read_cart) +{ + // 8K of RAM sits in 0x8000-0x9fff + if (offset >= 0x8000 && offset < 0xa000) + return m_ram[offset & 0x1fff]; + + return m_rom[offset % m_rom_size]; +} + +WRITE8_MEMBER(sega8_castle_device::write_cart) +{ + // 8K of RAM sits in 0x8000-0x9fff + if (offset >= 0x8000 && offset < 0xa000) + m_ram[offset & 0x1fff] = data; +} + + +/*------------------------------------------------- + + BASIC Level III cart featured 32K of + oncart RAM, mapped at 0x8000-0xffff? + + -------------------------------------------------*/ + +READ8_MEMBER(sega8_basic_l3_device::read_cart) +{ + // 8K of RAM sits in 0x8000-0x9fff + if (offset >= 0x8000) + return m_ram[offset & 0x3fff]; + + return m_rom[offset % m_rom_size]; +} + +WRITE8_MEMBER(sega8_basic_l3_device::write_cart) +{ + // 8K of RAM sits in 0x8000-0x9fff + if (offset >= 0x8000) + m_ram[offset & 0x3fff] = data; +} + +READ8_MEMBER(sega8_basic_l3_device::read_ram) +{ + return m_ram[0x4000 + (offset & 0x3fff)]; +} + +WRITE8_MEMBER(sega8_basic_l3_device::write_ram) +{ + m_ram[0x4000 + (offset & 0x3fff)] = data; +} + + +/*------------------------------------------------- + + Music Editor cart featured 10K of oncart RAM, mapped + in 0x8000-0x9fff and 0xc000-0xffff + + -------------------------------------------------*/ + +READ8_MEMBER(sega8_music_editor_device::read_cart) +{ + // 8K of RAM sits in 0x8000-0x9fff + if (offset >= 0x8000 && offset < 0xa000) + return m_ram[offset & 0x1fff]; + + return m_rom[offset % m_rom_size]; +} + +WRITE8_MEMBER(sega8_music_editor_device::write_cart) +{ + // 8K of RAM sits in 0x8000-0x9fff + if (offset >= 0x8000 && offset < 0xa000) + m_ram[offset & 0x1fff] = data; +} + +READ8_MEMBER(sega8_music_editor_device::read_ram) +{ + // 2K more of RAM sits in 0xc000-0xc3ff (and mirrored up to 0xffff) + // or should it simply go to the 2K of SC3000 RAM??? + return m_ram[0x2000 + (offset & 0x7ff)]; +} + +WRITE8_MEMBER(sega8_music_editor_device::write_ram) +{ + // 2K more of RAM sits in 0xc000-0xc3ff (and mirrored up to 0xffff) + // or should it simply go to the 2K of SC3000 RAM??? + m_ram[0x2000 + (offset & 0x7ff)] = data; +} + + +/*------------------------------------------------- + + SG-1000 Terebi Oekaki using a Tablet input device + + -------------------------------------------------*/ + +/* + + Terebi Oekaki (TV Draw) + + Address Access Bits + 7 6 5 4 3 2 1 0 + $6000 W - - - - - - - AXIS + $8000 R BUSY - - - - - - PRESS + $A000 R/W DATA + + AXIS: write 0 to select X axis, 1 to select Y axis. + BUSY: reads 1 when graphic board is busy sampling position, else 0. + PRESS: reads 0 when pen is touching graphic board, else 1. + DATA: when pen is touching graphic board, return 8-bit sample position for currently selected axis (X is in the 0-255 range, Y in the 0-191 range). Else, return 0. + + */ + + +READ8_MEMBER(sega8_terebi_device::read_cart) +{ + int bank = offset / 0x4000; + + if (offset == 0x8000) + return m_tvdraw_pen->read(); + if (offset == 0xa000) + return m_tvdraw_data; + + return m_rom[m_rom_bank_base[bank] * 0x4000 + (offset & 0x3fff)]; +} + +WRITE8_MEMBER(sega8_terebi_device::write_cart) +{ + switch (offset) + { + case 0x6000: + if (data & 0x01) + { + m_tvdraw_data = m_tvdraw_x->read(); + + if (m_tvdraw_data < 4) m_tvdraw_data = 4; + if (m_tvdraw_data > 251) m_tvdraw_data = 251; + } + else + m_tvdraw_data = m_tvdraw_y->read() + 0x20; + break; + case 0xa000: + // effect unknown + break; + } +} + +static INPUT_PORTS_START( tvdraw ) + PORT_START("TVDRAW_X") + PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X ) PORT_NAME("Tablet - X Axis") PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(50) PORT_KEYDELTA(10) PORT_PLAYER(1) + + PORT_START("TVDRAW_Y") + PORT_BIT( 0xff, 0x60, IPT_LIGHTGUN_Y ) PORT_NAME("Tablet - Y Axis") PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_MINMAX(0, 191) PORT_SENSITIVITY(50) PORT_KEYDELTA(10) PORT_PLAYER(1) + + PORT_START("TVDRAW_PEN") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("Tablet - Pen") +INPUT_PORTS_END + +ioport_constructor sega8_terebi_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( tvdraw ); +} + + +/*------------------------------------------------- + + Dahjee carts were sold with a RAM expansion pass-through + cart (which we don't emulate separately for the + moment) which allowed to play on old SG1000 machines + some MSX conversions requiring more RAM than available + + Two kind of expansion existed (for different games), + one with 9K of RAM (Type A) and one with 8K of + RAM (Type B). + + -------------------------------------------------*/ + +// TYPE A +READ8_MEMBER(sega8_dahjee_typea_device::read_cart) +{ + // 8K of RAM sits in 0x2000-0x3fff + if (offset >= 0x2000 && offset < 0x4000) + return m_ram[offset & 0x1fff]; + + return m_rom[offset % m_rom_size]; +} + +WRITE8_MEMBER(sega8_dahjee_typea_device::write_cart) +{ + // 8K of RAM sits in 0x2000-0x3fff + if (offset >= 0x2000 && offset < 0x4000) + m_ram[offset & 0x1fff] = data; +} + +READ8_MEMBER(sega8_dahjee_typea_device::read_ram) +{ + // 1K more of RAM sits in 0xc000-0xc3ff (and mirrored up to 0xffff + // or should it simply go to the 1K of SG1000 RAM??? + return m_ram[0x2000 + (offset & 0x3ff)]; +} + +WRITE8_MEMBER(sega8_dahjee_typea_device::write_ram) +{ + // 1K more of RAM sits in 0xc000-0xc3ff (and mirrored up to 0xffff + // or should it simply go to the 1K of SG1000 RAM??? + m_ram[0x2000 + (offset & 0x3ff)] = data; +} + + +// TYPE B +READ8_MEMBER(sega8_dahjee_typeb_device::read_cart) +{ + return m_rom[offset % m_rom_size]; +} + +READ8_MEMBER(sega8_dahjee_typeb_device::read_ram) +{ + // 8K more of RAM sits in 0xc000-0xffff + return m_ram[offset & 0x1fff]; +} + +WRITE8_MEMBER(sega8_dahjee_typeb_device::write_ram) +{ + // 8K more of RAM sits in 0xc000-0xffff + m_ram[offset & 0x1fff] = data; +} + + + + /*------------------------------------------------- Sega carts + EEPROM, used for some GameGear baseball @@ -381,63 +661,6 @@ machine_config_constructor sega8_eeprom_device::device_mconfig_additions() const } -/*------------------------------------------------- - - Sega 8-bit cart + Tablet input device, used for - SG-1000 Terebi Oekaki (compatible with Mark III) - - -------------------------------------------------*/ - -READ8_MEMBER(sega8_terebi_device::read_cart) -{ - int bank = offset / 0x4000; - - if (offset == 0x8000) - return m_tvdraw_pen->read(); - if (offset == 0xa000) - return m_tvdraw_data; - - return m_rom[m_rom_bank_base[bank] * 0x4000 + (offset & 0x3fff)]; -} - -WRITE8_MEMBER(sega8_terebi_device::write_cart) -{ - switch (offset) - { - case 0x6000: - if (data & 0x01) - { - m_tvdraw_data = m_tvdraw_x->read(); - - if (m_tvdraw_data < 4) m_tvdraw_data = 4; - if (m_tvdraw_data > 251) m_tvdraw_data = 251; - } - else - m_tvdraw_data = m_tvdraw_y->read() + 0x20; - break; - case 0xa000: - // effect unknown - break; - } -} - -static INPUT_PORTS_START( tvdraw ) - PORT_START("TVDRAW_X") - PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X ) PORT_NAME("Tablet - X Axis") PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(50) PORT_KEYDELTA(10) PORT_PLAYER(1) - - PORT_START("TVDRAW_Y") - PORT_BIT( 0xff, 0x60, IPT_LIGHTGUN_Y ) PORT_NAME("Tablet - Y Axis") PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_MINMAX(0, 191) PORT_SENSITIVITY(50) PORT_KEYDELTA(10) PORT_PLAYER(1) - - PORT_START("TVDRAW_PEN") - PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("Tablet - Pen") -INPUT_PORTS_END - -ioport_constructor sega8_terebi_device::device_input_ports() const -{ - return INPUT_PORTS_NAME( tvdraw ); -} - - /*------------------------------------------------- Codemasters carts, possibly having on cart RAM @@ -639,3 +862,4 @@ WRITE8_MEMBER(sega8_korean_device::write_cart) if (offset == 0xa000) m_rom_bank_base[2] = data % m_rom_page_count; } + diff --git a/src/mess/machine/sega8_rom.h b/src/mess/machine/sega8_rom.h index b5f6882a29c..30a9e3be614 100644 --- a/src/mess/machine/sega8_rom.h +++ b/src/mess/machine/sega8_rom.h @@ -32,6 +32,128 @@ protected: }; + + +// ======================> sega8_castle_device + +class sega8_castle_device : public sega8_rom_device +{ +public: + // construction/destruction + sega8_castle_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + virtual DECLARE_WRITE8_MEMBER(write_mapper) {} +}; + + +// ======================> sega8_basic_l3_device + +class sega8_basic_l3_device : public sega8_rom_device +{ +public: + // construction/destruction + sega8_basic_l3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + virtual DECLARE_WRITE8_MEMBER(write_mapper) {} + + // has internal RAM which overwrites the system one! + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); +}; + + +// ======================> sega8_music_editor_device + +class sega8_music_editor_device : public sega8_rom_device +{ +public: + // construction/destruction + sega8_music_editor_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + virtual DECLARE_WRITE8_MEMBER(write_mapper) {} + + // has internal RAM which overwrites the system one! + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); +}; + + +// ======================> sega8_terebi_device + +class sega8_terebi_device : public sega8_rom_device +{ +public: + // construction/destruction + sega8_terebi_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual ioport_constructor device_input_ports() const; + virtual void device_reset(); + + required_ioport m_tvdraw_x; + required_ioport m_tvdraw_y; + required_ioport m_tvdraw_pen; + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + virtual DECLARE_WRITE8_MEMBER(write_mapper) {} + +protected: + UINT8 m_tvdraw_data; +}; + + +// ======================> sega8_dahjee_typea_device + +class sega8_dahjee_typea_device : public sega8_rom_device +{ +public: + // construction/destruction + sega8_dahjee_typea_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + virtual DECLARE_WRITE8_MEMBER(write_mapper) {} + + // has internal RAM which overwrites the system one! + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); +}; + + +// ======================> sega8_dahjee_typeb_device + +class sega8_dahjee_typeb_device : public sega8_rom_device +{ +public: + // construction/destruction + sega8_dahjee_typeb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart) {} + virtual DECLARE_WRITE8_MEMBER(write_mapper) {} + + // has internal RAM which overwrites the system one! + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); +}; + + + + // ======================> sega8_eeprom_device class sega8_eeprom_device : public device_t, @@ -62,32 +184,6 @@ protected: }; -// ======================> sega8_terebi_device - -class sega8_terebi_device : public sega8_rom_device -{ -public: - // construction/destruction - sega8_terebi_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); - - // device-level overrides - virtual void device_start(); - virtual ioport_constructor device_input_ports() const; - virtual void device_reset(); - - required_ioport m_tvdraw_x; - required_ioport m_tvdraw_y; - required_ioport m_tvdraw_pen; - - // reading and writing - virtual DECLARE_READ8_MEMBER(read_cart); - virtual DECLARE_WRITE8_MEMBER(write_cart); - -protected: - UINT8 m_tvdraw_data; -}; - - // ======================> sega8_codemasters_device class sega8_codemasters_device : public device_t, @@ -183,9 +279,9 @@ class sega8_janggun_device : public device_t, public: // construction/destruction sega8_janggun_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); - + // device-level overrides - virtual void device_start(); + virtual void device_start() { save_item(NAME(m_rom_bank_base)); } virtual void late_bank_setup(); @@ -228,8 +324,14 @@ public: }; + // device type definition extern const device_type SEGA8_ROM_STD; +extern const device_type SEGA8_ROM_CASTLE; +extern const device_type SEGA8_ROM_BASIC_L3; +extern const device_type SEGA8_ROM_MUSIC_EDITOR; +extern const device_type SEGA8_ROM_DAHJEE_TYPEA; +extern const device_type SEGA8_ROM_DAHJEE_TYPEB; extern const device_type SEGA8_ROM_EEPROM; extern const device_type SEGA8_ROM_TEREBI; extern const device_type SEGA8_ROM_CODEMASTERS; diff --git a/src/mess/machine/sega8_slot.c b/src/mess/machine/sega8_slot.c index 90072bd0763..db47f312e77 100644 --- a/src/mess/machine/sega8_slot.c +++ b/src/mess/machine/sega8_slot.c @@ -182,7 +182,12 @@ static const sega8_slot slot_list[] = { SEGA8_NEMESIS, "nemesis" }, { SEGA8_JANGGUN, "janggun" }, { SEGA8_KOREAN, "korean" }, - { SEGA8_KOREAN_NOBANK, "korean_nobank" } + { SEGA8_KOREAN_NOBANK, "korean_nb" }, + { SEGA8_CASTLE, "castle" }, + { SEGA8_BASIC_L3, "level3" }, + { SEGA8_MUSIC_EDITOR, "music_editor" }, + { SEGA8_DAHJEE_TYPEA, "dahjee_typea" }, + { SEGA8_DAHJEE_TYPEB, "dahjee_typeb" } }; static int sega8_get_pcb_id(const char *slot) @@ -272,20 +277,45 @@ void sega8_cart_slot_device::setup_ram() { if (software_entry() == NULL) { - // from fullpath we have no way to know exactly if there was RAM, how much RAM was in the cart and if there was a battery - // so we always alloc 32KB and we save its content only if the game enable the RAM (unless it's Codemasters mapper...) - - if (m_type != SEGA8_CODEMASTERS) + if (m_type == SEGA8_CASTLE) { - m_cart->set_late_battery(TRUE); - m_cart->ram_alloc(machine(), 0x08000); + m_cart->ram_alloc(machine(), 0x2000); + m_cart->set_has_battery(FALSE); } - else + else if (m_type == SEGA8_BASIC_L3) { - // Codemasters cart can have 64KB of RAM (Ernie Els Golf) and no battery + m_cart->ram_alloc(machine(), 0x8000); + m_cart->set_has_battery(FALSE); + } + else if (m_type == SEGA8_MUSIC_EDITOR) + { + m_cart->ram_alloc(machine(), 0x2800); + m_cart->set_has_battery(FALSE); + } + else if (m_type == SEGA8_DAHJEE_TYPEA) + { + m_cart->ram_alloc(machine(), 0x2400); + m_cart->set_has_battery(FALSE); + } + else if (m_type == SEGA8_DAHJEE_TYPEB) + { + m_cart->ram_alloc(machine(), 0x2000); + m_cart->set_has_battery(FALSE); + } + else if (m_type == SEGA8_CODEMASTERS) + { + // Codemasters cart can have 64KB of RAM (Ernie Els Golf? or 8KB?) and no battery m_cart->ram_alloc(machine(), 0x10000); m_cart->set_has_battery(FALSE); } + else + { + // for generic carts loaded from fullpath we have no way to know exactly if there was RAM, + // how much RAM was in the cart and if there was a battery so we always alloc 32KB and + // we save its content only if the game enable the RAM + m_cart->set_late_battery(TRUE); + m_cart->ram_alloc(machine(), 0x08000); + } } else { @@ -456,9 +486,8 @@ int sms_state::detect_korean_mapper( UINT8 *rom ) int sega8_cart_slot_device::get_cart_type(UINT8 *ROM, UINT32 len) { int type = SEGA8_BASE_ROM; - static const UINT8 terebi_oekaki[7] = { 0x61, 0x6e, 0x6e, 0x61, 0x6b, 0x6d, 0x6e }; // "annakmn" - /* Check for special cartridge features (new routine, courtesy of Omar Cornut, from MEKA) */ + // Check for special cartridge features (new routine, courtesy of Omar Cornut, from MEKA) if (len >= 0x8000) { int _0002 = 0, _8000 = 0, _a000 = 0, _ffff = 0, _3ffe = 0, _4000 = 0, _6000 = 0; @@ -506,9 +535,64 @@ int sega8_cart_slot_device::get_cart_type(UINT8 *ROM, UINT32 len) type = SEGA8_JANGGUN; } - // Terebi Oekaki (TV Draw) is a SG1000 game with special input device which is compatible with SG1000 Mark III - if (!memcmp(&ROM[0x13b3], terebi_oekaki, 7)) + // Try to detect Dahjee RAM Expansions + if (len >= 0x8000) + { + int x2000_3000 = 0, xd000_e000_f000 = 0, x2000_ff = 0; + + for (int i = 0; i < 0x8000; i++) + { + if (ROM[i] == 0x32) + { + UINT16 addr = ROM[i + 1] | (ROM[i + 2] << 8); + + switch (addr & 0xf000) + { + case 0x2000: + case 0x3000: + i += 2; + x2000_3000++; + break; + + case 0xd000: + case 0xe000: + case 0xf000: + i += 2; + xd000_e000_f000++; + break; + } + } + } + for (int i = 0x2000; i < 0x4000; i++) + { + if (ROM[i] == 0xff) + x2000_ff++; + } + if (x2000_ff == 0x2000 && (xd000_e000_f000 > 10 || x2000_3000 > 10)) + { + if (xd000_e000_f000 > x2000_3000) + type = SEGA8_DAHJEE_TYPEB; + else + type = SEGA8_DAHJEE_TYPEA; + } + } + + // Terebi Oekaki (TV Draw) + if (!strncmp((const char *)&ROM[0x13b3], "annakmn", 7)) type = SEGA8_TEREBIOEKAKI; + + // The Castle (ROM+RAM) + if (!strncmp((const char *)&ROM[0x1cc3], "ASCII 1986", 10)) + type = SEGA8_CASTLE; + + // BASIC Level 3 + if (!strncmp((const char *)&ROM[0x6a20], "SC-3000 BASIC Level 3 ver 1.0", 29)) + type = SEGA8_BASIC_L3; + + // Music Editor + if (!strncmp((const char *)&ROM[0x0841], "PIANO", 5)) + type = SEGA8_MUSIC_EDITOR; + return type; } @@ -557,6 +641,14 @@ READ8_MEMBER(sega8_cart_slot_device::read_cart) return 0xff; } +READ8_MEMBER(sega8_cart_slot_device::read_ram) +{ + if (m_cart) + return m_cart->read_ram(space, offset); + else + return 0xff; +} + /*------------------------------------------------- write @@ -574,6 +666,12 @@ WRITE8_MEMBER(sega8_cart_slot_device::write_cart) m_cart->write_cart(space, offset, data); } +WRITE8_MEMBER(sega8_cart_slot_device::write_ram) +{ + if (m_cart) + m_cart->write_ram(space, offset, data); +} + /*------------------------------------------------- Internal header logging diff --git a/src/mess/machine/sega8_slot.h b/src/mess/machine/sega8_slot.h index bf1e6be6760..85bdd127010 100644 --- a/src/mess/machine/sega8_slot.h +++ b/src/mess/machine/sega8_slot.h @@ -18,7 +18,12 @@ enum SEGA8_NEMESIS, SEGA8_JANGGUN, SEGA8_KOREAN, - SEGA8_KOREAN_NOBANK + SEGA8_KOREAN_NOBANK, + SEGA8_CASTLE, + SEGA8_BASIC_L3, + SEGA8_MUSIC_EDITOR, + SEGA8_DAHJEE_TYPEA, + SEGA8_DAHJEE_TYPEB }; @@ -39,6 +44,9 @@ public: virtual DECLARE_READ8_MEMBER(read_cart) { return 0xff; } virtual DECLARE_WRITE8_MEMBER(write_cart) {} virtual DECLARE_WRITE8_MEMBER(write_mapper) {} + // a few carts (for SG1000) acts as a RAM expansion, taking control of the system RAM in 0xc000-0xffff + virtual DECLARE_READ8_MEMBER(read_ram) { return 0xff; } + virtual DECLARE_WRITE8_MEMBER(write_ram) {} void rom_alloc(running_machine &machine, UINT32 size); void ram_alloc(running_machine &machine, UINT32 size); @@ -132,6 +140,8 @@ public: virtual DECLARE_READ8_MEMBER(read_cart); virtual DECLARE_WRITE8_MEMBER(write_cart); virtual DECLARE_WRITE8_MEMBER(write_mapper); + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); //protected: diff --git a/src/mess/machine/sms.c b/src/mess/machine/sms.c index 966854690e5..dab8ed3c52d 100644 --- a/src/mess/machine/sms.c +++ b/src/mess/machine/sms.c @@ -1108,6 +1108,15 @@ MACHINE_START_MEMBER(sms_state,sms) m_cards[i] = machine().device(str); } } + + // a bunch of SG1000 carts (compatible with SG1000 Mark III) can access directly system RAM... let's install here the necessary handlers + // TODO: are BASIC and Music actually compatible with Mark III?? + if (m_cartslot->get_type() == SEGA8_BASIC_L3 || m_cartslot->get_type() == SEGA8_MUSIC_EDITOR + || m_cartslot->get_type() == SEGA8_DAHJEE_TYPEA || m_cartslot->get_type() == SEGA8_DAHJEE_TYPEB) + { + m_maincpu->space(AS_PROGRAM).install_read_handler(0xc000, 0xffff, 0, 0, read8_delegate(FUNC(sega8_cart_slot_device::read_ram),(sega8_cart_slot_device*)m_cartslot)); + m_maincpu->space(AS_PROGRAM).install_write_handler(0xc000, 0xffff, 0, 0, write8_delegate(FUNC(sega8_cart_slot_device::write_ram),(sega8_cart_slot_device*)m_cartslot)); + } } MACHINE_RESET_MEMBER(sms_state,sms)