mirror of
https://github.com/holub/mame
synced 2025-04-19 15:11:37 +03:00
(MESS) a2600.c: converted Atari VCS carts to be slot devices, cleaned up
the implementation and removed Supercharger tapes from the main system. The -cass media switch (to load the tape file) will become available only when you mount the Supercharger cart. [Fabio Priuli]
This commit is contained in:
parent
9ffe9e8bba
commit
a1cd7776c5
10
.gitattributes
vendored
10
.gitattributes
vendored
@ -1526,6 +1526,16 @@ src/emu/bus/tvc/hbf.c svneol=native#text/plain
|
||||
src/emu/bus/tvc/hbf.h svneol=native#text/plain
|
||||
src/emu/bus/tvc/tvc.c svneol=native#text/plain
|
||||
src/emu/bus/tvc/tvc.h svneol=native#text/plain
|
||||
src/emu/bus/vcs/compumat.c svneol=native#text/plain
|
||||
src/emu/bus/vcs/compumat.h svneol=native#text/plain
|
||||
src/emu/bus/vcs/dpc.c svneol=native#text/plain
|
||||
src/emu/bus/vcs/dpc.h svneol=native#text/plain
|
||||
src/emu/bus/vcs/rom.c svneol=native#text/plain
|
||||
src/emu/bus/vcs/rom.h svneol=native#text/plain
|
||||
src/emu/bus/vcs/scharger.c svneol=native#text/plain
|
||||
src/emu/bus/vcs/scharger.h svneol=native#text/plain
|
||||
src/emu/bus/vcs/vcs_slot.c svneol=native#text/plain
|
||||
src/emu/bus/vcs/vcs_slot.h svneol=native#text/plain
|
||||
src/emu/bus/vcs_ctrl/ctrl.c svneol=native#text/plain
|
||||
src/emu/bus/vcs_ctrl/ctrl.h svneol=native#text/plain
|
||||
src/emu/bus/vcs_ctrl/joybooster.c svneol=native#text/plain
|
||||
|
492
hash/a2600.xml
492
hash/a2600.xml
File diff suppressed because it is too large
Load Diff
@ -562,18 +562,33 @@ endif
|
||||
|
||||
#-------------------------------------------------
|
||||
#
|
||||
#@src/emu/bus/vcs/ctrl.h,BUSES += VCS
|
||||
#@src/emu/bus/vcs/vcs_slot.h,BUSES += VCS
|
||||
#-------------------------------------------------
|
||||
|
||||
ifneq ($(filter VCS,$(BUSES)),)
|
||||
OBJDIRS += $(BUSOBJ)/vcs
|
||||
BUSOBJS += $(BUSOBJ)/vcs/ctrl.o
|
||||
BUSOBJS += $(BUSOBJ)/vcs/joystick.o
|
||||
BUSOBJS += $(BUSOBJ)/vcs/joybooster.o
|
||||
BUSOBJS += $(BUSOBJ)/vcs/keypad.o
|
||||
BUSOBJS += $(BUSOBJ)/vcs/lightpen.o
|
||||
BUSOBJS += $(BUSOBJ)/vcs/paddles.o
|
||||
BUSOBJS += $(BUSOBJ)/vcs/wheel.o
|
||||
BUSOBJS += $(BUSOBJ)/vcs/vcs_slot.o
|
||||
BUSOBJS += $(BUSOBJ)/vcs/rom.o
|
||||
BUSOBJS += $(BUSOBJ)/vcs/compumat.o
|
||||
BUSOBJS += $(BUSOBJ)/vcs/dpc.o
|
||||
BUSOBJS += $(BUSOBJ)/vcs/scharger.o
|
||||
endif
|
||||
|
||||
|
||||
#-------------------------------------------------
|
||||
#
|
||||
#@src/emu/bus/vcs/ctrl.h,BUSES += VCS_CTRL
|
||||
#-------------------------------------------------
|
||||
|
||||
ifneq ($(filter VCS_CTRL,$(BUSES)),)
|
||||
OBJDIRS += $(BUSOBJ)/vcs_ctrl
|
||||
BUSOBJS += $(BUSOBJ)/vcs_ctrl/ctrl.o
|
||||
BUSOBJS += $(BUSOBJ)/vcs_ctrl/joystick.o
|
||||
BUSOBJS += $(BUSOBJ)/vcs_ctrl/joybooster.o
|
||||
BUSOBJS += $(BUSOBJ)/vcs_ctrl/keypad.o
|
||||
BUSOBJS += $(BUSOBJ)/vcs_ctrl/lightpen.o
|
||||
BUSOBJS += $(BUSOBJ)/vcs_ctrl/paddles.o
|
||||
BUSOBJS += $(BUSOBJ)/vcs_ctrl/wheel.o
|
||||
endif
|
||||
|
||||
|
||||
|
51
src/emu/bus/vcs/compumat.c
Normal file
51
src/emu/bus/vcs/compumat.c
Normal file
@ -0,0 +1,51 @@
|
||||
/***************************************************************************
|
||||
|
||||
Atari 2600 cart Spectravideo Compumate (Cart + keyboard!)
|
||||
|
||||
This is tricky to implement and it is only a skeleton ATM.
|
||||
The device needs to interface with both the TIA and the RIOT.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include "emu.h"
|
||||
#include "compumat.h"
|
||||
|
||||
const device_type A26_ROM_COMPUMATE = &device_creator<a26_rom_cm_device>;
|
||||
|
||||
|
||||
a26_rom_cm_device::a26_rom_cm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: a26_rom_f6_device(mconfig, A26_ROM_COMPUMATE, "Atari 2600 ROM Cart Compumate", tag, owner, clock, "a2600_cm", __FILE__)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// mapper specific start/reset
|
||||
//-------------------------------------------------
|
||||
|
||||
void a26_rom_cm_device::device_start()
|
||||
{
|
||||
save_item(NAME(m_base_bank));
|
||||
}
|
||||
|
||||
void a26_rom_cm_device::device_reset()
|
||||
{
|
||||
m_base_bank = 3;
|
||||
}
|
||||
|
||||
|
||||
static INPUT_PORTS_START( keyboard )
|
||||
INPUT_PORTS_END
|
||||
|
||||
|
||||
ioport_constructor a26_rom_cm_device::device_input_ports() const
|
||||
{
|
||||
return INPUT_PORTS_NAME( keyboard );
|
||||
}
|
||||
|
||||
|
||||
|
||||
READ8_MEMBER(a26_rom_cm_device::read_rom)
|
||||
{
|
||||
return m_rom[offset + (m_base_bank * 0x1000)];
|
||||
}
|
33
src/emu/bus/vcs/compumat.h
Normal file
33
src/emu/bus/vcs/compumat.h
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef __VCS_COMPUMAT_H
|
||||
#define __VCS_COMPUMAT_H
|
||||
|
||||
#include "rom.h"
|
||||
|
||||
//**************************************************************************
|
||||
// TYPE DEFINITIONS
|
||||
//**************************************************************************
|
||||
|
||||
// ======================> a26_rom_cm_device
|
||||
|
||||
class a26_rom_cm_device : public a26_rom_f6_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
a26_rom_cm_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();
|
||||
|
||||
// reading and writing
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
// device type definition
|
||||
extern const device_type A26_ROM_COMPUMATE;
|
||||
|
||||
#endif
|
282
src/emu/bus/vcs/dpc.c
Normal file
282
src/emu/bus/vcs/dpc.c
Normal file
@ -0,0 +1,282 @@
|
||||
/***************************************************************************
|
||||
|
||||
|
||||
Atari 2600 cart with DPC chip (Pitfall II)
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include "emu.h"
|
||||
#include "dpc.h"
|
||||
|
||||
|
||||
// DPC device
|
||||
|
||||
const device_type ATARI_DPC = &device_creator<dpc_device>;
|
||||
|
||||
|
||||
dpc_device::dpc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: device_t(mconfig, ATARI_DPC, "Atari DCP", tag, owner, clock, "atari_dcp", __FILE__),
|
||||
m_displaydata(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void dpc_device::device_start()
|
||||
{
|
||||
m_oscillator = timer_alloc(TIMER_OSC);
|
||||
m_oscillator->reset();
|
||||
}
|
||||
|
||||
void dpc_device::device_reset()
|
||||
{
|
||||
for (int data_fetcher = 0; data_fetcher < 8; data_fetcher++)
|
||||
{
|
||||
m_df[data_fetcher].osc_clk = 0;
|
||||
m_df[data_fetcher].flag = 0;
|
||||
m_df[data_fetcher].music_mode = 0;
|
||||
}
|
||||
m_oscillator->adjust(attotime::from_hz(18400), 0, attotime::from_hz(18400));
|
||||
|
||||
}
|
||||
|
||||
void dpc_device::check_flag(UINT8 data_fetcher)
|
||||
{
|
||||
/* Set flag when low counter equals top */
|
||||
if (m_df[data_fetcher].low == m_df[data_fetcher].top)
|
||||
m_df[data_fetcher].flag = 1;
|
||||
|
||||
/* Reset flag when low counter equals bottom */
|
||||
if (m_df[data_fetcher].low == m_df[data_fetcher].bottom)
|
||||
m_df[data_fetcher].flag = 0;
|
||||
}
|
||||
|
||||
void dpc_device::decrement_counter(UINT8 data_fetcher)
|
||||
{
|
||||
m_df[data_fetcher].low -= 1;
|
||||
if (m_df[data_fetcher].low == 0xff)
|
||||
{
|
||||
m_df[data_fetcher].high -= 1;
|
||||
if (data_fetcher > 4 && m_df[data_fetcher].music_mode)
|
||||
m_df[data_fetcher].low = m_df[data_fetcher].top;
|
||||
}
|
||||
|
||||
check_flag(data_fetcher);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_timer - handler timer events
|
||||
//-------------------------------------------------
|
||||
|
||||
void dpc_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
|
||||
{
|
||||
if (id == TIMER_OSC)
|
||||
{
|
||||
// callback
|
||||
for (int data_fetcher = 5; data_fetcher < 8; data_fetcher++)
|
||||
{
|
||||
if (m_df[data_fetcher].osc_clk)
|
||||
{
|
||||
decrement_counter(data_fetcher);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// Read / Write accesses
|
||||
//-------------------------------------------------
|
||||
|
||||
READ8_MEMBER(dpc_device::read)
|
||||
{
|
||||
static const UINT8 dpc_amplitude[8] = { 0x00, 0x04, 0x05, 0x09, 0x06, 0x0a, 0x0b, 0x0f };
|
||||
UINT8 data_fetcher = offset & 0x07;
|
||||
UINT8 data = 0xff;
|
||||
|
||||
//logerror("%04X: Read from DPC offset $%02X\n", machine().device<cpu_device>("maincpu")->pc(), offset);
|
||||
if (offset < 0x08)
|
||||
{
|
||||
switch(offset & 0x06)
|
||||
{
|
||||
case 0x00: // Random number generator
|
||||
case 0x02:
|
||||
return m_shift_reg;
|
||||
case 0x04: // Sound value, MOVAMT value AND'd with Draw Line Carry; with Draw Line Add
|
||||
m_latch_62 = m_latch_64;
|
||||
case 0x06: // Sound value, MOVAMT value AND'd with Draw Line Carry; without Draw Line Add
|
||||
m_latch_64 = m_latch_62 + m_df[4].top;
|
||||
m_dlc = (m_latch_62 + m_df[4].top > 0xff) ? 1 : 0;
|
||||
data = 0;
|
||||
if (m_df[5].music_mode && m_df[5].flag)
|
||||
data |= 0x01;
|
||||
|
||||
if (m_df[6].music_mode && m_df[6].flag)
|
||||
data |= 0x02;
|
||||
|
||||
if (m_df[7].music_mode && m_df[7].flag)
|
||||
data |= 0x04;
|
||||
|
||||
return (m_dlc ? m_movamt & 0xf0 : 0) | dpc_amplitude[data];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UINT8 display_data = m_displaydata[(~((m_df[data_fetcher].low | (m_df[data_fetcher].high << 8))) & 0x7ff)];
|
||||
|
||||
switch (offset & 0x38)
|
||||
{
|
||||
case 0x08: // display data
|
||||
data = display_data;
|
||||
break;
|
||||
case 0x10: // display data AND'd w/flag
|
||||
data = m_df[data_fetcher].flag ? display_data : 0x00;
|
||||
break;
|
||||
case 0x18: // display data AND'd w/flag, nibbles swapped
|
||||
data = m_df[data_fetcher].flag ? BITSWAP8(display_data,3,2,1,0,7,6,5,4) : 0x00;
|
||||
break;
|
||||
case 0x20: // display data AND'd w/flag, byte reversed
|
||||
data = m_df[data_fetcher].flag ? BITSWAP8(display_data,0,1,2,3,4,5,6,7) : 0x00;
|
||||
break;
|
||||
case 0x28: // display data AND'd w/flag, rotated right
|
||||
data = m_df[data_fetcher].flag ? (display_data >> 1) : 0x00;
|
||||
break;
|
||||
case 0x30: // display data AND'd w/flag, rotated left
|
||||
data = m_df[data_fetcher].flag ? (display_data << 1) : 0x00;
|
||||
break;
|
||||
case 0x38: // flag
|
||||
data = m_df[data_fetcher].flag ? 0xff : 0x00;
|
||||
break;
|
||||
}
|
||||
|
||||
if (data_fetcher < 5 || !m_df[data_fetcher].osc_clk)
|
||||
{
|
||||
decrement_counter(data_fetcher);
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(dpc_device::write)
|
||||
{
|
||||
UINT8 data_fetcher = offset & 0x07;
|
||||
|
||||
switch (offset & 0x38)
|
||||
{
|
||||
case 0x00: // Top count
|
||||
m_df[data_fetcher].top = data;
|
||||
m_df[data_fetcher].flag = 0;
|
||||
check_flag(data_fetcher);
|
||||
break;
|
||||
case 0x08: // Bottom count
|
||||
m_df[data_fetcher].bottom = data;
|
||||
check_flag(data_fetcher);
|
||||
break;
|
||||
case 0x10: // Counter low
|
||||
m_df[data_fetcher].low = data;
|
||||
if (data_fetcher == 4)
|
||||
m_latch_64 = data;
|
||||
|
||||
if (data_fetcher > 4 && m_df[data_fetcher].music_mode)
|
||||
m_df[data_fetcher].low = m_df[data_fetcher].top;
|
||||
|
||||
check_flag(data_fetcher);
|
||||
break;
|
||||
case 0x18: // Counter high
|
||||
m_df[data_fetcher].high = data;
|
||||
m_df[data_fetcher].music_mode = data & 0x10;
|
||||
m_df[data_fetcher].osc_clk = data & 0x20;
|
||||
if (data_fetcher > 4 && m_df[data_fetcher].music_mode && m_df[data_fetcher].low == 0xff)
|
||||
{
|
||||
m_df[data_fetcher].low = m_df[data_fetcher].top;
|
||||
check_flag(data_fetcher);
|
||||
}
|
||||
break;
|
||||
case 0x20: // Draw line movement value / MOVAMT
|
||||
m_movamt = data;
|
||||
break;
|
||||
case 0x28: // Not used
|
||||
logerror("%04X: Write to unused DPC register $%02X, data $%02X\n", machine().device<cpu_device>("maincpu")->pc(), offset, data);
|
||||
break;
|
||||
case 0x30: // Random number generator reset
|
||||
m_shift_reg = 0;
|
||||
break;
|
||||
case 0x38: // Not used
|
||||
logerror("%04X: Write to unused DPC register $%02X, data $%02X\n", machine().device<cpu_device>("maincpu")->pc(), offset, data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// cart device
|
||||
|
||||
const device_type A26_ROM_DPC = &device_creator<a26_rom_dpc_device>;
|
||||
|
||||
|
||||
a26_rom_dpc_device::a26_rom_dpc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: a26_rom_f8_device(mconfig, A26_ROM_DPC, "Atari 2600 ROM Cart Pitfall II", tag, owner, clock, "a2600_dcp", __FILE__),
|
||||
m_dpc(*this, "dpc")
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// mapper specific start/reset
|
||||
//-------------------------------------------------
|
||||
|
||||
void a26_rom_dpc_device::device_start()
|
||||
{
|
||||
save_item(NAME(m_base_bank));
|
||||
}
|
||||
|
||||
void a26_rom_dpc_device::device_reset()
|
||||
{
|
||||
m_base_bank = 0;
|
||||
}
|
||||
|
||||
void a26_rom_dpc_device::setup_addon_ptr(UINT8 *ptr)
|
||||
{
|
||||
m_dpc->set_display_data(ptr);
|
||||
}
|
||||
|
||||
|
||||
static MACHINE_CONFIG_FRAGMENT( a26_dpc )
|
||||
MCFG_DEVICE_ADD("dpc", ATARI_DPC, 0)
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
machine_config_constructor a26_rom_dpc_device::device_mconfig_additions() const
|
||||
{
|
||||
return MACHINE_CONFIG_NAME( a26_dpc );
|
||||
}
|
||||
|
||||
|
||||
READ8_MEMBER(a26_rom_dpc_device::read_rom)
|
||||
{
|
||||
if (offset < 0x40)
|
||||
return m_dpc->read(space, offset);
|
||||
else
|
||||
return a26_rom_f8_device::read_rom(space, offset);
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(a26_rom_dpc_device::write_bank)
|
||||
{
|
||||
if (offset >= 0x40 && offset < 0x80)
|
||||
m_dpc->write(space, offset, data);
|
||||
else
|
||||
a26_rom_f8_device::write_bank(space, offset, data);
|
||||
}
|
||||
|
||||
DIRECT_UPDATE_MEMBER(a26_rom_dpc_device::cart_opbase)
|
||||
{
|
||||
if (!direct.space().debugger_access())
|
||||
{
|
||||
UINT8 new_bit;
|
||||
new_bit = (m_dpc->m_shift_reg & 0x80) ^ ((m_dpc->m_shift_reg & 0x20) << 2);
|
||||
new_bit = new_bit ^ (((m_dpc->m_shift_reg & 0x10) << 3) ^ ((m_dpc->m_shift_reg & 0x08) << 4));
|
||||
new_bit = new_bit ^ 0x80;
|
||||
m_dpc->m_shift_reg = new_bit | (m_dpc->m_shift_reg >> 1);
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
93
src/emu/bus/vcs/dpc.h
Normal file
93
src/emu/bus/vcs/dpc.h
Normal file
@ -0,0 +1,93 @@
|
||||
#ifndef __VCS_DCP_H
|
||||
#define __VCS_DCP_H
|
||||
|
||||
#include "rom.h"
|
||||
|
||||
//**************************************************************************
|
||||
// TYPE DEFINITIONS
|
||||
//**************************************************************************
|
||||
|
||||
// TO DO: DPC should be made a separate device!
|
||||
|
||||
struct df_t {
|
||||
UINT8 top;
|
||||
UINT8 bottom;
|
||||
UINT8 low;
|
||||
UINT8 high;
|
||||
UINT8 flag;
|
||||
UINT8 music_mode; /* Only used by data fetchers 5,6, and 7 */
|
||||
UINT8 osc_clk; /* Only used by data fetchers 5,6, and 7 */
|
||||
};
|
||||
|
||||
// m_dpc.oscillator = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(a2600_state::modeDPC_timer_callback),this));
|
||||
|
||||
class dpc_device : public device_t
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
dpc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
df_t m_df[8];
|
||||
UINT8 m_movamt;
|
||||
UINT8 m_latch_62;
|
||||
UINT8 m_latch_64;
|
||||
UINT8 m_dlc;
|
||||
UINT8 m_shift_reg;
|
||||
UINT8 *m_displaydata;
|
||||
void set_display_data(UINT8 *data) { m_displaydata = data; }
|
||||
|
||||
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_reset();
|
||||
|
||||
virtual DECLARE_READ8_MEMBER(read);
|
||||
virtual DECLARE_WRITE8_MEMBER(write);
|
||||
|
||||
private:
|
||||
|
||||
void decrement_counter(UINT8 data_fetcher);
|
||||
void check_flag(UINT8 data_fetcher);
|
||||
|
||||
static const device_timer_id TIMER_OSC = 0;
|
||||
emu_timer *m_oscillator;
|
||||
};
|
||||
|
||||
|
||||
// device type definition
|
||||
extern const device_type ATARI_DPC;
|
||||
|
||||
|
||||
|
||||
// ======================> a26_rom_dpc_device
|
||||
|
||||
class a26_rom_dpc_device : public a26_rom_f8_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
a26_rom_dpc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual machine_config_constructor device_mconfig_additions() const;
|
||||
virtual void device_reset();
|
||||
|
||||
required_device<dpc_device> m_dpc;
|
||||
|
||||
// reading and writing
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_bank);
|
||||
virtual DECLARE_DIRECT_UPDATE_MEMBER(cart_opbase);
|
||||
|
||||
virtual void setup_addon_ptr(UINT8 *ptr);
|
||||
|
||||
protected:
|
||||
// int m_reset_bank;
|
||||
};
|
||||
|
||||
|
||||
// device type definition
|
||||
extern const device_type A26_ROM_DPC;
|
||||
|
||||
#endif
|
1054
src/emu/bus/vcs/rom.c
Executable file
1054
src/emu/bus/vcs/rom.c
Executable file
File diff suppressed because it is too large
Load Diff
389
src/emu/bus/vcs/rom.h
Executable file
389
src/emu/bus/vcs/rom.h
Executable file
@ -0,0 +1,389 @@
|
||||
#ifndef __VCS_ROM_H
|
||||
#define __VCS_ROM_H
|
||||
|
||||
#include "vcs_slot.h"
|
||||
|
||||
|
||||
// ======================> a26_rom_2k_device
|
||||
|
||||
class a26_rom_2k_device : public device_t,
|
||||
public device_vcs_cart_interface
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
a26_rom_2k_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);
|
||||
a26_rom_2k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_reset();
|
||||
|
||||
// reading and writing
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
};
|
||||
|
||||
|
||||
// ======================> a26_rom_4k_device
|
||||
|
||||
class a26_rom_4k_device : public a26_rom_2k_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
a26_rom_4k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// reading and writing
|
||||
|
||||
// accesses just use the 2K ones, since it is just direct access to ROM/RAM
|
||||
// masked with its size!
|
||||
};
|
||||
|
||||
|
||||
// ======================> a26_rom_f6_device
|
||||
|
||||
class a26_rom_f6_device : public a26_rom_2k_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
a26_rom_f6_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);
|
||||
a26_rom_f6_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_reset();
|
||||
|
||||
// reading and writing
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_bank);
|
||||
virtual DECLARE_DIRECT_UPDATE_MEMBER(cart_opbase);
|
||||
|
||||
protected:
|
||||
int m_base_bank;
|
||||
};
|
||||
|
||||
|
||||
// ======================> a26_rom_f4_device
|
||||
|
||||
class a26_rom_f4_device : public a26_rom_f6_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
a26_rom_f4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_reset();
|
||||
|
||||
// reading and writing
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_bank);
|
||||
};
|
||||
|
||||
|
||||
// ======================> a26_rom_f8_device
|
||||
|
||||
class a26_rom_f8_device : public a26_rom_f6_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
a26_rom_f8_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);
|
||||
a26_rom_f8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// reading and writing
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_bank);
|
||||
};
|
||||
|
||||
|
||||
// ======================> a26_rom_f8_sw_device
|
||||
|
||||
class a26_rom_f8_sw_device : public a26_rom_f8_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
a26_rom_f8_sw_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_reset();
|
||||
};
|
||||
|
||||
|
||||
// ======================> a26_rom_fa_device
|
||||
|
||||
class a26_rom_fa_device : public a26_rom_f6_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
a26_rom_fa_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// reading and writing
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_bank);
|
||||
};
|
||||
|
||||
|
||||
// ======================> a26_rom_fe_device
|
||||
|
||||
class a26_rom_fe_device : public a26_rom_2k_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
a26_rom_fe_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_reset();
|
||||
|
||||
// reading and writing
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
virtual DECLARE_READ8_MEMBER(read_bank);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_ram);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_bank);
|
||||
|
||||
protected:
|
||||
int m_base_bank;
|
||||
int m_trigger_on_next_access;
|
||||
};
|
||||
|
||||
|
||||
// ======================> a26_rom_3e_device
|
||||
|
||||
class a26_rom_3e_device : public a26_rom_f6_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
a26_rom_3e_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_reset();
|
||||
|
||||
// reading and writing
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_bank);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_ram);
|
||||
|
||||
protected:
|
||||
int m_num_bank;
|
||||
int m_ram_bank;
|
||||
int m_ram_enable;
|
||||
};
|
||||
|
||||
|
||||
// ======================> a26_rom_3f_device
|
||||
|
||||
class a26_rom_3f_device : public a26_rom_f6_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
a26_rom_3f_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_reset();
|
||||
|
||||
// reading and writing
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_bank);
|
||||
|
||||
protected:
|
||||
int m_num_bank;
|
||||
};
|
||||
|
||||
|
||||
// ======================> a26_rom_e0_device
|
||||
|
||||
class a26_rom_e0_device : public a26_rom_f6_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
a26_rom_e0_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_reset();
|
||||
|
||||
// reading and writing
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_bank);
|
||||
|
||||
protected:
|
||||
int m_base_banks[4];
|
||||
};
|
||||
|
||||
|
||||
// ======================> a26_rom_e7_device
|
||||
|
||||
class a26_rom_e7_device : public a26_rom_f6_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
a26_rom_e7_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_reset();
|
||||
|
||||
// reading and writing
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_bank);
|
||||
|
||||
protected:
|
||||
int m_ram_bank;
|
||||
};
|
||||
|
||||
|
||||
// ======================> a26_rom_ua_device
|
||||
|
||||
class a26_rom_ua_device : public a26_rom_f6_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
a26_rom_ua_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_reset();
|
||||
|
||||
// reading and writing
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
virtual DECLARE_READ8_MEMBER(read_bank);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_bank);
|
||||
};
|
||||
|
||||
|
||||
// ======================> a26_rom_cv_device
|
||||
|
||||
class a26_rom_cv_device : public a26_rom_2k_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
a26_rom_cv_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// reading and writing
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_bank);
|
||||
};
|
||||
|
||||
|
||||
// ======================> a26_rom_dc_device
|
||||
|
||||
class a26_rom_dc_device : public a26_rom_f6_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
a26_rom_dc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// reading and writing
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_bank);
|
||||
};
|
||||
|
||||
|
||||
// ======================> a26_rom_fv_device
|
||||
|
||||
class a26_rom_fv_device : public a26_rom_f6_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
a26_rom_fv_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_reset();
|
||||
|
||||
// reading and writing
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_bank);
|
||||
|
||||
protected:
|
||||
int m_locked;
|
||||
};
|
||||
|
||||
|
||||
// ======================> a26_rom_jvp_device
|
||||
|
||||
class a26_rom_jvp_device : public a26_rom_f6_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
a26_rom_jvp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// reading and writing
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_bank);
|
||||
};
|
||||
|
||||
|
||||
// ======================> a26_rom_4in1_device
|
||||
|
||||
class a26_rom_4in1_device : public a26_rom_f6_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
a26_rom_4in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_reset();
|
||||
|
||||
// reading and writing
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
};
|
||||
|
||||
|
||||
// ======================> a26_rom_8in1_device
|
||||
|
||||
class a26_rom_8in1_device : public a26_rom_f8_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
a26_rom_8in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_reset();
|
||||
|
||||
// reading and writing
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
|
||||
protected:
|
||||
int m_reset_bank;
|
||||
};
|
||||
|
||||
|
||||
// ======================> a26_rom_32in1_device
|
||||
|
||||
class a26_rom_32in1_device : public a26_rom_f6_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
a26_rom_32in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_reset();
|
||||
|
||||
// reading and writing
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
};
|
||||
|
||||
|
||||
// device type definition
|
||||
extern const device_type A26_ROM_2K;
|
||||
extern const device_type A26_ROM_4K;
|
||||
extern const device_type A26_ROM_F4;
|
||||
extern const device_type A26_ROM_F6;
|
||||
extern const device_type A26_ROM_F8;
|
||||
extern const device_type A26_ROM_F8_SW;
|
||||
extern const device_type A26_ROM_FA;
|
||||
extern const device_type A26_ROM_FE;
|
||||
extern const device_type A26_ROM_3E;
|
||||
extern const device_type A26_ROM_3F;
|
||||
extern const device_type A26_ROM_E0;
|
||||
extern const device_type A26_ROM_E7;
|
||||
extern const device_type A26_ROM_UA;
|
||||
extern const device_type A26_ROM_CV;
|
||||
extern const device_type A26_ROM_DC;
|
||||
extern const device_type A26_ROM_FV;
|
||||
extern const device_type A26_ROM_JVP;
|
||||
extern const device_type A26_ROM_4IN1;
|
||||
extern const device_type A26_ROM_8IN1;
|
||||
extern const device_type A26_ROM_32IN1;
|
||||
|
||||
|
||||
#endif
|
212
src/emu/bus/vcs/scharger.c
Normal file
212
src/emu/bus/vcs/scharger.c
Normal file
@ -0,0 +1,212 @@
|
||||
/***************************************************************************
|
||||
|
||||
Atari 2600 cart Starpath Supercharger (Cart + Tape drive!)
|
||||
|
||||
|
||||
|
||||
From kevtris notes ( http://blog.kevtris.org/blogfiles/Atari%202600%20Mappers.txt ):
|
||||
|
||||
|
||||
- Control register [0x1ff8]
|
||||
|
||||
7 0
|
||||
---------
|
||||
1FF8: DDDB BBWE
|
||||
|
||||
D: write delay (see below)
|
||||
B: bankswitching mode (see below)
|
||||
W: RAM write enable (1 = enabled, 0 = disabled)
|
||||
E: ROM power enable (0 = enabled, 1 = turn off ROM)
|
||||
|
||||
- Audio input register [0x1ff9]
|
||||
|
||||
7 0
|
||||
---------
|
||||
1FF9: 0000 000A
|
||||
|
||||
A: Supercharger audio data. 0 = low input, 1 = high input.
|
||||
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include "emu.h"
|
||||
#include "scharger.h"
|
||||
#include "sound/wave.h"
|
||||
#include "formats/a26_cas.h"
|
||||
|
||||
const device_type A26_ROM_SUPERCHARGER = &device_creator<a26_rom_ss_device>;
|
||||
|
||||
|
||||
a26_rom_ss_device::a26_rom_ss_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: a26_rom_f6_device(mconfig, A26_ROM_SUPERCHARGER, "Atari 2600 ROM Cart Supercharger", tag, owner, clock, "a2600_ss", __FILE__),
|
||||
m_cassette(*this, "cassette")
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// mapper specific start/reset
|
||||
//-------------------------------------------------
|
||||
|
||||
void a26_rom_ss_device::device_start()
|
||||
{
|
||||
m_maincpu = machine().device<cpu_device>("maincpu");
|
||||
|
||||
save_item(NAME(m_base_banks));
|
||||
save_item(NAME(m_reg));
|
||||
save_item(NAME(m_write_delay));
|
||||
save_item(NAME(m_ram_write_enabled));
|
||||
save_item(NAME(m_rom_enabled));
|
||||
save_item(NAME(m_byte_started));
|
||||
save_item(NAME(m_last_address));
|
||||
save_item(NAME(m_diff_adjust));
|
||||
}
|
||||
|
||||
void a26_rom_ss_device::device_reset()
|
||||
{
|
||||
// banks = 0, 1, 2 are 2K chunk of RAM (of the available 6K), banks = 3 is ROM!
|
||||
m_base_banks[0] = 2;
|
||||
m_base_banks[1] = 3;
|
||||
m_ram_write_enabled = 0;
|
||||
m_byte_started = 0;
|
||||
m_reg = 0;
|
||||
m_write_delay = 0;
|
||||
m_rom_enabled = 1;
|
||||
m_last_address = 0;
|
||||
m_diff_adjust = 0;
|
||||
}
|
||||
|
||||
|
||||
static MACHINE_CONFIG_FRAGMENT( a26_ss )
|
||||
MCFG_CASSETTE_ADD("cassette")
|
||||
MCFG_CASSETTE_FORMATS(a26_cassette_formats)
|
||||
MCFG_CASSETTE_DEFAULT_STATE(CASSETTE_STOPPED | CASSETTE_MOTOR_ENABLED | CASSETTE_SPEAKER_ENABLED)
|
||||
MCFG_CASSETTE_INTERFACE("a2600_cass")
|
||||
|
||||
// MCFG_SOUND_WAVE_ADD(WAVE_TAG, "cassette")
|
||||
// MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
machine_config_constructor a26_rom_ss_device::device_mconfig_additions() const
|
||||
{
|
||||
return MACHINE_CONFIG_NAME( a26_ss );
|
||||
}
|
||||
|
||||
inline UINT8 a26_rom_ss_device::read_byte(UINT32 offset)
|
||||
{
|
||||
if (offset < 0x800)
|
||||
return m_ram[(offset & 0x7ff) + (m_base_banks[0] * 0x800)];
|
||||
else if (m_base_banks[1] != 3)
|
||||
return m_ram[(offset & 0x7ff) + (m_base_banks[1] * 0x800)];
|
||||
else if (m_rom_enabled)
|
||||
return m_rom[offset & 0x7ff];
|
||||
else
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
READ8_MEMBER(a26_rom_ss_device::read_rom)
|
||||
{
|
||||
if (space.debugger_access())
|
||||
return read_byte(offset);
|
||||
|
||||
// Bankswitch
|
||||
if (offset == 0xff8)
|
||||
{
|
||||
//logerror("%04X: Access to control register data = %02X\n", m_maincpu->pc(), m_modeSS_byte);
|
||||
m_write_delay = m_reg >> 5;
|
||||
m_ram_write_enabled = BIT(m_reg, 1);
|
||||
m_rom_enabled = !BIT(m_reg, 0);
|
||||
|
||||
// compensate time spent in this access to avoid spurious RAM write
|
||||
m_byte_started -= 5;
|
||||
|
||||
// handle bankswitch
|
||||
switch (m_reg & 0x1c)
|
||||
{
|
||||
case 0x00:
|
||||
m_base_banks[0] = 2;
|
||||
m_base_banks[1] = 3;
|
||||
break;
|
||||
case 0x04:
|
||||
m_base_banks[0] = 0;
|
||||
m_base_banks[1] = 3;
|
||||
break;
|
||||
case 0x08:
|
||||
m_base_banks[0] = 2;
|
||||
m_base_banks[1] = 0;
|
||||
break;
|
||||
case 0x0c:
|
||||
m_base_banks[0] = 0;
|
||||
m_base_banks[1] = 2;
|
||||
break;
|
||||
case 0x10:
|
||||
m_base_banks[0] = 2;
|
||||
m_base_banks[1] = 3;
|
||||
break;
|
||||
case 0x14:
|
||||
m_base_banks[0] = 1;
|
||||
m_base_banks[1] = 3;
|
||||
break;
|
||||
case 0x18:
|
||||
m_base_banks[0] = 2;
|
||||
m_base_banks[1] = 1;
|
||||
break;
|
||||
case 0x1c:
|
||||
m_base_banks[0] = 1;
|
||||
m_base_banks[1] = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
return read_byte(offset);
|
||||
}
|
||||
// Cassette port read
|
||||
else if (offset == 0xff9)
|
||||
{
|
||||
//logerror("%04X: Cassette port read, tap_val = %f\n", m_maincpu->pc(), tap_val);
|
||||
double tap_val = m_cassette->input();
|
||||
|
||||
// compensate time spent in this access to avoid spurious RAM write
|
||||
m_byte_started -= 5;
|
||||
|
||||
if (tap_val < 0)
|
||||
return 0x00;
|
||||
else
|
||||
return 0x01;
|
||||
}
|
||||
// Possible RAM write
|
||||
else
|
||||
{
|
||||
if (m_ram_write_enabled)
|
||||
{
|
||||
/* Check for dummy read from same address */
|
||||
if (m_last_address == offset)
|
||||
m_diff_adjust++;
|
||||
|
||||
int diff = m_maincpu->total_cycles() - m_byte_started;
|
||||
//logerror("%04X: offset = %04X, %d\n", m_maincpu->pc(), offset, diff);
|
||||
|
||||
if (diff - m_diff_adjust == 5)
|
||||
{
|
||||
//logerror("%04X: RAM write offset = %04X, data = %02X\n", m_maincpu->pc(), offset, m_modeSS_byte );
|
||||
if (offset < 0x800)
|
||||
m_ram[(offset & 0x7ff) + (m_base_banks[0] * 0x800)] = m_reg;
|
||||
else if (m_base_banks[1] != 3)
|
||||
m_ram[(offset & 0x7ff) + (m_base_banks[1] * 0x800)] = m_reg;
|
||||
}
|
||||
else if (offset < 0x0100)
|
||||
{
|
||||
m_reg = offset;
|
||||
m_byte_started = m_maincpu->total_cycles();
|
||||
m_diff_adjust = 0;
|
||||
}
|
||||
}
|
||||
else if (offset < 0x0100)
|
||||
{
|
||||
m_reg = offset;
|
||||
m_byte_started = m_maincpu->total_cycles();
|
||||
m_diff_adjust = 0;
|
||||
}
|
||||
m_last_address = offset;
|
||||
return read_byte(offset);
|
||||
}
|
||||
}
|
45
src/emu/bus/vcs/scharger.h
Normal file
45
src/emu/bus/vcs/scharger.h
Normal file
@ -0,0 +1,45 @@
|
||||
#ifndef __VCS_SCHARGER_H
|
||||
#define __VCS_SCHARGER_H
|
||||
|
||||
#include "rom.h"
|
||||
#include "imagedev/cassette.h"
|
||||
|
||||
//**************************************************************************
|
||||
// TYPE DEFINITIONS
|
||||
//**************************************************************************
|
||||
|
||||
// ======================> a26_rom_ss_device
|
||||
|
||||
class a26_rom_ss_device : public a26_rom_f6_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
a26_rom_ss_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual machine_config_constructor device_mconfig_additions() const;
|
||||
virtual void device_reset();
|
||||
|
||||
required_device<cassette_image_device> m_cassette;
|
||||
|
||||
// reading and writing
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
|
||||
private:
|
||||
cpu_device *m_maincpu;
|
||||
inline UINT8 read_byte(UINT32 offset);
|
||||
|
||||
int m_base_banks[2];
|
||||
UINT8 m_reg;
|
||||
UINT8 m_write_delay, m_ram_write_enabled, m_rom_enabled;
|
||||
UINT32 m_byte_started;
|
||||
UINT16 m_last_address;
|
||||
UINT32 m_diff_adjust;
|
||||
};
|
||||
|
||||
|
||||
// device type definition
|
||||
extern const device_type A26_ROM_SUPERCHARGER;
|
||||
|
||||
#endif
|
838
src/emu/bus/vcs/vcs_slot.c
Executable file
838
src/emu/bus/vcs/vcs_slot.c
Executable file
@ -0,0 +1,838 @@
|
||||
/***********************************************************************************************************
|
||||
|
||||
|
||||
Atari VCS 2600 cart emulation
|
||||
(through slot devices)
|
||||
|
||||
Emulation of the cartslot for Atari 2600
|
||||
Several banking schemes have been used for larger roms,
|
||||
and some carts contained RAM (so called "Special Chip")
|
||||
|
||||
Mapper identification routines based on Cowering's code.
|
||||
|
||||
***********************************************************************************************************/
|
||||
|
||||
|
||||
#include "emu.h"
|
||||
#include "vcs_slot.h"
|
||||
|
||||
//**************************************************************************
|
||||
// GLOBAL VARIABLES
|
||||
//**************************************************************************
|
||||
|
||||
const device_type VCS_CART_SLOT = &device_creator<vcs_cart_slot_device>;
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_vcs_cart_interface - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
device_vcs_cart_interface::device_vcs_cart_interface(const machine_config &mconfig, device_t &device)
|
||||
: device_slot_card_interface(mconfig, device)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// ~device_vcs_cart_interface - destructor
|
||||
//-------------------------------------------------
|
||||
|
||||
device_vcs_cart_interface::~device_vcs_cart_interface()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// rom_alloc - alloc the space for the cart
|
||||
//-------------------------------------------------
|
||||
|
||||
void device_vcs_cart_interface::rom_alloc(UINT32 size)
|
||||
{
|
||||
if (m_rom == NULL)
|
||||
m_rom.resize(size);
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// ram_alloc - alloc the space for the on-cart RAM
|
||||
//-------------------------------------------------
|
||||
|
||||
void device_vcs_cart_interface::ram_alloc(UINT32 size)
|
||||
{
|
||||
if (m_ram == NULL)
|
||||
m_ram.resize(size);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// LIVE DEVICE
|
||||
//**************************************************************************
|
||||
|
||||
//-------------------------------------------------
|
||||
// vcs_cart_slot_device - constructor
|
||||
//-------------------------------------------------
|
||||
vcs_cart_slot_device::vcs_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
|
||||
device_t(mconfig, VCS_CART_SLOT, "Atari VCS 2600 Cartridge Slot", tag, owner, clock, "vcs_cart_slot", __FILE__),
|
||||
device_image_interface(mconfig, *this),
|
||||
device_slot_interface(mconfig, *this)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// vcs_cart_slot_device - destructor
|
||||
//-------------------------------------------------
|
||||
|
||||
vcs_cart_slot_device::~vcs_cart_slot_device()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_start - device-specific startup
|
||||
//-------------------------------------------------
|
||||
|
||||
void vcs_cart_slot_device::device_start()
|
||||
{
|
||||
m_cart = dynamic_cast<device_vcs_cart_interface *>(get_card_device());
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_config_complete - perform any
|
||||
// operations now that the configuration is
|
||||
// complete
|
||||
//-------------------------------------------------
|
||||
|
||||
void vcs_cart_slot_device::device_config_complete()
|
||||
{
|
||||
// set brief and instance name
|
||||
update_names();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
call load
|
||||
-------------------------------------------------*/
|
||||
|
||||
//-------------------------------------------------
|
||||
// VCS PCBs
|
||||
//-------------------------------------------------
|
||||
|
||||
struct vcs_slot
|
||||
{
|
||||
int pcb_id;
|
||||
const char *slot_option;
|
||||
};
|
||||
|
||||
// Here, we take the feature attribute from .xml (i.e. the PCB name) and we assign a unique ID to it
|
||||
static const vcs_slot slot_list[] =
|
||||
{
|
||||
{ A26_2K, "a26_2k" },
|
||||
{ A26_4K, "a26_4k" },
|
||||
{ A26_F4, "a26_f4" },
|
||||
{ A26_F6, "a26_f6" },
|
||||
{ A26_F8, "a26_f8" },
|
||||
{ A26_F8SW, "a26_f8sw" },
|
||||
{ A26_FA, "a26_fa" },
|
||||
{ A26_FE, "a26_fe" },
|
||||
{ A26_E0, "a26_e0" },
|
||||
{ A26_E7, "a26_e7" },
|
||||
{ A26_3E, "a26_3e" },
|
||||
{ A26_3F, "a26_3f" },
|
||||
{ A26_UA, "a26_ua" },
|
||||
{ A26_CV, "a26_cv" },
|
||||
{ A26_DC, "a26_dc" },
|
||||
{ A26_FV, "a26_fv" },
|
||||
{ A26_JVP, "a26_jvp" },
|
||||
{ A26_CM, "a26_cm" },
|
||||
{ A26_SS, "a26_ss" },
|
||||
{ A26_DPC, "a26_dpc" },
|
||||
{ A26_4IN1, "a26_4in1" },
|
||||
{ A26_8IN1, "a26_8in1" },
|
||||
{ A26_32IN1, "a26_32in1" },
|
||||
};
|
||||
|
||||
static int vcs_get_pcb_id(const char *slot)
|
||||
{
|
||||
for (int i = 0; i < ARRAY_LENGTH(slot_list); i++)
|
||||
{
|
||||
if (!core_stricmp(slot_list[i].slot_option, slot))
|
||||
return slot_list[i].pcb_id;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *vcs_get_slot(int type)
|
||||
{
|
||||
for (int i = 0; i < ARRAY_LENGTH(slot_list); i++)
|
||||
{
|
||||
if (slot_list[i].pcb_id == type)
|
||||
return slot_list[i].slot_option;
|
||||
}
|
||||
|
||||
return "a26_4k";
|
||||
}
|
||||
|
||||
bool vcs_cart_slot_device::call_load()
|
||||
{
|
||||
UINT8 *ROM;
|
||||
UINT32 len;
|
||||
|
||||
if (software_entry() != NULL)
|
||||
len = get_software_region_length("rom");
|
||||
else
|
||||
len = length();
|
||||
|
||||
//printf("Size: 0x%X\n", len);
|
||||
|
||||
// check that filesize is among the supported ones
|
||||
switch (len)
|
||||
{
|
||||
case 0x00800:
|
||||
case 0x01000:
|
||||
case 0x02000:
|
||||
case 0x028ff:
|
||||
case 0x02900:
|
||||
case 0x03000:
|
||||
case 0x04000:
|
||||
case 0x08000:
|
||||
case 0x10000:
|
||||
case 0x80000:
|
||||
break;
|
||||
|
||||
default:
|
||||
seterror(IMAGE_ERROR_UNSUPPORTED, "Invalid rom file size" );
|
||||
return IMAGE_INIT_FAIL;
|
||||
}
|
||||
|
||||
m_cart->rom_alloc(len);
|
||||
ROM = m_cart->get_rom_base();
|
||||
|
||||
if (software_entry() != NULL)
|
||||
{
|
||||
const char *pcb_name;
|
||||
memcpy(ROM, get_software_region("rom"), len);
|
||||
|
||||
if ((pcb_name = get_feature("slot")) != NULL)
|
||||
m_type = vcs_get_pcb_id(pcb_name);
|
||||
else
|
||||
{
|
||||
// identify type based on size
|
||||
switch (len)
|
||||
{
|
||||
case 0x800:
|
||||
m_type = A26_2K;
|
||||
break;
|
||||
case 0x1000:
|
||||
m_type = A26_4K;
|
||||
break;
|
||||
case 0x2000:
|
||||
m_type = A26_F8;
|
||||
break;
|
||||
case 0x28ff:
|
||||
case 0x2900:
|
||||
m_type = A26_DPC;
|
||||
break;
|
||||
case 0x3000:
|
||||
m_type = A26_FA;
|
||||
break;
|
||||
case 0x4000:
|
||||
m_type = A26_F6;
|
||||
break;
|
||||
case 0x8000:
|
||||
m_type = A26_F4;
|
||||
break;
|
||||
case 0x10000:
|
||||
m_type = A26_32IN1;
|
||||
break;
|
||||
case 0x80000:
|
||||
m_type = A26_3F;
|
||||
break;
|
||||
default:
|
||||
m_type = A26_4K;
|
||||
printf("Unrecognized cart type!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fread(ROM, len);
|
||||
m_type = identify_cart_type(ROM, len);
|
||||
}
|
||||
|
||||
//printf("Type: %s\n", vcs_get_slot(m_type));
|
||||
|
||||
// check for Special Chip (128bytes of RAM)
|
||||
if (len == 0x2000 || len == 0x4000 || len == 0x8000)
|
||||
if (detect_super_chip(ROM, len))
|
||||
{
|
||||
m_cart->ram_alloc(0x80);
|
||||
//printf("Super Chip detected!\n");
|
||||
}
|
||||
// Super chip games:
|
||||
// dig dig, crystal castles, millipede, stargate, defender ii, jr. Pac Man,
|
||||
// desert falcon, dark chambers, super football, sprintmaster, fatal run,
|
||||
// off the wall, shooting arcade, secret quest, radar lock, save mary, klax
|
||||
|
||||
// add CBS RAM+ (128bytes of RAM)
|
||||
if (m_type == A26_FA)
|
||||
m_cart->ram_alloc(0x100);
|
||||
// add M Network RAM
|
||||
else if (m_type == A26_E7)
|
||||
m_cart->ram_alloc(0x800);
|
||||
// add Commavid RAM
|
||||
else if (m_type == A26_CV)
|
||||
m_cart->ram_alloc(0x400);
|
||||
// add Starpath Superchager RAM
|
||||
else if (m_type == A26_SS)
|
||||
m_cart->ram_alloc(0x1800);
|
||||
// add Boulder Dash RAM
|
||||
else if (m_type == A26_3E)
|
||||
m_cart->ram_alloc(0x8000);
|
||||
|
||||
// pass a pointer to the now allocated ROM for the DPC chip
|
||||
if (m_type == A26_DPC)
|
||||
m_cart->setup_addon_ptr((UINT8 *)m_cart->get_rom_base() + 0x2000);
|
||||
|
||||
return IMAGE_INIT_PASS;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
call_unload
|
||||
-------------------------------------------------*/
|
||||
|
||||
void vcs_cart_slot_device::call_unload()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
call softlist load
|
||||
-------------------------------------------------*/
|
||||
|
||||
bool vcs_cart_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry)
|
||||
{
|
||||
load_software_part_region(*this, swlist, swname, start_entry );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
detection helper routines
|
||||
-------------------------------------------------*/
|
||||
|
||||
int vcs_cart_slot_device::detect_modeDC(UINT8 *cart, UINT32 len)
|
||||
{
|
||||
int numfound = 0;
|
||||
// signature is also in 'video reflex'.. maybe figure out that controller port someday...
|
||||
static const unsigned char signature[3] = { 0x8d, 0xf0, 0xff };
|
||||
|
||||
if (len == 0x10000)
|
||||
{
|
||||
for (int i = 0; i < len - sizeof signature; i++)
|
||||
{
|
||||
if (!memcmp(&cart[i], signature, sizeof signature))
|
||||
{
|
||||
numfound = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (numfound)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vcs_cart_slot_device::detect_modeF6(UINT8 *cart, UINT32 len)
|
||||
{
|
||||
int numfound = 0;
|
||||
static const unsigned char signature[3] = { 0x8d, 0xf6, 0xff };
|
||||
|
||||
if (len == 0x4000)
|
||||
{
|
||||
for (int i = 0; i < len - sizeof signature; i++)
|
||||
{
|
||||
if (!memcmp(&cart[i], signature, sizeof signature))
|
||||
{
|
||||
numfound = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (numfound)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vcs_cart_slot_device::detect_snowhite(UINT8 *cart, UINT32 len)
|
||||
{
|
||||
static const unsigned char snowwhite[] = { 0x10, 0xd0, 0xff, 0xff }; // Snow White Proto
|
||||
|
||||
if (len == 0x2000 && !memcmp(&cart[0x1ffc], snowwhite, sizeof(snowwhite)))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vcs_cart_slot_device::detect_mode3E(UINT8 *cart, UINT32 len)
|
||||
{
|
||||
// this one is a little hacky... looks for STY $3e, which is unique to
|
||||
// 'not boulderdash', but is the only example I have (cow)
|
||||
// Would have used STA $3e, but 'Alien' and 'Star Raiders' do that for unknown reasons
|
||||
int numfound = 0;
|
||||
static const unsigned char signature[3] = { 0x84, 0x3e, 0x9d };
|
||||
|
||||
if (len == 0x0800 || len == 0x1000)
|
||||
{
|
||||
for (int i = 0; i < len - sizeof signature; i++)
|
||||
{
|
||||
if (!memcmp(&cart[i], signature, sizeof signature))
|
||||
{
|
||||
numfound = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (numfound)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vcs_cart_slot_device::detect_modeSS(UINT8 *cart, UINT32 len)
|
||||
{
|
||||
int numfound = 0;
|
||||
static const unsigned char signature[5] = { 0xbd, 0xe5, 0xff, 0x95, 0x81 };
|
||||
|
||||
if (len == 0x0800 || len == 0x1000)
|
||||
{
|
||||
for (int i = 0; i < len - sizeof signature; i++)
|
||||
{
|
||||
if (!memcmp(&cart[i], signature, sizeof signature))
|
||||
{
|
||||
numfound = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (numfound)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vcs_cart_slot_device::detect_modeFE(UINT8 *cart, UINT32 len)
|
||||
{
|
||||
int numfound = 0;
|
||||
static const unsigned char signatures[][5] = {
|
||||
{ 0x20, 0x00, 0xd0, 0xc6, 0xc5 },
|
||||
{ 0x20, 0xc3, 0xf8, 0xa5, 0x82 },
|
||||
{ 0xd0, 0xfb, 0x20, 0x73, 0xfe },
|
||||
{ 0x20, 0x00, 0xf0, 0x84, 0xd6 }
|
||||
};
|
||||
|
||||
if (len == 0x2000)
|
||||
{
|
||||
for (int i = 0; i < len - (sizeof signatures/sizeof signatures[0]); i++)
|
||||
{
|
||||
for (int j = 0; j < (sizeof signatures/sizeof signatures[0]) && !numfound; j++)
|
||||
{
|
||||
if (!memcmp(&cart[i], &signatures[j], sizeof signatures[0]))
|
||||
{
|
||||
numfound = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (numfound)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vcs_cart_slot_device::detect_modeE0(UINT8 *cart, UINT32 len)
|
||||
{
|
||||
int numfound = 0;
|
||||
static const unsigned char signatures[][3] = {
|
||||
{ 0x8d, 0xe0, 0x1f },
|
||||
{ 0x8d, 0xe0, 0x5f },
|
||||
{ 0x8d, 0xe9, 0xff },
|
||||
{ 0xad, 0xe9, 0xff },
|
||||
{ 0xad, 0xed, 0xff },
|
||||
{ 0xad, 0xf3, 0xbf }
|
||||
};
|
||||
|
||||
if (len == 0x2000)
|
||||
{
|
||||
for (int i = 0; i < len - (sizeof signatures/sizeof signatures[0]); i++)
|
||||
{
|
||||
for (int j = 0; j < (sizeof signatures/sizeof signatures[0]) && !numfound; j++)
|
||||
{
|
||||
if (!memcmp(&cart[i], &signatures[j], sizeof signatures[0]))
|
||||
{
|
||||
numfound = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (numfound)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vcs_cart_slot_device::detect_modeCV(UINT8 *cart, UINT32 len)
|
||||
{
|
||||
int numfound = 0;
|
||||
static const unsigned char signatures[][3] = {
|
||||
{ 0x9d, 0xff, 0xf3 },
|
||||
{ 0x99, 0x00, 0xf4 }
|
||||
};
|
||||
|
||||
if (len == 0x0800 || len == 0x1000)
|
||||
{
|
||||
for (int i = 0; i < len - (sizeof signatures/sizeof signatures[0]); i++)
|
||||
{
|
||||
for (int j = 0; j < (sizeof signatures/sizeof signatures[0]) && !numfound; j++)
|
||||
{
|
||||
if (!memcmp(&cart[i], &signatures[j], sizeof signatures[0]))
|
||||
{
|
||||
numfound = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (numfound)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vcs_cart_slot_device::detect_modeFV(UINT8 *cart, UINT32 len)
|
||||
{
|
||||
int numfound = 0;
|
||||
static const unsigned char signatures[][3] = { { 0x2c, 0xd0, 0xff } };
|
||||
|
||||
if (len == 0x2000)
|
||||
{
|
||||
for (int i = 0; i < len - (sizeof signatures/sizeof signatures[0]); i++)
|
||||
{
|
||||
for (int j = 0; j < (sizeof signatures/sizeof signatures[0]) && !numfound; j++)
|
||||
{
|
||||
if (!memcmp(&cart[i], &signatures[j], sizeof signatures[0]))
|
||||
{
|
||||
numfound = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (numfound)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vcs_cart_slot_device::detect_modeJVP(UINT8 *cart, UINT32 len)
|
||||
{
|
||||
int numfound = 0;
|
||||
static const unsigned char signatures[][4] = {
|
||||
{ 0x2c, 0xc0, 0xef, 0x60 },
|
||||
{ 0x8d, 0xa0, 0x0f, 0xf0 }
|
||||
};
|
||||
|
||||
if (len == 0x4000 || len == 0x2000)
|
||||
{
|
||||
for (int i = 0; i < len - (sizeof signatures/sizeof signatures[0]); i++)
|
||||
{
|
||||
for (int j = 0; j < (sizeof signatures/sizeof signatures[0]) && !numfound; j++)
|
||||
{
|
||||
if (!memcmp(&cart[i], &signatures[j], sizeof signatures[0]))
|
||||
{
|
||||
numfound = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (numfound)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vcs_cart_slot_device::detect_modeE7(UINT8 *cart, UINT32 len)
|
||||
{
|
||||
int numfound = 0;
|
||||
static const unsigned char signatures[][3] = {
|
||||
{ 0xad, 0xe5, 0xff },
|
||||
{ 0x8d, 0xe7, 0xff }
|
||||
};
|
||||
|
||||
if (len == 0x2000 || len == 0x4000)
|
||||
{
|
||||
for (int i = 0; i < len - (sizeof signatures/sizeof signatures[0]); i++)
|
||||
{
|
||||
for (int j = 0; j < (sizeof signatures/sizeof signatures[0]) && !numfound; j++)
|
||||
{
|
||||
if (!memcmp(&cart[i], &signatures[j], sizeof signatures[0]))
|
||||
{
|
||||
numfound = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (numfound)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vcs_cart_slot_device::detect_modeUA(UINT8 *cart, UINT32 len)
|
||||
{
|
||||
int numfound = 0;
|
||||
static const unsigned char signature[3] = { 0x8d, 0x40, 0x02 };
|
||||
|
||||
if (len == 0x2000)
|
||||
{
|
||||
for (int i = 0; i < len - sizeof signature; i++)
|
||||
{
|
||||
if (!memcmp(&cart[i], signature, sizeof signature))
|
||||
{
|
||||
numfound = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (numfound)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vcs_cart_slot_device::detect_8K_mode3F(UINT8 *cart, UINT32 len)
|
||||
{
|
||||
int numfound = 0;
|
||||
static const unsigned char signature1[4] = { 0xa9, 0x01, 0x85, 0x3f };
|
||||
static const unsigned char signature2[4] = { 0xa9, 0x02, 0x85, 0x3f };
|
||||
// have to look for two signatures because 'not boulderdash' gives false positive otherwise
|
||||
|
||||
if (len == 0x2000)
|
||||
{
|
||||
for (int i = 0; i < len - sizeof signature1; i++)
|
||||
{
|
||||
if (!memcmp(&cart[i], signature1, sizeof signature1))
|
||||
{
|
||||
numfound |= 0x01;
|
||||
}
|
||||
if (!memcmp(&cart[i], signature2, sizeof signature2))
|
||||
{
|
||||
numfound |= 0x02;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (numfound == 0x03)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vcs_cart_slot_device::detect_32K_mode3F(UINT8 *cart, UINT32 len)
|
||||
{
|
||||
int numfound = 0;
|
||||
static const unsigned char signature[4] = { 0xa9, 0x0e, 0x85, 0x3f };
|
||||
|
||||
if (len >= 0x8000)
|
||||
{
|
||||
for (int i = 0; i < len - sizeof signature; i++)
|
||||
{
|
||||
if (!memcmp(&cart[i], signature, sizeof signature))
|
||||
{
|
||||
numfound++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (numfound > 1)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vcs_cart_slot_device::detect_super_chip(UINT8 *cart, UINT32 len)
|
||||
{
|
||||
static const unsigned char signatures[][5] = {
|
||||
{ 0xa2, 0x7f, 0x9d, 0x00, 0xf0 }, // dig dug
|
||||
{ 0xae, 0xf6, 0xff, 0x4c, 0x00 } // off the wall
|
||||
};
|
||||
|
||||
if (len == 0x4000)
|
||||
{
|
||||
for (int i = 0; i < len - (sizeof signatures/sizeof signatures[0]); i++)
|
||||
{
|
||||
for (int j = 0; j < (sizeof signatures/sizeof signatures[0]); j++)
|
||||
{
|
||||
if (!memcmp(&cart[i], &signatures[j], sizeof signatures[0]))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0x1000; i < len; i += 0x1000)
|
||||
{
|
||||
if (memcmp(cart, cart + i, 0x100))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* Check the reset vector does not point into the super chip RAM area */
|
||||
if ((((cart[0x0ffd] << 8) | cart[0x0ffc]) & 0x0fff) < 0x0100)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
identify_cart_type - code to detect cart type from
|
||||
fullpath
|
||||
-------------------------------------------------*/
|
||||
|
||||
// 4in1 & 8in1 are not currently detected from fullpath...
|
||||
int vcs_cart_slot_device::identify_cart_type(UINT8 *ROM, UINT32 len)
|
||||
{
|
||||
int type = 0xff;
|
||||
|
||||
// auto-detect bank mode
|
||||
if (detect_modeDC(ROM, len))
|
||||
type = A26_DC;
|
||||
else if (detect_mode3E(ROM, len))
|
||||
type = A26_3E;
|
||||
else if (detect_modeFE(ROM, len))
|
||||
type = A26_FE;
|
||||
else if (detect_modeSS(ROM, len))
|
||||
type = A26_SS;
|
||||
else if (detect_modeE0(ROM, len))
|
||||
type = A26_E0;
|
||||
else if (detect_modeCV(ROM, len))
|
||||
type = A26_CV;
|
||||
else if (detect_modeFV(ROM, len))
|
||||
type = A26_FV;
|
||||
else if (detect_modeJVP(ROM, len))
|
||||
type = A26_JVP;
|
||||
else if (detect_modeUA(ROM, len))
|
||||
type = A26_UA;
|
||||
else if (detect_8K_mode3F(ROM, len))
|
||||
type = A26_3F;
|
||||
else if (detect_32K_mode3F(ROM, len))
|
||||
type = A26_3F;
|
||||
else if (detect_modeE7(ROM, len))
|
||||
type = A26_E7;
|
||||
else if (detect_snowhite(ROM, len))
|
||||
type = A26_F8SW;
|
||||
|
||||
// otherwise, choose based on size
|
||||
if (type == 0xff)
|
||||
{
|
||||
switch (len)
|
||||
{
|
||||
case 0x800:
|
||||
type = A26_2K;
|
||||
break;
|
||||
case 0x1000:
|
||||
type = A26_4K;
|
||||
break;
|
||||
case 0x2000:
|
||||
type = A26_F8;
|
||||
break;
|
||||
case 0x28ff:
|
||||
case 0x2900:
|
||||
type = A26_DPC;
|
||||
break;
|
||||
case 0x3000:
|
||||
type = A26_FA;
|
||||
break;
|
||||
case 0x4000:
|
||||
type = A26_F6;
|
||||
break;
|
||||
case 0x8000:
|
||||
type = A26_F4;
|
||||
break;
|
||||
case 0x10000:
|
||||
type = A26_32IN1;
|
||||
break;
|
||||
case 0x80000:
|
||||
type = A26_3F;
|
||||
break;
|
||||
default:
|
||||
type = A26_4K;
|
||||
printf("Unrecognized cart type!\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
get default card software
|
||||
-------------------------------------------------*/
|
||||
|
||||
void vcs_cart_slot_device::get_default_card_software(astring &result)
|
||||
{
|
||||
if (open_image_file(mconfig().options()))
|
||||
{
|
||||
const char *slot_string = "a26_4k";
|
||||
UINT32 len = core_fsize(m_file);
|
||||
dynamic_buffer rom(len);
|
||||
int type;
|
||||
|
||||
core_fread(m_file, rom, len);
|
||||
|
||||
type = identify_cart_type(rom, len);
|
||||
slot_string = vcs_get_slot(type);
|
||||
|
||||
clear();
|
||||
|
||||
result.cpy(slot_string);
|
||||
}
|
||||
else
|
||||
software_get_default_slot(result, "a26_4k");
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
read
|
||||
-------------------------------------------------*/
|
||||
|
||||
READ8_MEMBER(vcs_cart_slot_device::read_rom)
|
||||
{
|
||||
if (m_cart)
|
||||
return m_cart->read_rom(space, offset, mem_mask);
|
||||
else
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
READ8_MEMBER(vcs_cart_slot_device::read_bank)
|
||||
{
|
||||
if (m_cart)
|
||||
return m_cart->read_bank(space, offset, mem_mask);
|
||||
else
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
write
|
||||
-------------------------------------------------*/
|
||||
|
||||
WRITE8_MEMBER(vcs_cart_slot_device::write_bank)
|
||||
{
|
||||
if (m_cart)
|
||||
m_cart->write_bank(space, offset, data, mem_mask);
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(vcs_cart_slot_device::write_ram)
|
||||
{
|
||||
if (m_cart)
|
||||
m_cart->write_ram(space, offset, data, mem_mask);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
direct update
|
||||
-------------------------------------------------*/
|
||||
|
||||
DIRECT_UPDATE_MEMBER(vcs_cart_slot_device::cart_opbase)
|
||||
{
|
||||
if (m_cart)
|
||||
return m_cart->cart_opbase(direct, address);
|
||||
else
|
||||
return address;
|
||||
}
|
154
src/emu/bus/vcs/vcs_slot.h
Executable file
154
src/emu/bus/vcs/vcs_slot.h
Executable file
@ -0,0 +1,154 @@
|
||||
#ifndef __VCS_SLOT_H
|
||||
#define __VCS_SLOT_H
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
TYPE DEFINITIONS
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
/* PCB */
|
||||
enum
|
||||
{
|
||||
A26_2K = 0,
|
||||
A26_4K,
|
||||
A26_F4,
|
||||
A26_F6,
|
||||
A26_F8,
|
||||
A26_F8SW,
|
||||
A26_FA,
|
||||
A26_FE,
|
||||
A26_3E, // to test
|
||||
A26_3F,
|
||||
A26_E0,
|
||||
A26_E7,
|
||||
A26_UA,
|
||||
A26_DC,
|
||||
A26_CV,
|
||||
A26_FV,
|
||||
A26_JVP, // to test
|
||||
A26_32IN1,
|
||||
A26_8IN1,
|
||||
A26_4IN1,
|
||||
A26_DPC,
|
||||
A26_SS,
|
||||
A26_CM
|
||||
};
|
||||
|
||||
|
||||
// ======================> device_vcs_cart_interface
|
||||
|
||||
class device_vcs_cart_interface : public device_slot_card_interface
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
device_vcs_cart_interface(const machine_config &mconfig, device_t &device);
|
||||
virtual ~device_vcs_cart_interface();
|
||||
|
||||
// reading from ROM
|
||||
virtual DECLARE_READ8_MEMBER(read_rom) { return 0xff; }
|
||||
// writing to RAM chips (sometimes it is in a different range than write_bank!)
|
||||
virtual DECLARE_WRITE8_MEMBER(write_ram) {}
|
||||
|
||||
// read/write to bankswitch address
|
||||
virtual DECLARE_READ8_MEMBER(read_bank) { return 0xff; }
|
||||
virtual DECLARE_WRITE8_MEMBER(write_bank) {}
|
||||
|
||||
// direct update handler
|
||||
virtual DECLARE_DIRECT_UPDATE_MEMBER(cart_opbase) { return address; }
|
||||
|
||||
virtual void setup_addon_ptr(UINT8 *ptr) {}
|
||||
|
||||
void rom_alloc(UINT32 size);
|
||||
void ram_alloc(UINT32 size);
|
||||
UINT8* get_rom_base() { return m_rom; }
|
||||
UINT8* get_ram_base() { return m_ram; }
|
||||
UINT32 get_rom_size() { return m_rom.bytes(); }
|
||||
UINT32 get_ram_size() { return m_ram.bytes(); }
|
||||
|
||||
protected:
|
||||
// internal state
|
||||
dynamic_buffer m_rom;
|
||||
dynamic_buffer m_ram;
|
||||
};
|
||||
|
||||
|
||||
// ======================> vcs_cart_slot_device
|
||||
|
||||
class vcs_cart_slot_device : public device_t,
|
||||
public device_image_interface,
|
||||
public device_slot_interface
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
vcs_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
virtual ~vcs_cart_slot_device();
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_config_complete();
|
||||
|
||||
// image-level overrides
|
||||
virtual bool call_load();
|
||||
virtual void call_unload();
|
||||
virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry);
|
||||
|
||||
int get_cart_type() { return m_type; };
|
||||
int identify_cart_type(UINT8 *ROM, UINT32 len);
|
||||
|
||||
virtual iodevice_t image_type() const { return IO_CARTSLOT; }
|
||||
virtual bool is_readable() const { return 1; }
|
||||
virtual bool is_writeable() const { return 0; }
|
||||
virtual bool is_creatable() const { return 0; }
|
||||
virtual bool must_be_loaded() const { return 1; }
|
||||
virtual bool is_reset_on_load() const { return 1; }
|
||||
virtual const option_guide *create_option_guide() const { return NULL; }
|
||||
virtual const char *image_interface() const { return "a2600_cart"; }
|
||||
virtual const char *file_extensions() const { return "bin,a26"; }
|
||||
|
||||
// slot interface overrides
|
||||
virtual void get_default_card_software(astring &result);
|
||||
|
||||
// reading and writing
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
virtual DECLARE_READ8_MEMBER(read_bank);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_bank);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_ram);
|
||||
virtual DECLARE_DIRECT_UPDATE_MEMBER(cart_opbase);
|
||||
|
||||
private:
|
||||
device_vcs_cart_interface* m_cart;
|
||||
int m_type;
|
||||
|
||||
int detect_snowhite(UINT8 *cart, UINT32 len);
|
||||
int detect_modeDC(UINT8 *cart, UINT32 len);
|
||||
int detect_modeF6(UINT8 *cart, UINT32 len);
|
||||
int detect_mode3E(UINT8 *cart, UINT32 len);
|
||||
int detect_modeSS(UINT8 *cart, UINT32 len);
|
||||
int detect_modeFE(UINT8 *cart, UINT32 len);
|
||||
int detect_modeE0(UINT8 *cart, UINT32 len);
|
||||
int detect_modeCV(UINT8 *cart, UINT32 len);
|
||||
int detect_modeFV(UINT8 *cart, UINT32 len);
|
||||
int detect_modeJVP(UINT8 *cart, UINT32 len);
|
||||
int detect_modeE7(UINT8 *cart, UINT32 len);
|
||||
int detect_modeUA(UINT8 *cart, UINT32 len);
|
||||
int detect_8K_mode3F(UINT8 *cart, UINT32 len);
|
||||
int detect_32K_mode3F(UINT8 *cart, UINT32 len);
|
||||
int detect_super_chip(UINT8 *cart, UINT32 len);
|
||||
};
|
||||
|
||||
|
||||
// device type definition
|
||||
extern const device_type VCS_CART_SLOT;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
DEVICE CONFIGURATION MACROS
|
||||
***************************************************************************/
|
||||
|
||||
#define MCFG_VCS_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \
|
||||
MCFG_DEVICE_ADD(_tag, VCS_CART_SLOT, 0) \
|
||||
MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false)
|
||||
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user