mirror of
https://github.com/holub/mame
synced 2025-04-22 16:31:49 +03:00
(MESS) spc1000: added support for tapes in .cas format [Fabio Priuli]
(MESS) spc1000: added emulation of joystick inputs [Fabio Priuli] (MESS) added software list for Samsung spc1000 tapes [Fabio Priuli] out of whatsnew: addition of joystick support made playable Space Invaders, Super Xevious, The Goonies and King's Valley.
This commit is contained in:
parent
700981f762
commit
7e23a90317
@ -10,12 +10,14 @@ Tape formats:
|
||||
TAP: This is a series of 0x30 and 0x31 bytes, representing binary
|
||||
0 and 1. It includes the header and leaders.
|
||||
|
||||
CAS: This format has not been investigated yet.
|
||||
CAS: Files in this format consist of a 16 bytes header (SPC-1000.CASfmt )
|
||||
followed by cassette bits packed together (each byte of a .cas file
|
||||
are 8 bits, most significant bit first)
|
||||
|
||||
STA: This format has not been investigated yet, but is assumed to
|
||||
be the save state of some other emulator.
|
||||
|
||||
IPL: This format has not been investigated yet.
|
||||
IPL: This seems a quickload format containing RAM dump, not a real tape
|
||||
|
||||
********************************************************************/
|
||||
|
||||
@ -58,68 +60,132 @@ static int spc1000_output_bit(INT16 *buffer, int sample_pos, bool bit)
|
||||
return samples;
|
||||
}
|
||||
|
||||
static int spc1000_handle_cassette(INT16 *buffer, const UINT8 *bytes)
|
||||
static int spc1000_handle_tap(INT16 *buffer, const UINT8 *bytes)
|
||||
{
|
||||
UINT32 sample_count = 0;
|
||||
UINT32 i;
|
||||
|
||||
/* data */
|
||||
for (i=0; i<spc1000_image_size; i++)
|
||||
sample_count += spc1000_output_bit(buffer, sample_count, bytes[i]&1);
|
||||
for (UINT32 i = 0; i < spc1000_image_size; i++)
|
||||
sample_count += spc1000_output_bit(buffer, sample_count, bytes[i] & 1);
|
||||
|
||||
return sample_count;
|
||||
}
|
||||
|
||||
static int spc1000_handle_cas(INT16 *buffer, const UINT8 *bytes)
|
||||
{
|
||||
UINT32 sample_count = 0;
|
||||
|
||||
/* data (skipping first 16 bytes, which is CAS header) */
|
||||
for (UINT32 i = 0x10; i < spc1000_image_size; i++)
|
||||
for (int j = 0; j < 8; j++)
|
||||
sample_count += spc1000_output_bit(buffer, sample_count, (bytes[i] >> (7 - j)) & 1);
|
||||
|
||||
return sample_count;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
Generate samples for the tape image
|
||||
********************************************************************/
|
||||
|
||||
static int spc1000_cassette_fill_wave(INT16 *buffer, int length, UINT8 *bytes)
|
||||
static int spc1000_tap_fill_wave(INT16 *buffer, int length, UINT8 *bytes)
|
||||
{
|
||||
return spc1000_handle_cassette(buffer, bytes);
|
||||
return spc1000_handle_tap(buffer, bytes);
|
||||
}
|
||||
|
||||
static int spc1000_cas_fill_wave(INT16 *buffer, int length, UINT8 *bytes)
|
||||
{
|
||||
return spc1000_handle_cas(buffer, bytes);
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
Calculate the number of samples needed for this tape image
|
||||
********************************************************************/
|
||||
|
||||
static int spc1000_cassette_calculate_size_in_samples(const UINT8 *bytes, int length)
|
||||
static int spc1000_tap_calculate_size_in_samples(const UINT8 *bytes, int length)
|
||||
{
|
||||
spc1000_image_size = length;
|
||||
|
||||
return spc1000_handle_cassette(NULL, bytes);
|
||||
return spc1000_handle_tap(NULL, bytes);
|
||||
}
|
||||
|
||||
static const struct CassetteLegacyWaveFiller spc1000_legacy_fill_wave =
|
||||
static int spc1000_cas_calculate_size_in_samples(const UINT8 *bytes, int length)
|
||||
{
|
||||
spc1000_cassette_fill_wave, /* fill_wave */
|
||||
spc1000_image_size = length;
|
||||
|
||||
return spc1000_handle_cas(NULL, bytes);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
Formats
|
||||
********************************************************************/
|
||||
|
||||
|
||||
// TAP
|
||||
static const struct CassetteLegacyWaveFiller spc1000_tap_legacy_fill_wave =
|
||||
{
|
||||
spc1000_tap_fill_wave, /* fill_wave */
|
||||
-1, /* chunk_size */
|
||||
0, /* chunk_samples */
|
||||
spc1000_cassette_calculate_size_in_samples, /* chunk_sample_calc */
|
||||
spc1000_tap_calculate_size_in_samples, /* chunk_sample_calc */
|
||||
SPC1000_WAV_FREQUENCY, /* sample_frequency */
|
||||
0, /* header_samples */
|
||||
0 /* trailer_samples */
|
||||
};
|
||||
|
||||
static casserr_t spc1000_cassette_identify(cassette_image *cassette, struct CassetteOptions *opts)
|
||||
static casserr_t spc1000_tap_cassette_identify(cassette_image *cassette, struct CassetteOptions *opts)
|
||||
{
|
||||
return cassette_legacy_identify(cassette, opts, &spc1000_legacy_fill_wave);
|
||||
return cassette_legacy_identify(cassette, opts, &spc1000_tap_legacy_fill_wave);
|
||||
}
|
||||
|
||||
static casserr_t spc1000_cassette_load(cassette_image *cassette)
|
||||
static casserr_t spc1000_tap_cassette_load(cassette_image *cassette)
|
||||
{
|
||||
return cassette_legacy_construct(cassette, &spc1000_legacy_fill_wave);
|
||||
return cassette_legacy_construct(cassette, &spc1000_tap_legacy_fill_wave);
|
||||
}
|
||||
|
||||
static const struct CassetteFormat spc1000_cassette_image_format =
|
||||
static const struct CassetteFormat spc1000_tap_cassette_image_format =
|
||||
{
|
||||
"tap",
|
||||
spc1000_cassette_identify,
|
||||
spc1000_cassette_load,
|
||||
spc1000_tap_cassette_identify,
|
||||
spc1000_tap_cassette_load,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
// CAS
|
||||
static const struct CassetteLegacyWaveFiller spc1000_cas_legacy_fill_wave =
|
||||
{
|
||||
spc1000_cas_fill_wave, /* fill_wave */
|
||||
-1, /* chunk_size */
|
||||
0, /* chunk_samples */
|
||||
spc1000_cas_calculate_size_in_samples, /* chunk_sample_calc */
|
||||
SPC1000_WAV_FREQUENCY, /* sample_frequency */
|
||||
0, /* header_samples */
|
||||
0 /* trailer_samples */
|
||||
};
|
||||
|
||||
static casserr_t spc1000_cas_cassette_identify(cassette_image *cassette, struct CassetteOptions *opts)
|
||||
{
|
||||
return cassette_legacy_identify(cassette, opts, &spc1000_cas_legacy_fill_wave);
|
||||
}
|
||||
|
||||
static casserr_t spc1000_cas_cassette_load(cassette_image *cassette)
|
||||
{
|
||||
return cassette_legacy_construct(cassette, &spc1000_cas_legacy_fill_wave);
|
||||
}
|
||||
|
||||
static const struct CassetteFormat spc1000_cas_cassette_image_format =
|
||||
{
|
||||
"cas",
|
||||
spc1000_cas_cassette_identify,
|
||||
spc1000_cas_cassette_load,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
|
||||
CASSETTE_FORMATLIST_START(spc1000_cassette_formats)
|
||||
CASSETTE_FORMAT(spc1000_cassette_image_format)
|
||||
CASSETTE_FORMAT(spc1000_tap_cassette_image_format)
|
||||
CASSETTE_FORMAT(spc1000_cas_cassette_image_format)
|
||||
CASSETTE_FORMATLIST_END
|
||||
|
@ -54,6 +54,7 @@ public:
|
||||
, m_pio(*this, "d8255_master")
|
||||
, m_ram(*this, RAM_TAG)
|
||||
, m_cass(*this, "cassette")
|
||||
, m_io_joy(*this, "JOY")
|
||||
{}
|
||||
|
||||
DECLARE_WRITE8_MEMBER(spc1000_iplk_w);
|
||||
@ -69,8 +70,8 @@ public:
|
||||
DECLARE_WRITE8_MEMBER(fdc_8255_b_w);
|
||||
DECLARE_READ8_MEMBER(fdc_8255_c_r);
|
||||
DECLARE_WRITE8_MEMBER(fdc_8255_c_w);
|
||||
DECLARE_READ8_MEMBER( upd765_tc_r );
|
||||
DECLARE_WRITE8_MEMBER( fdc_control_w );
|
||||
DECLARE_READ8_MEMBER(upd765_tc_r);
|
||||
DECLARE_WRITE8_MEMBER(fdc_control_w);
|
||||
MC6847_GET_CHARROM_MEMBER(get_char_rom)
|
||||
{
|
||||
return m_p_videoram[0x1000 + (ch & 0x7f) * 16 + line];
|
||||
@ -82,6 +83,7 @@ private:
|
||||
UINT8 m_GMODE;
|
||||
UINT16 m_page;
|
||||
UINT8 *m_work_ram;
|
||||
virtual void machine_start();
|
||||
virtual void machine_reset();
|
||||
required_device<mc6847_base_device> m_vdg;
|
||||
required_device<cpu_device> m_maincpu;
|
||||
@ -90,6 +92,7 @@ private:
|
||||
required_device<i8255_device> m_pio;
|
||||
required_device<ram_device> m_ram;
|
||||
required_device<cassette_image_device> m_cass;
|
||||
required_ioport m_io_joy;
|
||||
|
||||
floppy_image_device *m_fd0;
|
||||
floppy_image_device *m_fd1;
|
||||
@ -110,36 +113,23 @@ void spc1000_state::device_timer(emu_timer &timer, device_timer_id id, int param
|
||||
|
||||
static ADDRESS_MAP_START(spc1000_mem, AS_PROGRAM, 8, spc1000_state )
|
||||
ADDRESS_MAP_UNMAP_HIGH
|
||||
AM_RANGE( 0x0000, 0x7fff ) AM_READ_BANK("bank1") AM_WRITE_BANK("bank2")
|
||||
AM_RANGE( 0x8000, 0xffff ) AM_READ_BANK("bank3") AM_WRITE_BANK("bank4")
|
||||
AM_RANGE(0x0000, 0x7fff) AM_READ_BANK("bank1") AM_WRITE_BANK("bank2")
|
||||
AM_RANGE(0x8000, 0xffff) AM_READ_BANK("bank3") AM_WRITE_BANK("bank4")
|
||||
ADDRESS_MAP_END
|
||||
|
||||
WRITE8_MEMBER(spc1000_state::spc1000_iplk_w)
|
||||
{
|
||||
m_IPLK = m_IPLK ? 0 : 1;
|
||||
if (m_IPLK == 1) {
|
||||
UINT8 *mem = memregion("maincpu")->base();
|
||||
membank("bank1")->set_base(mem);
|
||||
membank("bank3")->set_base(mem);
|
||||
} else {
|
||||
UINT8 *ram = m_ram->pointer();
|
||||
membank("bank1")->set_base(ram);
|
||||
membank("bank3")->set_base(ram + 0x8000);
|
||||
}
|
||||
membank("bank1")->set_entry(m_IPLK);
|
||||
membank("bank3")->set_entry(m_IPLK);
|
||||
}
|
||||
|
||||
READ8_MEMBER(spc1000_state::spc1000_iplk_r)
|
||||
{
|
||||
m_IPLK = m_IPLK ? 0 : 1;
|
||||
if (m_IPLK == 1) {
|
||||
UINT8 *mem = memregion("maincpu")->base();
|
||||
membank("bank1")->set_base(mem);
|
||||
membank("bank3")->set_base(mem);
|
||||
} else {
|
||||
UINT8 *ram = m_ram->pointer();
|
||||
membank("bank1")->set_base(ram);
|
||||
membank("bank3")->set_base(ram + 0x8000);
|
||||
}
|
||||
membank("bank1")->set_entry(m_IPLK);
|
||||
membank("bank3")->set_entry(m_IPLK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -350,25 +340,38 @@ static INPUT_PORTS_START( spc1000 )
|
||||
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("L") PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') PORT_CHAR(0x0c)
|
||||
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("O") PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') PORT_CHAR(0x0e)
|
||||
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("9 )") PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR(')')
|
||||
|
||||
PORT_START("JOY")
|
||||
PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_PLAYER(1)
|
||||
PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(1)
|
||||
PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(1)
|
||||
PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(1)
|
||||
PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(1)
|
||||
PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_UNUSED) // Button 2?
|
||||
PORT_BIT(0xc0, IP_ACTIVE_HIGH, IPT_UNUSED) // Cassette related
|
||||
INPUT_PORTS_END
|
||||
|
||||
|
||||
void spc1000_state::machine_reset()
|
||||
void spc1000_state::machine_start()
|
||||
{
|
||||
address_space &space = m_maincpu->space(AS_PROGRAM);
|
||||
UINT8 *mem = memregion("maincpu")->base();
|
||||
UINT8 *ram = m_ram->pointer();
|
||||
|
||||
space.install_read_bank(0x0000, 0x7fff, "bank1");
|
||||
space.install_read_bank(0x8000, 0xffff, "bank3");
|
||||
// configure and intialize banks 1 & 3 (read banks)
|
||||
membank("bank1")->configure_entry(0, ram);
|
||||
membank("bank1")->configure_entry(1, mem);
|
||||
membank("bank3")->configure_entry(0, ram + 0x8000);
|
||||
membank("bank3")->configure_entry(1, mem);
|
||||
membank("bank1")->set_entry(1);
|
||||
membank("bank3")->set_entry(1);
|
||||
|
||||
space.install_write_bank(0x0000, 0x7fff, "bank2");
|
||||
space.install_write_bank(0x8000, 0xffff, "bank4");
|
||||
|
||||
membank("bank1")->set_base(mem);
|
||||
// intialize banks 2 & 4 (write banks)
|
||||
membank("bank2")->set_base(ram);
|
||||
membank("bank3")->set_base(mem);
|
||||
membank("bank4")->set_base(ram + 0x8000);
|
||||
}
|
||||
|
||||
void spc1000_state::machine_reset()
|
||||
{
|
||||
|
||||
m_work_ram = auto_alloc_array_clear(machine(), UINT8, 0x10000);
|
||||
m_fdccpu->set_input_line_vector(0, 0);
|
||||
@ -407,10 +410,11 @@ READ8_MEMBER(spc1000_state::mc6847_videoram_r)
|
||||
|
||||
READ8_MEMBER( spc1000_state::porta_r )
|
||||
{
|
||||
UINT8 data = 0;
|
||||
UINT8 data = 0x3f;
|
||||
data |= (m_cass->input() > 0.0038) ? 0x80 : 0;
|
||||
data |= ((m_cass->get_state() & CASSETTE_MASK_UISTATE) == CASSETTE_PLAY) ? 0x00 : 0x40;
|
||||
|
||||
data &= ~(m_io_joy->read() & 0x3f);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@ -491,6 +495,8 @@ static MACHINE_CONFIG_START( spc1000, spc1000_state )
|
||||
MCFG_CASSETTE_FORMATS(spc1000_cassette_formats)
|
||||
MCFG_CASSETTE_DEFAULT_STATE(CASSETTE_STOPPED | CASSETTE_SPEAKER_ENABLED | CASSETTE_MOTOR_ENABLED)
|
||||
|
||||
MCFG_SOFTWARE_LIST_ADD("cass_list", "spc1000_cass")
|
||||
|
||||
/* internal ram */
|
||||
MCFG_RAM_ADD(RAM_TAG)
|
||||
MCFG_RAM_DEFAULT_SIZE("64K")
|
||||
|
Loading…
Reference in New Issue
Block a user