summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/nubus/nubus.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bus/nubus/nubus.c')
-rw-r--r--src/devices/bus/nubus/nubus.c475
1 files changed, 475 insertions, 0 deletions
diff --git a/src/devices/bus/nubus/nubus.c b/src/devices/bus/nubus/nubus.c
new file mode 100644
index 00000000000..5d6548289ec
--- /dev/null
+++ b/src/devices/bus/nubus/nubus.c
@@ -0,0 +1,475 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/***************************************************************************
+
+ nubus.c - NuBus bus and card emulation
+
+ by R. Belmont, based heavily on Miodrag Milanovic's ISA8/16 implementation
+
+***************************************************************************/
+
+#include "emu.h"
+#include "emuopts.h"
+#include "nubus.h"
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type NUBUS_SLOT = &device_creator<nubus_slot_device>;
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// nubus_slot_device - constructor
+//-------------------------------------------------
+nubus_slot_device::nubus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, NUBUS_SLOT, "NUBUS_SLOT", tag, owner, clock, "nubus_slot", __FILE__),
+ device_slot_interface(mconfig, *this)
+{
+}
+
+nubus_slot_device::nubus_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) :
+ device_t(mconfig, type, name, tag, owner, clock, shortname, source),
+ device_slot_interface(mconfig, *this)
+{
+}
+
+void nubus_slot_device::static_set_nubus_slot(device_t &device, const char *tag, const char *slottag)
+{
+ nubus_slot_device &nubus_card = dynamic_cast<nubus_slot_device &>(device);
+ nubus_card.m_nubus_tag = tag;
+ nubus_card.m_nubus_slottag = slottag;
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void nubus_slot_device::device_start()
+{
+ device_nubus_card_interface *dev = dynamic_cast<device_nubus_card_interface *>(get_card_device());
+
+ if (dev) device_nubus_card_interface::static_set_nubus_tag(*dev, m_nubus_tag, m_nubus_slottag);
+}
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type NUBUS = &device_creator<nubus_device>;
+
+void nubus_device::static_set_cputag(device_t &device, const char *tag)
+{
+ nubus_device &nubus = downcast<nubus_device &>(device);
+ nubus.m_cputag = tag;
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// nubus_device - constructor
+//-------------------------------------------------
+
+nubus_device::nubus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, NUBUS, "NUBUS", tag, owner, clock, "nubus", __FILE__),
+ m_out_irq9_cb(*this),
+ m_out_irqa_cb(*this),
+ m_out_irqb_cb(*this),
+ m_out_irqc_cb(*this),
+ m_out_irqd_cb(*this),
+ m_out_irqe_cb(*this)
+{
+}
+
+nubus_device::nubus_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) :
+ device_t(mconfig, type, name, tag, owner, clock, shortname, source),
+ m_out_irq9_cb(*this),
+ m_out_irqa_cb(*this),
+ m_out_irqb_cb(*this),
+ m_out_irqc_cb(*this),
+ m_out_irqd_cb(*this),
+ m_out_irqe_cb(*this)
+{
+}
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void nubus_device::device_start()
+{
+ m_maincpu = machine().device<cpu_device>(m_cputag);
+ // resolve callbacks
+ m_out_irq9_cb.resolve_safe();
+ m_out_irqa_cb.resolve_safe();
+ m_out_irqb_cb.resolve_safe();
+ m_out_irqc_cb.resolve_safe();
+ m_out_irqd_cb.resolve_safe();
+ m_out_irqe_cb.resolve_safe();
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void nubus_device::device_reset()
+{
+}
+
+void nubus_device::add_nubus_card(device_nubus_card_interface *card)
+{
+ m_device_list.append(*card);
+}
+
+void nubus_device::install_device(offs_t start, offs_t end, read8_delegate rhandler, write8_delegate whandler, UINT32 mask)
+{
+ m_maincpu = machine().device<cpu_device>(m_cputag);
+ int buswidth = m_maincpu->space_config(AS_PROGRAM)->m_databus_width;
+ switch(buswidth)
+ {
+ case 32:
+ m_maincpu->space(AS_PROGRAM).install_readwrite_handler(start, end, rhandler, whandler, mask);
+ break;
+ case 64:
+ m_maincpu->space(AS_PROGRAM).install_readwrite_handler(start, end, rhandler, whandler, ((UINT64)mask<<32)|mask);
+ break;
+ default:
+ fatalerror("NUBUS: Bus width %d not supported\n", buswidth);
+ }
+}
+
+void nubus_device::install_device(offs_t start, offs_t end, read16_delegate rhandler, write16_delegate whandler, UINT32 mask)
+{
+ m_maincpu = machine().device<cpu_device>(m_cputag);
+ int buswidth = m_maincpu->space_config(AS_PROGRAM)->m_databus_width;
+ switch(buswidth)
+ {
+ case 32:
+ m_maincpu->space(AS_PROGRAM).install_readwrite_handler(start, end, rhandler, whandler, mask);
+ break;
+ case 64:
+ m_maincpu->space(AS_PROGRAM).install_readwrite_handler(start, end, rhandler, whandler, ((UINT64)mask<<32)|mask);
+ break;
+ default:
+ fatalerror("NUBUS: Bus width %d not supported\n", buswidth);
+ }
+}
+
+void nubus_device::install_device(offs_t start, offs_t end, read32_delegate rhandler, write32_delegate whandler, UINT32 mask)
+{
+ m_maincpu = machine().device<cpu_device>(m_cputag);
+ int buswidth = m_maincpu->space_config(AS_PROGRAM)->m_databus_width;
+ switch(buswidth)
+ {
+ case 32:
+ m_maincpu->space(AS_PROGRAM).install_readwrite_handler(start, end, rhandler, whandler, mask);
+ break;
+ case 64:
+ m_maincpu->space(AS_PROGRAM).install_readwrite_handler(start, end, rhandler, whandler, ((UINT64)mask<<32)|mask);
+ break;
+ default:
+ fatalerror("NUBUS: Bus width %d not supported\n", buswidth);
+ }
+}
+
+void nubus_device::install_readonly_device(offs_t start, offs_t end, read32_delegate rhandler, UINT32 mask)
+{
+ m_maincpu = machine().device<cpu_device>(m_cputag);
+ int buswidth = m_maincpu->space_config(AS_PROGRAM)->m_databus_width;
+ switch(buswidth)
+ {
+ case 32:
+ m_maincpu->space(AS_PROGRAM).install_read_handler(start, end, rhandler, mask);
+ break;
+ case 64:
+ m_maincpu->space(AS_PROGRAM).install_read_handler(start, end, rhandler, ((UINT64)mask<<32)|mask);
+ break;
+ default:
+ fatalerror("NUBUS: Bus width %d not supported\n", buswidth);
+ }
+}
+
+void nubus_device::install_writeonly_device(offs_t start, offs_t end, write32_delegate whandler, UINT32 mask)
+{
+ m_maincpu = machine().device<cpu_device>(m_cputag);
+ int buswidth = m_maincpu->space_config(AS_PROGRAM)->m_databus_width;
+ switch(buswidth)
+ {
+ case 32:
+ m_maincpu->space(AS_PROGRAM).install_write_handler(start, end, whandler, mask);
+ break;
+ case 64:
+ m_maincpu->space(AS_PROGRAM).install_write_handler(start, end, whandler, ((UINT64)mask<<32)|mask);
+ break;
+ default:
+ fatalerror("NUBUS: Bus width %d not supported\n", buswidth);
+ }
+}
+
+void nubus_device::install_bank(offs_t start, offs_t end, offs_t mask, offs_t mirror, const char *tag, UINT8 *data)
+{
+// printf("install_bank: %s @ %x->%x mask %x mirror %x\n", tag, start, end, mask, mirror);
+ m_maincpu = machine().device<cpu_device>(m_cputag);
+ address_space &space = m_maincpu->space(AS_PROGRAM);
+ space.install_readwrite_bank(start, end, mask, mirror, tag );
+ machine().root_device().membank(tag)->set_base(data);
+}
+
+void nubus_device::set_irq_line(int slot, int state)
+{
+ switch (slot)
+ {
+ case 0x9: irq9_w(state); break;
+ case 0xa: irqa_w(state); break;
+ case 0xb: irqb_w(state); break;
+ case 0xc: irqc_w(state); break;
+ case 0xd: irqd_w(state); break;
+ case 0xe: irqe_w(state); break;
+ }
+}
+
+// interrupt request from nubus card
+WRITE_LINE_MEMBER( nubus_device::irq9_w ) { m_out_irq9_cb(state); }
+WRITE_LINE_MEMBER( nubus_device::irqa_w ) { m_out_irqa_cb(state); }
+WRITE_LINE_MEMBER( nubus_device::irqb_w ) { m_out_irqb_cb(state); }
+WRITE_LINE_MEMBER( nubus_device::irqc_w ) { m_out_irqc_cb(state); }
+WRITE_LINE_MEMBER( nubus_device::irqd_w ) { m_out_irqd_cb(state); }
+WRITE_LINE_MEMBER( nubus_device::irqe_w ) { m_out_irqe_cb(state); }
+
+//**************************************************************************
+// DEVICE CONFIG NUBUS CARD INTERFACE
+//**************************************************************************
+
+
+//**************************************************************************
+// DEVICE NUBUS CARD INTERFACE
+//**************************************************************************
+
+//-------------------------------------------------
+// device_nubus_card_interface - constructor
+//-------------------------------------------------
+
+device_nubus_card_interface::device_nubus_card_interface(const machine_config &mconfig, device_t &device)
+ : device_slot_card_interface(mconfig, device),
+ m_nubus(NULL),
+ m_nubus_tag(NULL)
+{
+}
+
+
+//-------------------------------------------------
+// ~device_nubus_card_interface - destructor
+//-------------------------------------------------
+
+device_nubus_card_interface::~device_nubus_card_interface()
+{
+}
+
+void device_nubus_card_interface::static_set_nubus_tag(device_t &device, const char *tag, const char *slottag)
+{
+ device_nubus_card_interface &nubus_card = dynamic_cast<device_nubus_card_interface &>(device);
+ nubus_card.m_nubus_tag = tag;
+ nubus_card.m_nubus_slottag = slottag;
+}
+
+void device_nubus_card_interface::set_nubus_device()
+{
+ if (!strncmp(m_nubus_slottag, "pds030", 6))
+ {
+ m_slot = 0x9; // '030 PDS slots phantom slot as NuBus slots $9, $A, and $B
+ }
+ else if (!strncmp(m_nubus_slottag, "lcpds", 6))
+ {
+ m_slot = 0xe; // LC PDS slots phantom slot as NuBus slot $E
+ }
+ else
+ {
+ // extract the slot number from the last digit of the slot tag
+ int tlen = strlen(m_nubus_slottag);
+
+ if (m_nubus_slottag[tlen-1] == '9')
+ {
+ m_slot = (m_nubus_slottag[tlen-1] - '9') + 9;
+ }
+ else
+ {
+ m_slot = (m_nubus_slottag[tlen-1] - 'a') + 0xa;
+ }
+ }
+
+ if (m_slot < 9 || m_slot > 0xe)
+ {
+ fatalerror("Slot %x out of range for Apple NuBus\n", m_slot);
+ }
+
+ m_nubus = dynamic_cast<nubus_device *>(device().machine().device(m_nubus_tag));
+ m_nubus->add_nubus_card(this);
+}
+
+void device_nubus_card_interface::install_bank(offs_t start, offs_t end, offs_t mask, offs_t mirror, const char *tag, UINT8 *data)
+{
+ char bank[256];
+
+ // append an underscore and the slot name to the bank so it's guaranteed unique
+ strcpy(bank, tag);
+ strcat(bank, "_");
+ strcat(bank, m_nubus_slottag);
+
+ m_nubus->install_bank(start, end, mask, mirror, bank, data);
+}
+
+void device_nubus_card_interface::install_declaration_rom(device_t *dev, const char *romregion, bool mirror_all_mb, bool reverse_rom)
+{
+ bool inverted = false;
+
+ UINT8 *rom = device().machine().root_device().memregion(dev->subtag(romregion).c_str())->base();
+ UINT32 romlen = device().machine().root_device().memregion(dev->subtag(romregion).c_str())->bytes();
+
+// printf("ROM length is %x, last bytes are %02x %02x\n", romlen, rom[romlen-2], rom[romlen-1]);
+
+ if (reverse_rom)
+ {
+ UINT8 temp;
+ UINT32 endptr = romlen-1;
+
+ for (UINT32 idx = 0; idx < romlen / 2; idx++)
+ {
+ temp = rom[idx];
+ rom[idx] = rom[endptr];
+ rom[endptr] = temp;
+ endptr--;
+ }
+ }
+
+ UINT8 byteLanes = rom[romlen-1];
+ // check if all bits are inverted
+ if (rom[romlen-2] == 0xff)
+ {
+ byteLanes ^= 0xff;
+ inverted = true;
+ }
+
+ #if 0
+ FILE *f;
+ f = fopen("romout.bin", "wb");
+ fwrite(rom, romlen, 1, f);
+ fclose(f);
+ #endif
+
+ switch (byteLanes)
+ {
+ case 0x0f: // easy case: all 4 lanes (still must scramble for 32-bit BE bus though)
+ m_declaration_rom.resize(romlen);
+ for (int i = 0; i < romlen; i++)
+ {
+ m_declaration_rom[BYTE4_XOR_BE(i)] = rom[i];
+ }
+ break;
+
+ case 0xe1: // lane 0 only
+ m_declaration_rom.resize(romlen*4);
+ memset(&m_declaration_rom[0], 0, romlen*4);
+ for (int i = 0; i < romlen; i++)
+ {
+ m_declaration_rom[BYTE4_XOR_BE(i*4)] = rom[i];
+ }
+ romlen *= 4;
+ break;
+
+ case 0xd2: // lane 1 only
+ m_declaration_rom.resize(romlen*4);
+ memset(&m_declaration_rom[0], 0, romlen*4);
+ for (int i = 0; i < romlen; i++)
+ {
+ m_declaration_rom[BYTE4_XOR_BE((i*4)+1)] = rom[i];
+ }
+ romlen *= 4;
+ break;
+
+ case 0xb4: // lane 2 only
+ m_declaration_rom.resize(romlen*4);
+ memset(&m_declaration_rom[0], 0, romlen*4);
+ for (int i = 0; i < romlen; i++)
+ {
+ m_declaration_rom[BYTE4_XOR_BE((i*4)+2)] = rom[i];
+ }
+ romlen *= 4;
+ break;
+
+ case 0x78: // lane 3 only
+ m_declaration_rom.resize(romlen*4);
+ memset(&m_declaration_rom[0], 0, romlen*4);
+ for (int i = 0; i < romlen; i++)
+ {
+ m_declaration_rom[BYTE4_XOR_BE((i*4)+3)] = rom[i];
+ }
+ romlen *= 4;
+ break;
+
+ case 0xc3: // lanes 0, 1
+ m_declaration_rom.resize(romlen*2);
+ memset(&m_declaration_rom[0], 0, romlen*4);
+ for (int i = 0; i < romlen/2; i++)
+ {
+ m_declaration_rom[BYTE4_XOR_BE((i*4)+0)] = rom[(i*2)];
+ m_declaration_rom[BYTE4_XOR_BE((i*4)+1)] = rom[(i*2)+1];
+ }
+ romlen *= 2;
+ break;
+
+ case 0xa5: // lanes 0, 2
+ m_declaration_rom.resize(romlen*2);
+ memset(&m_declaration_rom[0], 0, romlen*4);
+ for (int i = 0; i < romlen/2; i++)
+ {
+ m_declaration_rom[BYTE4_XOR_BE((i*4)+0)] = rom[(i*2)];
+ m_declaration_rom[BYTE4_XOR_BE((i*4)+2)] = rom[(i*2)+1];
+ }
+ romlen *= 2;
+ break;
+
+ case 0x3c: // lanes 2,3
+ m_declaration_rom.resize(romlen*2);
+ memset(&m_declaration_rom[0], 0, romlen*4);
+ for (int i = 0; i < romlen/2; i++)
+ {
+ m_declaration_rom[BYTE4_XOR_BE((i*4)+2)] = rom[(i*2)];
+ m_declaration_rom[BYTE4_XOR_BE((i*4)+3)] = rom[(i*2)+1];
+ }
+ romlen *= 2;
+ break;
+
+ default:
+ fatalerror("NuBus: unhandled byteLanes value %02x\n", byteLanes);
+ }
+
+ // the slot manager can supposedly handle inverted ROMs by itself, but let's do it for it anyway
+ if (inverted)
+ {
+ for (int i = 0; i < romlen; i++)
+ {
+ m_declaration_rom[i] ^= 0xff;
+ }
+ }
+
+ // now install the ROM
+ UINT32 addr = get_slotspace() + 0x01000000;
+ char bankname[128];
+ strcpy(bankname, "rom_");
+ strcat(bankname, m_nubus_slottag);
+ addr -= romlen;
+// printf("Installing ROM at %x, length %x\n", addr, romlen);
+ if (mirror_all_mb) // mirror the declaration ROM across all 16 megs of the slot space
+ {
+ m_nubus->install_bank(addr, addr+romlen-1, 0, 0x00f00000, bankname, &m_declaration_rom[0]);
+ }
+ else
+ {
+ m_nubus->install_bank(addr, addr+romlen-1, 0, 0, bankname, &m_declaration_rom[0]);
+ }
+}