mirror of
https://github.com/holub/mame
synced 2025-04-22 16:31:49 +03:00
Add very preliminary Intel 82355 BMIC device
This commit is contained in:
parent
112062f7bb
commit
9b3a449790
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
};
|
||||
|
884
src/devices/machine/i82355.cpp
Normal file
884
src/devices/machine/i82355.cpp
Normal 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;
|
||||
}
|
||||
}
|
91
src/devices/machine/i82355.h
Normal file
91
src/devices/machine/i82355.h
Normal 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
|
Loading…
Reference in New Issue
Block a user