New devices for Archimedes machines:

- Acorn Battery Management Unit
- Acorn LC ASIC (preliminary)
- Universal Peripheral Controller 82C710/82C711
This commit is contained in:
Nigel Barnes 2021-11-14 13:05:28 +00:00
parent 7481bdef86
commit 8acb4d846d
10 changed files with 1776 additions and 1 deletions

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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];
}

View File

@ -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

View File

@ -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<char>('0'+i), 0};
floppy_connector *conn = m_fdc->subdevice<floppy_connector>(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);
}

View File

@ -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<ata_interface_device> m_ide;
required_device<upd765_family_device> m_fdc;
required_device<pc_lpt_device> m_lpt;
required_device<ns16450_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

View File

@ -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<char>('0'+i), 0};
floppy_connector *conn = m_fdc->subdevice<floppy_connector>(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);
}

View File

@ -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<ata_interface_device> m_ide;
required_device<upd765_family_device> m_fdc;
required_device<pc_lpt_device> m_lpt;
required_device_array<ns16450_device, 2> 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