// license:BSD-3-Clause // copyright-holders:Curt Coder /********************************************************************** Commodore 2031 Single Disk Drive emulation **********************************************************************/ #include "emu.h" #include "c2031.h" //************************************************************************** // MACROS / CONSTANTS //************************************************************************** #define M6502_TAG "ucd5" #define M6522_0_TAG "uab1" #define M6522_1_TAG "ucd4" #define C64H156_TAG "64h156" enum { LED_POWER = 0, LED_ACT }; //************************************************************************** // DEVICE DEFINITIONS //************************************************************************** DEFINE_DEVICE_TYPE(C2031, c2031_device, "c2031", "Commodore 2031") //------------------------------------------------- // ROM( c2031 ) //------------------------------------------------- ROM_START( c2031 ) ROM_REGION( 0x4000, M6502_TAG, 0 ) ROM_LOAD( "901484-03.u5f", 0x0000, 0x2000, CRC(ee4b893b) SHA1(54d608f7f07860f24186749f21c96724dd48bc50) ) ROM_LOAD( "901484-05.u5h", 0x2000, 0x2000, CRC(6a629054) SHA1(ec6b75ecfdd4744e5d57979ef6af990444c11ae1) ) ROM_END //------------------------------------------------- // rom_region - device-specific ROM region //------------------------------------------------- const tiny_rom_entry *c2031_device::device_rom_region() const { return ROM_NAME( c2031 ); } //------------------------------------------------- // ADDRESS_MAP( c2031_mem ) //------------------------------------------------- void c2031_device::c2031_mem(address_map &map) { map(0x0000, 0x07ff).mirror(0x6000).ram(); map(0x1800, 0x180f).mirror(0x63f0).rw(M6522_0_TAG, FUNC(via6522_device::read), FUNC(via6522_device::write)); map(0x1c00, 0x1c0f).mirror(0x63f0).rw(M6522_1_TAG, FUNC(via6522_device::read), FUNC(via6522_device::write)); map(0x8000, 0xbfff).mirror(0x4000).rom().region(M6502_TAG, 0); } WRITE_LINE_MEMBER( c2031_device::via0_irq_w ) { m_via0_irq = state; m_maincpu->set_input_line(INPUT_LINE_IRQ0, (m_via0_irq || m_via1_irq) ? ASSERT_LINE : CLEAR_LINE); } READ8_MEMBER( c2031_device::via0_pa_r ) { /* bit description PA0 DI0 PA1 DI1 PA2 DI2 PA3 DI3 PA4 DI4 PA5 DI5 PA6 DI6 PA7 DI7 */ return m_bus->dio_r(); } WRITE8_MEMBER( c2031_device::via0_pa_w ) { /* bit description PA0 DI0 PA1 DI1 PA2 DI2 PA3 DI3 PA4 DI4 PA5 DI5 PA6 DI6 PA7 DI7 */ m_bus->dio_w(this, data); } READ8_MEMBER( c2031_device::via0_pb_r ) { /* bit description PB0 ATNA PB1 NRFD PB2 NDAC PB3 EOI PB4 T/_R PB5 HD SEL PB6 DAV PB7 _ATN */ uint8_t data = 0; // not ready for data data |= m_bus->nrfd_r() << 1; // not data accepted data |= m_bus->ndac_r() << 2; // end or identify data |= m_bus->eoi_r() << 3; // data valid data |= m_bus->dav_r() << 6; // attention data |= !m_bus->atn_r() << 7; return data; } WRITE8_MEMBER( c2031_device::via0_pb_w ) { /* bit description PB0 ATNA PB1 NRFD PB2 NDAC PB3 EOI PB4 T/_R PB5 HD SEL PB6 DAV PB7 _ATN */ int atna = BIT(data, 0); int nrfd = BIT(data, 1); int ndac = BIT(data, 2); // not ready for data m_nrfd_out = nrfd; // not data accepted m_ndac_out = ndac; // end or identify m_bus->eoi_w(this, BIT(data, 3)); // data valid m_bus->dav_w(this, BIT(data, 6)); // attention acknowledge m_atna = atna; if ((!m_bus->atn_r()) ^ atna) { nrfd = ndac = 0; } m_bus->nrfd_w(this, nrfd); m_bus->ndac_w(this, ndac); m_via0->write_ca2(get_device_number()); } WRITE_LINE_MEMBER( c2031_device::via1_irq_w ) { m_via1_irq = state; m_maincpu->set_input_line(INPUT_LINE_IRQ0, (m_via0_irq || m_via1_irq) ? ASSERT_LINE : CLEAR_LINE); } READ8_MEMBER( c2031_device::via1_pb_r ) { /* bit signal description PB0 PB1 PB2 PB3 PB4 WPS write protect sense PB5 PB6 PB7 SYNC SYNC detect line */ uint8_t data = 0; // write protect sense data |= !m_floppy->wpt_r() << 4; // SYNC detect line data |= m_ga->sync_r() << 7; return data; } WRITE8_MEMBER( c2031_device::via1_pb_w ) { /* bit signal description PB0 STP0 stepping motor bit 0 PB1 STP1 stepping motor bit 1 PB2 MTR motor ON/OFF PB3 ACT drive 0 LED PB4 PB5 DS0 density select 0 PB6 DS1 density select 1 PB7 SYNC SYNC detect line */ // spindle motor m_ga->mtr_w(BIT(data, 2)); // stepper motor m_ga->stp_w(data & 0x03); // activity LED m_led[LED_ACT] = BIT(data, 3); // density select m_ga->ds_w((data >> 5) & 0x03); } //------------------------------------------------- // C64H156_INTERFACE( ga_intf ) //------------------------------------------------- WRITE_LINE_MEMBER( c2031_device::byte_w ) { m_maincpu->set_input_line(M6502_SET_OVERFLOW, state); m_via1->write_ca1(state); } //------------------------------------------------- // SLOT_INTERFACE( c2031_floppies ) //------------------------------------------------- static void c2031_floppies(device_slot_interface &device) { device.option_add("525ssqd", FLOPPY_525_SSQD); } //------------------------------------------------- // FLOPPY_FORMATS( floppy_formats ) //------------------------------------------------- FLOPPY_FORMATS_MEMBER( c2031_device::floppy_formats ) FLOPPY_D64_FORMAT, FLOPPY_G64_FORMAT FLOPPY_FORMATS_END //------------------------------------------------- // device_add_mconfig - add device configuration //------------------------------------------------- MACHINE_CONFIG_START(c2031_device::device_add_mconfig) MCFG_DEVICE_ADD(M6502_TAG, M6502, XTAL(16'000'000)/16) MCFG_DEVICE_PROGRAM_MAP(c2031_mem) MCFG_QUANTUM_PERFECT_CPU(M6502_TAG) MCFG_DEVICE_ADD(M6522_0_TAG, VIA6522, XTAL(16'000'000)/16) MCFG_VIA6522_READPA_HANDLER(READ8(*this, c2031_device, via0_pa_r)) MCFG_VIA6522_READPB_HANDLER(READ8(*this, c2031_device, via0_pb_r)) MCFG_VIA6522_WRITEPA_HANDLER(WRITE8(*this, c2031_device, via0_pa_w)) MCFG_VIA6522_WRITEPB_HANDLER(WRITE8(*this, c2031_device, via0_pb_w)) MCFG_VIA6522_IRQ_HANDLER(WRITELINE(*this, c2031_device, via0_irq_w)) MCFG_DEVICE_ADD(M6522_1_TAG, VIA6522, XTAL(16'000'000)/16) MCFG_VIA6522_READPA_HANDLER(READ8(C64H156_TAG, c64h156_device, yb_r)) MCFG_VIA6522_READPB_HANDLER(READ8(*this, c2031_device, via1_pb_r)) MCFG_VIA6522_WRITEPA_HANDLER(WRITE8(C64H156_TAG, c64h156_device, yb_w)) MCFG_VIA6522_WRITEPB_HANDLER(WRITE8(*this, c2031_device, via1_pb_w)) MCFG_VIA6522_CA2_HANDLER(WRITELINE(C64H156_TAG, c64h156_device, soe_w)) MCFG_VIA6522_CB2_HANDLER(WRITELINE(C64H156_TAG, c64h156_device, oe_w)) MCFG_VIA6522_IRQ_HANDLER(WRITELINE(*this, c2031_device, via1_irq_w)) MCFG_DEVICE_ADD(C64H156_TAG, C64H156, XTAL(16'000'000)) MCFG_64H156_BYTE_CALLBACK(WRITELINE(*this, c2031_device, byte_w)) MCFG_FLOPPY_DRIVE_ADD_FIXED(C64H156_TAG":0", c2031_floppies, "525ssqd", c2031_device::floppy_formats) MACHINE_CONFIG_END //------------------------------------------------- // INPUT_PORTS( c2031 ) //------------------------------------------------- static INPUT_PORTS_START( c2031 ) PORT_START("ADDRESS") PORT_DIPNAME( 0x03, 0x00, "Device Address" ) PORT_DIPSETTING( 0x00, "8" ) PORT_DIPSETTING( 0x01, "9" ) PORT_DIPSETTING( 0x02, "10" ) PORT_DIPSETTING( 0x03, "11" ) INPUT_PORTS_END //------------------------------------------------- // input_ports - device-specific input ports //------------------------------------------------- ioport_constructor c2031_device::device_input_ports() const { return INPUT_PORTS_NAME( c2031 ); } //************************************************************************** // INLINE HELPERS //************************************************************************** //------------------------------------------------- // get_device_number - //------------------------------------------------- inline int c2031_device::get_device_number() { int state = 1; switch ((m_slot->get_address() - 8) & 0x03) { case 0: state = (m_atna && m_nrfd_out); break; case 1: state = m_nrfd_out; break; case 2: state = m_atna; break; case 3: state = 1; break; } return state; } //************************************************************************** // LIVE DEVICE //************************************************************************** //------------------------------------------------- // c2031_device - constructor //------------------------------------------------- c2031_device::c2031_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, C2031, tag, owner, clock) , device_ieee488_interface(mconfig, *this) , m_maincpu(*this, M6502_TAG) , m_via0(*this, M6522_0_TAG) , m_via1(*this, M6522_1_TAG) , m_ga(*this, C64H156_TAG) , m_floppy(*this, C64H156_TAG":0:525ssqd") , m_address(*this, "ADDRESS") , m_led(*this, "led%u", 0U) , m_nrfd_out(1) , m_ndac_out(1) , m_atna(1) , m_ifc(0) , m_via0_irq(0) , m_via1_irq(0) { } //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- void c2031_device::device_start() { m_led.resolve(); // install image callbacks m_ga->set_floppy(m_floppy); // register for state saving save_item(NAME(m_nrfd_out)); save_item(NAME(m_ndac_out)); save_item(NAME(m_atna)); save_item(NAME(m_via0_irq)); save_item(NAME(m_via1_irq)); } //------------------------------------------------- // device_reset - device-specific reset //------------------------------------------------- void c2031_device::device_reset() { m_maincpu->reset(); m_via0->reset(); m_via1->reset(); } //------------------------------------------------- // ieee488_atn_w - //------------------------------------------------- void c2031_device::ieee488_atn(int state) { int nrfd = m_nrfd_out; int ndac = m_ndac_out; m_via0->write_ca1(!state); if ((!state) ^ m_atna) { nrfd = ndac = 0; } m_bus->nrfd_w(this, nrfd); m_bus->ndac_w(this, ndac); } //------------------------------------------------- // ieee488_ifc_w - //------------------------------------------------- void c2031_device::ieee488_ifc(int state) { if (!m_ifc && state) { device_reset(); } m_ifc = state; }