summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/sis630_host.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/sis630_host.cpp')
-rw-r--r--src/devices/machine/sis630_host.cpp441
1 files changed, 441 insertions, 0 deletions
diff --git a/src/devices/machine/sis630_host.cpp b/src/devices/machine/sis630_host.cpp
new file mode 100644
index 00000000000..5088585aa5f
--- /dev/null
+++ b/src/devices/machine/sis630_host.cpp
@@ -0,0 +1,441 @@
+// license: BSD-3-Clause
+// copyright-holders: Angelo Salese
+/**************************************************************************************************
+
+ SiS630 host implementation (northbridge)
+
+ TODO:
+ - AGP and VGA interfaces;
+ - Is ACPI declared here shared with LPC or a different one?
+ \- shutms11 maps it to the exact same place (I/O $5000), may be interleaved?
+ - HW trap control;
+ - PCI-Hole;
+ - Convert RAM to device;
+ - Integrated VGA control;
+
+**************************************************************************************************/
+
+#include "emu.h"
+#include "sis630_host.h"
+
+
+#define LOG_IO (1U << 1) // log PCI register accesses
+#define LOG_TODO (1U << 2) // log unimplemented registers
+#define LOG_MAP (1U << 3) // log full remaps
+#define LOG_AGP (1U << 4) // log AGP
+
+#define VERBOSE (LOG_GENERAL | LOG_IO | LOG_TODO | LOG_AGP)
+//#define LOG_OUTPUT_FUNC osd_printf_warning
+
+#include "logmacro.h"
+
+#define LOGIO(...) LOGMASKED(LOG_IO, __VA_ARGS__)
+#define LOGMAP(...) LOGMASKED(LOG_MAP, __VA_ARGS__)
+#define LOGTODO(...) LOGMASKED(LOG_TODO, __VA_ARGS__)
+#define LOGAGP(...) LOGMASKED(LOG_AGP, __VA_ARGS__)
+
+DEFINE_DEVICE_TYPE(SIS630_HOST, sis630_host_device, "sis630_host", "SiS 630 Host-to-PCI Bridge")
+
+sis630_host_device::sis630_host_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : pci_host_device(mconfig, SIS630_HOST, tag, owner, clock)
+ , m_host_cpu(*this, finder_base::DUMMY_TAG)
+{
+}
+
+void sis630_host_device::device_start()
+{
+ pci_host_device::device_start();
+
+ memory_window_start = 0;
+ memory_window_end = 0xffffffff;
+ memory_offset = 0;
+ io_window_start = 0;
+ io_window_end = 0xffff;
+ io_offset = 0;
+
+ memory_space = &m_host_cpu->space(AS_PROGRAM);
+ io_space = &m_host_cpu->space(AS_IO);
+ add_map(8*1024*1024, M_MEM, FUNC(sis630_host_device::memory_map));
+
+ m_ram.resize(m_ram_size/4);
+}
+
+void sis630_host_device::device_reset()
+{
+ pci_host_device::device_reset();
+
+ command = 0x0005;
+ status = 0x0210;
+
+ m_shadow_ram_ctrl = 0;
+ m_vga_control = 0;
+ std::fill(std::begin(m_agp_mailbox), std::end(m_agp_mailbox), 0);
+
+ remap_cb();
+}
+
+void sis630_host_device::device_add_mconfig(machine_config &config)
+{
+
+}
+
+void sis630_host_device::config_map(address_map &map)
+{
+ pci_host_device::config_map(map);
+ // override header type, needed for actual IDE detection
+ map(0x0e, 0x0e).lr8(NAME([] () { return 0x80; }));
+
+ // override first BAR slot for gfx window base address
+ map(0x10, 0x13).rw(FUNC(pci_device::address_base_r), FUNC(pci_device::address_base_w));
+
+ map(0x34, 0x34).r(FUNC(sis630_host_device::capptr_r));
+
+ // host & DRAM regs
+// map(0x50, 0x51) host interface control
+// map(0x52, 0x53) DRAM misc control 1 & 2
+// map(0x54, 0x55) DRAM timing control 1 & 2
+// map(0x56, 0x56) DRAM misc control 3
+// map(0x57, 0x57) SDRAM/VCM init control
+// map(0x58, 0x58) DRAM buffer slew rating
+// map(0x59, 0x5a) DRAM buffer strength and current rating
+// map(0x5b, 0x5b) PCI buffer strength and current rating
+// map(0x60, 0x62) DRAMx type register (x = 0, 1 or 2)
+ map(0x63, 0x63).rw(FUNC(sis630_host_device::dram_status_r), FUNC(sis630_host_device::dram_status_w));
+// map(0x64, 0x64) FBC control register
+// map(0x65, 0x65) DIMM switch control
+// map(0x68, 0x69) ACPI I/O base
+ map(0x6a, 0x6a).rw(FUNC(sis630_host_device::smram_r), FUNC(sis630_host_device::smram_w));
+// map(0x6b, 0x6b) self refresh command output timing control
+// map(0x6c, 0x6c) power management DRAM self refresh control
+
+// Shadow RAM & PCI-Hole area
+ map(0x70, 0x73).rw(FUNC(sis630_host_device::shadow_ram_ctrl_r), FUNC(sis630_host_device::shadow_ram_ctrl_w));
+ map(0x77, 0x77).rw(FUNC(sis630_host_device::pci_hole_r), FUNC(sis630_host_device::pci_hole_w));
+// map(0x78, 0x79) PCI-Hole #1 allocation
+// map(0x7a, 0x7b) PCI-Hole #2 allocation
+
+// HW Trap control
+// map(0x7c, 0x7c) VGA
+// map(0x7d, 0x7d) Southbridge
+// map(0x7e, 0x7f) Northbridge
+
+// Host Bridge & PCI arbiter characteristics
+// map(0x80, 0x80) Target bridge DRAM characteristics
+// map(0x81, 0x81) PCI discard timer for delay transaction
+// map(0x82, 0x82) PCI target bridge bus characteristics
+// map(0x83, 0x83) CPU to PCI characteristics
+// map(0x84, 0x85) PCI grant timer
+// map(0x86, 0x86) CPU idle timer for PCI
+// map(0x87, 0x87) Host bridge & PCI master priority timer
+// map(0x88, 0x89) PCI discard timer for PCI hold
+
+// Clock Control
+// map(0x8c, 0x8c) SDRCLK/SDWCLK
+// map(0x8d, 0x8d) SDWCLK
+// map(0x8e, 0x8e) CPU & SDRAM clock relationship
+// map(0x8f, 0x8f) FBCRCLK/FBCWCLK control
+
+// GART and page table regs
+// map(0x90, 0x93) GART base address
+// map(0x94, 0x94) Graphic window control
+// map(0x97, 0x97) Page table cache control
+// map(0x98, 0x98) Page table cache invalidation control
+
+ // Integrated VGA control
+ map(0x9c, 0x9c).rw(FUNC(sis630_host_device::vga_control_r), FUNC(sis630_host_device::vga_control_w));
+
+// AGP
+// map(0xa0, 0xa3) DRAM priority timer control
+ map(0xa0, 0xa3).rw(FUNC(sis630_host_device::agp_priority_timer_r), FUNC(sis630_host_device::agp_priority_timer_w));
+// map(0xa4, 0xaf) General purpose register (generic mailboxes?)
+ map(0xa4, 0xaf).rw(FUNC(sis630_host_device::agp_mailbox_r), FUNC(sis630_host_device::agp_mailbox_w));
+// map(0xc0, 0xc3) AGP capability identifier
+ map(0xc0, 0xc3).r(FUNC(sis630_host_device::agp_id_r));
+ map(0xc4, 0xc7).r(FUNC(sis630_host_device::agp_status_r));
+ map(0xc8, 0xcb).rw(FUNC(sis630_host_device::agp_command_r), FUNC(sis630_host_device::agp_command_w));
+}
+
+// TODO: verify if we need these trampolines
+void sis630_host_device::memory_map(address_map &map)
+{
+}
+
+void sis630_host_device::map_shadowram(address_space *memory_space, uint32_t start_offs, uint32_t end_offs, bool read_enable, bool write_enable)
+{
+ LOGMAP("- 0x%08x-0x%08x ", start_offs, end_offs);
+
+ switch(write_enable << 1 | read_enable)
+ {
+ case 0:
+ LOGMAP("shadow RAM off\n");
+ //memory_space->unmap_write(start_offs, end_offs);
+ break;
+ case 1:
+ LOGMAP("shadow RAM r/o\n");
+ memory_space->install_rom(start_offs, end_offs, &m_ram[start_offs/4]);
+ break;
+ case 2:
+ LOGMAP("shadow RAM w/o\n");
+ //memory_space->install_rom(start_offs, end_offs, m_region->base() + bios_rom_offset);
+ memory_space->install_writeonly(start_offs, end_offs, &m_ram[start_offs/4]);
+ break;
+ case 3:
+ LOGMAP("shadow RAM r/w\n");
+ memory_space->install_ram(start_offs, end_offs, &m_ram[start_offs/4]);
+ break;
+ }
+}
+
+
+void sis630_host_device::map_extra(
+ uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
+ uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space
+) {
+ io_space->install_device(0, 0xffff, *static_cast<pci_host_device *>(this), &pci_host_device::io_configuration_access_map);
+
+ regenerate_config_mapping();
+
+ memory_space->install_ram(0x00000000, 0x0009ffff, &m_ram[0x00000000/4]);
+// memory_space->install_ram(0x000a0000, 0x000bffff, &m_ram[0x000a0000/4]);
+
+ LOGMAP("Host Remapping table (shadow: %08x smram: %02x):\n", m_shadow_ram_ctrl, m_smram);
+
+ for (int i = 0; i < 12; i ++)
+ {
+ u32 start_offs = 0x000c0000 + i * 0x4000;
+ u32 end_offs = start_offs + 0x3fff;
+
+ map_shadowram(
+ memory_space,
+ start_offs, end_offs,
+ bool(BIT(m_shadow_ram_ctrl, i)), bool(BIT(m_shadow_ram_ctrl, i + 16))
+ );
+ }
+
+ map_shadowram(
+ memory_space,
+ 0xf0000, 0xfffff,
+ bool(BIT(m_shadow_ram_ctrl, 12)), bool(BIT(m_shadow_ram_ctrl, 28))
+ );
+
+ // System Management Memory Region handling
+ // Potentially overrides VGA VRAM if on
+ if (BIT(m_smram, 4))
+ {
+ u8 smram_config = m_smram >> 5;
+
+ // POST checks for config 6 only, other settings aren't tested
+ // TODO: setting 3 and 5 are undocumented, verify if mirror logic is correct
+ if (smram_config == 3 || smram_config == 5)
+ throw emu_fatalerror("SMRAM config = %d!", smram_config);
+
+ const u32 host_addresses[8] = {
+ 0xe0000, 0xb0000, 0xe0000, 0xb0000,
+ 0xe0000, 0xe0000, 0xa0000, 0xa0000
+ };
+ const u32 smram_sizes[8] = {
+ 0x07fff, 0xffff, 0x7fff, 0xffff,
+ 0x07fff, 0x7fff, 0xffff, 0x1ffff
+ };
+ const u32 system_memory_addresses[8] = {
+ 0xe0000, 0xb0000, 0xa0000, 0xb0000,
+ 0xb0000, 0xb0000, 0xa0000, 0xa0000
+ };
+ const u32 host_address_start = host_addresses[smram_config];
+ const u32 host_address_end = host_address_start + smram_sizes[smram_config];
+ const u32 system_memory_address = system_memory_addresses[smram_config];
+ LOGMAP("- SMRAM %02x relocation %08x-%08x to %08x\n"
+ , m_smram
+ , host_address_start
+ , host_address_end
+ , system_memory_address
+ );
+ memory_space->install_ram(host_address_start, host_address_end, &m_ram[system_memory_address/4]);
+ }
+
+ // TODO: shadow RAM bit 15?
+ // Always on after POST, should give shared access to PCI cards on the bus,
+ // BIOS mentions 8M of "shared memory", unknown how this works out.
+ // TODO: undocumented shadow RAM configs bits 7 and 23 after POST IDE check on shutms11 (programmer errors?)
+
+ memory_space->install_ram(0x00100000, m_ram_size - 1, &m_ram[0x00100000/4]);
+}
+
+
+
+
+
+/*
+ *
+ * I/O implemtation
+ *
+ */
+
+u8 sis630_host_device::capptr_r()
+{
+ LOGIO("Read capptr_r [$34]\n");
+ return 0xc0;
+}
+
+u8 sis630_host_device::dram_status_r()
+{
+ LOGIO("Read DRAM status [$63] (%02x)\n", m_dram_status);
+ return m_dram_status;
+}
+
+void sis630_host_device::dram_status_w(u8 data)
+{
+ LOGIO("Write DRAM status [$63] %02x\n", data);
+
+ m_dram_status = data;
+ // TODO: bit 7 is shared memory control
+}
+
+
+u8 sis630_host_device::smram_r()
+{
+ LOGIO("Read SMRAM [$6a] (%02x)\n", m_smram);
+ return m_smram;
+}
+
+void sis630_host_device::smram_w(u8 data)
+{
+ LOGIO("Write SMRAM [$6a] %02x\n", data);
+ m_smram = data;
+ remap_cb();
+}
+
+u32 sis630_host_device::shadow_ram_ctrl_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGIO("Read shadow RAM setting [$70] %08x (%08x)\n", mem_mask, m_shadow_ram_ctrl);
+ return m_shadow_ram_ctrl;
+}
+
+void sis630_host_device::shadow_ram_ctrl_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ COMBINE_DATA(&m_shadow_ram_ctrl);
+ LOGMAP("Write shadow RAM setting [$70] %08x & %08x (%08x)\n", data, mem_mask, m_shadow_ram_ctrl);
+ remap_cb();
+}
+
+u8 sis630_host_device::pci_hole_r()
+{
+ LOGIO("Read PCI hole [$77]\n");
+ return 0;
+}
+
+void sis630_host_device::pci_hole_w(u8 data)
+{
+ LOGIO("Write PCI hole [$77] %02x\n", data);
+ if (data)
+ LOG("Warning: PCI hole area enabled! %02x\n", data);
+}
+
+u8 sis630_host_device::vga_control_r()
+{
+ LOGIO("Read integrated VGA control data [$9c] %02x\n", m_vga_control);
+ return m_vga_control;
+}
+
+void sis630_host_device::vga_control_w(u8 data)
+{
+ LOGIO("Write integrated VGA control data [$9c] %02x\n", data);
+ // TODO: "integrated VGA control" (?)
+ m_vga_control = data;
+// remap_cb();
+}
+
+u32 sis630_host_device::agp_priority_timer_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGIO("Read AGP priority timer [$a0] %08x (%08x)\n", mem_mask, m_agp_priority_timer);
+ return m_agp_priority_timer;
+}
+
+void sis630_host_device::agp_priority_timer_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ COMBINE_DATA(&m_agp_priority_timer);
+ LOGIO("Write AGP priority timer [$a0] %08x & %08x (%08x)\n", data, mem_mask, m_agp_priority_timer);
+}
+
+u8 sis630_host_device::agp_mailbox_r(offs_t offset)
+{
+ LOGIO("Read AGP mailbox [$%02x] (%02x)\n", offset + 0xa4, m_agp_mailbox[offset]);
+ return m_agp_mailbox[offset];
+}
+
+void sis630_host_device::agp_mailbox_w(offs_t offset, u8 data)
+{
+ LOGIO("Write AGP mailbox [$%02x] %02x\n", offset + 0xa4, data);
+ m_agp_mailbox[offset] = data;
+}
+
+// TODO: move to generic interface
+u32 sis630_host_device::agp_id_r()
+{
+ LOGAGP("Read AGP ID [$c0]\n");
+ // bits 23-16 AGP v2.0
+ // bits 15-8 0x00 no NEXT_PTR (NULL terminates here)
+ // bits 7-0 CAP_ID (0x02 for AGP)
+ return 0x00200002;
+}
+
+u32 sis630_host_device::agp_status_r()
+{
+ LOGAGP("Read AGP status [$c4]\n");
+ // bits 31-24 RQ max number of AGP command requests (0x1f + 1 = 32)
+ // bit 9: SBA, side band addressing enabled
+ // ---- -xxx RATE
+ // ---- -1-- 4X transfer capable
+ // ---- --1- 2X transfer capable
+ // ---- ---1 1X transfer capable
+ // NB: documentation claims a RATE of 0x03 then contradicts with "111b" value, do the math
+ // It gets setup with a 4X at POST, assume 0x07 is right
+
+ // Stuff that isn't enabled here:
+ // bit 5: 4G support address greater than 4 GB
+ // bit 4: FW transfer support
+
+ return 0x1f000207;
+}
+
+u32 sis630_host_device::agp_command_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGAGP("Read AGP command [$c8] %d %d %02x\n", m_agp.sba_enable, m_agp.enable, m_agp.data_rate);
+ // TODO: enable gets cleared by AGP_RESET, or even from PCI RST#
+ return m_agp.sba_enable << 9 | m_agp.enable << 8 | (m_agp.data_rate & 7);
+}
+
+void sis630_host_device::agp_command_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGAGP("Write AGP command [$c8] %08x & %08x\n", data, mem_mask);
+ if (ACCESSING_BITS_8_15)
+ {
+ m_agp.sba_enable = bool(BIT(m_agp.sba_enable, 9));
+ m_agp.enable = bool(BIT(m_agp.enable, 8));
+ LOGAGP("- SBA_ENABLE = %d AGP_ENABLE = %d\n", m_agp.sba_enable, m_agp.enable);
+ }
+
+ if (ACCESSING_BITS_0_7)
+ {
+ // quick checker, to be translated into an AGP interface
+ std::map<u8, std::string> agp_transfer_rates = {
+ { 0, "(illegal 0)" },
+ { 1, "1X" },
+ { 2, "2X" },
+ { 3, "(illegal 3)" },
+ { 4, "4X" },
+ { 5, "(illegal 5)" },
+ { 6, "(illegal 6)" },
+ { 7, "(illegal 7)" }
+ };
+
+ // make sure the AGP DATA_RATE specs are honored
+ const u8 data_rate = data & 7;
+ LOGAGP("- DATA_RATE = %s enabled=%d\n", agp_transfer_rates.at(data_rate), m_agp.enable);
+ m_agp.data_rate = data_rate;
+
+ // should probably never be enabled since it reads out from the ID
+ if (data & 0x30)
+ LOG("Warning: AGP unsupported i/f set 4G=%d FW_Enable=%d\n", bool(BIT(data, 5)), bool(BIT(data, 4)));
+ }
+}