diff --git a/scripts/src/machine.lua b/scripts/src/machine.lua index 7d96d01761e..cfb5d1d3c58 100644 --- a/scripts/src/machine.lua +++ b/scripts/src/machine.lua @@ -70,6 +70,18 @@ files { } +--------------------------------------------------- +-- +--@src/devices/machine/acorn_bmu.h,MACHINES["ACORN_BMU"] = true +--------------------------------------------------- + +if (MACHINES["ACORN_BMU"]~=null) then + files { + MAME_DIR .. "src/devices/machine/acorn_bmu.cpp", + MAME_DIR .. "src/devices/machine/acorn_bmu.h", + } +end + -------------------------------------------------- -- --@src/devices/machine/acorn_ioc.h,MACHINES["ACORN_IOC"] = true @@ -82,6 +94,18 @@ if (MACHINES["ACORN_IOC"]~=null) then } end +--------------------------------------------------- +-- +--@src/devices/machine/acorn_lc.h,MACHINES["ACORN_LC"] = true +--------------------------------------------------- + +if (MACHINES["ACORN_LC"]~=null) then + files { + MAME_DIR .. "src/devices/machine/acorn_lc.cpp", + MAME_DIR .. "src/devices/machine/acorn_lc.h", + } +end + -------------------------------------------------- -- --@src/devices/machine/acorn_memc.h,MACHINES["ACORN_MEMC"] = true @@ -3179,6 +3203,7 @@ if (MACHINES["SPG290"]~=null) then MAME_DIR .. "src/devices/machine/spg290_ppu.h", } end + --------------------------------------------------- -- --@src/devices/machine/stvcd.h,MACHINES["STVCD"] = true @@ -3452,6 +3477,30 @@ if (MACHINES["UCB1200"]~=null) then } end +--------------------------------------------------- +-- +--@src/devices/machine/upc82c710.h,MACHINES["UPC82C710"] = true +--------------------------------------------------- + +if (MACHINES["UPC82C710"]~=null) then + files { + MAME_DIR .. "src/devices/machine/upc82c710.cpp", + MAME_DIR .. "src/devices/machine/upc82c710.h", + } +end + +--------------------------------------------------- +-- +--@src/devices/machine/upc82c711.h,MACHINES["UPC82C711"] = true +--------------------------------------------------- + +if (MACHINES["UPC82C711"]~=null) then + files { + MAME_DIR .. "src/devices/machine/upc82c711.cpp", + MAME_DIR .. "src/devices/machine/upc82c711.h", + } +end + --------------------------------------------------- -- --@src/devices/machine/upd1990a.h,MACHINES["UPD1990A"] = true diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index 9e3b26b1748..782a5c9d55a 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -304,7 +304,7 @@ SOUNDS["VRC6"] = true --SOUNDS["AC97"] = true --SOUNDS["ES1373"] = true SOUNDS["L7A1045"] = true ---SOUNDS["AD1848"] = true +SOUNDS["AD1848"] = true SOUNDS["UPD1771"] = true SOUNDS["GB_SOUND"] = true SOUNDS["PCD3311"] = true @@ -460,7 +460,9 @@ MACHINES["68681"] = true MACHINES["7200FIFO"] = true MACHINES["8530SCC"] = true MACHINES["ACIA6850"] = true +MACHINES["ACORN_BMU"] = true MACHINES["ACORN_IOC"] = true +MACHINES["ACORN_LC"] = true MACHINES["ACORN_MEMC"] = true MACHINES["ACORN_VIDC"] = true MACHINES["ADC0804"] = true @@ -730,6 +732,8 @@ MACHINES["TTL74543"] = true MACHINES["TTL7474"] = true MACHINES["TUBE"] = true MACHINES["UCB1200"] = true +MACHINES["UPC82C710"] = true +MACHINES["UPC82C711"] = true MACHINES["UPD1990A"] = true MACHINES["UPD4991A"] = true --MACHINES["UPD4992"] = true diff --git a/src/devices/machine/acorn_bmu.cpp b/src/devices/machine/acorn_bmu.cpp new file mode 100644 index 00000000000..3ff529525ff --- /dev/null +++ b/src/devices/machine/acorn_bmu.cpp @@ -0,0 +1,263 @@ +// license:BSD-3-Clause +// copyright-holders:Nigel Barnes +/********************************************************************* + + Acorn Battery Management Unit + + The BMU is actually a 4-bit Hitachi HD404304F MCU, marked as + BMU 0290032. + + TODO: + - configurable status + - callback when battery low + +*********************************************************************/ + +#include "emu.h" +#include "acorn_bmu.h" + +#define LOG_DATA (1 << 1) +#define LOG_LINE (1 << 2) + +#define VERBOSE (0) +#include "logmacro.h" + + +DEFINE_DEVICE_TYPE(ACORN_BMU, acorn_bmu_device, "acorn_bmu", "Acorn Battery Management Unit") + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// acorn_bmu_device - constructor +//------------------------------------------------- + +acorn_bmu_device::acorn_bmu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, ACORN_BMU, tag, owner, clock) + , m_slave_address(BMU_SLAVE_ADDRESS) + , m_scl(0) + , m_sdaw(0) + , m_sdar(1) + , m_state(STATE_IDLE) + , m_bits(0) + , m_shift(0) + , m_devsel(0) + , m_register(0) + , m_estimate(0) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void acorn_bmu_device::device_start() +{ + save_item(NAME(m_scl)); + save_item(NAME(m_sdaw)); + save_item(NAME(m_sdar)); + save_item(NAME(m_state)); + save_item(NAME(m_bits)); + save_item(NAME(m_shift)); + save_item(NAME(m_devsel)); + save_item(NAME(m_register)); + save_item(NAME(m_slave_address)); + save_item(NAME(m_estimate)); +} + + +//************************************************************************** +// READ/WRITE HANDLERS +//************************************************************************** + +WRITE_LINE_MEMBER(acorn_bmu_device::scl_w) +{ + if (m_scl != state) + { + m_scl = state; + LOGMASKED(LOG_LINE, "set_scl_line %d\n", m_scl); + + switch (m_state) + { + case STATE_DEVSEL: + case STATE_REGISTER: + case STATE_DATAIN: + if (m_bits < 8) + { + if (m_scl) + { + m_shift = ((m_shift << 1) | m_sdaw) & 0xff; + m_bits++; + } + } + else + { + if (m_scl) + { + switch (m_state) + { + case STATE_DEVSEL: + m_devsel = m_shift; + + if ((m_devsel & 0xfe) != m_slave_address) + { + LOGMASKED(LOG_DATA, "devsel %02x: not this device\n", m_devsel); + m_state = STATE_IDLE; + } + else if ((m_devsel & 1) == 0) + { + LOGMASKED(LOG_DATA, "devsel %02x: write\n", m_devsel); + m_state = STATE_REGISTER; + } + else + { + LOGMASKED(LOG_DATA, "devsel %02x: read\n", m_devsel); + m_state = STATE_DATAOUT; + } + break; + + case STATE_REGISTER: + m_register = m_shift; + + LOGMASKED(LOG_DATA, "register %02x\n", m_register); + + m_state = STATE_DATAIN; + break; + + case STATE_DATAIN: + LOGMASKED(LOG_DATA, "register[ %02x ] <- %02x\n", m_register, m_shift); + + switch (m_register) + { + case BMU_CHARGE_ESTIMATE: + m_estimate = m_shift; + break; + } + + m_register++; + break; + } + + m_bits++; + } + else + { + if (m_bits == 8) + { + m_sdar = 0; + } + else + { + m_bits = 0; + m_sdar = 1; + } + } + } + break; + + case STATE_DATAOUT: + if (m_bits < 8) + { + if (m_scl) + { + if (m_bits == 0) + { + switch (m_register) + { + case BMU_VERSION: + m_shift = 0x03; + break; + + case BMU_STATUS: + m_shift = STATUS_CHARGER_PRESENT | STATUS_BATTERY_PRESENT | STATUS_CHARGE_STATE_KNOWN | STATUS_LID_OPEN; + break; + + case BMU_CAPACITY_USED: + m_shift = 0x40; + break; + + case BMU_CHARGE_ESTIMATE: + m_shift = m_estimate; + break; + + case BMU_COMMAND: + m_shift = 0; + break; + } + + LOGMASKED(LOG_DATA, "register[ %02x ] -> %02x\n", m_register, m_shift); + m_register++; + } + + m_sdar = (m_shift >> 7) & 1; + + m_shift = (m_shift << 1) & 0xff; + m_bits++; + } + } + else + { + if (m_scl) + { + if (m_sdaw) + { + LOGMASKED(LOG_DATA, "nack\n"); + m_state = STATE_IDLE; + } + + m_bits++; + } + else + { + if (m_bits == 8) + { + m_sdar = 1; + } + else + { + m_bits = 0; + } + } + } + break; + } + } +} + +WRITE_LINE_MEMBER(acorn_bmu_device::sda_w) +{ + state &= 1; + if (m_sdaw != state) + { + LOGMASKED(LOG_LINE, "set sda %d\n", state); + m_sdaw = state; + + if (m_scl) + { + if (m_sdaw) + { + LOGMASKED(LOG_DATA, "stop\n"); + m_state = STATE_IDLE; + } + else + { + LOGMASKED(LOG_DATA, "start\n"); + m_state = STATE_DEVSEL; + m_bits = 0; + } + + m_sdar = 1; + } + } +} + +READ_LINE_MEMBER(acorn_bmu_device::sda_r) +{ + int res = m_sdar & 1; + + LOGMASKED(LOG_LINE, "read sda %d\n", res); + + return res; +} diff --git a/src/devices/machine/acorn_bmu.h b/src/devices/machine/acorn_bmu.h new file mode 100644 index 00000000000..56c6c32a3df --- /dev/null +++ b/src/devices/machine/acorn_bmu.h @@ -0,0 +1,87 @@ +// license:BSD-3-Clause +// copyright-holders:Nigel Barnes +/********************************************************************* + + Acorn Battery Management Unit + +*********************************************************************/ + +#ifndef MAME_MACHINE_ACORN_BMU_H +#define MAME_MACHINE_ACORN_BMU_H + +#pragma once + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> acorn_bmu_device + +class acorn_bmu_device : public device_t +{ +public: + acorn_bmu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + DECLARE_WRITE_LINE_MEMBER(scl_w); + DECLARE_WRITE_LINE_MEMBER(sda_w); + DECLARE_READ_LINE_MEMBER(sda_r); + +protected: + // device-level overrides + virtual void device_start() override; + +private: + static constexpr uint8_t BMU_SLAVE_ADDRESS = 0xa2; + + // internal state + int m_slave_address; + int m_scl; + int m_sdaw; + int m_sdar; + int m_state; + int m_bits; + int m_shift; + int m_devsel; + int m_register; + + enum { STATE_IDLE, STATE_DEVSEL, STATE_REGISTER, STATE_DATAIN, STATE_DATAOUT }; + + // registers + enum + { + BMU_VERSION = 0x50, + BMU_TEMPERATURE = 0x52, + BMU_CURRENT = 0x54, + BMU_VOLTAGE = 0x56, + BMU_STATUS = 0x5c, + BMU_CHARGE_RATE = 0x5e, + BMU_CAPACITY_NOMINAL = 0x80, + BMU_CAPACITY_MEASURED = 0x82, + BMU_CAPACITY_USED = 0x88, + BMU_CAPACITY_USABLE = 0x8a, + BMU_CHARGE_ESTIMATE = 0x8e, + BMU_COMMAND = 0x90, + BMU_AUTOSTART = 0x9e + }; + + // flags + enum + { + STATUS_THRESHOLD_3 = 1 << 0, // Battery fully charged + STATUS_LID_OPEN = 1 << 1, // Lid open + STATUS_THRESHOLD_2 = 1 << 2, // Battery flat [shutdown now] + STATUS_THRESHOLD_1 = 1 << 3, // Battery low [warn user] + STATUS_CHARGING_FAULT = 1 << 4, // Fault in charging system + STATUS_CHARGE_STATE_KNOWN = 1 << 5, // Charge state known + STATUS_BATTERY_PRESENT = 1 << 6, // Battery present + STATUS_CHARGER_PRESENT = 1 << 7 // Charger present + }; + + uint8_t m_estimate; +}; + +// device type definition +DECLARE_DEVICE_TYPE(ACORN_BMU, acorn_bmu_device) + +#endif // MAME_MACHINE_ACORN_BMU_H diff --git a/src/devices/machine/acorn_lc.cpp b/src/devices/machine/acorn_lc.cpp new file mode 100644 index 00000000000..71a545521cb --- /dev/null +++ b/src/devices/machine/acorn_lc.cpp @@ -0,0 +1,152 @@ +// license:BSD-3-Clause +// copyright-holders:Nigel Barnes +/********************************************************************* + + Acorn LC ASIC (for Acorn A4) + + No public documentation exists, this is mostly based on the A4 TRM. + +*********************************************************************/ + +#include "emu.h" +#include "acorn_lc.h" +#include "screen.h" + + +DEFINE_DEVICE_TYPE(ACORN_LC, acorn_lc_device, "acorn_lc", "Acorn LC ASIC") + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// acorn_lc_device - constructor +//------------------------------------------------- + +acorn_lc_device::acorn_lc_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, ACORN_LC, tag, owner, clock) + //, device_memory_interface(mconfig, *this) + //, device_palette_interface(mconfig, *this) + //, device_video_interface(mconfig, *this) + , m_vdsr(0) + , m_vdlr(0) + , m_hdsr(0) + , m_hdlr(0) + , m_licr(0) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void acorn_lc_device::device_start() +{ + // state saving + save_item(NAME(m_vdsr)); + save_item(NAME(m_vdlr)); + save_item(NAME(m_hdsr)); + save_item(NAME(m_hdlr)); + save_item(NAME(m_licr)); +} + + +//************************************************************************** +// READ/WRITE HANDLERS +//************************************************************************** + +u8 acorn_lc_device::read(offs_t offset) +{ + u8 data = 0xff; + + switch (offset & 0x0f) + { + case LC_LICR_L: + data = m_licr & 0x0f; + break; + case LC_LICR_M: + data = (m_licr >> 4) & 0x0f; + break; + case LC_LICR_H: + data = (m_licr >> 8) & 0x0f; + break; + + case LC_RESET: + data = 0x04; + break; + } + logerror("lc_r: % 04x % 02x\n", offset, data); + return data; +} + +void acorn_lc_device::write(offs_t offset, u8 data) +{ + logerror("lc_w: % 04x % 02x\n", offset, data); + switch (offset & 0x0f) + { + case LC_VDSR_L: + m_vdsr = (m_vdsr & 0x0ff0) | (data & 0x0f); + break; + case LC_VDSR_M: + m_vdsr = (m_vdsr & 0x0f0f) | ((data & 0x0f) << 4); + break; + case LC_VDSR_H: + m_vdsr = (m_vdsr & 0x00ff) | ((data & 0x0f) << 8); + break; + + case LC_VDLR_L: + m_vdlr = (m_vdlr & 0x0ff0) | (data & 0x0f); + break; + case LC_VDLR_M: + m_vdlr = (m_vdlr & 0x0f0f) | ((data & 0x0f) << 4); + break; + case LC_VDLR_H: + m_vdlr = (m_vdlr & 0x00ff) | ((data & 0x0f) << 8); + break; + + case LC_HDSR_L: + m_hdsr = (m_hdsr & 0x0ff0) | (data & 0x0f); + break; + case LC_HDSR_M: + m_hdsr = (m_hdsr & 0x0f0f) | ((data & 0x0f) << 4); + break; + case LC_HDSR_H: + m_hdsr = (m_hdsr & 0x00ff) | ((data & 0x0f) << 8); + break; + + case LC_HDLR_L: + m_hdlr = (m_hdlr & 0x0ff0) | (data & 0x0f); + break; + case LC_HDLR_M: + m_hdlr = (m_hdlr & 0x0f0f) | ((data & 0x0f) << 4); + break; + case LC_HDLR_H: + m_hdlr = (m_hdlr & 0x00ff) | ((data & 0x0f) << 8); + break; + + case LC_LICR_L: + m_licr = (m_licr & 0x0ff0) | (data & 0x0f); + break; + case LC_LICR_M: + m_licr = (m_licr & 0x0f0f) | ((data & 0x0f) << 4); + switch (m_licr & LICR_CLOCK_MASK) + { + case LICR_CLOCK_CRYS: + //m_vidc->set_unscaled_clock(24_MHz_XTAL); + break; + case LICR_CLOCK_CRYS2: + //m_vidc->set_unscaled_clock(24_MHz_XTAL / 2); + break; + case LICR_CLOCK_IOEB: + default: + //m_vidc->set_unscaled_cloc(ioeb_clock_select); + break; + } + break; + case LC_LICR_H: + m_licr = (m_licr & 0x00ff) | ((data & 0x0f) << 8); + break; + } + //if (offset & 0x40) + //pal[(offset >> 2) & 0xf] = lc_palette[data & 0xf]; +} diff --git a/src/devices/machine/acorn_lc.h b/src/devices/machine/acorn_lc.h new file mode 100644 index 00000000000..8367c90fdf1 --- /dev/null +++ b/src/devices/machine/acorn_lc.h @@ -0,0 +1,85 @@ +// license:BSD-3-Clause +// copyright-holders:Nigel Barnes +/********************************************************************* + + Acorn LC ASIC + +*********************************************************************/ + +#ifndef MAME_MACHINE_ACORN_LC_H +#define MAME_MACHINE_ACORN_LC_H + +#pragma once + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> acorn_lc_device + +class acorn_lc_device : public device_t + //public device_memory_interface, + //public device_palette_interface, + //public device_video_interface +{ +public: + acorn_lc_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + + u8 read(offs_t offset); + void write(offs_t offset, u8 data); + +protected: + // device-level overrides + virtual void device_start() override; + +private: + + enum + { + // VDSR = 512 - lines from start of VSYNC to start of display + LC_VDSR_L = 0, + LC_VDSR_M, + LC_VDSR_H, + + // VDLC = lines per panel - 3 + LC_VDLR_L, + LC_VDLR_M, + LC_VDLR_H, + + // HDSR = 2047 - pixels of HSYNC + back porch + LC_HDSR_L, + LC_HDSR_M, + LC_HDSR_H, + + // HDLR = horizontal display pixels / 8 + LC_HDLR_L, + LC_HDLR_M , + LC_HDLR_H, + + LC_LICR_L, + LC_LICR_M, + LC_LICR_H, + + LC_RESET, + }; + + enum + { + LICR_CLOCK_IOEB = 0 << 5, + LICR_CLOCK_CRYS2 = 1 << 5, + LICR_CLOCK_CRYS = 2 << 5, + LICR_CLOCK_MASK = 3 << 5 + }; + + u32 m_vdsr; + u32 m_vdlr; + u32 m_hdsr; + u32 m_hdlr; + u32 m_licr; +}; + +// device type definition +DECLARE_DEVICE_TYPE(ACORN_LC, acorn_lc_device) + +#endif // MAME_MACHINE_ACORN_LC_H diff --git a/src/devices/machine/upc82c710.cpp b/src/devices/machine/upc82c710.cpp new file mode 100644 index 00000000000..b2812291a1d --- /dev/null +++ b/src/devices/machine/upc82c710.cpp @@ -0,0 +1,419 @@ +// license:BSD-3-Clause +// copyright-holders:Nigel Barnes +/********************************************************************** + + Universal Peripheral Controller 82C710 emulation + +**********************************************************************/ + +#include "emu.h" +#include "machine/upc82c710.h" + +#define LOG_CFG (1 << 0) +#define LOG_FDC (1 << 1) +#define LOG_IDE (1 << 2) +#define LOG_LPT (1 << 3) +#define LOG_SER (1 << 4) + +#define VERBOSE (0) + +#include "logmacro.h" + +DEFINE_DEVICE_TYPE(UPC82C710, upc82c710_device, "upc82c710", "Universal Peripheral Controller 82C710") + + +upc82c710_device::upc82c710_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, UPC82C710, tag, owner, clock) + , m_ide(*this, "ide") + , m_fdc(*this, "fdc") + , m_lpt(*this, "parallel") + , m_serial(*this, "serial") + , m_fintr_callback(*this) + , m_fdrq_callback(*this) + , m_pintr_callback(*this) + , m_sintr_callback(*this) + , m_txd_callback(*this) + , m_dtr_callback(*this) + , m_rts_callback(*this) + , m_cfg_mode(0) +{ +} + + +void upc82c710_device::device_add_mconfig(machine_config &config) +{ + // ide interface + ATA_INTERFACE(config, m_ide); + + // floppy disc controller + UPD765A(config, m_fdc, clock() / 3, false, false); // uPD72065B + m_fdc->intrq_wr_callback().set(FUNC(upc82c710_device::fdc_irq_w)); + m_fdc->drq_wr_callback().set(FUNC(upc82c710_device::fdc_drq_w)); + + // parallel port + PC_LPT(config, m_lpt); + m_lpt->irq_handler().set([this](int state) { m_pintr_callback(state); }); + + // serial port + NS16450(config, m_serial, clock() / 13); + m_serial->out_int_callback().set([this](int state) { m_sintr_callback(state); }); + m_serial->out_tx_callback().set([this](int state) { m_txd_callback(state); }); + m_serial->out_dtr_callback().set([this](int state) { m_dtr_callback(state); }); + m_serial->out_rts_callback().set([this](int state) { m_rts_callback(state); }); +} + + +void upc82c710_device::device_start() +{ + for (int i=0; i<4; i++) + { + char name[2] = {static_cast('0'+i), 0}; + floppy_connector *conn = m_fdc->subdevice(name); + floppy[i] = conn ? conn->get_device() : nullptr; + } + + irq = drq = false; + fdc_irq = fdc_drq = false; + + m_fintr_callback.resolve_safe(); + m_fdrq_callback.resolve_safe(); + m_pintr_callback.resolve_safe(); + m_sintr_callback.resolve_safe(); + m_txd_callback.resolve_safe(); + m_dtr_callback.resolve_safe(); + m_rts_callback.resolve_safe(); + + // default addresses + device_address[LogicalDevice::CFG] = 0x390; + device_address[LogicalDevice::IDE] = 0x1f0; + device_address[LogicalDevice::FDC] = 0x3f0; + device_address[LogicalDevice::LPT] = 0x278; + device_address[LogicalDevice::SER] = 0x3f8; + + const u8 cfg_regs_defaults[] = { 0x0e, 0x00, 0x08, 0x00, 0xfe, 0xbe, 0x9e, 0x00, 0xec, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + // Set the value first and then use write_config because some flags + // rely on other flags being initialized properly first + std::copy(std::begin(cfg_regs_defaults), std::end(cfg_regs_defaults), std::begin(m_cfg_regs)); + for (int i = 0; i < std::size(cfg_regs_defaults); i++) + { + write_cfg(i, cfg_regs_defaults[i]); + } + + save_item(NAME(m_cfg_regs)); + save_item(NAME(m_cfg_indx)); + save_item(NAME(m_cfg_mode)); +} + +void upc82c710_device::device_reset() +{ + dor_w(0x00); +} + + +u16 upc82c710_device::io_r(offs_t offset, u16 mem_mask) +{ + u16 data = 0xffff; + + // configuration + if (offset == 0x391 && m_cfg_mode == 5) + { + data = m_cfg_regs[m_cfg_indx]; + LOGMASKED(LOG_CFG, "CFG read %04x -> %02x\n", offset, data); + } + + // ide + if (device_enabled[LogicalDevice::IDE] && (offset & ~7) == 0x1f0) + { + data = m_ide->cs0_r(offset & 7); + LOGMASKED(LOG_IDE, "IDE read %04x -> %04x\n", offset, data); + } + if (device_enabled[LogicalDevice::IDE] && offset == 0x3f6) + { + data = m_ide->cs1_r(offset & 7); + LOGMASKED(LOG_IDE, "IDE read %04x -> %04x\n", offset, data); + } + + // fdc + if (device_enabled[LogicalDevice::FDC] && (offset & ~7) == 0x3f0 && offset != 0x3f0 && offset != 0x3f1 && offset != 0x3f6) + { + switch (offset & 7) + { + case 3: + data = 0x20; + break; + case 4: + data = m_fdc->msr_r(); + break; + case 5: + data = m_fdc->fifo_r(); + break; + case 7: + data = m_fdc->dir_r() | (m_ide->cs1_r(7) & 0x7f); + break; + } + LOGMASKED(LOG_FDC, "FDC read %04x -> %02x\n", offset, data); + } + + // parallel + if (device_enabled[LogicalDevice::LPT] && (offset & ~3) == device_address[LogicalDevice::LPT]) + { + data = m_lpt->read(offset & 3); + LOGMASKED(LOG_LPT, "LPT read %04x -> %02x\n", offset, data); + } + + // serial + if (device_enabled[LogicalDevice::SER] && (offset & ~7) == device_address[LogicalDevice::SER]) + { + data = m_serial->ins8250_r(offset & 7); + LOGMASKED(LOG_SER, "SER read %04x -> %02x\n", offset, data); + } + + return data; +} + +void upc82c710_device::io_w(offs_t offset, u16 data, u16 mem_mask) +{ + switch (m_cfg_mode) + { + case 0: + if (offset == 0x2fa && data == 0x55) + { + m_cfg_mode++; + LOGMASKED(LOG_CFG, "CFG step %d write %04x <- %02x\n", m_cfg_mode, offset, data); + } + break; + case 1: + if (offset == 0x3fa && data == 0xaa) + { + m_cfg_mode++; + LOGMASKED(LOG_CFG, "CFG step %d write %04x <- %02x\n", m_cfg_mode, offset, data); + } + break; + case 2: + if (offset == 0x3fa && data == 0x36) + { + m_cfg_mode++; + LOGMASKED(LOG_CFG, "CFG step %d write %04x <- %02x\n", m_cfg_mode, offset, data); + } + break; + case 3: + if (offset == 0x3fa) + { + m_cfg_mode++; + LOGMASKED(LOG_CFG, "CFG step %d write %04x <- %02x\n", m_cfg_mode, offset, data); + m_cfg_regs[0x0f] = data; + device_address[LogicalDevice::CFG] = data << 2; + LOGMASKED(LOG_CFG, "CFG address %04x\n", device_address[LogicalDevice::CFG]); + } + break; + case 4: + // enter configuration + if (offset == 0x2fa && data == (~m_cfg_regs[0x0f] & 0xff)) + { + m_cfg_mode++; + LOGMASKED(LOG_CFG, "CFG step %d write %04x <- %02x\n", m_cfg_mode, offset, data); + LOGMASKED(LOG_CFG, "CFG -- mode on --\n"); + } + break; + } + + // configuration + if (offset == device_address[LogicalDevice::CFG]) + { + LOGMASKED(LOG_CFG, "CFG write %04x <- %02x\n", offset, data); + if (m_cfg_mode == 5) + { + m_cfg_indx = data & 0x0f; + } + else + { + m_cfg_mode = 0; + } + } + else if (offset == device_address[LogicalDevice::CFG] + 1) + { + LOGMASKED(LOG_CFG, "CFG write %04x <- %02x\n", offset, data); + if (m_cfg_mode == 5) + { + write_cfg(m_cfg_indx, data); + } + else + { + m_cfg_mode = 0; + } + } + + // ide + if (device_enabled[LogicalDevice::IDE] && (offset & ~7) == 0x1f0) + { + m_ide->cs0_w(offset & 7, data); + LOGMASKED(LOG_IDE, "IDE write %04x <- %04x\n", offset, data); + } + if (device_enabled[LogicalDevice::IDE] && offset == 0x3f6) + { + m_ide->cs1_w(offset & 7, data); + LOGMASKED(LOG_IDE, "IDE write %04x <- %04x\n", offset, data); + } + + // fdc + if (device_enabled[LogicalDevice::FDC] && (offset & ~7) == 0x3f0 && offset != 0x3f0 && offset != 0x3f1 && offset != 0x3f6) + { + switch (offset & 7) + { + case 2: + dor_w(data); + break; + case 5: + m_fdc->fifo_w(data); + break; + case 7: + m_fdc->ccr_w(data); + break; + } + LOGMASKED(LOG_FDC, "FDC write %04x <- %02x\n", offset, data); + } + + // parallel + if (device_enabled[LogicalDevice::LPT] && (offset & ~3) == device_address[LogicalDevice::LPT]) + { + m_lpt->write(offset & 3, data); + LOGMASKED(LOG_LPT, "LPT write %04x <- %02x\n", offset, data); + } + + // serial + if (device_enabled[LogicalDevice::SER] && (offset & ~7) == device_address[LogicalDevice::SER]) + { + m_serial->ins8250_w(offset & 7, data); + LOGMASKED(LOG_SER, "SER write %04x <- %02x\n", offset, data); + } +} + + +u8 upc82c710_device::dack_r() +{ + return m_fdc->dma_r(); +} + +void upc82c710_device::dack_w(u8 data) +{ + m_fdc->dma_w(data); +} + +void upc82c710_device::tc_w(bool state) +{ + m_fdc->tc_w(state); +} + + +void upc82c710_device::dor_w(uint8_t data) +{ + dor = data; + + for (int i=0; i<4; i++) + if (floppy[i]) + floppy[i]->mon_w(!(dor & (0x10 << i))); + + int fid = dor & 3; + if (dor & (0x10 << fid)) + m_fdc->set_floppy(floppy[fid]); + else + m_fdc->set_floppy(nullptr); + + check_irq(); + check_drq(); + m_fdc->reset_w(!BIT(dor, 2)); +} + +WRITE_LINE_MEMBER(upc82c710_device::fdc_irq_w) +{ + fdc_irq = state; + check_irq(); +} + +WRITE_LINE_MEMBER(upc82c710_device::fdc_drq_w) +{ + fdc_drq = state; + check_drq(); +} + +void upc82c710_device::check_irq() +{ + bool pirq = irq; + irq = fdc_irq && (dor & 4) && (dor & 8); + if (irq != pirq) + m_fintr_callback(irq); +} + +void upc82c710_device::check_drq() +{ + bool pdrq = drq; + drq = fdc_drq && (dor & 4) && (dor & 8); + if (drq != pdrq) + m_fdrq_callback(drq); +} + + +void upc82c710_device::write_cfg(int index, u8 data) +{ + m_cfg_regs[index] = data; + LOGMASKED(LOG_CFG, "CR[%02x] = %02x\n", index, data); + + switch (index) + { + case 0x00: // Chip Selects and Enable + device_enabled[LogicalDevice::LPT]= BIT(m_cfg_regs[index], 3); + device_enabled[LogicalDevice::SER]= BIT(m_cfg_regs[index], 2); + LOGMASKED(LOG_CFG, "LPT %s\n", device_enabled[LogicalDevice::LPT] ? "enabled" : "disabled"); + LOGMASKED(LOG_CFG, "SER %s\n", device_enabled[LogicalDevice::SER] ? "enabled" : "disabled"); + break; + + case 0x04: // Serial Port Address + device_address[LogicalDevice::SER] = (data & 0xfe) << 2; + LOGMASKED(LOG_CFG, "SER address %04x\n", device_address[LogicalDevice::SER]); + break; + + case 0x06: // Parallel Port Address + device_address[LogicalDevice::LPT] = data << 2; + LOGMASKED(LOG_CFG, "LPT address %04x\n", device_address[LogicalDevice::LPT]); + break; + + case 0x0c: + device_enabled[LogicalDevice::IDE] = BIT(m_cfg_regs[index], 7); + device_enabled[LogicalDevice::FDC] = BIT(m_cfg_regs[index], 5); + LOGMASKED(LOG_CFG, "IDE %s\n", device_enabled[LogicalDevice::IDE] ? "enabled" : "disabled"); + LOGMASKED(LOG_CFG, "FDC %s\n", device_enabled[LogicalDevice::FDC] ? "enabled" : "disabled"); + break; + + case 0x0f: + m_cfg_mode = 0; + LOGMASKED(LOG_CFG, "CFG -- mode off --\n"); + break; + } +} + + +WRITE_LINE_MEMBER(upc82c710_device::rxd_w) +{ + m_serial->rx_w(state); +} + +WRITE_LINE_MEMBER(upc82c710_device::dcd_w) +{ + m_serial->dcd_w(state); +} + +WRITE_LINE_MEMBER(upc82c710_device::dsr_w) +{ + m_serial->dsr_w(state); +} + +WRITE_LINE_MEMBER(upc82c710_device::ri_w) +{ + m_serial->ri_w(state); +} + +WRITE_LINE_MEMBER(upc82c710_device::cts_w) +{ + m_serial->cts_w(state); +} diff --git a/src/devices/machine/upc82c710.h b/src/devices/machine/upc82c710.h new file mode 100644 index 00000000000..7fa9b44a687 --- /dev/null +++ b/src/devices/machine/upc82c710.h @@ -0,0 +1,110 @@ +// license:BSD-3-Clause +// copyright-holders:Nigel Barnes +/********************************************************************** + + Universal Peripheral Controller 82C710 emulation + +**********************************************************************/ + +#ifndef MAME_MACHINE_UPC82C710_H +#define MAME_MACHINE_UPC82C710_H + +#pragma once + +#include "machine/ins8250.h" +#include "machine/pc_lpt.h" +#include "machine/upd765.h" +#include "machine/idectrl.h" +#include "imagedev/floppy.h" + + +class upc82c710_device : public device_t +{ +public: + // construction/destruction + upc82c710_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + + u16 io_r(offs_t offset, u16 mem_mask = ~0); + void io_w(offs_t offset, u16 data, u16 mem_mask = ~0); + u8 dack_r(); + void dack_w(u8 data); + void tc_w(bool state); + + u8 dack_tc0_r() { tc_w(false); return dack_r(); } + void dack_tc0_w(u8 data) { tc_w(false); dack_w(data); } + u8 dack_tc1_r() { tc_w(true); return dack_r(); } + void dack_tc1_w(u8 data) { tc_w(true); dack_w(data); } + + auto fintr() { return m_fintr_callback.bind(); } + auto fdrq() { return m_fdrq_callback.bind(); } + auto pintr() { return m_pintr_callback.bind(); } + auto sintr() { return m_sintr_callback.bind(); } + auto txd() { return m_txd_callback.bind(); } + auto dtr() { return m_dtr_callback.bind(); } + auto rts() { return m_rts_callback.bind(); } + + // chip pins for uarts + DECLARE_WRITE_LINE_MEMBER(rxd_w); + DECLARE_WRITE_LINE_MEMBER(dcd_w); + DECLARE_WRITE_LINE_MEMBER(dsr_w); + DECLARE_WRITE_LINE_MEMBER(ri_w); + DECLARE_WRITE_LINE_MEMBER(cts_w); + +protected: + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_add_mconfig(machine_config &config) override; + +private: + required_device m_ide; + required_device m_fdc; + required_device m_lpt; + required_device m_serial; + + void dor_w(u8 data); + DECLARE_WRITE_LINE_MEMBER(fdc_irq_w); + DECLARE_WRITE_LINE_MEMBER(fdc_drq_w); + + bool irq, drq, fdc_drq, fdc_irq; + u8 dor; + + floppy_image_device *floppy[4]; + + void check_irq(); + void check_drq(); + + devcb_write_line m_fintr_callback; + devcb_write_line m_fdrq_callback; + devcb_write_line m_pintr_callback; + devcb_write_line m_sintr_callback; + + devcb_write_line m_txd_callback; + devcb_write_line m_dtr_callback; + devcb_write_line m_rts_callback; + + void write_cfg(int index, u8 data); + + enum LogicalDevice + { + CFG = 0, + FDC, + IDE, + LPT, + SER, + + LogicalDeviceEnd + }; + + bool device_enabled[LogicalDevice::LogicalDeviceEnd]; + u16 device_address[LogicalDevice::LogicalDeviceEnd]; + + int m_cfg_mode; + u8 m_cfg_regs[16]; + u8 m_cfg_indx; +}; + + +DECLARE_DEVICE_TYPE(UPC82C710, upc82c710_device) + +#endif // MAME_MACHINE_UPC82C710_H diff --git a/src/devices/machine/upc82c711.cpp b/src/devices/machine/upc82c711.cpp new file mode 100644 index 00000000000..34d58cd6001 --- /dev/null +++ b/src/devices/machine/upc82c711.cpp @@ -0,0 +1,478 @@ +// license:BSD-3-Clause +// copyright-holders:Nigel Barnes +/********************************************************************** + + Universal Peripheral Controller 82C711 emulation + +**********************************************************************/ + +#include "emu.h" +#include "machine/upc82c711.h" + +#define LOG_CFG (1 << 0) +#define LOG_FDC (1 << 1) +#define LOG_IDE (1 << 2) +#define LOG_LPT (1 << 3) +#define LOG_SER (1 << 4) + +#define VERBOSE (0) + +#include "logmacro.h" + +DEFINE_DEVICE_TYPE(UPC82C711, upc82c711_device, "upc82c711", "Universal Peripheral Controller 82C711") + + +upc82c711_device::upc82c711_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, UPC82C711, tag, owner, clock) + , m_ide(*this, "ide") + , m_fdc(*this, "fdc") + , m_lpt(*this, "parallel") + , m_serial(*this, "serial%u", 1U) + , m_fintr_callback(*this) + , m_fdrq_callback(*this) + , m_pintr_callback(*this) + , m_irq3_callback(*this) + , m_irq4_callback(*this) + , m_txd1_callback(*this) + , m_dtr1_callback(*this) + , m_rts1_callback(*this) + , m_txd2_callback(*this) + , m_dtr2_callback(*this) + , m_rts2_callback(*this) + , m_cfg_mode(0) +{ +} + + +void upc82c711_device::device_add_mconfig(machine_config &config) +{ + // ide interface + ATA_INTERFACE(config, m_ide); + + // floppy disc controller + UPD765A(config, m_fdc, clock() / 3, false, false); // uPD72065B + m_fdc->intrq_wr_callback().set(FUNC(upc82c711_device::fdc_irq_w)); + m_fdc->drq_wr_callback().set(FUNC(upc82c711_device::fdc_drq_w)); + + // parallel port + PC_LPT(config, m_lpt); + m_lpt->irq_handler().set([this](int state) { m_pintr_callback(state); }); + + // serial ports + NS16450(config, m_serial[0], clock() / 13); + m_serial[0]->out_int_callback().set([this](int state) { m_irq4_callback(state); }); + m_serial[0]->out_tx_callback().set([this](int state) { m_txd1_callback(state); }); + m_serial[0]->out_dtr_callback().set([this](int state) { m_dtr1_callback(state); }); + m_serial[0]->out_rts_callback().set([this](int state) { m_rts1_callback(state); }); + + NS16450(config, m_serial[1], clock() / 13); + m_serial[1]->out_int_callback().set([this](int state) { m_irq3_callback(state); }); + m_serial[1]->out_tx_callback().set([this](int state) { m_txd2_callback(state); }); + m_serial[1]->out_dtr_callback().set([this](int state) { m_dtr2_callback(state); }); + m_serial[1]->out_rts_callback().set([this](int state) { m_rts2_callback(state); }); +} + + +void upc82c711_device::device_start() +{ + for (int i=0; i<4; i++) + { + char name[2] = {static_cast('0'+i), 0}; + floppy_connector *conn = m_fdc->subdevice(name); + floppy[i] = conn ? conn->get_device() : nullptr; + } + + irq = drq = false; + fdc_irq = fdc_drq = false; + + m_fintr_callback.resolve_safe(); + m_fdrq_callback.resolve_safe(); + m_pintr_callback.resolve_safe(); + m_irq3_callback.resolve_safe(); + m_irq4_callback.resolve_safe(); + m_txd1_callback.resolve_safe(); + m_dtr1_callback.resolve_safe(); + m_rts1_callback.resolve_safe(); + m_txd2_callback.resolve_safe(); + m_dtr2_callback.resolve_safe(); + m_rts2_callback.resolve_safe(); + + // default addresses + com_address[0] = 0x3f8; + com_address[1] = 0x2f8; + com_address[2] = 0x338; + com_address[3] = 0x238; + + device_address[LogicalDevice::IDE] = 0x1f0; + device_address[LogicalDevice::FDC] = 0x3f0; + device_address[LogicalDevice::LPT] = 0x278; + device_address[LogicalDevice::SER1] = com_address[0]; + device_address[LogicalDevice::SER2] = com_address[1]; + + const u8 cfg_regs_defaults[] = { 0x3f, 0x9f, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + // Set the value first and then use write_config because some flags + // rely on other flags being initialized properly first + std::copy(std::begin(cfg_regs_defaults), std::end(cfg_regs_defaults), std::begin(m_cfg_regs)); + for (int i = 0; i < std::size(cfg_regs_defaults); i++) + { + write_cfg(i, cfg_regs_defaults[i]); + } + + save_item(NAME(m_cfg_regs)); + save_item(NAME(m_cfg_indx)); + save_item(NAME(m_cfg_mode)); +} + +void upc82c711_device::device_reset() +{ + dor_w(0x00); +} + + +u16 upc82c711_device::io_r(offs_t offset, u16 mem_mask) +{ + u16 data = 0xffff; + + // configuration + if (offset == 0x3f1 && m_cfg_mode == 2) + { + data = m_cfg_regs[m_cfg_indx]; + LOGMASKED(LOG_CFG, "CFG read %04x -> %02x\n", offset, data); + } + + // ide + if (device_enabled[LogicalDevice::IDE] && (offset & ~7) == 0x1f0) + { + data = m_ide->cs0_r(offset & 7); + LOGMASKED(LOG_IDE, "IDE read %04x -> %04x\n", offset, data); + } + if (device_enabled[LogicalDevice::IDE] && offset == 0x3f6) + { + data = m_ide->cs1_r(offset & 7); + LOGMASKED(LOG_IDE, "IDE read %04x -> %04x\n", offset, data); + } + + // fdc + if (device_enabled[LogicalDevice::FDC] && (offset & ~7) == 0x3f0 && offset != 0x3f0 && offset != 0x3f1 && offset != 0x3f6) + { + switch (offset & 7) + { + case 3: + data = 0x20; + break; + case 4: + data = m_fdc->msr_r(); + break; + case 5: + data = m_fdc->fifo_r(); + break; + case 7: + data = m_fdc->dir_r() | (m_ide->cs1_r(7) & 0x7f); + break; + } + LOGMASKED(LOG_FDC, "FDC read %04x -> %02x\n", offset, data); + } + + // parallel + if (device_enabled[LogicalDevice::LPT] && (offset & ~3) == device_address[LogicalDevice::LPT]) + { + data = m_lpt->read(offset & 3); + LOGMASKED(LOG_LPT, "LPT read %04x -> %02x\n", offset, data); + } + + // serial 1 + if (device_enabled[LogicalDevice::SER1] && (offset & ~7) == device_address[LogicalDevice::SER1]) + { + data = m_serial[0]->ins8250_r(offset & 7); + LOGMASKED(LOG_SER, "SER1 read %04x -> %02x\n", offset, data); + } + + // serial 2 + if (device_enabled[LogicalDevice::SER2] && (offset & ~7) == device_address[LogicalDevice::SER2]) + { + data = m_serial[1]->ins8250_r(offset & 7); + LOGMASKED(LOG_SER, "SER2 read %04x -> %02x\n", offset, data); + } + + return data; +} + +void upc82c711_device::io_w(offs_t offset, u16 data, u16 mem_mask) +{ + // configuration + if (offset == 0x3f0) + { + LOGMASKED(LOG_CFG, "CFG write %04x <- %02x\n", offset, data); + if (m_cfg_mode == 2) + { + if (data == 0xaa) // escape configuration + { + m_cfg_mode = 0; + LOGMASKED(LOG_CFG, "CFG -- mode off --\n"); + } + else + { + m_cfg_indx = data & 0x0f; + } + } + else + { + if (data == 0x55) // enter configuration + { + m_cfg_mode++; + if (m_cfg_mode == 2) + LOGMASKED(LOG_CFG, "CFG -- mode on --\n"); + } + else + { + m_cfg_mode = 0; + } + } + } + else if (offset == 0x3f1) + { + LOGMASKED(LOG_CFG, "CFG write %04x <- %02x\n", offset, data); + if (m_cfg_mode == 2) + { + write_cfg(m_cfg_indx, data); + } + } + + // ide + if (device_enabled[LogicalDevice::IDE] && (offset & ~7) == 0x1f0) + { + m_ide->cs0_w(offset & 7, data); + LOGMASKED(LOG_IDE, "IDE write %04x <- %04x\n", offset, data); + } + if (device_enabled[LogicalDevice::IDE] && offset == 0x3f6) + { + m_ide->cs1_w(offset & 7, data); + LOGMASKED(LOG_IDE, "IDE write %04x <- %04x\n", offset, data); + } + + // fdc + if (device_enabled[LogicalDevice::FDC] && (offset & ~7) == 0x3f0 && offset != 0x3f0 && offset != 0x3f1 && offset != 0x3f6) + { + switch (offset & 7) + { + case 2: + dor_w(data); + break; + case 5: + m_fdc->fifo_w(data); + break; + case 7: + m_fdc->ccr_w(data); + break; + } + LOGMASKED(LOG_FDC, "FDC write %04x <- %02x\n", offset, data); + } + + // parallel + if (device_enabled[LogicalDevice::LPT] && (offset & ~3) == device_address[LogicalDevice::LPT]) + { + m_lpt->write(offset & 3, data); + LOGMASKED(LOG_LPT, "LPT write %04x <- %02x\n", offset, data); + } + + // serial 1 + if (device_enabled[LogicalDevice::SER1] && (offset & ~7) == device_address[LogicalDevice::SER1]) + { + m_serial[0]->ins8250_w(offset & 7, data); + LOGMASKED(LOG_SER, "SER1 write %04x <- %02x\n", offset, data); + } + + // serial 2 + if (device_enabled[LogicalDevice::SER2] && (offset & ~7) == device_address[LogicalDevice::SER2]) + { + m_serial[1]->ins8250_w(offset & 7, data); + LOGMASKED(LOG_SER, "SER2 write %04x <- %02x\n", offset, data); + } +} + + +u8 upc82c711_device::dack_r() +{ + return m_fdc->dma_r(); +} + +void upc82c711_device::dack_w(u8 data) +{ + m_fdc->dma_w(data); +} + +void upc82c711_device::tc_w(bool state) +{ + m_fdc->tc_w(state); +} + + +void upc82c711_device::dor_w(uint8_t data) +{ + dor = data; + + for (int i=0; i<4; i++) + if (floppy[i]) + floppy[i]->mon_w(!(dor & (0x10 << i))); + + int fid = dor & 3; + if (dor & (0x10 << fid)) + m_fdc->set_floppy(floppy[fid]); + else + m_fdc->set_floppy(nullptr); + + check_irq(); + check_drq(); + m_fdc->reset_w(!BIT(dor, 2)); +} + +WRITE_LINE_MEMBER(upc82c711_device::fdc_irq_w) +{ + fdc_irq = state; + check_irq(); +} + +WRITE_LINE_MEMBER(upc82c711_device::fdc_drq_w) +{ + fdc_drq = state; + check_drq(); +} + +void upc82c711_device::check_irq() +{ + bool pirq = irq; + irq = fdc_irq && (dor & 4) && (dor & 8); + if (irq != pirq) + m_fintr_callback(irq); +} + +void upc82c711_device::check_drq() +{ + bool pdrq = drq; + drq = fdc_drq && (dor & 4) && (dor & 8); + if (drq != pdrq) + m_fdrq_callback(drq); +} + + +void upc82c711_device::write_cfg(int index, u8 data) +{ + m_cfg_regs[index] = data; + LOGMASKED(LOG_CFG, "CR[%02x] = %02x\n", index, data); + + switch (index) + { + case 0x00: + device_enabled[LogicalDevice::IDE] = BIT(m_cfg_regs[index], 0); + device_enabled[LogicalDevice::FDC] = BIT(m_cfg_regs[index], 3) && BIT(m_cfg_regs[index], 4); + LOGMASKED(LOG_CFG, "IDE %s\n", device_enabled[LogicalDevice::IDE] ? "enabled" : "disabled"); + LOGMASKED(LOG_CFG, "FDC %s\n", device_enabled[LogicalDevice::FDC] ? "enabled" : "disabled"); + break; + + case 0x01: + { + device_enabled[LogicalDevice::LPT] = BIT(m_cfg_regs[index], 2); + + auto lpt_port = BIT(m_cfg_regs[index], 0, 2); + switch (lpt_port) + { + case 0: // Disabled + device_enabled[LogicalDevice::LPT] = false; + break; + case 1: + device_address[LogicalDevice::LPT] = 0x3bc; + break; + case 2: + device_address[LogicalDevice::LPT] = 0x378; + break; + case 3: // Default + device_address[LogicalDevice::LPT] = 0x278; + break; + } + LOGMASKED(LOG_CFG, "LPT %04x %s\n", device_address[LogicalDevice::LPT], device_enabled[LogicalDevice::LPT] ? "enabled" : "disabled"); + auto com34 = BIT(m_cfg_regs[index], 5, 2); + switch (com34) + { + case 0: // Default + com_address[2] = 0x338; + com_address[3] = 0x238; + break; + case 1: + com_address[2] = 0x3e8; + com_address[3] = 0x2e8; + break; + case 2: + com_address[2] = 0x2e8; + com_address[3] = 0x2e0; + break; + case 3: + com_address[2] = 0x220; + com_address[3] = 0x228; + break; + } + break; + } + case 0x02: + device_enabled[LogicalDevice::SER1] = BIT(m_cfg_regs[index], 2) && BIT(m_cfg_regs[index], 3); + device_address[LogicalDevice::SER1] = com_address[BIT(m_cfg_regs[index], 0, 2)]; + + device_enabled[LogicalDevice::SER2] = BIT(m_cfg_regs[index], 6) && BIT(m_cfg_regs[index], 7); + device_address[LogicalDevice::SER2] = com_address[BIT(m_cfg_regs[index], 4, 2)]; + + LOGMASKED(LOG_CFG, "SER1 %04x %s\n", device_address[LogicalDevice::SER1], device_enabled[LogicalDevice::SER1] ? "enabled" : "disabled"); + LOGMASKED(LOG_CFG, "SER2 %04x %s\n", device_address[LogicalDevice::SER2], device_enabled[LogicalDevice::SER2] ? "enabled" : "disabled"); + break; + } +} + + +WRITE_LINE_MEMBER(upc82c711_device::rxd1_w) +{ + m_serial[0]->rx_w(state); +} + +WRITE_LINE_MEMBER(upc82c711_device::dcd1_w) +{ + m_serial[0]->dcd_w(state); +} + +WRITE_LINE_MEMBER(upc82c711_device::dsr1_w) +{ + m_serial[0]->dsr_w(state); +} + +WRITE_LINE_MEMBER(upc82c711_device::ri1_w) +{ + m_serial[0]->ri_w(state); +} + +WRITE_LINE_MEMBER(upc82c711_device::cts1_w) +{ + m_serial[0]->cts_w(state); +} + +WRITE_LINE_MEMBER(upc82c711_device::rxd2_w) +{ + m_serial[1]->rx_w(state); +} + +WRITE_LINE_MEMBER(upc82c711_device::dcd2_w) +{ + m_serial[1]->dcd_w(state); +} + +WRITE_LINE_MEMBER(upc82c711_device::dsr2_w) +{ + m_serial[1]->dsr_w(state); +} + +WRITE_LINE_MEMBER(upc82c711_device::ri2_w) +{ + m_serial[1]->ri_w(state); +} + +WRITE_LINE_MEMBER(upc82c711_device::cts2_w) +{ + m_serial[1]->cts_w(state); +} diff --git a/src/devices/machine/upc82c711.h b/src/devices/machine/upc82c711.h new file mode 100644 index 00000000000..dfaa243be0b --- /dev/null +++ b/src/devices/machine/upc82c711.h @@ -0,0 +1,128 @@ +// license:BSD-3-Clause +// copyright-holders:Nigel Barnes +/********************************************************************** + + Universal Peripheral Controller 82C711 emulation + +**********************************************************************/ + +#ifndef MAME_MACHINE_UPC82C711_H +#define MAME_MACHINE_UPC82C711_H + +#pragma once + +#include "machine/ins8250.h" +#include "machine/pc_lpt.h" +#include "machine/upd765.h" +#include "bus/ata/ataintf.h" +#include "imagedev/floppy.h" + + +// ======================> upc82c710_device + +class upc82c711_device : public device_t +{ +public: + // construction/destruction + upc82c711_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + + u16 io_r(offs_t offset, u16 mem_mask = ~0); + void io_w(offs_t offset, u16 data, u16 mem_mask = ~0); + + u8 dack_r(); + void dack_w(u8 data); + void tc_w(bool state); + + u8 dack_tc0_r() { tc_w(false); return dack_r(); } + void dack_tc0_w(u8 data) { tc_w(false); dack_w(data); } + u8 dack_tc1_r() { tc_w(true); return dack_r(); } + void dack_tc1_w(u8 data) { tc_w(true); dack_w(data); } + + auto fintr() { return m_fintr_callback.bind(); } + auto fdrq() { return m_fdrq_callback.bind(); } + auto pintr() { return m_pintr_callback.bind(); } + auto irq3() { return m_irq3_callback.bind(); } + auto irq4() { return m_irq4_callback.bind(); } + auto txd1() { return m_txd1_callback.bind(); } + auto dtr1() { return m_dtr1_callback.bind(); } + auto rts1() { return m_rts1_callback.bind(); } + auto txd2() { return m_txd2_callback.bind(); } + auto dtr2() { return m_dtr2_callback.bind(); } + auto rts2() { return m_rts2_callback.bind(); } + + // chip pins for uarts + DECLARE_WRITE_LINE_MEMBER(rxd1_w); + DECLARE_WRITE_LINE_MEMBER(dcd1_w); + DECLARE_WRITE_LINE_MEMBER(dsr1_w); + DECLARE_WRITE_LINE_MEMBER(ri1_w); + DECLARE_WRITE_LINE_MEMBER(cts1_w); + DECLARE_WRITE_LINE_MEMBER(rxd2_w); + DECLARE_WRITE_LINE_MEMBER(dcd2_w); + DECLARE_WRITE_LINE_MEMBER(dsr2_w); + DECLARE_WRITE_LINE_MEMBER(ri2_w); + DECLARE_WRITE_LINE_MEMBER(cts2_w); + +protected: + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_add_mconfig(machine_config &config) override; + +private: + required_device m_ide; + required_device m_fdc; + required_device m_lpt; + required_device_array m_serial; + + void dor_w(u8 data); + DECLARE_WRITE_LINE_MEMBER(fdc_irq_w); + DECLARE_WRITE_LINE_MEMBER(fdc_drq_w); + + bool irq, drq, fdc_drq, fdc_irq; + u8 dor; + + floppy_image_device *floppy[4]; + + void check_irq(); + void check_drq(); + + devcb_write_line m_fintr_callback; + devcb_write_line m_fdrq_callback; + devcb_write_line m_pintr_callback; + devcb_write_line m_irq3_callback; // Serial Port COM1/COM3 + devcb_write_line m_irq4_callback; // Serial Port COM2/COM4 + + devcb_write_line m_txd1_callback; + devcb_write_line m_dtr1_callback; + devcb_write_line m_rts1_callback; + devcb_write_line m_txd2_callback; + devcb_write_line m_dtr2_callback; + devcb_write_line m_rts2_callback; + + void write_cfg(int index, u8 data); + + enum LogicalDevice + { + FDC = 0, + IDE, + LPT, + SER1, + SER2, + + LogicalDeviceEnd + }; + + bool device_enabled[LogicalDevice::LogicalDeviceEnd]; + u16 device_address[LogicalDevice::LogicalDeviceEnd]; + + u16 com_address[4]; + + int m_cfg_mode; + u8 m_cfg_regs[16]; + u8 m_cfg_indx; +}; + + +DECLARE_DEVICE_TYPE(UPC82C711, upc82c711_device) + +#endif // MAME_MACHINE_UPC82C711_H