From 9b3a449790644eb2f72352c1f877ce8df4e43280 Mon Sep 17 00:00:00 2001 From: AJR Date: Sun, 21 Apr 2019 00:34:29 -0400 Subject: Add very preliminary Intel 82355 BMIC device --- scripts/src/machine.lua | 12 + scripts/target/mame/arcade.lua | 1 + scripts/target/mame/mess.lua | 1 + src/devices/bus/isa/aha174x.cpp | 7 +- src/devices/bus/isa/tekram_dc820.cpp | 16 +- src/devices/bus/isa/ultra24f.cpp | 16 +- src/devices/bus/isa/ultra24f.h | 5 + src/devices/machine/i82355.cpp | 884 +++++++++++++++++++++++++++++++++++ src/devices/machine/i82355.h | 91 ++++ 9 files changed, 1026 insertions(+), 7 deletions(-) create mode 100644 src/devices/machine/i82355.cpp create mode 100644 src/devices/machine/i82355.h 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 @@ -1217,6 +1217,18 @@ if (MACHINES["I8214"]~=null) then } 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 m_uscpu; + required_device m_bmic; required_device m_fdc; required_region_ptr 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 -- cgit v1.2.3