Add very preliminary Intel 82355 BMIC device

This commit is contained in:
AJR 2019-04-21 00:34:29 -04:00
parent 112062f7bb
commit 9b3a449790
9 changed files with 1026 additions and 7 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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