From ba5952efabce8896fd669c1d1c289babbbc9bee4 Mon Sep 17 00:00:00 2001 From: Sven Schnelle <41547105+svenschnelle@users.noreply.github.com> Date: Thu, 18 Jul 2024 00:00:18 +0200 Subject: bus/ieee488: Added HP9133 Floppy/Fixed disk drive. (#12561) * machine/wd2010.cpp: Increased maximum sectors per track to 32. * machine/wd2010.cpp: Implemented multi-sector transfers. * machine/wd2010.cpp: Don't change current cylinder on reset. * cpu/m6809: Added sync acknowledge callback. * hp/hp98x6.cpp: Added HP9133 slot option. --- scripts/src/bus.lua | 2 + src/devices/bus/ieee488/hp9133.cpp | 879 ++++++++++++++++++++++++++++++++++++ src/devices/bus/ieee488/hp9133.h | 18 + src/devices/bus/ieee488/ieee488.cpp | 2 + src/devices/cpu/m6809/base6x09.lst | 2 + src/devices/cpu/m6809/m6809.cpp | 1 + src/devices/cpu/m6809/m6809.h | 7 +- src/devices/machine/wd2010.cpp | 49 +- src/devices/machine/wd2010.h | 2 + src/mame/hp/hp98x6.cpp | 1 + 10 files changed, 950 insertions(+), 13 deletions(-) create mode 100644 src/devices/bus/ieee488/hp9133.cpp create mode 100644 src/devices/bus/ieee488/hp9133.h diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua index 04c56bb019e..15f7ab64734 100644 --- a/scripts/src/bus.lua +++ b/scripts/src/bus.lua @@ -1582,6 +1582,8 @@ if (BUSES["IEEE488"]~=null) then MAME_DIR .. "src/devices/bus/ieee488/shark.h", MAME_DIR .. "src/devices/bus/ieee488/hp9122c.cpp", MAME_DIR .. "src/devices/bus/ieee488/hp9122c.h", + MAME_DIR .. "src/devices/bus/ieee488/hp9133.cpp", + MAME_DIR .. "src/devices/bus/ieee488/hp9133.h", MAME_DIR .. "src/devices/bus/ieee488/hp9895.cpp", MAME_DIR .. "src/devices/bus/ieee488/hp9895.h", MAME_DIR .. "src/devices/bus/ieee488/remote488.cpp", diff --git a/src/devices/bus/ieee488/hp9133.cpp b/src/devices/bus/ieee488/hp9133.cpp new file mode 100644 index 00000000000..bc2b1ff9b72 --- /dev/null +++ b/src/devices/bus/ieee488/hp9133.cpp @@ -0,0 +1,879 @@ +// license:BSD-3-Clause +// copyright-holders: Sven Schnelle +/********************************************************************* + + hp9133.cpp + + HP9133 hard disk/floppy drive + +*********************************************************************/ + +#include "emu.h" +#include "hp9133.h" + +#include "ieee488.h" + +#include "cpu/m6809/m6809.h" +#include "machine/i8291a.h" +#include "machine/wd2010.h" +#include "machine/wd_fdc.h" +#include "imagedev/floppy.h" +#include "imagedev/harddriv.h" + +#include + +//#define VERBOSE 1 +#include "logmacro.h" + +namespace { + +class hp9133_device : public device_t, + public device_ieee488_interface +{ +public: + // construction/destruction + hp9133_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + // device_t implementation + virtual void device_start() override; + virtual void device_reset() override; + virtual ioport_constructor device_input_ports() const override; + virtual const tiny_rom_entry *device_rom_region() const override; + virtual void device_add_mconfig(machine_config &config) override; + + // device_ieee488_interface implementation + virtual void ieee488_eoi(int state) override; + virtual void ieee488_dav(int state) override; + virtual void ieee488_nrfd(int state) override; + virtual void ieee488_ndac(int state) override; + virtual void ieee488_ifc(int state) override; + virtual void ieee488_srq(int state) override; + virtual void ieee488_atn(int state) override; + virtual void ieee488_ren(int state) override; + +private: + static constexpr int IO1_R_BCS_N = 0x10; + static constexpr int IO1_R_BDRQ = 0x20; + static constexpr int IO1_R_HDINT = 0x40; + static constexpr int IO1_R_HDIND = 0x80; + + static constexpr int IO2_R_FDCINT = 0x10; + static constexpr int IO2_R_FDKDCH_N = 0x20; + static constexpr int IO2_R_WRTFLTERR = 0x80; + + static constexpr int IO3_R_FASTDON = 0x20; + static constexpr int IO3_R_SELTST = 0x40; + static constexpr int IO3_R_TEST = 0x80; + + static constexpr int IO1_W_FLT_N = 0x01; + static constexpr int IO1_W_DS1 = 0x02; + static constexpr int IO1_W_BRDY = 0x40; + static constexpr int IO1_W_WDRESET_N = 0x80; + + static constexpr int IO2_W_FDCRES_N = 0x01; + static constexpr int IO2_W_CLRIND_N = 0x04; + static constexpr int IO2_W_DKCHRES_N = 0x08; + static constexpr int IO2_W_FDHDLD_N = 0x10; + static constexpr int IO2_W_FDMOTON_N = 0x20; + static constexpr int IO2_W_FDHDSEL_N = 0x40; + + static constexpr int IO3_W_INTSEL_MASK = 0x03; + static constexpr int IO3_W_INTENBL_N = 0x04; + static constexpr int IO3_W_FAST = 0x10; + static constexpr int IO3_W_DMAR_W_N = 0x20; + static constexpr int IO3_W_HPB_FDC_N = 0x40; + static constexpr int IO3_W_DMA = 0x80; + + required_device m_cpu; + required_device m_gpib; + required_device m_hdc; + required_device m_harddisk; + required_device m_fdc; + required_device m_floppy; + required_ioport m_hpib_addr; + required_ioport m_selftest; + required_ioport m_selftesten; + required_ioport m_volcfg; + required_ioport m_model; + + TIMER_CALLBACK_MEMBER(floppy_motor_timeout); + TIMER_CALLBACK_MEMBER(index_timer); + TIMER_CALLBACK_MEMBER(fast_timer); + + void i8291a_eoi_w(int state); + void i8291a_dav_w(int state); + void i8291a_nrfd_w(int state); + void i8291a_ndac_w(int state); + void i8291a_ifc_w(int state); + void i8291a_srq_w(int state); + void i8291a_atn_w(int state); + void i8291a_ren_w(int state); + void i8291a_dio_w(uint8_t data); + void i8291a_int_w(int state); + void i8291a_drq_w(int state); + void fdc_intrq_w(int state); + void fdc_drq_w(int state); + void hdc_reg_w(offs_t offset, uint8_t data); + uint8_t hdc_reg_r(offs_t offset); + uint8_t i8291a_dio_r(); + void io1_w(uint8_t data); + void io2_w(uint8_t data); + void io3_w(uint8_t data); + uint8_t io1_r(); + uint8_t io2_r(); + uint8_t io3_r(); + + void dma_ram_w(uint8_t data); + uint8_t dma_ram_r(offs_t offset); + void cpu_map(address_map &map); + void floppy_index_cb(floppy_image_device *floppy, int state); + void hdc_bcs_cb(int state); + void hdc_bcr_cb(int state); + void hdc_bdrq_cb(int state); + void hdc_intrq_cb(int state); + void hdc_wg_cb(int state); + void hdc_readwrite_sector(bool write); + void update_intsel(); + void cpu_sync_ack(int state); + + emu_timer *m_motor_timer; + emu_timer *m_index_timer; + emu_timer *m_fast_timer; + uint8_t m_dma_ram[2048]; + int m_dma_addr; + int m_intsel; + int m_head; + + bool m_harddisk_index; + bool m_floppy_index_int; + bool m_intenable; + bool m_dmaenable; + bool m_dmaack_switch; + bool m_dma_rwn; + bool m_gpib_irq; + bool m_gpib_drq; + bool m_fdc_irq; + bool m_fdc_drq; + bool m_cpuirq; + bool m_cpufirq; + bool m_hdc_intrq; + bool m_hdc_bdrq; + bool m_hdc_bcs; + bool m_hdc_wg; + bool m_fast; + + uint16_t m_hdc_cylinder; + uint8_t m_hdc_sdh; + uint8_t m_hdc_sector_count; + uint8_t m_hdc_sector_number; + uint8_t m_hdc_cmd; +}; + +hp9133_device::hp9133_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + device_t{mconfig, HP9133, tag, owner, clock}, + device_ieee488_interface{mconfig, *this}, + m_cpu{*this, "cpu"}, + m_gpib{*this, "i8291a"}, + m_hdc{*this, "wd2010"}, + m_harddisk{*this, "harddisk"}, + m_fdc{*this, "wd2793"}, + m_floppy{*this, "floppy0"}, + m_hpib_addr{*this, "ADDRESS"}, + m_selftest{*this, "SELFTEST"}, + m_selftesten{*this, "SELFTESTEN"}, + m_volcfg{*this, "VOLCFG"}, + m_model{*this, "MODEL"} +{ +} + +static INPUT_PORTS_START(hp9133_port) + PORT_START("ADDRESS") + PORT_CONFNAME(0xf, 0x00, "HPIB address") + PORT_CONFSETTING(0, "0") + PORT_CONFSETTING(1, "1") + PORT_CONFSETTING(2, "2") + PORT_CONFSETTING(3, "3") + PORT_CONFSETTING(4, "4") + PORT_CONFSETTING(5, "5") + PORT_CONFSETTING(6, "6") + PORT_CONFSETTING(7, "7") + PORT_CONFSETTING(8, "8") + PORT_CONFSETTING(9, "9") + PORT_CONFSETTING(10, "10") + PORT_CONFSETTING(11, "11") + PORT_CONFSETTING(12, "12") + PORT_CONFSETTING(13, "13") + PORT_CONFSETTING(14, "14") + PORT_CONFSETTING(15, "15") + + PORT_START("SELFTESTEN") + PORT_CONFNAME(0x1, 0x00, "Selftest Enable") + PORT_CONFSETTING(0x0, DEF_STR(Off)) + PORT_CONFSETTING(0x1, DEF_STR(On)) + + PORT_START("SELFTEST") + PORT_CONFNAME(0xf, 0x00, "Selftest") + PORT_CONFSETTING(0x0, "RAM") + PORT_CONFSETTING(0x1, "ROM checksum") + PORT_CONFSETTING(0x2, "GPIB") + PORT_CONFSETTING(0x3, "FDC Chip") + PORT_CONFSETTING(0x4, "Floppy Seek") + PORT_CONFSETTING(0x5, "Winchester Seek") + PORT_CONFSETTING(0x6, "Floppy Speed") + PORT_CONFSETTING(0x7, "Winchester Speed") + PORT_CONFSETTING(0x8, "Floppy Write Verify") + PORT_CONFSETTING(0x9, "Winchester Write Verify") + PORT_CONFSETTING(0xa, "Floppy Verify") + PORT_CONFSETTING(0xb, "Winchester Verify") + PORT_CONFSETTING(0xc, "Floppy format") + PORT_CONFSETTING(0xd, "HDC Check") + PORT_CONFSETTING(0xe, "WD1100 Check") + PORT_CONFSETTING(0xf, "WD1100 Buffer RAM") + + PORT_START("VOLCFG") + PORT_CONFNAME(0x0f, 0x00, "Volume config") + PORT_CONFSETTING(0, "0") + PORT_CONFSETTING(1, "1") + PORT_CONFSETTING(2, "2") + PORT_CONFSETTING(3, "3") + PORT_CONFSETTING(4, "4") + PORT_CONFSETTING(5, "5") + PORT_CONFSETTING(6, "6") + PORT_CONFSETTING(7, "7") + PORT_CONFSETTING(8, "8") + PORT_CONFSETTING(9, "9") + + PORT_START("MODEL") + PORT_CONFNAME(0x03, 0x00, "Disc Model") + PORT_CONFSETTING(0x0, "9133D") + PORT_CONFSETTING(0x1, "9133L") + PORT_CONFSETTING(0x2, "9133H") +INPUT_PORTS_END + +ioport_constructor hp9133_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(hp9133_port); +} + +TIMER_CALLBACK_MEMBER(hp9133_device::floppy_motor_timeout) +{ + auto *floppy = m_floppy->get_device(); + + floppy->mon_w(1); +} + +void hp9133_device::device_start() +{ + save_item(NAME(m_dma_ram)); + save_item(NAME(m_dma_addr)); + save_item(NAME(m_head)); + save_item(NAME(m_intsel)); + save_item(NAME(m_harddisk_index)); + save_item(NAME(m_floppy_index_int)); + save_item(NAME(m_intenable)); + save_item(NAME(m_dmaenable)); + save_item(NAME(m_dmaack_switch)); + save_item(NAME(m_dma_rwn)); + save_item(NAME(m_gpib_irq)); + save_item(NAME(m_gpib_drq)); + save_item(NAME(m_fdc_irq)); + save_item(NAME(m_fdc_drq)); + save_item(NAME(m_cpuirq)); + save_item(NAME(m_cpufirq)); + save_item(NAME(m_hdc_intrq)); + save_item(NAME(m_hdc_bdrq)); + save_item(NAME(m_hdc_bcs)); + save_item(NAME(m_hdc_wg)); + save_item(NAME(m_fast)); + save_item(NAME(m_hdc_cylinder)); + save_item(NAME(m_hdc_sdh)); + save_item(NAME(m_hdc_sector_count)); + save_item(NAME(m_hdc_sector_number)); + save_item(NAME(m_hdc_cmd)); + + // HP firmware tests whether ECC errors are detected. MAME's WD2010 + // doesn't emulate ECC so patch the ROM to ignore the ECC test result. + uint8_t *rom = memregion("cpu")->base(); + rom[0x279e] = 0x12; + rom[0x279f] = 0x12; + // disable ROM checksum + rom[0x36ea] = 0x20; + + m_motor_timer = timer_alloc(FUNC(hp9133_device::floppy_motor_timeout), this); + m_index_timer = timer_alloc(FUNC(hp9133_device::index_timer), this); + m_index_timer->adjust(attotime::from_hz(3600 / 60)); + m_fast_timer = timer_alloc(FUNC(hp9133_device::fast_timer), this); + auto *floppy = m_floppy->get_device(); + floppy->setup_index_pulse_cb(floppy_image_device::index_pulse_cb(&hp9133_device::floppy_index_cb, this)); +} + +void hp9133_device::device_reset() +{ + std::fill(std::begin(m_dma_ram), std::end(m_dma_ram), 0); + m_dma_addr = 0; + m_intsel = 0; + m_head = 0; + m_harddisk_index = false; + m_floppy_index_int = false; + m_intenable = false; + m_dmaenable = false; + m_dmaack_switch = false; + m_dma_rwn = false; + m_gpib_irq = false; + m_gpib_drq = false; + m_fdc_irq = false; + m_fdc_drq = false; + m_cpuirq = false; + m_cpufirq = false; + m_hdc_intrq = false; + m_hdc_bdrq = false; + m_hdc_bcs = false; + m_hdc_wg = false; + m_fast = false; + m_fdc->set_floppy(m_floppy->get_device()); +} + +void hp9133_device::ieee488_eoi(int state) +{ + m_gpib->eoi_w(state); +} + +void hp9133_device::ieee488_dav(int state) +{ + m_gpib->dav_w(state); +} + +void hp9133_device::ieee488_nrfd(int state) +{ + m_gpib->nrfd_w(state); +} + +void hp9133_device::ieee488_ndac(int state) +{ + m_gpib->ndac_w(state); +} + +void hp9133_device::ieee488_srq(int state) +{ + m_gpib->srq_w(state); +} + +void hp9133_device::ieee488_ifc(int state) +{ + m_gpib->ifc_w(state); +} + +void hp9133_device::ieee488_atn(int state) +{ + m_gpib->atn_w(state); +} + +void hp9133_device::ieee488_ren(int state) +{ + m_gpib->ren_w(state); +} + +void hp9133_device::i8291a_eoi_w(int state) +{ + m_bus->eoi_w(this, state); +} + +void hp9133_device::i8291a_dav_w(int state) +{ + m_bus->dav_w(this, state); +} + +void hp9133_device::i8291a_nrfd_w(int state) +{ + m_bus->nrfd_w(this, state); +} + +void hp9133_device::i8291a_ndac_w(int state) +{ + m_bus->ndac_w(this, state); +} + +void hp9133_device::i8291a_srq_w(int state) +{ + m_bus->srq_w(this, state); +} + +void hp9133_device::i8291a_int_w(int state) +{ + LOG("%s: %d\n", __func__, state); + m_gpib_irq = state; + update_intsel(); +} + +uint8_t hp9133_device::i8291a_dio_r() +{ + uint8_t ret = m_bus->dio_r(); + LOG("%s: %02x\n", __func__, (uint8_t)~ret); + return ret; +} + +void hp9133_device::i8291a_dio_w(uint8_t data) +{ + m_bus->dio_w(this, data); +} + +void hp9133_device::i8291a_drq_w(int state) +{ + LOG("%s: %d\n", __func__, state); + m_gpib_drq = state; + update_intsel(); +} + +TIMER_CALLBACK_MEMBER(hp9133_device::index_timer) +{ + attotime next = attotime::from_hz(3600 / 60); + + m_harddisk_index ^= true; + if (!m_harddisk_index) + next /= 10; + else + next -= next / 10; + m_index_timer->adjust(next); +} + +void hp9133_device::cpu_sync_ack(int state) +{ + LOG("%s: %d: enabled %d\n", __func__, state, m_dmaenable); + if (!m_dmaenable) + return; + if (state) { + if (m_gpib_drq) + m_cpu->set_input_line(M6809_IRQ_LINE, ASSERT_LINE); + } else { + uint8_t data; + if (!m_dma_rwn) { + data = dma_ram_r(0); + m_gpib->dout_w(data); + } else { + data = m_gpib->din_r(); + dma_ram_w(data); + } + m_cpu->set_input_line(M6809_IRQ_LINE, CLEAR_LINE); + LOG("%s: sync data: %02x\n", __func__, data); + if (m_dma_addr > 256) { + LOG("DMA: all bytes transferred\n"); + m_dmaenable = false; + } + } +} + +void hp9133_device::update_intsel() +{ + bool irq = false, firq = false; + + // IRQ Multiplexing: + // +--------+----------+-----------+-------------------+---------+ + // | INTSEL | 0 | 1 | 2 | 3 | + // +--------+----------+-+---------+-------------------+---------+ + // | IRQ# | GPIBDREQ | GND | DMASYNC | FDCDREQ | + // | FIRQ# | GPIBINT | INDEXINT | FDCINT || GPIBINT | FDCINT | + // +--------+---------+-----------+-------------------+----------+ + switch (m_intsel) { + case 0: + irq = m_gpib_drq; + firq = m_gpib_irq; + break; + case 1: + irq = false; + firq = m_floppy_index_int; + break; + case 2: + irq = (m_dmaenable && m_gpib_drq); + firq = m_fdc_irq || m_gpib_irq; + break; + case 3: + irq = m_fdc_drq; + firq = m_fdc_irq; + break; + } + + if (!m_intenable) { + irq = false; + firq = false; + } + + if (m_cpuirq != irq) { + m_cpu->set_input_line(M6809_IRQ_LINE, irq ? ASSERT_LINE : CLEAR_LINE); + m_cpuirq = irq; + } + + if (m_cpufirq != firq) { + m_cpu->set_input_line(M6809_FIRQ_LINE, firq ? ASSERT_LINE : CLEAR_LINE); + m_cpufirq = firq; + } +} + +TIMER_CALLBACK_MEMBER(hp9133_device::fast_timer) +{ + if (!m_fast) + return; + if (m_gpib_drq) { + if (!m_dma_rwn) + m_gpib->dout_w(dma_ram_r(0)); + else + dma_ram_w(m_gpib->din_r()); + } + m_fast_timer->adjust(attotime::from_usec(50)); +} + +void hp9133_device::io1_w(uint8_t data) +{ + // 7 - HDC Rst# + // 6 - HDC BRDY + // 5 - HD Precomp# + // 4 - HD Head 2 + // 3 - HD Head 1 + // 2 - HD Head 0 + // 1 - Active LED + // 0 - Fault LED# + m_head = (data >> 2) & 7; + LOG("%s: %02x Head %d %s%s%s%s\n", __func__, + data, m_head, + (data & IO1_W_BRDY) ? "BRDY " : "", + (data & IO1_W_WDRESET_N) ? "" : "HDCRESET ", + (data & IO1_W_DS1) ? "ACTIVE " : "", + (data & IO1_W_FLT_N) ? "" : "FAULT "); + if (!(data & IO1_W_WDRESET_N)) + m_hdc->reset(); + m_hdc->buffer_ready(data & IO1_W_BRDY); +} + +void hp9133_device::io2_w(uint8_t data) +{ + auto *floppy = m_floppy->get_device(); + + // 7 - HDRecMode + // 6 - FlopHLO#? + // 5 - FlopMotor# + // 4 - FlopSide# + // 3 - Floppy Disk change reset + // 2 - ClrIdxInt + // 1 + // 0 - FDCRst# + LOG("%s: %02x\n", __func__, data); + if (!(data & IO2_W_CLRIND_N)) + m_floppy_index_int = false; + if (data & IO2_W_FDMOTON_N) { + m_motor_timer->adjust(attotime::from_msec(2000)); + } else { + m_motor_timer->reset(); + floppy->mon_w(0); + } + if (!(data & IO2_W_DKCHRES_N)) + m_floppy->get_device()->dskchg_w(false); + m_floppy->get_device()->ss_w((data & IO2_W_FDHDSEL_N) ? 0 : 1); + if (!(data & IO2_W_FDCRES_N)) + m_fdc->reset(); +} + +void hp9133_device::io3_w(uint8_t data) +{ + // 7 - DMA enable + // 6 - 1 GPIPACK, 0 FDCACK + // 5 - Write Precomp? + // 4 - FAST enable? + // 3 - + // 2 - Interrupt Enable + // 0:1 - Interrupt select + + m_dmaenable = data & IO3_W_DMA; + m_dmaack_switch = data & IO3_W_HPB_FDC_N; + m_dma_rwn = data & IO3_W_DMAR_W_N; + m_intenable = !(data & IO3_W_INTENBL_N); + m_fast = data & IO3_W_FAST; + m_intsel = data & IO3_W_INTSEL_MASK; + + LOG("%s: %02x = INTSEL %d, INT %d DMA %d DMA start %d DMA ACK %s\n", __func__, + data, m_intsel, m_intenable, m_dmaenable, BIT(data, 4), + m_dmaack_switch ? "GPIB" : "FDC"); + update_intsel(); + if (m_fast) + m_fast_timer->adjust(attotime::from_usec(1000)); + else + m_fast_timer->adjust(attotime::never); +} + +uint8_t hp9133_device::io1_r() +{ + uint8_t ret; + + // 7 - hdindex + // 6 - HDC int + // 5 - HDC DRQ + // 4 - HDC BCS + // 3 - 0 Ident + ret = m_model->read() ^ 0xf; + if (m_harddisk_index) + ret |= IO1_R_HDIND; + if (m_hdc_intrq) + ret |= IO1_R_HDINT; + if (m_hdc_bdrq) + ret |= IO1_R_BDRQ; + if (m_hdc_bcs) + ret |= IO1_R_BCS_N; + if (!machine().side_effects_disabled()) + LOG("%s: %02x\n", __func__, ret); + return ret; +} + +uint8_t hp9133_device::io2_r() +{ + uint8_t ret = 0; + + // 7 - Write Fault Latch + // 5 - FlopDC# + // 4 - FDC interrupt + // 3 - 0 GPIB Address + + if (m_selftesten->read()) { + ret = (m_selftest->read() & 7) ^ 0xf; + } else { + ret = m_hpib_addr->read() ^ 0xf; + } + if (m_fdc_irq) + ret |= IO2_R_FDCINT; + if (!m_floppy->get_device()->dskchg_r()) + ret |= IO2_R_FDKDCH_N; + if (!machine().side_effects_disabled()) + LOG("%s: %02x\n", __func__, ret); + return ret; +} + +uint8_t hp9133_device::io3_r() +{ + uint8_t ret = 0; + + // 7 - self test enable + // 6 - self test MSB + // 5 - FASTDON + // 3-0 Volume switch + ret = m_volcfg->read() ^ 0xf; + if (!m_selftesten->read()) { + ret |= IO3_R_TEST; + } else { + if (m_selftest->read() & 8) + ret |= IO3_R_SELTST; + } + + if (m_dma_addr >= 256) + ret |= IO3_R_FASTDON; + if (!machine().side_effects_disabled()) + LOG("%s: %02x\n", __func__, ret); + return ret; +} + +void hp9133_device::dma_ram_w(uint8_t data) +{ + LOG("%s: %03x = %02x\n", __func__, m_dma_addr, data); + if (m_dma_addr < sizeof(m_dma_ram)) + m_dma_ram[m_dma_addr++] = data; +} + +uint8_t hp9133_device::dma_ram_r(offs_t offset) +{ + if (m_dma_addr >= sizeof(m_dma_ram)) + return 0; + uint8_t ret = m_dma_ram[m_dma_addr]; + if (!machine().side_effects_disabled()) { + LOG("%s: %03x = %02x\n", __func__, m_dma_addr, ret); + m_dma_addr++; + } + return ret; +} + +static int sdh_sector_size(uint8_t sdh) +{ + constexpr int sizes[4] = { 256, 512, 1024, 128 }; + + return sizes[(sdh >> 5) & 3]; +} + +static int sdh_devsel(uint8_t sdh) +{ + return (sdh >> 3) & 3; +} + +void hp9133_device::hdc_readwrite_sector(bool write) +{ + int sector = m_hdc->read(3); + uint32_t lba; + + if (sdh_devsel(m_hdc_sdh)) + return; + if (sdh_sector_size(m_hdc_sdh) != 256) + return; + if (!m_harddisk->exists()) + return; + const auto &info = m_harddisk->get_info(); + lba = (m_hdc_cylinder * info.heads + m_head) * info.sectors + sector; + LOG("%s: %s cyl %4d, head %d, sector %2d lba %8d\n", __func__, + write ? "WRITE" : "READ ", m_hdc_cylinder, m_head, sector, lba); + if (write) { + m_harddisk->write(lba, m_dma_ram); + } else { + m_harddisk->read(lba, m_dma_ram); + m_dma_addr = 256; + } +} + +void hp9133_device::fdc_intrq_w(int state) +{ + m_fdc_irq = state; + update_intsel(); +} + +void hp9133_device::fdc_drq_w(int state) +{ + m_fdc_drq = state; + update_intsel(); +} + +void hp9133_device::floppy_index_cb(floppy_image_device *floppy, int state) +{ + m_fdc->index_callback(floppy, state); + if (state) + m_floppy_index_int = true; + update_intsel(); +} + +void hp9133_device::hdc_bcs_cb(int state) +{ + m_hdc_bcs = state; +} + +void hp9133_device::hdc_bcr_cb(int state) +{ + m_dma_addr = 0; +} + +void hp9133_device::hdc_bdrq_cb(int state) +{ + bool is_read = m_hdc_cmd >> 4 == 2; + + m_hdc_bdrq = state; + if (state && is_read) + hdc_readwrite_sector(false); +} + + +void hp9133_device::hdc_wg_cb(int state) +{ + bool is_write = (m_hdc_cmd >> 4) == 3; + + m_hdc_wg = state; + if (state && is_write) + hdc_readwrite_sector(true); +} + +void hp9133_device::hdc_intrq_cb(int state) +{ + m_hdc_intrq = state; + update_intsel(); +} + +uint8_t hp9133_device::hdc_reg_r(offs_t offset) +{ + return m_hdc->read(offset); +} + +void hp9133_device::hdc_reg_w(offs_t offset, uint8_t data) +{ + switch (offset) { + case 2: + m_hdc_sector_count = data; + break; + case 3: + m_hdc_sector_number = data; + break; + case 4: + m_hdc_cylinder &= ~0xff; + m_hdc_cylinder |= data; + break; + case 5: + m_hdc_cylinder &= ~0xff00; + m_hdc_cylinder |= data << 8; + break; + case 6: + m_hdc_sdh = data; + break; + case 7: + m_hdc_cmd = data; + break; + } + m_hdc->write(offset, data); +} + +void hp9133_device::cpu_map(address_map &map) +{ + map(0x0000, 0x0007).m(m_gpib, FUNC(i8291a_device::map)); + map(0x0008, 0x000b).rw(m_fdc, FUNC(wd2793_device::read), FUNC(wd2793_device::write)); + map(0x0010, 0x0017).rw(FUNC(hp9133_device::hdc_reg_r), FUNC(hp9133_device::hdc_reg_w)); + map(0x0020, 0x0027).rw(FUNC(hp9133_device::dma_ram_r), FUNC(hp9133_device::dma_ram_w)); + map(0x0028, 0x002f).lw8(NAME([this] (u8 data) { LOG("clear ram addr\n"); m_dma_addr = 0; })); + map(0x003f, 0x003f).nopw(); + map(0x0040, 0x0040).rw(FUNC(hp9133_device::io1_r), FUNC(hp9133_device::io1_w)).mirror(0x3f3f); + map(0x0080, 0x0080).rw(FUNC(hp9133_device::io2_r), FUNC(hp9133_device::io2_w)).mirror(0x3f3f); + map(0x00c0, 0x00c0).rw(FUNC(hp9133_device::io3_r), FUNC(hp9133_device::io3_w)).mirror(0x3f3f); + map(0x4000, 0x47ff).ram().mirror(0x3800); + map(0x8000, 0xffff).rom().region("cpu", 0); +} + +static void hp9133_floppies(device_slot_interface &device) +{ + device.option_add("d32w", SONY_OA_D32W); +} + +void hp9133_device::device_add_mconfig(machine_config &config) +{ + MC6809(config, m_cpu, XTAL(8'000'000)); + m_cpu->set_addrmap(AS_PROGRAM, &hp9133_device::cpu_map); + m_cpu->sync_acknowledge_write().set(FUNC(hp9133_device::cpu_sync_ack)); + + I8291A(config, m_gpib, XTAL(8'000'000)); + m_gpib->eoi_write().set(FUNC(hp9133_device::i8291a_eoi_w)); + m_gpib->dav_write().set(FUNC(hp9133_device::i8291a_dav_w)); + m_gpib->nrfd_write().set(FUNC(hp9133_device::i8291a_nrfd_w)); + m_gpib->ndac_write().set(FUNC(hp9133_device::i8291a_ndac_w)); + m_gpib->srq_write().set(FUNC(hp9133_device::i8291a_srq_w)); + m_gpib->dio_write().set(FUNC(hp9133_device::i8291a_dio_w)); + m_gpib->dio_read().set(FUNC(hp9133_device::i8291a_dio_r)); + m_gpib->int_write().set(FUNC(hp9133_device::i8291a_int_w)); + m_gpib->dreq_write().set(FUNC(hp9133_device::i8291a_drq_w)); + + WD2010(config, m_hdc, XTAL(5'000'000)); + m_hdc->in_sc_callback().set_constant(1); + m_hdc->in_drdy_callback().set_constant(1); + m_hdc->out_bcs_callback().set(FUNC(hp9133_device::hdc_bcs_cb)); + m_hdc->out_bcr_callback().set(FUNC(hp9133_device::hdc_bcr_cb)); + m_hdc->out_bdrq_callback().set(FUNC(hp9133_device::hdc_bdrq_cb)); + m_hdc->out_intrq_callback().set(FUNC(hp9133_device::hdc_intrq_cb)); + m_hdc->out_wg_callback().set(FUNC(hp9133_device::hdc_wg_cb)); + HARDDISK(config, m_harddisk); + + WD2793(config, m_fdc, XTAL(2'000'000)); + m_fdc->intrq_wr_callback().set(FUNC(hp9133_device::fdc_intrq_w)); + m_fdc->drq_wr_callback().set(FUNC(hp9133_device::fdc_drq_w)); + FLOPPY_CONNECTOR(config, "floppy0", hp9133_floppies, "d32w", + floppy_image_device::default_mfm_floppy_formats, true).enable_sound(true); +} + +ROM_START(hp9133) + ROM_REGION(0x8000, "cpu", 0) + ROM_LOAD("09133-89110_9133.bin", 0x0000, 0x4000, CRC(d7ff6b3e) SHA1(aeeae063fa43c3b163ba5c176f31df6ec1b73d0d)) + ROM_LOAD("09133-89210_9133.bin", 0x4000, 0x4000, CRC(08f825e2) SHA1(61766b1f64473c17f01cbc97bd817f6076827d6a)) +ROM_END + +const tiny_rom_entry *hp9133_device::device_rom_region() const +{ + return ROM_NAME(hp9133); +} + +} // anonymous namespace + +DEFINE_DEVICE_TYPE_PRIVATE(HP9133, device_ieee488_interface, hp9133_device, "hp9133", "HP9133 Floppy/Fixed disk drive") diff --git a/src/devices/bus/ieee488/hp9133.h b/src/devices/bus/ieee488/hp9133.h new file mode 100644 index 00000000000..b137596c004 --- /dev/null +++ b/src/devices/bus/ieee488/hp9133.h @@ -0,0 +1,18 @@ +// license:BSD-3-Clause +// copyright-holders: Sven Schnelle +/********************************************************************* + + hp9133.h + + HP9133 Fixed disk drive + +*********************************************************************/ + +#ifndef MAME_BUS_IEEE488_HP9133_H +#define MAME_BUS_IEEE488_HP9133_H + +#pragma once + +DECLARE_DEVICE_TYPE(HP9133, device_ieee488_interface) + +#endif // MAME_BUS_IEEE488_HP9133_H diff --git a/src/devices/bus/ieee488/ieee488.cpp b/src/devices/bus/ieee488/ieee488.cpp index 94a93e424e4..686fc0ae5ad 100644 --- a/src/devices/bus/ieee488/ieee488.cpp +++ b/src/devices/bus/ieee488/ieee488.cpp @@ -421,11 +421,13 @@ void cbm_ieee488_devices(device_slot_interface &device) // slot devices #include "hp9122c.h" +#include "hp9133.h" #include "hp9895.h" void hp_ieee488_devices(device_slot_interface &device) { device.option_add("hp9122c", HP9122C); + device.option_add("hp9133", HP9133); device.option_add("hp9895", HP9895); } diff --git a/src/devices/cpu/m6809/base6x09.lst b/src/devices/cpu/m6809/base6x09.lst index ed000701cc2..c3ef727d49d 100644 --- a/src/devices/cpu/m6809/base6x09.lst +++ b/src/devices/cpu/m6809/base6x09.lst @@ -442,6 +442,7 @@ SYNC: // is disabled, execution continues with the next instruction. @dummy_read_opcode_arg(0); + m_syncack_write_func(1); while(!m_nmi_asserted && !m_firq_line && !m_irq_line) { // massaging the PC this way makes the debugger's behavior more @@ -453,6 +454,7 @@ SYNC: // unmassage... m_pc.w++; } + m_syncack_write_func(0); @eat(1); return; diff --git a/src/devices/cpu/m6809/m6809.cpp b/src/devices/cpu/m6809/m6809.cpp index 18152c9b09c..83e4662a855 100644 --- a/src/devices/cpu/m6809/m6809.cpp +++ b/src/devices/cpu/m6809/m6809.cpp @@ -145,6 +145,7 @@ DEFINE_DEVICE_TYPE(M6809, m6809_device, "m6809", "MC6809 (legacy)") m6809_base_device::m6809_base_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, const device_type type, int divider) : cpu_device(mconfig, type, tag, owner, clock), m_lic_func(*this), + m_syncack_write_func(*this), m_program_config("program", ENDIANNESS_BIG, 8, 16), m_sprogram_config("decrypted_opcodes", ENDIANNESS_BIG, 8, 16), m_clock_divider(divider) diff --git a/src/devices/cpu/m6809/m6809.h b/src/devices/cpu/m6809/m6809.h index aeebc6066cc..df9f74d1882 100644 --- a/src/devices/cpu/m6809/m6809.h +++ b/src/devices/cpu/m6809/m6809.h @@ -26,6 +26,8 @@ DECLARE_DEVICE_TYPE(M6809, m6809_device) // Used by core CPU interface class m6809_base_device : public cpu_device { +public: + auto sync_acknowledge_write() { return m_syncack_write_func.bind(); } protected: // construction/destruction m6809_base_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, const device_type type, int divider); @@ -171,10 +173,11 @@ protected: bool m_lds_encountered; int m_icount; int m_addressing_mode; - PAIR16 m_ea; // effective address + PAIR16 m_ea; // effective address // Callbacks - devcb_write_line m_lic_func; // LIC pin on the 6809E + devcb_write_line m_lic_func; // LIC pin on the 6809E + devcb_write_line m_syncack_write_func; // Indicates sync acknowledge buscycle // eat cycles inline void eat(int cycles) { m_icount -= cycles; } diff --git a/src/devices/machine/wd2010.cpp b/src/devices/machine/wd2010.cpp index 28f7b8ebbc3..6f47f4ba291 100644 --- a/src/devices/machine/wd2010.cpp +++ b/src/devices/machine/wd2010.cpp @@ -38,7 +38,7 @@ UNIMPLEMENTED FEATURES : #include "emu.h" #include "wd2010.h" -#define VERBOSE 1 +//#define VERBOSE 1 #include "logmacro.h" #include @@ -57,7 +57,8 @@ UNIMPLEMENTED FEATURES : // #define CYLINDER_HIGH_MASK 0x03 // -------------------------------------------------------- -#define MAX_MFM_SECTORS 17 // STANDARD MFM SECTORS/TRACK +// Maximum sector number before ID not found is returned. +#define MAX_MFM_SECTORS 32 // -------------------------------------------------------- // Typical access times for MFM drives (as listed in ST412_OEM Manual_Apr82) @@ -187,6 +188,8 @@ void wd2010_device::device_start() m_complete_write_timer = timer_alloc(FUNC(wd2010_device::complete_write), this); m_deassert_write_timer = timer_alloc(FUNC(wd2010_device::deassert_write), this); m_deassert_read_timer = timer_alloc(FUNC(wd2010_device::deassert_read), this); + m_next_sector_timer = timer_alloc(FUNC(wd2010_device::next_sector), this); + m_present_cylinder = 0; // start somewhere } @@ -199,8 +202,6 @@ void wd2010_device::device_reset() m_out_intrq_cb(CLEAR_LINE); buffer_ready(false); - - m_present_cylinder = 0; // start somewhere } @@ -231,10 +232,10 @@ uint8_t wd2010_device::read(offs_t offset) if (offset == TASK_FILE_SDH_REGISTER) { - logerror("(READ) %s WD2010 SDH: %u\n", machine().describe_context(), data); - logerror("(READ) %s WD2010 Head: %u\n", machine().describe_context(), HEAD); - logerror("(READ) %s WD2010 Drive: %u\n", machine().describe_context(), DRIVE); - logerror("(READ) %s WD2010 Sector Size: %u\n", machine().describe_context(), SECTOR_SIZE); + LOG("(READ) %s WD2010 SDH: %u\n", machine().describe_context(), data); + LOG("(READ) %s WD2010 Head: %u\n", machine().describe_context(), HEAD); + LOG("(READ) %s WD2010 Drive: %u\n", machine().describe_context(), DRIVE); + LOG("(READ) %s WD2010 Sector Size: %u\n", machine().describe_context(), SECTOR_SIZE); } break; @@ -582,9 +583,7 @@ void wd2010_device::read_sector(uint8_t data) // FLAG "M" SET? (MULTIPLE SECTOR TRANSFERS) if (data & 4) - logerror("WD2010 (READ): MULTIPLE SECTOR READ (M = 1).\n"); - - // Assume: NO "M" (MULTIPLE SECTOR TRANSFERS) + LOG("WD2010 (READ): MULTIPLE SECTOR READ (M = 1).\n"); m_out_bcs_cb(0); // deactivate BCS (!) @@ -906,6 +905,23 @@ TIMER_CALLBACK_MEMBER(wd2010_device::deassert_read) } } +TIMER_CALLBACK_MEMBER(wd2010_device::next_sector) +{ + uint8_t cmd = m_task_file[TASK_FILE_COMMAND]; + + switch (cmd & 0xf0) + { + case 0x20: + read_sector(cmd); + break; + case 0x30: + write_sector(cmd); + break; + default: + break; + } +} + // Called by timer callbacks - void wd2010_device::complete_immediate(uint8_t status) { @@ -919,6 +935,17 @@ void wd2010_device::complete_immediate(uint8_t status) m_out_bdrq_cb(0); } + uint8_t cmd = m_task_file[TASK_FILE_COMMAND] & 0xf4; + if ((cmd == 0x24) || (cmd == 0x34)) + { + if (--m_task_file[TASK_FILE_SECTOR_COUNT] > 1) + { + m_task_file[TASK_FILE_SECTOR_NUMBER]++; + m_next_sector_timer->adjust(attotime::from_usec(100)); + return; + } + } + // Set current status (M_STATUS) m_status = status & (255 - STATUS_DWC); // minus "unused" bit 2 (DWC) diff --git a/src/devices/machine/wd2010.h b/src/devices/machine/wd2010.h index a39935326ba..de43f23e002 100644 --- a/src/devices/machine/wd2010.h +++ b/src/devices/machine/wd2010.h @@ -54,6 +54,7 @@ protected: TIMER_CALLBACK_MEMBER(complete_write); TIMER_CALLBACK_MEMBER(deassert_write); TIMER_CALLBACK_MEMBER(deassert_read); + TIMER_CALLBACK_MEMBER(next_sector); private: void compute_correction(uint8_t data); @@ -91,6 +92,7 @@ private: emu_timer *m_complete_write_timer; emu_timer *m_deassert_write_timer; emu_timer *m_deassert_read_timer; + emu_timer *m_next_sector_timer; void complete_write_sector(uint8_t status); void complete_cmd(uint8_t status); diff --git a/src/mame/hp/hp98x6.cpp b/src/mame/hp/hp98x6.cpp index 7bad24e88a0..2ff1cac4c96 100644 --- a/src/mame/hp/hp98x6.cpp +++ b/src/mame/hp/hp98x6.cpp @@ -202,6 +202,7 @@ void hp9816_state::hp9816(machine_config &config) ieee.atn_callback().set(m_hpib , FUNC(tms9914_device::atn_w)); ieee.ren_callback().set(m_hpib , FUNC(tms9914_device::ren_w)); IEEE488_SLOT(config, "ieee_rem", 0, remote488_devices, nullptr); + IEEE488_SLOT(config, "ieee0", 0, hp_ieee488_devices, nullptr); INS8250(config, m_uart, UART_CLOCK); m_uart->out_int_callback().set(FUNC(hp9816_state::uart_irq_w)); -- cgit v1.2.3