(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:
Fabio Priuli 2014-08-24 08:45:33 +00:00
parent 9ffe9e8bba
commit a1cd7776c5
14 changed files with 3794 additions and 1613 deletions

10
.gitattributes vendored
View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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

View 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)];
}

View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

389
src/emu/bus/vcs/rom.h Executable file
View 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
View 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);
}
}

View 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
View 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
View 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