diff options
Diffstat (limited to 'src/devices/bus/hp_dio/hp98265a.cpp')
-rw-r--r-- | src/devices/bus/hp_dio/hp98265a.cpp | 308 |
1 files changed, 308 insertions, 0 deletions
diff --git a/src/devices/bus/hp_dio/hp98265a.cpp b/src/devices/bus/hp_dio/hp98265a.cpp new file mode 100644 index 00000000000..78c2065a263 --- /dev/null +++ b/src/devices/bus/hp_dio/hp98265a.cpp @@ -0,0 +1,308 @@ +// license:BSD-3-Clause +// copyright-holders:Sven Schnelle +/*************************************************************************** + + HP98265A SCSI interface + +***************************************************************************/ + +#include "emu.h" + +#define VERBOSE 0 +#include "logmacro.h" +#include "hp98265a.h" +#include "machine/nscsi_bus.h" +#include "machine/nscsi_cd.h" +#include "machine/nscsi_hd.h" +#include "machine/mb87030.h" + +DEFINE_DEVICE_TYPE_NS(HPDIO_98265A, bus::hp_dio, dio16_98265a_device, "hp98265a", "HP98265A SCSI S16 Interface") + +namespace bus { + namespace hp_dio { + +static void scsi_devices(device_slot_interface &device) +{ + device.option_add("cdrom", NSCSI_CDROM); + device.option_add("harddisk", NSCSI_HARDDISK); +} + +void dio16_98265a_device::mb87030_scsi_adapter(device_t *device) +{ + mb87030_device &spc = downcast<mb87030_device &>(*device); + spc.set_clock(8_MHz_XTAL); + + spc.out_irq_callback().set("^^", FUNC(dio16_98265a_device::irq_w)); + spc.out_dreq_callback().set("^^", FUNC(dio16_98265a_device::dmar0_w)); +} + +void dio16_98265a_device::device_add_mconfig(machine_config &config) +{ + NSCSI_BUS(config, m_scsibus, 0); + nscsi_connector &scsicon0(NSCSI_CONNECTOR(config, "scsibus:0", 0)); + scsi_devices(scsicon0); + scsicon0.set_default_option("harddisk"); + + scsi_devices(NSCSI_CONNECTOR(config, "scsibus:1", 0)); + scsi_devices(NSCSI_CONNECTOR(config, "scsibus:2", 0)); + scsi_devices(NSCSI_CONNECTOR(config, "scsibus:3", 0)); + scsi_devices(NSCSI_CONNECTOR(config, "scsibus:4", 0)); + + nscsi_connector &scsicon6(NSCSI_CONNECTOR(config, "scsibus:5", 0)); + scsi_devices(scsicon6); + scsicon6.set_default_option("cdrom"); + + scsi_devices(NSCSI_CONNECTOR(config, "scsibus:6", 0)); + nscsi_connector &scsicon7(NSCSI_CONNECTOR(config, "scsibus:7", 0)); + scsicon7.option_add_internal("mb87030", MB87030); + scsicon7.set_default_option("mb87030"); + scsicon7.set_fixed(true); + scsicon7.set_option_machine_config("mb87030", mb87030_scsi_adapter); +} + +dio16_98265a_device::dio16_98265a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + dio16_98265a_device(mconfig, HPDIO_98265A, tag, owner, clock) +{ +} + +dio16_98265a_device::dio16_98265a_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, type, tag, owner, clock), + device_dio32_card_interface(mconfig, *this), + m_scsibus(*this, "scsibus"), + m_spc(*this, "scsibus:7:mb87030"), + m_sw1(*this, "SW1"), + m_sw2(*this, "SW2"), + m_irq_state(false) +{ +} + +constexpr int REG_SW1_INT_LEVEL_SHIFT = 0; +constexpr int REG_SW1_INT_LEVEL_MASK = 0x3; + +constexpr int REG_SW1_SELECT_CODE_SHIFT = 2; +constexpr int REG_SW1_SELECT_CODE_MASK = 0x1f; + +constexpr int REG_SW2_SCSI_ADDR_SHIFT = 0; +constexpr int REG_SW2_SCSI_ADDR_MASK = 0x07; + +constexpr int REG_SW2_SCSI_PARITY = 0x08; + +static INPUT_PORTS_START(hp98265a_port) + PORT_START("SW1") + PORT_DIPNAME(REG_SW1_INT_LEVEL_MASK << REG_SW1_INT_LEVEL_SHIFT, 0x01, "INT Level") + PORT_DIPSETTING(0 << REG_SW1_INT_LEVEL_SHIFT, "3") + PORT_DIPSETTING(1 << REG_SW1_INT_LEVEL_SHIFT, "4") + PORT_DIPSETTING(2 << REG_SW1_INT_LEVEL_SHIFT, "5") + PORT_DIPSETTING(3 << REG_SW1_INT_LEVEL_SHIFT, "6") + + PORT_DIPNAME(REG_SW1_SELECT_CODE_MASK << REG_SW1_SELECT_CODE_SHIFT, 0x0e << REG_SW1_SELECT_CODE_SHIFT, "Select code") + PORT_DIPSETTING(0 << REG_SW1_SELECT_CODE_SHIFT, "0") + PORT_DIPSETTING(1 << REG_SW1_SELECT_CODE_SHIFT, "1") + PORT_DIPSETTING(2 << REG_SW1_SELECT_CODE_SHIFT, "2") + PORT_DIPSETTING(3 << REG_SW1_SELECT_CODE_SHIFT, "3") + PORT_DIPSETTING(4 << REG_SW1_SELECT_CODE_SHIFT, "4") + PORT_DIPSETTING(5 << REG_SW1_SELECT_CODE_SHIFT, "5") + PORT_DIPSETTING(6 << REG_SW1_SELECT_CODE_SHIFT, "6") + PORT_DIPSETTING(7 << REG_SW1_SELECT_CODE_SHIFT, "7") + PORT_DIPSETTING(8 << REG_SW1_SELECT_CODE_SHIFT, "8") + PORT_DIPSETTING(9 << REG_SW1_SELECT_CODE_SHIFT, "9") + PORT_DIPSETTING(10 << REG_SW1_SELECT_CODE_SHIFT, "10") + PORT_DIPSETTING(11 << REG_SW1_SELECT_CODE_SHIFT, "11") + PORT_DIPSETTING(12 << REG_SW1_SELECT_CODE_SHIFT, "12") + PORT_DIPSETTING(13 << REG_SW1_SELECT_CODE_SHIFT, "13") + PORT_DIPSETTING(14 << REG_SW1_SELECT_CODE_SHIFT, "14") + PORT_DIPSETTING(15 << REG_SW1_SELECT_CODE_SHIFT, "15") + PORT_DIPSETTING(16 << REG_SW1_SELECT_CODE_SHIFT, "16") + PORT_DIPSETTING(17 << REG_SW1_SELECT_CODE_SHIFT, "17") + PORT_DIPSETTING(18 << REG_SW1_SELECT_CODE_SHIFT, "18") + PORT_DIPSETTING(19 << REG_SW1_SELECT_CODE_SHIFT, "19") + PORT_DIPSETTING(20 << REG_SW1_SELECT_CODE_SHIFT, "20") + PORT_DIPSETTING(21 << REG_SW1_SELECT_CODE_SHIFT, "21") + PORT_DIPSETTING(22 << REG_SW1_SELECT_CODE_SHIFT, "22") + PORT_DIPSETTING(23 << REG_SW1_SELECT_CODE_SHIFT, "23") + PORT_DIPSETTING(24 << REG_SW1_SELECT_CODE_SHIFT, "24") + PORT_DIPSETTING(25 << REG_SW1_SELECT_CODE_SHIFT, "25") + PORT_DIPSETTING(26 << REG_SW1_SELECT_CODE_SHIFT, "26") + PORT_DIPSETTING(27 << REG_SW1_SELECT_CODE_SHIFT, "27") + PORT_DIPSETTING(28 << REG_SW1_SELECT_CODE_SHIFT, "28") + PORT_DIPSETTING(29 << REG_SW1_SELECT_CODE_SHIFT, "29") + PORT_DIPSETTING(30 << REG_SW1_SELECT_CODE_SHIFT, "30") + PORT_DIPSETTING(31 << REG_SW1_SELECT_CODE_SHIFT, "31") + + PORT_START("SW2") + PORT_DIPNAME(REG_SW2_SCSI_ADDR_MASK << REG_SW2_SCSI_ADDR_SHIFT, 0x00, "SCSI Address") + PORT_DIPSETTING(0 << REG_SW2_SCSI_ADDR_SHIFT, "0") + PORT_DIPSETTING(1 << REG_SW2_SCSI_ADDR_SHIFT, "1") + PORT_DIPSETTING(2 << REG_SW2_SCSI_ADDR_SHIFT, "2") + PORT_DIPSETTING(3 << REG_SW2_SCSI_ADDR_SHIFT, "3") + PORT_DIPSETTING(4 << REG_SW2_SCSI_ADDR_SHIFT, "4") + PORT_DIPSETTING(5 << REG_SW2_SCSI_ADDR_SHIFT, "5") + PORT_DIPSETTING(6 << REG_SW2_SCSI_ADDR_SHIFT, "6") + PORT_DIPSETTING(7 << REG_SW2_SCSI_ADDR_SHIFT, "7") + + PORT_DIPNAME(REG_SW2_SCSI_PARITY, 0x00, "SCSI Parity") + PORT_DIPSETTING(0, "Off") + PORT_DIPSETTING(REG_SW2_SCSI_PARITY, "On") + +INPUT_PORTS_END + +ioport_constructor dio16_98265a_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(hp98265a_port); +} + +void dio16_98265a_device::device_start() +{ + save_item(NAME(m_irq_state)); + save_item(NAME(m_installed_io)); + save_item(NAME(m_control)); + save_item(NAME(m_dmar0)); + + m_installed_io = false; +} + +void dio16_98265a_device::map(address_map &map) +{ + +} + +void dio16_98265a_device::device_reset() +{ + uint8_t code = m_sw1->read() >> REG_SW1_SELECT_CODE_SHIFT; + code &= REG_SW1_SELECT_CODE_MASK; + + if (!m_installed_io) + { + program_space()->install_readwrite_handler( + 0x600000 + (code * 0x10000), + 0x6007ff + (code * 0x10000), + read16_delegate(FUNC(dio16_98265a_device::io_r), this), + write16_delegate(FUNC(dio16_98265a_device::io_w), this)); + program_space()->install_device(0x6e0020, 0x6e003f, *m_spc, &mb87030_device::map, 0x00ff00ff); + m_installed_io = true; + } + m_control = 0; + m_irq_state = false; + m_spc->reset_w(true); + m_spc->reset_w(false); +} + +int dio16_98265a_device::get_int_level() +{ + return (m_sw1->read() >> REG_SW1_INT_LEVEL_SHIFT) & + REG_SW1_INT_LEVEL_MASK; + +} +READ16_MEMBER(dio16_98265a_device::io_r) +{ + + uint16_t ret = 0xffff; + + switch(offset) { + case 0: /* ID */ + ret = 0x07; + break; + case 1: + ret = m_control | (m_irq_state ? 0x40 : 0) | (get_int_level() << 4); + break; + case 2: + ret = m_spc->data_read(); + break; + case 3: + ret = 0xe8; /* Flush/Configuration register */ + break; + } + LOG("io_r: offset=%02X ret=%02X\n",offset, ret); + return ret; +} + +WRITE16_MEMBER(dio16_98265a_device::io_w) +{ + LOG("io_w: offset=%02X, data=%02X\n", offset, data); + + switch(offset) { + case 0: + device_reset(); + break; + case 1: + if (data & 0x80) + update_irq(m_irq_state); + else + update_irq(false); + m_control = data & 0x8f; + update_dma(); + break; + case 2: + uint8_t val = 0; + if (data & 0x80) + val |= nscsi_device::S_REQ; + if (data & 0x40) + val |= nscsi_device::S_ACK; + if (data & 0x08) + val |= nscsi_device::S_BSY; + if (data & 0x04) + val |= nscsi_device::S_MSG; + if (data & 0x02) + val |= nscsi_device::S_CTL; + if (data & 0x01) + val |= nscsi_device::S_INP; + m_spc->ctrl_write(val, nscsi_device::S_ALL); + break; + } +} + +void dio16_98265a_device::update_irq(bool state) +{ + int irq_level = get_int_level(); + LOG("irq_w: %sassert %d\n", state ? "" : "de", irq_level+3); + + irq3_out(state && irq_level == 0); + irq4_out(state && irq_level == 1); + irq5_out(state && irq_level == 2); + irq6_out(state && irq_level == 3); +} + +WRITE_LINE_MEMBER(dio16_98265a_device::irq_w) +{ + LOG("%s: %s\n", __FUNCTION__, state ? "true" : "false"); + + if ((m_control & 0x80) && m_irq_state != state) + update_irq(state); + + m_irq_state = state; +} + +void dio16_98265a_device::dmack_w_in(int channel, uint8_t data) +{ + if(channel == 0 && !(m_control & REG_CONTROL_DE0)) + return; + if(channel == 1 && !(m_control & REG_CONTROL_DE1)) + return; + + m_spc->dma_w(data); +} + +uint8_t dio16_98265a_device::dmack_r_in(int channel) +{ + if(channel == 0 && !(m_control & REG_CONTROL_DE0)) + return 0xff; + if(channel == 1 && !(m_control & REG_CONTROL_DE1)) + return 0xff; + + return m_spc->dma_r(); +} + +void dio16_98265a_device::update_dma() +{ + dmar0_out((m_control & REG_CONTROL_DE0) && m_dmar0); + dmar1_out((m_control & REG_CONTROL_DE1) && m_dmar0); +} +WRITE_LINE_MEMBER(dio16_98265a_device::dmar0_w) +{ + m_dmar0 = state; + update_dma(); + +} + +} +} |