summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author AJR <ajrhacker@users.noreply.github.com>2019-04-21 00:34:29 -0400
committer AJR <ajrhacker@users.noreply.github.com>2019-04-21 00:35:59 -0400
commit9b3a449790644eb2f72352c1f877ce8df4e43280 (patch)
tree1b6412b1e487109d249577c705ef7baa10c94ad0
parent112062f7bbad1a42dc856cd1fd8d2ac05ad7ed37 (diff)
Add very preliminary Intel 82355 BMIC device
-rw-r--r--scripts/src/machine.lua12
-rw-r--r--scripts/target/mame/arcade.lua1
-rw-r--r--scripts/target/mame/mess.lua1
-rw-r--r--src/devices/bus/isa/aha174x.cpp7
-rw-r--r--src/devices/bus/isa/tekram_dc820.cpp16
-rw-r--r--src/devices/bus/isa/ultra24f.cpp16
-rw-r--r--src/devices/bus/isa/ultra24f.h5
-rw-r--r--src/devices/machine/i82355.cpp884
-rw-r--r--src/devices/machine/i82355.h91
9 files changed, 1026 insertions, 7 deletions
diff --git a/scripts/src/machine.lua b/scripts/src/machine.lua
index 9f9fba08549..323310c1707 100644
--- a/scripts/src/machine.lua
+++ b/scripts/src/machine.lua
@@ -1219,6 +1219,18 @@ end
---------------------------------------------------
--
+--@src/devices/machine/i82355.h,MACHINES["I82355"] = true
+---------------------------------------------------
+
+if (MACHINES["I8214"]~=null) then
+ files {
+ MAME_DIR .. "src/devices/machine/i82355.cpp",
+ MAME_DIR .. "src/devices/machine/i82355.h",
+ }
+end
+
+---------------------------------------------------
+--
--@src/devices/machine/i8243.h,MACHINES["I8243"] = true
---------------------------------------------------
diff --git a/scripts/target/mame/arcade.lua b/scripts/target/mame/arcade.lua
index 71dd5555213..4dde461c1ed 100644
--- a/scripts/target/mame/arcade.lua
+++ b/scripts/target/mame/arcade.lua
@@ -456,6 +456,7 @@ MACHINES["I2CMEM"] = true
MACHINES["I8155"] = true
MACHINES["I8212"] = true
MACHINES["I8214"] = true
+MACHINES["I82355"] = true
MACHINES["I8243"] = true
MACHINES["I8251"] = true
MACHINES["I8255"] = true
diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua
index 9fd4c3a1551..8e233c29304 100644
--- a/scripts/target/mame/mess.lua
+++ b/scripts/target/mame/mess.lua
@@ -464,6 +464,7 @@ MACHINES["I8087"] = true
MACHINES["I8155"] = true
MACHINES["I8212"] = true
MACHINES["I8214"] = true
+MACHINES["I82355"] = true
MACHINES["I8243"] = true
MACHINES["I8251"] = true
MACHINES["I8255"] = true
diff --git a/src/devices/bus/isa/aha174x.cpp b/src/devices/bus/isa/aha174x.cpp
index 06b6ddf5f62..0130522e4f8 100644
--- a/src/devices/bus/isa/aha174x.cpp
+++ b/src/devices/bus/isa/aha174x.cpp
@@ -34,7 +34,7 @@
#include "aha174x.h"
#include "machine/aic6250.h"
-//#include "machine/i82355.h"
+#include "machine/i82355.h"
#include "machine/nscsi_bus.h"
#include "machine/nscsi_hd.h"
@@ -68,6 +68,7 @@ void aha174x_device::device_start()
void aha174x_device::hpc_map(address_map &map)
{
+ map(0x4000, 0x4002).rw("bmic", FUNC(i82355_device::local_r), FUNC(i82355_device::local_w));
map(0x5000, 0x500f).m("scsi:7:scsic", FUNC(aic6251a_device::map));
map(0x8000, 0xffff).rom().region("mcode", 0);
}
@@ -88,6 +89,8 @@ void aha1740_device::device_add_mconfig(machine_config &config)
HPC46003(config, m_hpc, 40_MHz_XTAL / 2);
m_hpc->set_addrmap(AS_PROGRAM, &aha1740_device::hpc_map);
+ I82355(config, "bmic", 0);
+
NSCSI_BUS(config, "scsi");
NSCSI_CONNECTOR(config, "scsi:0", aha174x_scsi_devices, nullptr);
NSCSI_CONNECTOR(config, "scsi:1", aha174x_scsi_devices, nullptr);
@@ -105,6 +108,8 @@ void aha1742a_device::device_add_mconfig(machine_config &config)
HPC46003(config, m_hpc, 40_MHz_XTAL / 2);
m_hpc->set_addrmap(AS_PROGRAM, &aha1742a_device::hpc_map);
+ I82355(config, "bmic", 0);
+
NSCSI_BUS(config, "scsi");
NSCSI_CONNECTOR(config, "scsi:0", aha174x_scsi_devices, nullptr);
NSCSI_CONNECTOR(config, "scsi:1", aha174x_scsi_devices, nullptr);
diff --git a/src/devices/bus/isa/tekram_dc820.cpp b/src/devices/bus/isa/tekram_dc820.cpp
index 3cdd9f8509f..37711aef72b 100644
--- a/src/devices/bus/isa/tekram_dc820.cpp
+++ b/src/devices/bus/isa/tekram_dc820.cpp
@@ -18,7 +18,7 @@
#include "cpu/i86/i186.h"
//#include "machine/eepromser.h"
-//#include "machine/i82355.h"
+#include "machine/i82355.h"
#include "machine/ncr5390.h"
#include "machine/nscsi_bus.h"
#include "machine/nscsi_hd.h"
@@ -65,7 +65,7 @@ void tekram_eisa_scsi_device::mpu_map(address_map &map)
{
map(0x00000, 0x0ffff).ram();
map(0x10040, 0x1005f).m("scsi:7:scsic", FUNC(ncr53cf94_device::map)).umask16(0xff00);
- //map(0x10080, 0x10085).rw("bmic", FUNC(i82355_device::local_r), FUNC(i82355_device::local_w)).umask16(0x00ff);
+ map(0x10080, 0x10085).rw("bmic", FUNC(i82355_device::local_r), FUNC(i82355_device::local_w)).umask16(0x00ff);
map(0xf0000, 0xfffff).rom().region("firmware", 0);
}
@@ -73,7 +73,7 @@ void tekram_dc320b_device::mpu_map(address_map &map)
{
map(0x00000, 0x03fff).ram();
map(0x08000, 0x0801f).m("scsi:7:scsic", FUNC(ncr53cf94_device::map)).umask16(0x00ff);
- //map(0x08080, 0x08085).rw("bmic", FUNC(i82355_device::local_r), FUNC(i82355_device::local_w)).umask16(0x00ff);
+ map(0x08080, 0x08085).rw("bmic", FUNC(i82355_device::local_r), FUNC(i82355_device::local_w)).umask16(0x00ff);
map(0xf0000, 0xfffff).rom().region("firmware", 0);
}
@@ -81,7 +81,7 @@ void tekram_dc820_device::mpu_map(address_map &map)
{
map(0x00000, 0x0ffff).ram();
map(0x10000, 0x1001f).m("scsi:7:scsic", FUNC(ncr53cf94_device::map)).umask16(0x00ff);
- //map(0x10080, 0x10085).rw("bmic", FUNC(i82355_device::local_r), FUNC(i82355_device::local_w)).umask16(0x00ff);
+ map(0x10080, 0x10085).rw("bmic", FUNC(i82355_device::local_r), FUNC(i82355_device::local_w)).umask16(0x00ff);
map(0xf0000, 0xfffff).rom().region("firmware", 0);
}
@@ -117,6 +117,8 @@ void tekram_dc320b_device::device_add_mconfig(machine_config &config)
//EEPROM_93C46_16BIT(config, m_eeprom);
+ I82355(config, "bmic", 0);
+
scsi_add(config);
WD37C65C(config, m_fdc, 32'000'000, 9'600'000); // clocks verified for DC-320, but not DC-320B
@@ -129,6 +131,8 @@ void tekram_dc320e_device::device_add_mconfig(machine_config &config)
//EEPROM_93C46_16BIT(config, m_eeprom);
+ I82355(config, "bmic", 0);
+
scsi_add(config);
WD37C65C(config, m_fdc, 32'000'000, 9'600'000); // clocks verified for DC-320, but not DC-320E
@@ -141,6 +145,8 @@ void tekram_dc820_device::device_add_mconfig(machine_config &config)
//EEPROM_93C46_16BIT(config, m_eeprom);
+ I82355(config, "bmic", 0);
+
scsi_add(config);
PC8477A(config, m_fdc, 24_MHz_XTAL); // PC8477AVF
@@ -153,6 +159,8 @@ void tekram_dc820b_device::device_add_mconfig(machine_config &config)
//EEPROM_93C46_16BIT(config, m_eeprom);
+ I82355(config, "bmic", 0);
+
scsi_add(config);
PC8477A(config, m_fdc, 24_MHz_XTAL); // PC8477BVF
diff --git a/src/devices/bus/isa/ultra24f.cpp b/src/devices/bus/isa/ultra24f.cpp
index 199545404ca..46341bed4c2 100644
--- a/src/devices/bus/isa/ultra24f.cpp
+++ b/src/devices/bus/isa/ultra24f.cpp
@@ -10,7 +10,6 @@
#include "ultra24f.h"
#include "cpu/m68000/m68000.h"
-//#include "machine/i82355.h"
#include "machine/ncr5390.h"
#include "machine/nscsi_bus.h"
#include "machine/nscsi_hd.h"
@@ -21,6 +20,7 @@ ultra24f_device::ultra24f_device(const machine_config &mconfig, const char *tag,
: device_t(mconfig, ULTRA24F, tag, owner, clock)
, device_isa16_card_interface(mconfig, *this)
, m_uscpu(*this, "uscpu")
+ , m_bmic(*this, "bmic")
, m_fdc(*this, "fdc")
, m_bios16(*this, "bios16")
{
@@ -39,11 +39,21 @@ void ultra24f_device::device_start()
}
}
+u8 ultra24f_device::bmic_r(offs_t offset)
+{
+ return m_bmic->local_r(offset >> 3);
+}
+
+void ultra24f_device::bmic_w(offs_t offset, u8 data)
+{
+ m_bmic->local_w(offset >> 3, data);
+}
+
void ultra24f_device::uscpu_map(address_map &map)
{
map(0x000000, 0x00ffff).rom().region("firmware", 0);
map(0xa00000, 0xa00001).nopr();
- //map(0xff8001, 0xff8001).select(0x18).rw(FUNC(ultra24f_device::bmic_r), FUNC(ultra24f_device::bmic_w));
+ map(0xff8001, 0xff8001).select(0x18).rw(FUNC(ultra24f_device::bmic_r), FUNC(ultra24f_device::bmic_w));
map(0xff9000, 0xff901f).m("scsi:7:scsic", FUNC(ncr53cf94_device::map)).umask16(0x00ff);
map(0xffc000, 0xffffff).ram();
}
@@ -65,6 +75,8 @@ void ultra24f_device::device_add_mconfig(machine_config &config)
M68000(config, m_uscpu, 32_MHz_XTAL / 4); // custom-marked as USC080-5-12A; clock guessed
m_uscpu->set_addrmap(AS_PROGRAM, &ultra24f_device::uscpu_map);
+ I82355(config, m_bmic, 0);
+
NSCSI_BUS(config, "scsi");
NSCSI_CONNECTOR(config, "scsi:0", u24f_scsi_devices, nullptr);
NSCSI_CONNECTOR(config, "scsi:1", u24f_scsi_devices, nullptr);
diff --git a/src/devices/bus/isa/ultra24f.h b/src/devices/bus/isa/ultra24f.h
index 49e7e39f66f..69a5d3a29d2 100644
--- a/src/devices/bus/isa/ultra24f.h
+++ b/src/devices/bus/isa/ultra24f.h
@@ -12,6 +12,7 @@
#pragma once
#include "isa.h"
+#include "machine/i82355.h"
#include "machine/upd765.h"
class ultra24f_device : public device_t, public device_isa16_card_interface
@@ -27,10 +28,14 @@ protected:
virtual const tiny_rom_entry *device_rom_region() const override;
private:
+ u8 bmic_r(offs_t offset);
+ void bmic_w(offs_t offset, u8 data);
+
void uscpu_map(address_map &map);
void scsic_config(device_t *device);
required_device<cpu_device> m_uscpu;
+ required_device<i82355_device> m_bmic;
required_device<upd765_family_device> m_fdc;
required_region_ptr<u16> m_bios16;
};
diff --git a/src/devices/machine/i82355.cpp b/src/devices/machine/i82355.cpp
new file mode 100644
index 00000000000..c2436c994f1
--- /dev/null
+++ b/src/devices/machine/i82355.cpp
@@ -0,0 +1,884 @@
+// license:BSD-3-Clause
+// copyright-holders:AJR
+/**********************************************************************
+
+ Intel 82355 Bus Master Interface Chip (BMIC)
+
+ Currently very little of this device is emulated besides storing
+ data that the local processor writes to it. Its interface will
+ likely evolve greatly in tandem with EISA bus emulation.
+
+**********************************************************************/
+
+#include "emu.h"
+#include "i82355.h"
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// device type definition
+DEFINE_DEVICE_TYPE(I82355, i82355_device, "i82355", "Intel 82355 BMIC")
+
+
+//**************************************************************************
+// DEVICE INITIALIZATION
+//**************************************************************************
+
+//-------------------------------------------------
+// i82355_device - constructor
+//-------------------------------------------------
+
+i82355_device::i82355_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, I82355, tag, owner, clock)
+ , m_eint_callback(*this)
+ , m_lint_callback(*this)
+ , m_local_index(0x00)
+ , m_local_status(0x00)
+ , m_id{0}
+ , m_global_config(0x00) // TBD: revision code in upper 4 bits
+ , m_system_interrupt(0x00)
+ , m_semaphore_flag{false, false}
+ , m_semaphore_etest{false, false}
+ , m_semaphore_ltest{false, false}
+ , m_local_doorbell_status(0x00)
+ , m_local_doorbell_enable(0x00)
+ , m_eisa_doorbell_status(0x00)
+ , m_eisa_doorbell_enable(0x00)
+ , m_peek_poke_data{0}
+ , m_peek_poke_address{0}
+ , m_peek_poke_status(0x00)
+ , m_io_decode_base{0x00, 0x00}
+ , m_io_decode_control{0x00, 0x00}
+ , m_transfer_config{0x00, 0x00}
+ , m_transfer_status{0x00, 0x00}
+ , m_base_count{{0}, {0}}
+ , m_base_address{{0}, {0}}
+ , m_current_count{{0}, {0}}
+ , m_current_address{{0}, {0}}
+ , m_tbi_base{{0}, {0}}
+ , m_tbi_current{{0}, {0}}
+{
+ // TODO: 24-byte FIFO for each data transfer channel
+ std::fill(std::begin(m_mailbox), std::end(m_mailbox), 0x00);
+}
+
+
+//-------------------------------------------------
+// device_resolve_objects - resolve objects that
+// may be needed for other devices to set
+// initial conditions at start time
+//-------------------------------------------------
+
+void i82355_device::device_resolve_objects()
+{
+ m_eint_callback.resolve_safe();
+ m_lint_callback.resolve_safe();
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void i82355_device::device_start()
+{
+ // Register save state
+ save_item(NAME(m_local_index));
+ save_item(NAME(m_local_status));
+ save_item(NAME(m_id.d));
+ save_item(NAME(m_global_config));
+ save_item(NAME(m_system_interrupt));
+ save_item(NAME(m_semaphore_flag));
+ save_item(NAME(m_semaphore_etest));
+ save_item(NAME(m_semaphore_ltest));
+ save_item(NAME(m_local_doorbell_status));
+ save_item(NAME(m_local_doorbell_enable));
+ save_item(NAME(m_eisa_doorbell_enable));
+ save_item(NAME(m_eisa_doorbell_status));
+ save_item(NAME(m_mailbox));
+ save_item(NAME(m_peek_poke_data.d));
+ save_item(NAME(m_peek_poke_address.d));
+ save_item(NAME(m_peek_poke_control));
+ save_item(NAME(m_peek_poke_status));
+ save_item(NAME(m_io_decode_base));
+ save_item(NAME(m_io_decode_control));
+ save_item(NAME(m_transfer_config));
+ save_item(NAME(m_transfer_status));
+ for (int i = 0; i < 2; i++)
+ {
+ save_item(NAME(m_base_count[i].d), i);
+ save_item(NAME(m_base_address[i].d), i);
+ save_item(NAME(m_current_count[i].d), i);
+ save_item(NAME(m_current_address[i].d), i);
+ save_item(NAME(m_tbi_base[i].w), i);
+ save_item(NAME(m_tbi_current[i].w), i);
+ }
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void i82355_device::device_reset()
+{
+ // Reset local index register
+ m_local_index = 0x00;
+
+ // Reset interrupt/status registers
+ m_local_status = 0x00;
+ m_local_doorbell_status = 0x00;
+ m_local_doorbell_enable = 0x00;
+ m_eisa_doorbell_enable = 0x00;
+ m_eisa_doorbell_status = 0x00;
+ m_system_interrupt = 0x00;
+ m_eint_callback(1);
+ m_lint_callback(1);
+
+ // Reset global configuration register
+ m_global_config &= 0xf0;
+
+ // Reset semaphore flags
+ for (int i = 0; i < 2; i++)
+ m_semaphore_flag[i] = m_semaphore_etest[i] = m_semaphore_ltest[i] = false;
+
+ // ID register byte 0 set to delay value
+ m_id.b.h3 = 0x70 | (m_id.b.h3 & 0x0f);
+
+ // Reset peek/poke address and control registers
+ m_peek_poke_address.d = 0x00000000;
+ m_peek_poke_control = 0x00;
+
+ // Reset data transfer configuration and status registers (TODO: 24-byte FIFOs)
+ for (int i = 0; i < 2; i++)
+ {
+ m_transfer_config[i] = 0x00;
+ m_transfer_status[i] = 0x00;
+ }
+
+ // Reset I/O range decode registers (TODO: differs if local processor not present)
+ m_io_decode_base[0] = 0xe0;
+ m_io_decode_base[1] = 0x00;
+ m_io_decode_control[0] = m_io_decode_control[1] = 0x20;
+}
+
+//**************************************************************************
+// INTERRUPT REGISTRATION AND CONFIGURATION
+//**************************************************************************
+
+//-------------------------------------------------
+// set_local_interrupt - set an interrupt flag
+// in the local register; maybe assert LINT
+//-------------------------------------------------
+
+void i82355_device::set_local_interrupt(u8 flag)
+{
+ m_local_status |= flag;
+ if ((m_local_status & 0x18) == 0x10)
+ {
+ m_local_status |= 0x08;
+ if (BIT(m_global_config, 2))
+ m_lint_callback(1);
+ else
+ m_lint_callback(0);
+ }
+}
+
+
+//-------------------------------------------------
+// clear_local_interrupt - clear an interrupt
+// flag in the local register; maybe clear LINT
+//-------------------------------------------------
+
+void i82355_device::clear_local_interrupt(u8 flag)
+{
+ m_local_status &= ~flag;
+ if ((m_local_status & 0xf8) == 0x18)
+ {
+ m_local_status &= 0xf7;
+ if (BIT(m_global_config, 2))
+ m_lint_callback(0);
+ else
+ m_lint_callback(1);
+ }
+}
+
+
+//-------------------------------------------------
+// set_system_interrupt - set an interrupt flag
+// in the system register; maybe assert EINT
+//-------------------------------------------------
+
+void i82355_device::set_system_interrupt(u8 flag)
+{
+ if (m_system_interrupt == 0x01)
+ {
+ if (BIT(m_global_config, 3))
+ m_eint_callback(1);
+ else
+ m_eint_callback(0);
+ }
+ m_system_interrupt |= flag;
+}
+
+
+//-------------------------------------------------
+// clear_system_interrupt - clear an interrupt
+// flag in the system register; maybe clear EINT
+//-------------------------------------------------
+
+void i82355_device::clear_system_interrupt(u8 flag)
+{
+ if ((m_system_interrupt & flag) == 0)
+ return;
+
+ m_system_interrupt &= ~flag;
+ if (m_system_interrupt == 0x01)
+ {
+ if (BIT(m_global_config, 3))
+ m_eint_callback(0);
+ else
+ m_eint_callback(1);
+ }
+}
+
+
+//-------------------------------------------------
+// global_config - handle writes to the global
+// configuration register
+//-------------------------------------------------
+
+void i82355_device::global_config(u8 data)
+{
+ // Handle changes in interrupt line polarity
+ if (BIT(data, 3) != BIT(m_global_config, 3) && BIT(m_system_interrupt, 0))
+ {
+ if (BIT(data, 3))
+ m_eint_callback((m_system_interrupt & 0xfe) != 0 ? 1 : 0);
+ else
+ m_eint_callback((m_system_interrupt & 0xfe) != 0 ? 0 : 1);
+ }
+ if (BIT(data, 2) != BIT(m_global_config, 2))
+ {
+ if (BIT(data, 2))
+ m_lint_callback(BIT(m_local_status, 3) ? 1 : 0);
+ else
+ m_lint_callback(BIT(m_local_status, 3) ? 0 : 1);
+ }
+
+ // Revision code remains the same
+ m_global_config = (m_global_config & 0xf0) | (data & 0x0f);
+ logerror("%s: Global configuration = %02X\n", machine().describe_context(), m_global_config);
+}
+
+
+//-------------------------------------------------
+// identify_board - report board ID
+//-------------------------------------------------
+
+void i82355_device::identify_board()
+{
+ logerror("%s: Board identified as %c%c%c (%04X) product %02X.%02X\n", machine().describe_context(),
+ ((m_id.w.h & 0x7c00) >> 10) + 'A' - 1,
+ ((m_id.w.h & 0x03e0) >> 5) + 'A' - 1,
+ (m_id.w.h & 0x001f) + 'A' - 1,
+ m_id.w.h,
+ m_id.b.h,
+ m_id.b.l);
+}
+
+
+//**************************************************************************
+// PEEK/POKE INTERFACE
+//**************************************************************************
+
+//-------------------------------------------------
+// peek_poke_control - handle writes to the
+// peek/poke control register
+//-------------------------------------------------
+
+void i82355_device::peek_poke_control(u8 data)
+{
+ const u32 lane_mask = (BIT(data, 3) ? 0xff000000 : 0)
+ | (BIT(data, 2) ? 0x00ff0000 : 0)
+ | (BIT(data, 1) ? 0x0000ff00 : 0)
+ | (BIT(data, 0) ? 0x000000ff : 0);
+
+ switch (data & 0x60)
+ {
+ case 0x40:
+ logerror("%s: Requesting %s peek (read cycle) at %08X & %08X\n", machine().describe_context(),
+ BIT(data, 4) ? "memory" : "I/O",
+ m_peek_poke_address.d & 0xfffffffc, lane_mask);
+ break;
+
+ case 0x20:
+ logerror("%s: Requesting %s poke (write cycle) at %08X & %08X\n", machine().describe_context(),
+ BIT(data, 4) ? "memory" : "I/O",
+ m_peek_poke_address.d & 0xfffffffc, lane_mask);
+ break;
+
+ case 0x60:
+ logerror("%s: Requesting %s peek/poke (locked exchange) at %08X & %08X\n", machine().describe_context(),
+ BIT(data, 4) ? "memory" : "I/O",
+ m_peek_poke_address.d & 0xfffffffc, lane_mask);
+ break;
+ }
+
+ m_peek_poke_control = data;
+}
+
+//**************************************************************************
+// DATA TRANSFER CHANNELS
+//**************************************************************************
+
+//-------------------------------------------------
+// transfer_config - handle writes to each data
+// transfer channel's configuration register
+//-------------------------------------------------
+
+void i82355_device::transfer_config(int channel, u8 data)
+{
+ logerror("%s: Data channel %d transfer configuration register = %02X\n", machine().describe_context(), channel, data);
+ m_transfer_config[channel] = data;
+}
+
+
+//-------------------------------------------------
+// transfer_strobe - programmed strobe for either
+// data transfer channel
+//-------------------------------------------------
+
+void i82355_device::transfer_strobe(int channel)
+{
+ logerror("%s: Data channel %d transfer strobe\n", machine().describe_context(), channel);
+}
+
+//**************************************************************************
+// LOCAL REGISTER ACCESS
+//**************************************************************************
+
+//-------------------------------------------------
+// local_register_read - read data from a given
+// register from the local interface
+//-------------------------------------------------
+
+u8 i82355_device::local_register_read(u8 reg)
+{
+ switch (reg)
+ {
+ case 0x00:
+ // ID register byte 0
+ return m_id.b.h3;
+
+ case 0x01:
+ // ID register byte 1
+ return m_id.b.h2;
+
+ case 0x02:
+ // ID register byte 2
+ return m_id.b.h;
+
+ case 0x03:
+ // ID register byte 3
+ return m_id.b.l;
+
+ case 0x08:
+ // Global configuration register
+ return m_global_config;
+
+ case 0x09:
+ // System interrupt enable register
+ return m_system_interrupt;
+
+ case 0x0a:
+ case 0x0b:
+ // Semaphore ports
+ return m_semaphore_flag[BIT(reg, 0)] | (m_semaphore_ltest[BIT(reg, 0)] << 1);
+
+ case 0x0c:
+ // Local doorbell enable register
+ return m_local_doorbell_enable;
+
+ case 0x0d:
+ // Local doorbell status register
+ return m_local_doorbell_status;
+
+ case 0x0e:
+ // EISA doorbell enable register
+ return m_eisa_doorbell_enable;
+
+ case 0x0f:
+ // EISA doorbell status register
+ return m_eisa_doorbell_status;
+
+ case 0x10:
+ case 0x11:
+ case 0x12:
+ case 0x13:
+ case 0x14:
+ case 0x15:
+ case 0x16:
+ case 0x17:
+ case 0x18:
+ case 0x19:
+ case 0x1a:
+ case 0x1b:
+ case 0x1c:
+ case 0x1d:
+ case 0x1e:
+ case 0x1f:
+ // Mailbox registers
+ return m_mailbox[reg & 0x0f];
+
+ case 0x30:
+ // Peek data register byte 0
+ return m_peek_poke_data.b.l;
+
+ case 0x31:
+ // Peek data register byte 1
+ return m_peek_poke_data.b.h;
+
+ case 0x32:
+ // Peek data register byte 2
+ return m_peek_poke_data.b.h2;
+
+ case 0x33:
+ // Peek data register byte 3
+ return m_peek_poke_data.b.h3;
+
+ case 0x34:
+ // Peek/poke address register byte 0
+ return m_peek_poke_address.b.l;
+
+ case 0x35:
+ // Peek/poke address register byte 1
+ return m_peek_poke_address.b.h;
+
+ case 0x36:
+ // Peek/poke address register byte 2
+ return m_peek_poke_address.b.h2;
+
+ case 0x37:
+ // Peek/poke address register byte 3
+ return m_peek_poke_address.b.h3;
+
+ case 0x38:
+ // Peek/poke control register
+ return m_peek_poke_control;
+
+ case 0x39:
+ // Range 0 I/O decode base address
+ return m_io_decode_base[0];
+
+ case 0x3a:
+ // Range 0 I/O decode control address
+ return m_io_decode_control[0];
+
+ case 0x3b:
+ // Range 1 I/O decode base address
+ return m_io_decode_base[1];
+
+ case 0x3c:
+ // Range 1 I/O decode control address
+ return m_io_decode_control[1];
+
+ case 0x40:
+ case 0x60:
+ // Data transfer base count register byte 0
+ return m_base_count[BIT(reg, 5)].b.l;
+
+ case 0x41:
+ case 0x61:
+ // Data transfer base count register byte 1
+ return m_base_count[BIT(reg, 5)].b.h;
+
+ case 0x42:
+ case 0x62:
+ // Data transfer base count register byte 2
+ return m_base_count[BIT(reg, 5)].b.h2;
+
+ case 0x43:
+ case 0x63:
+ // Data transfer base address register byte 0
+ return m_base_address[BIT(reg, 5)].b.l;
+
+ case 0x44:
+ case 0x64:
+ // Data transfer base address register byte 1
+ return m_base_address[BIT(reg, 5)].b.h;
+
+ case 0x45:
+ case 0x65:
+ // Data transfer base address register byte 2
+ return m_base_address[BIT(reg, 5)].b.h2;
+
+ case 0x46:
+ case 0x66:
+ // Data transfer base address register byte 3
+ return m_base_address[BIT(reg, 5)].b.h3;
+
+ case 0x48:
+ case 0x68:
+ // Data transfer channel configuration register
+ return m_transfer_config[BIT(reg, 5)];
+
+ case 0x4a:
+ case 0x6a:
+ // Data transfer channel status register
+ return m_transfer_status[BIT(reg, 5)];
+
+ case 0x4b:
+ case 0x6b:
+ // TBI base register byte 0
+ return m_tbi_base[BIT(reg, 5)].b.l;
+
+ case 0x4c:
+ case 0x6c:
+ // TBI base register byte 1
+ return m_tbi_base[BIT(reg, 5)].b.h;
+
+ case 0x50:
+ case 0x70:
+ // Data transfer current count register byte 0
+ return m_current_count[BIT(reg, 5)].b.l;
+
+ case 0x51:
+ case 0x71:
+ // Data transfer current count register byte 1
+ return m_current_count[BIT(reg, 5)].b.h;
+
+ case 0x52:
+ case 0x72:
+ // Data transfer current count register byte 2
+ return m_current_count[BIT(reg, 5)].b.h2;
+
+ case 0x53:
+ case 0x73:
+ // Data transfer current address register byte 0
+ return m_current_address[BIT(reg, 5)].b.l;
+
+ case 0x54:
+ case 0x74:
+ // Data transfer current address register byte 1
+ return m_current_address[BIT(reg, 5)].b.h;
+
+ case 0x55:
+ case 0x75:
+ // Data transfer current address register byte 2
+ return m_current_address[BIT(reg, 5)].b.h2;
+
+ case 0x56:
+ case 0x76:
+ // Data transfer current address register byte 3
+ return m_current_address[BIT(reg, 5)].b.h3;
+
+ case 0x5b:
+ case 0x7b:
+ // TBI current register byte 0
+ return m_tbi_current[BIT(reg, 5)].b.l;
+
+ case 0x5c:
+ case 0x7c:
+ // TBI current register byte 1
+ return m_tbi_current[BIT(reg, 5)].b.h;
+
+ default:
+ if (!machine().side_effects_disabled())
+ logerror("%s: Local read from undefined register %02X\n", machine().describe_context(), reg);
+ return 0;
+ }
+}
+
+
+//-------------------------------------------------
+// local_register_write - write data to a given
+// register from the local interface
+//-------------------------------------------------
+
+void i82355_device::local_register_write(u8 reg, u8 data)
+{
+ switch (reg)
+ {
+ case 0x00:
+ // ID register byte 0 (manufacturer's code, first and second portions
+ // According to Intel, this should be written after the other 3 ID bytes, but manufacturers don't agree
+ if ((std::exchange(m_id.b.h3, data) & 0xf0) == 0x70 && m_id.w.l != 0x0000)
+ identify_board();
+ break;
+
+ case 0x01:
+ // ID register byte 1 (manufacturer's code, second and third portions)
+ m_id.b.h2 = data;
+ break;
+
+ case 0x02:
+ // ID register byte 2 (product number)
+ m_id.b.h = data;
+ break;
+
+ case 0x03:
+ // ID register byte 3 (product revision)
+ m_id.b.l = data;
+ if ((m_id.b.h3 & 0xf0) != 0x70)
+ identify_board();
+ break;
+
+ case 0x08:
+ // Global configuration register
+ global_config(data);
+ break;
+
+ case 0x0a:
+ case 0x0b:
+ // Semaphore ports
+ m_semaphore_ltest[BIT(reg, 0)] = std::exchange(m_semaphore_flag[BIT(reg, 0)], BIT(data, 0));
+ break;
+
+ case 0x0c:
+ // Local doorbell enable register
+ m_local_doorbell_enable = data;
+ if ((m_local_doorbell_status & m_local_doorbell_enable) != 0x00)
+ set_local_interrupt(0x80);
+ else
+ clear_local_interrupt(0x80);
+ break;
+
+ case 0x0d:
+ // Local doorbell interrupt register (reset bits)
+ m_local_doorbell_status &= ~data;
+ if ((m_local_doorbell_status & m_local_doorbell_enable) == 0x00)
+ clear_local_interrupt(0x80);
+ break;
+
+ case 0x0f:
+ // EISA doorbell interrupt register (set bits)
+ m_eisa_doorbell_status |= data;
+ if ((m_eisa_doorbell_status & m_eisa_doorbell_enable) != 0x00)
+ set_system_interrupt(0x02);
+ break;
+
+ case 0x10:
+ case 0x11:
+ case 0x12:
+ case 0x13:
+ case 0x14:
+ case 0x15:
+ case 0x16:
+ case 0x17:
+ case 0x18:
+ case 0x19:
+ case 0x1a:
+ case 0x1b:
+ case 0x1c:
+ case 0x1d:
+ case 0x1e:
+ case 0x1f:
+ // Mailbox registers
+ m_mailbox[reg & 0x0f] = data;
+ break;
+
+ case 0x30:
+ // Poke data register byte 0
+ m_peek_poke_data.b.l = data;
+ break;
+
+ case 0x31:
+ // Poke data register byte 1
+ m_peek_poke_data.b.h = data;
+ break;
+
+ case 0x32:
+ // Poke data register byte 2
+ m_peek_poke_data.b.h2 = data;
+ break;
+
+ case 0x33:
+ // Poke data register byte 3
+ m_peek_poke_data.b.h3 = data;
+ break;
+
+ case 0x34:
+ // Peek/poke address register byte 0 (lowest 2 bits unused)
+ m_peek_poke_address.b.l = data;
+ break;
+
+ case 0x35:
+ // Peek/poke address register byte 1
+ m_peek_poke_address.b.h = data;
+ break;
+
+ case 0x36:
+ // Peek/poke address register byte 2
+ m_peek_poke_address.b.h2 = data;
+ break;
+
+ case 0x37:
+ // Peek/poke address register byte 3
+ m_peek_poke_address.b.h3 = data;
+ break;
+
+ case 0x38:
+ // Peek/poke control register
+ peek_poke_control(data);
+ break;
+
+ case 0x39:
+ // Range 0 I/O decode base address
+ m_io_decode_base[0] = data;
+ break;
+
+ case 0x3a:
+ // Range 0 I/O decode control address
+ m_io_decode_control[0] = data;
+ break;
+
+ case 0x3b:
+ // Range 1 I/O decode base address
+ m_io_decode_base[1] = data;
+ break;
+
+ case 0x3c:
+ // Range 1 I/O decode control address
+ m_io_decode_control[1] = data;
+ break;
+
+ case 0x40:
+ case 0x60:
+ // Data transfer base count register byte 0
+ m_base_count[BIT(reg, 5)].b.l = data;
+ break;
+
+ case 0x41:
+ case 0x61:
+ // Data transfer base count register byte 1
+ m_base_count[BIT(reg, 5)].b.h = data;
+ break;
+
+ case 0x42:
+ case 0x62:
+ // Data transfer base count register byte 2
+ m_base_count[BIT(reg, 5)].b.h2 = data;
+ break;
+
+ case 0x43:
+ case 0x63:
+ // Data transfer base address register byte 0
+ m_base_address[BIT(reg, 5)].b.l = data;
+ break;
+
+ case 0x44:
+ case 0x64:
+ // Data transfer base address register byte 1
+ m_base_address[BIT(reg, 5)].b.h = data;
+ break;
+
+ case 0x45:
+ case 0x65:
+ // Data transfer base address register byte 2
+ m_base_address[BIT(reg, 5)].b.h2 = data;
+ break;
+
+ case 0x46:
+ case 0x66:
+ // Data transfer base address register byte 3
+ m_base_address[BIT(reg, 5)].b.h3 = data;
+ break;
+
+ case 0x48:
+ case 0x68:
+ // Data transfer channel configuration register
+ transfer_config(BIT(reg, 5), data);
+ break;
+
+ case 0x49:
+ case 0x69:
+ // Data transfer strobe registers (data written is ignored)
+ transfer_strobe(BIT(reg, 5));
+ break;
+
+ case 0x4a:
+ case 0x6a:
+ // Data transfer channel status register (reset bits)
+ m_transfer_status[BIT(reg, 5)] &= ~(data & 0x03);
+ break;
+
+ default:
+ logerror("%s: Local write to undefined or read-only register %02X (%02X)\n", machine().describe_context(), reg, data);
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// local_r - read data onto the local CPU bus
+//-------------------------------------------------
+
+u8 i82355_device::local_r(offs_t offset)
+{
+ switch (offset & 3)
+ {
+ case 0:
+ {
+ u8 result = local_register_read(m_local_index & 0x7f);
+
+ // Autoincrement mode
+ if (BIT(m_local_index, 7) && !machine().side_effects_disabled())
+ m_local_index = (m_local_index + 1) | 0x80;
+
+ return result;
+ }
+
+ case 1:
+ return m_local_index;
+
+ case 2:
+ return m_local_status;
+
+ default:
+ if (!machine().side_effects_disabled())
+ logerror("%s: Local read from reserved register\n", machine().describe_context());
+ return 0;
+ }
+}
+
+
+//-------------------------------------------------
+// local_w - write data from the local CPU bus
+//-------------------------------------------------
+
+void i82355_device::local_w(offs_t offset, u8 data)
+{
+ switch (offset & 3)
+ {
+ case 0:
+ local_register_write(m_local_index & 0x7f, data);
+
+ // Autoincrement mode
+ if (BIT(m_local_index, 7) && !machine().side_effects_disabled())
+ m_local_index = (m_local_index + 1) | 0x80;
+
+ break;
+
+ case 1:
+ m_local_index = data;
+ break;
+
+ case 2:
+ // Local control register (all but one bit is read-only)
+ if (BIT(data, 4))
+ m_local_status |= 0x10;
+ else
+ {
+ m_local_status &= 0xef;
+ clear_local_interrupt(0xe0);
+ }
+ break;
+
+ default:
+ logerror("%s: Local write to reserved register (%02X)\n", machine().describe_context(), data);
+ break;
+ }
+}
diff --git a/src/devices/machine/i82355.h b/src/devices/machine/i82355.h
new file mode 100644
index 00000000000..4b0280edae8
--- /dev/null
+++ b/src/devices/machine/i82355.h
@@ -0,0 +1,91 @@
+// license:BSD-3-Clause
+// copyright-holders:AJR
+/**********************************************************************
+
+ Intel 82355 Bus Master Interface Chip (BMIC)
+
+**********************************************************************/
+
+#ifndef MAME_MACHINE_I82355_H
+#define MAME_MACHINE_I82355_H 1
+
+#pragma once
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> i82355_device
+
+class i82355_device : public device_t
+{
+public:
+ // construction/destruction
+ i82355_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+
+ // callback configuration
+ auto eint_callback() { return m_eint_callback.bind(); }
+ auto lint_callback() { return m_lint_callback.bind(); }
+
+ // local CPU access
+ u8 local_r(offs_t offset);
+ void local_w(offs_t offset, u8 data);
+
+protected:
+ // device-level overrides
+ virtual void device_resolve_objects() override;
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+ // helpers
+ void set_local_interrupt(u8 flag);
+ void clear_local_interrupt(u8 flag);
+ void set_system_interrupt(u8 flag);
+ void clear_system_interrupt(u8 flag);
+ void global_config(u8 flag);
+ void identify_board();
+ void peek_poke_control(u8 flag);
+ void transfer_config(int channel, u8 flag);
+ void transfer_strobe(int channel);
+ u8 local_register_read(u8 reg);
+ void local_register_write(u8 reg, u8 data);
+
+ // callbacks
+ devcb_write_line m_eint_callback;
+ devcb_write_line m_lint_callback;
+
+ // internal state
+ u8 m_local_index;
+ u8 m_local_status;
+ PAIR m_id;
+ u8 m_global_config;
+ u8 m_system_interrupt;
+ bool m_semaphore_flag[2];
+ bool m_semaphore_etest[2];
+ bool m_semaphore_ltest[2];
+ u8 m_local_doorbell_status;
+ u8 m_local_doorbell_enable;
+ u8 m_eisa_doorbell_status;
+ u8 m_eisa_doorbell_enable;
+ u8 m_mailbox[16];
+ PAIR m_peek_poke_data;
+ PAIR m_peek_poke_address;
+ u8 m_peek_poke_control;
+ u8 m_peek_poke_status;
+ u8 m_io_decode_base[2];
+ u8 m_io_decode_control[2];
+ u8 m_transfer_config[2];
+ u8 m_transfer_status[2];
+ PAIR m_base_count[2];
+ PAIR m_base_address[2];
+ PAIR m_current_count[2];
+ PAIR m_current_address[2];
+ PAIR16 m_tbi_base[2];
+ PAIR16 m_tbi_current[2];
+};
+
+// device type declaration
+DECLARE_DEVICE_TYPE(I82355, i82355_device)
+
+#endif // MAME_MACHINE_I82355_H