(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:
etabeta78 2014-10-24 06:06:55 +02:00
parent 700981f762
commit 7e23a90317
2 changed files with 126 additions and 54 deletions

View File

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

View File

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