summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/sega/315-6154.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/sega/315-6154.cpp')
-rw-r--r--src/mame/sega/315-6154.cpp164
1 files changed, 164 insertions, 0 deletions
diff --git a/src/mame/sega/315-6154.cpp b/src/mame/sega/315-6154.cpp
new file mode 100644
index 00000000000..9fcdbf42da8
--- /dev/null
+++ b/src/mame/sega/315-6154.cpp
@@ -0,0 +1,164 @@
+// license:BSD-3-Clause
+// copyright-holders:Samuele Zannoli
+
+#include "emu.h"
+#include "315-6154.h"
+
+DEFINE_DEVICE_TYPE(SEGA315_6154, sega_315_6154_device, "sega315_6154", "Sega 315-6154 Northbridge")
+
+sega_315_6154_device::sega_315_6154_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : pci_host_device(mconfig, SEGA315_6154, tag, owner, clock),
+ m_configuration_config("configuration_space", ENDIANNESS_LITTLE, 32, 20),
+ m_memory_config("memory_space", ENDIANNESS_LITTLE, 32, 32)
+{
+ memset(m_registers, 0, sizeof(m_registers));
+ memset(m_bases, 0, sizeof(m_bases));
+ m_useconfig_14x = false;
+ m_useconfig_18x = false;
+}
+
+void sega_315_6154_device::device_start()
+{
+ pci_host_device::device_start();
+ set_spaces(&space(AS_PCI_MEMORY));
+ // never unmap addresses lower than start
+ memory_window_start = 0x80000000;
+ memory_window_end = 0xffffffff;
+ memory_offset = 0;
+
+ m_configuration = &space(AS_PCI_CONFIG);
+
+ io_window_start = 0xc0000000;
+ io_window_end = 0xc000ffff;
+ io_offset = 0xc0000000;
+
+ save_item(NAME(m_registers));
+ save_item(NAME(m_bases));
+ save_item(NAME(m_useconfig_14x));
+ save_item(NAME(m_useconfig_18x));
+}
+
+void sega_315_6154_device::device_reset()
+{
+ pci_host_device::device_reset();
+ memset(m_registers, 0, sizeof(m_registers));
+}
+
+device_memory_interface::space_config_vector sega_315_6154_device::memory_space_config() const
+{
+ return space_config_vector{
+ std::make_pair(AS_PCI_CONFIG, &m_configuration_config),
+ std::make_pair(AS_PCI_MEMORY, &m_memory_config)
+ };
+}
+
+void sega_315_6154_device::regenerate_config_mapping()
+{
+ // like pci_bridge_device::regenerate_config_mapping() in pci.cpp
+ // but each device n is assigned bit n+11 in the configuration space
+ // devices in different buses must have different numbers
+ address_space *config_space = &space(AS_PCI_CONFIG);
+ config_space->unmap_readwrite(0x00000, 0xfffff);
+ for (int i = 0; i < 9; i++)
+ if (sub_devices[i])
+ {
+ const int s = i >> 3;
+ const int o = (i & 7) << 8;
+ config_space->install_device((0x800 << s) + o, ((0x800 << s) + o) | 0xff, *sub_devices[i], &pci_device::config_map);
+ }
+}
+
+u32 sega_315_6154_device::registers_r(offs_t offset)
+{
+ return m_registers[offset];
+}
+
+static inline void parse_address_register(u32 reg, u32 *base)
+{
+ base[0] = (reg & 0xff) << 24;
+ reg = reg >> 8;
+ base[1] = (reg & 0xff) << 24;
+ reg = reg >> 8;
+ base[2] = (reg & 0xff) << 24;
+ reg = reg >> 8;
+ base[3] = reg << 24;
+}
+
+void sega_315_6154_device::registers_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ COMBINE_DATA(m_registers + offset);
+
+ if (offset == 0x10 / 4)
+ parse_address_register(m_registers[0x10 / 4], m_bases);
+ else if (offset == 0x14 / 4)
+ parse_address_register(m_registers[0x14 / 4], m_bases + 4);
+ else if (offset == 0x18 / 4)
+ parse_address_register(m_registers[0x18 / 4], m_bases + 8);
+ else if (offset == 0x1c / 4)
+ {
+ m_useconfig_14x = (m_registers[0x1c / 4] & 1) != 0;
+ m_useconfig_18x = (m_registers[0x1c / 4] & 2) != 0;
+ }
+ else if (offset == 0x38 / 4)
+ {
+ if (m_registers[0x38 / 4] & 0x01000000)
+ {
+ uint32_t s, d, l;
+
+ s = m_registers[0x30 / 4];
+ d = m_registers[0x34 / 4];
+ l = m_registers[0x38 / 4] & 0xffffff;
+ logerror("got dma transfer request from 0x%08x to 0x%08x size 0x%08x bytes\n", s, d, l << 2);
+ while (l != 0)
+ {
+ space(AS_PCI_MEMORY).write_dword(d, space(AS_PCI_MEMORY).read_dword(s));
+ s += 4;
+ d += 4;
+ l--;
+ }
+ }
+ m_registers[0x38 / 4] &= ~0x01000000;
+ }
+}
+
+template<int Aperture>
+u32 sega_315_6154_device::aperture_r(offs_t offset, u32 mem_mask)
+{
+ const u32 destination_offset = offset & 0x3fffff;
+ const int destination = (offset >> 22) & 3;
+ const int index = Aperture * 4 + destination;
+
+ if ((Aperture == 0) && (destination == 0) && (m_useconfig_14x == true))
+ return m_configuration->read_dword(destination_offset << 2, mem_mask);
+ if ((Aperture == 1) && (destination == 0) && (m_useconfig_18x == true))
+ return m_configuration->read_dword(destination_offset << 2, mem_mask);
+ return space(AS_PCI_MEMORY).read_dword(m_bases[index] + (destination_offset << 2), mem_mask);
+}
+
+template u32 sega_315_6154_device::aperture_r<0>(offs_t offset, u32 mem_mask);
+template u32 sega_315_6154_device::aperture_r<1>(offs_t offset, u32 mem_mask);
+template u32 sega_315_6154_device::aperture_r<2>(offs_t offset, u32 mem_mask);
+
+template<int Aperture>
+void sega_315_6154_device::aperture_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ const u32 destination_offset = offset & 0x3fffff;
+ const int destination = (offset >> 22) & 3;
+ const int index = Aperture * 4 + destination;
+
+ if ((Aperture == 0) && (destination == 0) && (m_useconfig_14x == true))
+ {
+ m_configuration->write_dword(destination_offset << 2, data, mem_mask);
+ return;
+ }
+ if ((Aperture == 1) && (destination == 0) && (m_useconfig_18x == true))
+ {
+ m_configuration->write_dword(destination_offset << 2, data, mem_mask);
+ return;
+ }
+ space(AS_PCI_MEMORY).write_dword(m_bases[index] + (destination_offset << 2), data, mem_mask);
+}
+
+template void sega_315_6154_device::aperture_w<0>(offs_t offset, u32 data, u32 mem_mask);
+template void sega_315_6154_device::aperture_w<1>(offs_t offset, u32 data, u32 mem_mask);
+template void sega_315_6154_device::aperture_w<2>(offs_t offset, u32 data, u32 mem_mask);