trunk/src/lib/formats/spc1000_cas.c
| r241428 | r241429 | |
| 10 | 10 | TAP: This is a series of 0x30 and 0x31 bytes, representing binary |
| 11 | 11 | 0 and 1. It includes the header and leaders. |
| 12 | 12 | |
| 13 | | CAS: This format has not been investigated yet. |
| 13 | CAS: Files in this format consist of a 16 bytes header (SPC-1000.CASfmt ) |
| 14 | followed by cassette bits packed together (each byte of a .cas file |
| 15 | are 8 bits, most significant bit first) |
| 14 | 16 | |
| 15 | 17 | STA: This format has not been investigated yet, but is assumed to |
| 16 | 18 | be the save state of some other emulator. |
| 17 | 19 | |
| 18 | | IPL: This format has not been investigated yet. |
| 20 | IPL: This seems a quickload format containing RAM dump, not a real tape |
| 19 | 21 | |
| 20 | 22 | ********************************************************************/ |
| 21 | 23 | |
| r241428 | r241429 | |
| 58 | 60 | return samples; |
| 59 | 61 | } |
| 60 | 62 | |
| 61 | | static int spc1000_handle_cassette(INT16 *buffer, const UINT8 *bytes) |
| 63 | static int spc1000_handle_tap(INT16 *buffer, const UINT8 *bytes) |
| 62 | 64 | { |
| 63 | 65 | UINT32 sample_count = 0; |
| 64 | | UINT32 i; |
| 65 | 66 | |
| 66 | 67 | /* data */ |
| 67 | | for (i=0; i<spc1000_image_size; i++) |
| 68 | | sample_count += spc1000_output_bit(buffer, sample_count, bytes[i]&1); |
| 68 | for (UINT32 i = 0; i < spc1000_image_size; i++) |
| 69 | sample_count += spc1000_output_bit(buffer, sample_count, bytes[i] & 1); |
| 69 | 70 | |
| 70 | 71 | return sample_count; |
| 71 | 72 | } |
| 72 | 73 | |
| 74 | static int spc1000_handle_cas(INT16 *buffer, const UINT8 *bytes) |
| 75 | { |
| 76 | UINT32 sample_count = 0; |
| 77 | |
| 78 | /* data (skipping first 16 bytes, which is CAS header) */ |
| 79 | for (UINT32 i = 0x10; i < spc1000_image_size; i++) |
| 80 | for (int j = 0; j < 8; j++) |
| 81 | sample_count += spc1000_output_bit(buffer, sample_count, (bytes[i] >> (7 - j)) & 1); |
| 82 | |
| 83 | return sample_count; |
| 84 | } |
| 73 | 85 | |
| 86 | |
| 74 | 87 | /******************************************************************* |
| 75 | 88 | Generate samples for the tape image |
| 76 | 89 | ********************************************************************/ |
| 77 | 90 | |
| 78 | | static int spc1000_cassette_fill_wave(INT16 *buffer, int length, UINT8 *bytes) |
| 91 | static int spc1000_tap_fill_wave(INT16 *buffer, int length, UINT8 *bytes) |
| 79 | 92 | { |
| 80 | | return spc1000_handle_cassette(buffer, bytes); |
| 93 | return spc1000_handle_tap(buffer, bytes); |
| 81 | 94 | } |
| 82 | 95 | |
| 96 | static int spc1000_cas_fill_wave(INT16 *buffer, int length, UINT8 *bytes) |
| 97 | { |
| 98 | return spc1000_handle_cas(buffer, bytes); |
| 99 | } |
| 100 | |
| 83 | 101 | /******************************************************************* |
| 84 | 102 | Calculate the number of samples needed for this tape image |
| 85 | 103 | ********************************************************************/ |
| 86 | 104 | |
| 87 | | static int spc1000_cassette_calculate_size_in_samples(const UINT8 *bytes, int length) |
| 105 | static int spc1000_tap_calculate_size_in_samples(const UINT8 *bytes, int length) |
| 88 | 106 | { |
| 89 | 107 | spc1000_image_size = length; |
| 90 | 108 | |
| 91 | | return spc1000_handle_cassette(NULL, bytes); |
| 109 | return spc1000_handle_tap(NULL, bytes); |
| 92 | 110 | } |
| 93 | 111 | |
| 94 | | static const struct CassetteLegacyWaveFiller spc1000_legacy_fill_wave = |
| 112 | static int spc1000_cas_calculate_size_in_samples(const UINT8 *bytes, int length) |
| 95 | 113 | { |
| 96 | | spc1000_cassette_fill_wave, /* fill_wave */ |
| 114 | spc1000_image_size = length; |
| 115 | |
| 116 | return spc1000_handle_cas(NULL, bytes); |
| 117 | } |
| 118 | |
| 119 | |
| 120 | /******************************************************************* |
| 121 | Formats |
| 122 | ********************************************************************/ |
| 123 | |
| 124 | |
| 125 | // TAP |
| 126 | static const struct CassetteLegacyWaveFiller spc1000_tap_legacy_fill_wave = |
| 127 | { |
| 128 | spc1000_tap_fill_wave, /* fill_wave */ |
| 97 | 129 | -1, /* chunk_size */ |
| 98 | 130 | 0, /* chunk_samples */ |
| 99 | | spc1000_cassette_calculate_size_in_samples, /* chunk_sample_calc */ |
| 131 | spc1000_tap_calculate_size_in_samples, /* chunk_sample_calc */ |
| 100 | 132 | SPC1000_WAV_FREQUENCY, /* sample_frequency */ |
| 101 | 133 | 0, /* header_samples */ |
| 102 | 134 | 0 /* trailer_samples */ |
| 103 | 135 | }; |
| 104 | 136 | |
| 105 | | static casserr_t spc1000_cassette_identify(cassette_image *cassette, struct CassetteOptions *opts) |
| 137 | static casserr_t spc1000_tap_cassette_identify(cassette_image *cassette, struct CassetteOptions *opts) |
| 106 | 138 | { |
| 107 | | return cassette_legacy_identify(cassette, opts, &spc1000_legacy_fill_wave); |
| 139 | return cassette_legacy_identify(cassette, opts, &spc1000_tap_legacy_fill_wave); |
| 108 | 140 | } |
| 109 | 141 | |
| 110 | | static casserr_t spc1000_cassette_load(cassette_image *cassette) |
| 142 | static casserr_t spc1000_tap_cassette_load(cassette_image *cassette) |
| 111 | 143 | { |
| 112 | | return cassette_legacy_construct(cassette, &spc1000_legacy_fill_wave); |
| 144 | return cassette_legacy_construct(cassette, &spc1000_tap_legacy_fill_wave); |
| 113 | 145 | } |
| 114 | 146 | |
| 115 | | static const struct CassetteFormat spc1000_cassette_image_format = |
| 147 | static const struct CassetteFormat spc1000_tap_cassette_image_format = |
| 116 | 148 | { |
| 117 | 149 | "tap", |
| 118 | | spc1000_cassette_identify, |
| 119 | | spc1000_cassette_load, |
| 150 | spc1000_tap_cassette_identify, |
| 151 | spc1000_tap_cassette_load, |
| 120 | 152 | NULL |
| 121 | 153 | }; |
| 122 | 154 | |
| 155 | |
| 156 | // CAS |
| 157 | static const struct CassetteLegacyWaveFiller spc1000_cas_legacy_fill_wave = |
| 158 | { |
| 159 | spc1000_cas_fill_wave, /* fill_wave */ |
| 160 | -1, /* chunk_size */ |
| 161 | 0, /* chunk_samples */ |
| 162 | spc1000_cas_calculate_size_in_samples, /* chunk_sample_calc */ |
| 163 | SPC1000_WAV_FREQUENCY, /* sample_frequency */ |
| 164 | 0, /* header_samples */ |
| 165 | 0 /* trailer_samples */ |
| 166 | }; |
| 167 | |
| 168 | static casserr_t spc1000_cas_cassette_identify(cassette_image *cassette, struct CassetteOptions *opts) |
| 169 | { |
| 170 | return cassette_legacy_identify(cassette, opts, &spc1000_cas_legacy_fill_wave); |
| 171 | } |
| 172 | |
| 173 | static casserr_t spc1000_cas_cassette_load(cassette_image *cassette) |
| 174 | { |
| 175 | return cassette_legacy_construct(cassette, &spc1000_cas_legacy_fill_wave); |
| 176 | } |
| 177 | |
| 178 | static const struct CassetteFormat spc1000_cas_cassette_image_format = |
| 179 | { |
| 180 | "cas", |
| 181 | spc1000_cas_cassette_identify, |
| 182 | spc1000_cas_cassette_load, |
| 183 | NULL |
| 184 | }; |
| 185 | |
| 186 | |
| 187 | |
| 123 | 188 | CASSETTE_FORMATLIST_START(spc1000_cassette_formats) |
| 124 | | CASSETTE_FORMAT(spc1000_cassette_image_format) |
| 189 | CASSETTE_FORMAT(spc1000_tap_cassette_image_format) |
| 190 | CASSETTE_FORMAT(spc1000_cas_cassette_image_format) |
| 125 | 191 | CASSETTE_FORMATLIST_END |
trunk/src/mess/drivers/spc1000.c
| r241428 | r241429 | |
| 54 | 54 | , m_pio(*this, "d8255_master") |
| 55 | 55 | , m_ram(*this, RAM_TAG) |
| 56 | 56 | , m_cass(*this, "cassette") |
| 57 | , m_io_joy(*this, "JOY") |
| 57 | 58 | {} |
| 58 | 59 | |
| 59 | 60 | DECLARE_WRITE8_MEMBER(spc1000_iplk_w); |
| r241428 | r241429 | |
| 69 | 70 | DECLARE_WRITE8_MEMBER(fdc_8255_b_w); |
| 70 | 71 | DECLARE_READ8_MEMBER(fdc_8255_c_r); |
| 71 | 72 | DECLARE_WRITE8_MEMBER(fdc_8255_c_w); |
| 72 | | DECLARE_READ8_MEMBER( upd765_tc_r ); |
| 73 | | DECLARE_WRITE8_MEMBER( fdc_control_w ); |
| 73 | DECLARE_READ8_MEMBER(upd765_tc_r); |
| 74 | DECLARE_WRITE8_MEMBER(fdc_control_w); |
| 74 | 75 | MC6847_GET_CHARROM_MEMBER(get_char_rom) |
| 75 | 76 | { |
| 76 | 77 | return m_p_videoram[0x1000 + (ch & 0x7f) * 16 + line]; |
| r241428 | r241429 | |
| 82 | 83 | UINT8 m_GMODE; |
| 83 | 84 | UINT16 m_page; |
| 84 | 85 | UINT8 *m_work_ram; |
| 86 | virtual void machine_start(); |
| 85 | 87 | virtual void machine_reset(); |
| 86 | 88 | required_device<mc6847_base_device> m_vdg; |
| 87 | 89 | required_device<cpu_device> m_maincpu; |
| r241428 | r241429 | |
| 90 | 92 | required_device<i8255_device> m_pio; |
| 91 | 93 | required_device<ram_device> m_ram; |
| 92 | 94 | required_device<cassette_image_device> m_cass; |
| 95 | required_ioport m_io_joy; |
| 93 | 96 | |
| 94 | 97 | floppy_image_device *m_fd0; |
| 95 | 98 | floppy_image_device *m_fd1; |
| r241428 | r241429 | |
| 110 | 113 | |
| 111 | 114 | static ADDRESS_MAP_START(spc1000_mem, AS_PROGRAM, 8, spc1000_state ) |
| 112 | 115 | ADDRESS_MAP_UNMAP_HIGH |
| 113 | | AM_RANGE( 0x0000, 0x7fff ) AM_READ_BANK("bank1") AM_WRITE_BANK("bank2") |
| 114 | | AM_RANGE( 0x8000, 0xffff ) AM_READ_BANK("bank3") AM_WRITE_BANK("bank4") |
| 116 | AM_RANGE(0x0000, 0x7fff) AM_READ_BANK("bank1") AM_WRITE_BANK("bank2") |
| 117 | AM_RANGE(0x8000, 0xffff) AM_READ_BANK("bank3") AM_WRITE_BANK("bank4") |
| 115 | 118 | ADDRESS_MAP_END |
| 116 | 119 | |
| 117 | 120 | WRITE8_MEMBER(spc1000_state::spc1000_iplk_w) |
| 118 | 121 | { |
| 119 | 122 | m_IPLK = m_IPLK ? 0 : 1; |
| 120 | | if (m_IPLK == 1) { |
| 121 | | UINT8 *mem = memregion("maincpu")->base(); |
| 122 | | membank("bank1")->set_base(mem); |
| 123 | | membank("bank3")->set_base(mem); |
| 124 | | } else { |
| 125 | | UINT8 *ram = m_ram->pointer(); |
| 126 | | membank("bank1")->set_base(ram); |
| 127 | | membank("bank3")->set_base(ram + 0x8000); |
| 128 | | } |
| 123 | membank("bank1")->set_entry(m_IPLK); |
| 124 | membank("bank3")->set_entry(m_IPLK); |
| 129 | 125 | } |
| 130 | 126 | |
| 131 | 127 | READ8_MEMBER(spc1000_state::spc1000_iplk_r) |
| 132 | 128 | { |
| 133 | 129 | m_IPLK = m_IPLK ? 0 : 1; |
| 134 | | if (m_IPLK == 1) { |
| 135 | | UINT8 *mem = memregion("maincpu")->base(); |
| 136 | | membank("bank1")->set_base(mem); |
| 137 | | membank("bank3")->set_base(mem); |
| 138 | | } else { |
| 139 | | UINT8 *ram = m_ram->pointer(); |
| 140 | | membank("bank1")->set_base(ram); |
| 141 | | membank("bank3")->set_base(ram + 0x8000); |
| 142 | | } |
| 130 | membank("bank1")->set_entry(m_IPLK); |
| 131 | membank("bank3")->set_entry(m_IPLK); |
| 132 | |
| 143 | 133 | return 0; |
| 144 | 134 | } |
| 145 | 135 | |
| r241428 | r241429 | |
| 350 | 340 | PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("L") PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') PORT_CHAR(0x0c) |
| 351 | 341 | PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("O") PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') PORT_CHAR(0x0e) |
| 352 | 342 | PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("9 )") PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR(')') |
| 343 | |
| 344 | PORT_START("JOY") |
| 345 | PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_PLAYER(1) |
| 346 | PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(1) |
| 347 | PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(1) |
| 348 | PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(1) |
| 349 | PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(1) |
| 350 | PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_UNUSED) // Button 2? |
| 351 | PORT_BIT(0xc0, IP_ACTIVE_HIGH, IPT_UNUSED) // Cassette related |
| 353 | 352 | INPUT_PORTS_END |
| 354 | 353 | |
| 355 | 354 | |
| 356 | | void spc1000_state::machine_reset() |
| 355 | void spc1000_state::machine_start() |
| 357 | 356 | { |
| 358 | | address_space &space = m_maincpu->space(AS_PROGRAM); |
| 359 | 357 | UINT8 *mem = memregion("maincpu")->base(); |
| 360 | 358 | UINT8 *ram = m_ram->pointer(); |
| 361 | 359 | |
| 362 | | space.install_read_bank(0x0000, 0x7fff, "bank1"); |
| 363 | | space.install_read_bank(0x8000, 0xffff, "bank3"); |
| 360 | // configure and intialize banks 1 & 3 (read banks) |
| 361 | membank("bank1")->configure_entry(0, ram); |
| 362 | membank("bank1")->configure_entry(1, mem); |
| 363 | membank("bank3")->configure_entry(0, ram + 0x8000); |
| 364 | membank("bank3")->configure_entry(1, mem); |
| 365 | membank("bank1")->set_entry(1); |
| 366 | membank("bank3")->set_entry(1); |
| 364 | 367 | |
| 365 | | space.install_write_bank(0x0000, 0x7fff, "bank2"); |
| 366 | | space.install_write_bank(0x8000, 0xffff, "bank4"); |
| 367 | | |
| 368 | | membank("bank1")->set_base(mem); |
| 368 | // intialize banks 2 & 4 (write banks) |
| 369 | 369 | membank("bank2")->set_base(ram); |
| 370 | | membank("bank3")->set_base(mem); |
| 371 | 370 | membank("bank4")->set_base(ram + 0x8000); |
| 371 | } |
| 372 | 372 | |
| 373 | void spc1000_state::machine_reset() |
| 374 | { |
| 375 | |
| 373 | 376 | m_work_ram = auto_alloc_array_clear(machine(), UINT8, 0x10000); |
| 374 | 377 | m_fdccpu->set_input_line_vector(0, 0); |
| 375 | 378 | |
| r241428 | r241429 | |
| 407 | 410 | |
| 408 | 411 | READ8_MEMBER( spc1000_state::porta_r ) |
| 409 | 412 | { |
| 410 | | UINT8 data = 0; |
| 413 | UINT8 data = 0x3f; |
| 411 | 414 | data |= (m_cass->input() > 0.0038) ? 0x80 : 0; |
| 412 | 415 | data |= ((m_cass->get_state() & CASSETTE_MASK_UISTATE) == CASSETTE_PLAY) ? 0x00 : 0x40; |
| 413 | | |
| 416 | data &= ~(m_io_joy->read() & 0x3f); |
| 417 | |
| 414 | 418 | return data; |
| 415 | 419 | } |
| 416 | 420 | |
| r241428 | r241429 | |
| 491 | 495 | MCFG_CASSETTE_FORMATS(spc1000_cassette_formats) |
| 492 | 496 | MCFG_CASSETTE_DEFAULT_STATE(CASSETTE_STOPPED | CASSETTE_SPEAKER_ENABLED | CASSETTE_MOTOR_ENABLED) |
| 493 | 497 | |
| 498 | MCFG_SOFTWARE_LIST_ADD("cass_list", "spc1000_cass") |
| 499 | |
| 494 | 500 | /* internal ram */ |
| 495 | 501 | MCFG_RAM_ADD(RAM_TAG) |
| 496 | 502 | MCFG_RAM_DEFAULT_SIZE("64K") |