From e6180e3510bef6ea8ffb6abddf64d7d3006829ed Mon Sep 17 00:00:00 2001 From: Angelo Salese Date: Mon, 23 May 2022 17:27:33 +0200 Subject: [PATCH] Initial work towards a sis630 based chipset driver (#9635) - Add more or less complete implementations of sis630_host, sis950_lpc, sis630_gui, sis5513_ide, sis7001_usb, sis7018_audio, sis900_eth devices; - Removed gamecstl.cpp in favour to the new sis630.cpp driver; - i386.cpp: enable CMOV feature for Pentium III and 4; - i386.cpp: add PSN stub feature for Pentium III; New machines marked as NOT_WORKING ---------------------------------- Shuttle MS-11 [Angelo Salese, archive.org] --- scripts/src/machine.lua | 16 + scripts/target/mame/arcade.lua | 2 +- scripts/target/mame/mess.lua | 1 + src/devices/cpu/i386/i386.cpp | 32 +- src/devices/cpu/i386/i386.h | 2 + src/devices/machine/pci.cpp | 22 + src/devices/machine/pci.h | 2 +- src/devices/machine/sis5513_ide.cpp | 363 ++++++++++++ src/devices/machine/sis5513_ide.h | 89 +++ src/devices/machine/sis630_gui.cpp | 709 ++++++++++++++++++++++++ src/devices/machine/sis630_gui.h | 144 +++++ src/devices/machine/sis630_host.cpp | 441 +++++++++++++++ src/devices/machine/sis630_host.h | 98 ++++ src/devices/machine/sis7001_usb.cpp | 93 ++++ src/devices/machine/sis7001_usb.h | 53 ++ src/devices/machine/sis7018_audio.cpp | 126 +++++ src/devices/machine/sis7018_audio.h | 46 ++ src/devices/machine/sis900_eth.cpp | 161 ++++++ src/devices/machine/sis900_eth.h | 53 ++ src/devices/machine/sis950_lpc.cpp | 764 ++++++++++++++++++++++++++ src/devices/machine/sis950_lpc.h | 176 ++++++ src/devices/machine/sis950_smbus.cpp | 108 ++++ src/devices/machine/sis950_smbus.h | 32 ++ src/devices/video/pc_vga.cpp | 8 + src/devices/video/pc_vga.h | 7 +- src/mame/arcade.flt | 2 +- src/mame/drivers/gamecstl.cpp | 506 ----------------- src/mame/drivers/sis630.cpp | 305 ++++++++++ src/mame/mame.lst | 9 +- src/mame/mess.flt | 1 + 30 files changed, 3853 insertions(+), 518 deletions(-) create mode 100644 src/devices/machine/sis5513_ide.cpp create mode 100644 src/devices/machine/sis5513_ide.h create mode 100644 src/devices/machine/sis630_gui.cpp create mode 100644 src/devices/machine/sis630_gui.h create mode 100644 src/devices/machine/sis630_host.cpp create mode 100644 src/devices/machine/sis630_host.h create mode 100644 src/devices/machine/sis7001_usb.cpp create mode 100644 src/devices/machine/sis7001_usb.h create mode 100644 src/devices/machine/sis7018_audio.cpp create mode 100644 src/devices/machine/sis7018_audio.h create mode 100644 src/devices/machine/sis900_eth.cpp create mode 100644 src/devices/machine/sis900_eth.h create mode 100644 src/devices/machine/sis950_lpc.cpp create mode 100644 src/devices/machine/sis950_lpc.h create mode 100644 src/devices/machine/sis950_smbus.cpp create mode 100644 src/devices/machine/sis950_smbus.h delete mode 100644 src/mame/drivers/gamecstl.cpp create mode 100644 src/mame/drivers/sis630.cpp diff --git a/scripts/src/machine.lua b/scripts/src/machine.lua index 06d11c4d388..ff31c758e05 100644 --- a/scripts/src/machine.lua +++ b/scripts/src/machine.lua @@ -2737,6 +2737,22 @@ if (MACHINES["PCI"]~=null) then MAME_DIR .. "src/devices/machine/vrc5074.h", MAME_DIR .. "src/devices/machine/gt64xxx.cpp", MAME_DIR .. "src/devices/machine/gt64xxx.h", + MAME_DIR .. "src/devices/machine/sis5513_ide.cpp", + MAME_DIR .. "src/devices/machine/sis5513_ide.h", + MAME_DIR .. "src/devices/machine/sis630_host.cpp", + MAME_DIR .. "src/devices/machine/sis630_host.h", + MAME_DIR .. "src/devices/machine/sis630_gui.cpp", + MAME_DIR .. "src/devices/machine/sis630_gui.h", + MAME_DIR .. "src/devices/machine/sis7001_usb.cpp", + MAME_DIR .. "src/devices/machine/sis7001_usb.h", + MAME_DIR .. "src/devices/machine/sis7018_audio.cpp", + MAME_DIR .. "src/devices/machine/sis7018_audio.h", + MAME_DIR .. "src/devices/machine/sis900_eth.cpp", + MAME_DIR .. "src/devices/machine/sis900_eth.h", + MAME_DIR .. "src/devices/machine/sis950_lpc.cpp", + MAME_DIR .. "src/devices/machine/sis950_lpc.h", + MAME_DIR .. "src/devices/machine/sis950_smbus.cpp", + MAME_DIR .. "src/devices/machine/sis950_smbus.h", MAME_DIR .. "src/devices/machine/sis85c496.cpp", MAME_DIR .. "src/devices/machine/sis85c496.h", } diff --git a/scripts/target/mame/arcade.lua b/scripts/target/mame/arcade.lua index 16ab338b889..530315717eb 100644 --- a/scripts/target/mame/arcade.lua +++ b/scripts/target/mame/arcade.lua @@ -2116,6 +2116,7 @@ files { MAME_DIR .. "src/mame/drivers/pcxt.cpp", MAME_DIR .. "src/mame/drivers/quakeat.cpp", MAME_DIR .. "src/mame/drivers/queen.cpp", + MAME_DIR .. "src/mame/drivers/sis630.cpp", } createMAMEProjects(_target, _subtarget, "igs") @@ -4844,7 +4845,6 @@ files { MAME_DIR .. "src/mame/drivers/gambl186.cpp", MAME_DIR .. "src/mame/drivers/galaxi.cpp", MAME_DIR .. "src/mame/drivers/galgame.cpp", - MAME_DIR .. "src/mame/drivers/gamecstl.cpp", MAME_DIR .. "src/mame/drivers/gamemasters.cpp", MAME_DIR .. "src/mame/drivers/gammagic.cpp", MAME_DIR .. "src/mame/drivers/gamtor.cpp", diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index 6dca65f2fb9..69747cf033d 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -3390,6 +3390,7 @@ files { MAME_DIR .. "src/mame/drivers/nforcepc.cpp", MAME_DIR .. "src/mame/drivers/pc.cpp", MAME_DIR .. "src/mame/drivers/pcipc.cpp", + MAME_DIR .. "src/mame/drivers/sis630.cpp", MAME_DIR .. "src/mame/drivers/tandy1t.cpp", MAME_DIR .. "src/mame/drivers/tosh1000.cpp", MAME_DIR .. "src/mame/machine/tosh1000_bram.cpp", diff --git a/src/devices/cpu/i386/i386.cpp b/src/devices/cpu/i386/i386.cpp index 82d26e9b2c7..152691db3c3 100644 --- a/src/devices/cpu/i386/i386.cpp +++ b/src/devices/cpu/i386/i386.cpp @@ -3333,12 +3333,38 @@ void pentium3_device::device_reset() // [ 0:0] FPU on chip // [ 4:4] Time Stamp Counter + // [ 8:8] CMPXCHG8B instruction // [ D:D] PTE Global Bit - m_feature_flags = 0x00002011; // TODO: enable relevant flags here + // [15:15] CMOV and FCMOV + // [18:18] PSN (Processor Serial Number, P3 only) + m_feature_flags = 0x0004a111; // TODO: enable relevant flags here CHANGE_PC(m_eip); } +void pentium3_device::opcode_cpuid() +{ + switch (REG32(EAX)) + { + case 0x00000003: + { + // TODO: lower part of 96 bits s/n for Pentium III processors only (ditched in 4) + // (upper 32-bits part is in EAX=1 EAX return) + // NB: if this is triggered from an Arcade system then there's a very good chance + // that is trying to tie the serial as a form of copy protection cfr. gamecstl + logerror("CPUID with EAX=00000003 (Pentium III PSN?) at %08x!\n", m_eip); + REG32(EAX) = 0x00000000; + REG32(EBX) = 0x00000000; + REG32(ECX) = 0x01234567; + REG32(EDX) = 0x89abcdef; + CYCLES(CYCLES_CPUID); + break; + } + default: + pentium_pro_device::opcode_cpuid(); + } +} + /*****************************************************************************/ /* Intel Pentium 4 */ @@ -3402,7 +3428,9 @@ void pentium4_device::device_reset() m_cpu_version = REG32(EDX); // [ 0:0] FPU on chip - m_feature_flags = 0x00000001; // TODO: enable relevant flags here + // [ 8:8] CMPXCHG8B instruction + // [15:15] CMOV and FCMOV + m_feature_flags = 0x00008101; // TODO: enable relevant flags here CHANGE_PC(m_eip); } diff --git a/src/devices/cpu/i386/i386.h b/src/devices/cpu/i386/i386.h index 5c769994699..60bf5b59b8d 100644 --- a/src/devices/cpu/i386/i386.h +++ b/src/devices/cpu/i386/i386.h @@ -1650,6 +1650,8 @@ public: protected: virtual void device_start() override; virtual void device_reset() override; + + virtual void opcode_cpuid() override; }; diff --git a/src/devices/machine/pci.cpp b/src/devices/machine/pci.cpp index 2620f1fc642..993d45efed4 100644 --- a/src/devices/machine/pci.cpp +++ b/src/devices/machine/pci.cpp @@ -1,5 +1,10 @@ // license:BSD-3-Clause // copyright-holders:Olivier Galibert +/* + * References: + * - PCI local bus (rev 2.x) + * - https://wiki.osdev.org/PCI + */ #include "emu.h" #include "pci.h" @@ -87,6 +92,12 @@ pci_device::pci_device(const machine_config &mconfig, device_type type, const ch } } +// main_id << 16 = vendor ID ($00-$01) +// main_id & 0xffff = device ID ($02-$03) +// revision = board versioning ($08) +// pclass = programming interface/sub class code/base class code ($09-$0b) +// subsystem_id << 16 = sub vendor ID ($2c-$2d) - NB: not all cards have these +// subsystem_id & 0xffff = sub device ID ($2e-$2f) / void pci_device::set_ids(uint32_t _main_id, uint8_t _revision, uint32_t _pclass, uint32_t _subsystem_id) { main_id = _main_id; @@ -257,6 +268,17 @@ void pci_device::expansion_base_w(offs_t offset, uint32_t data, uint32_t mem_mas remap_cb(); } +// if non-zero a CAPability PoinTeR marks an offset in PCI config space where a standard extension is located +// For example if capptr_r is 0xc0 then [offset+0xc0] has a capability identifier that is set with: +// bits 31-16 +// bits 15-8 next capptr offset, 0x00 to determine the given item as last +// bits 7-0 capability ID: +// - 0x01 PMI Power Management Interface +// - 0x02 AGP Accelerated Graphics Port +// - 0x03 VPD Vital Product Data +// - 0x04 Slot Identification +// - 0x05 MSI Message Signaled Interrupts +// - 0x06 CompactPCI Hot Swap uint8_t pci_device::capptr_r() { return 0x00; diff --git a/src/devices/machine/pci.h b/src/devices/machine/pci.h index 0a0a570b451..c8ed2e84c18 100644 --- a/src/devices/machine/pci.h +++ b/src/devices/machine/pci.h @@ -193,7 +193,7 @@ public: uint16_t iolimitu_r(); void iolimitu_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); uint16_t bridge_control_r(); - void bridge_control_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + virtual void bridge_control_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); protected: enum diff --git a/src/devices/machine/sis5513_ide.cpp b/src/devices/machine/sis5513_ide.cpp new file mode 100644 index 00000000000..503751c6388 --- /dev/null +++ b/src/devices/machine/sis5513_ide.cpp @@ -0,0 +1,363 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese +/************************************************************************************************** + + SiS 5513 IDE controller + + TODO: + - Derive from common pci-ide.cpp interface + (what flavour that emulates tho? PCI regs 0x40-0x52 don't match) + +**************************************************************************************************/ + +#include "emu.h" +#include "sis5513_ide.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 VERBOSE (LOG_GENERAL | LOG_IO | LOG_TODO | LOG_MAP) +//#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_DEVICE_TYPE(SIS5513_IDE, sis5513_ide_device, "sis5513_ide", "SiS 5513 IDE Controller") + +sis5513_ide_device::sis5513_ide_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : pci_device(mconfig, SIS5513_IDE, tag, owner, clock) + , m_ide1(*this, "ide1") + , m_ide2(*this, "ide2") + , m_irq_pri_callback(*this) + , m_irq_sec_callback(*this) + , m_bus_master_space(*this, finder_base::DUMMY_TAG, AS_PROGRAM) +{ +} + +void sis5513_ide_device::device_add_mconfig(machine_config &config) +{ + BUS_MASTER_IDE_CONTROLLER(config, m_ide1).options(ata_devices, "hdd", nullptr, false); + m_ide1->irq_handler().set([this](int state) { m_irq_pri_callback(state); }); + m_ide1->set_bus_master_space(m_bus_master_space); + + BUS_MASTER_IDE_CONTROLLER(config, m_ide2).options(ata_devices, "cdrom", nullptr, false); + m_ide2->irq_handler().set([this](int state) { m_irq_sec_callback(state); }); + m_ide2->set_bus_master_space(m_bus_master_space); +} + +void sis5513_ide_device::config_map(address_map &map) +{ + pci_device::config_map(map); +// map(0x10, 0x4f).unmaprw(); + map(0x09, 0x09).w(FUNC(sis5513_ide_device::prog_if_w)); + // base I/O relocation (effective only when native mode is on) +// map(0x10, 0x13) Primary channel command base +// map(0x14, 0x17) Primary channel control base +// map(0x18, 0x1b) Secondary channel command base +// map(0x1c, 0x1f) Secondary channel control base + +// map(0x20, 0x23) Bus master IDE control register base (0x10 I/O regs) + map(0x10, 0x23).rw(FUNC(sis5513_ide_device::bar_r), FUNC(sis5513_ide_device::bar_w)); + map(0x24, 0x27).unmaprw(); + map(0x40, 0x52).rw(FUNC(sis5513_ide_device::unmap_log_r), FUNC(sis5513_ide_device::unmap_log_w)); + map(0x4a, 0x4a).rw(FUNC(sis5513_ide_device::ide_ctrl_0_r), FUNC(sis5513_ide_device::ide_ctrl_0_w)); + map(0x52, 0x52).rw(FUNC(sis5513_ide_device::ide_misc_ctrl_r), FUNC(sis5513_ide_device::ide_misc_ctrl_w)); + + +// map(0x2c, 0x2f) subsystem ID (written once) + +// map(0x3c, 0x3d) interrupt line/pin + +// map(0x40, 0x40) IDE Primary channel master data recovery time +// map(0x41, 0x41) IDE Primary channel master data active time (Ultra DMA) +// map(0x42, 0x42) IDE Primary channel slave data recovery time +// map(0x43, 0x43) IDE Primary channel slave data active time (Ultra DMA) +// map(0x44, 0x47) ^ Same for IDE Secondary + +// map(0x48, 0x48) IDE status +// map(0x4a, 0x4b) IDE general control regs + +// map(0x4c, 0x4d) prefetch count of primary channel +// map(0x4e, 0x4f) prefetch count of secondary channel + +// map(0x52, 0x52) IDE misc control regs +} + +#if 0 +void sis5513_ide_device::compatible_io_map(address_map &map) +{ + map(0x0170, 0x0177).rw(FUNC(sis5513_ide_device::ide2_read32_cs0_r), FUNC(sis5513_ide_device::ide2_write32_cs0_w)); + map(0x01f0, 0x01f7).rw(FUNC(sis5513_ide_device::ide1_read32_cs0_r), FUNC(sis5513_ide_device::ide1_write32_cs0_w)); + map(0x0376, 0x0376).rw(FUNC(sis5513_ide_device::ide2_read_cs1_r), FUNC(sis5513_ide_device::ide2_write_cs1_w)); + map(0x03f6, 0x03f6).rw(FUNC(sis5513_ide_device::ide1_read_cs1_r), FUNC(sis5513_ide_device::ide1_write_cs1_w)); +} +#endif + +// $1f0 +void sis5513_ide_device::ide1_command_map(address_map &map) +{ + map(0, 7).rw(FUNC(sis5513_ide_device::ide1_read32_cs0_r), FUNC(sis5513_ide_device::ide1_write32_cs0_w)); +} + +// $3f4 +void sis5513_ide_device::ide1_control_map(address_map &map) +{ + map(2, 2).rw(FUNC(sis5513_ide_device::ide1_read_cs1_r), FUNC(sis5513_ide_device::ide1_write_cs1_w)); +} + +// $170 +void sis5513_ide_device::ide2_command_map(address_map &map) +{ + map(0, 7).rw(FUNC(sis5513_ide_device::ide2_read32_cs0_r), FUNC(sis5513_ide_device::ide2_write32_cs0_w)); +} + +// $374 +void sis5513_ide_device::ide2_control_map(address_map &map) +{ + map(2, 2).rw(FUNC(sis5513_ide_device::ide2_read_cs1_r), FUNC(sis5513_ide_device::ide2_write_cs1_w)); +} + +void sis5513_ide_device::bus_master_ide_control_map(address_map &map) +{ + map(0x0, 0x7).rw(m_ide1, FUNC(bus_master_ide_controller_device::bmdma_r), FUNC(bus_master_ide_controller_device::bmdma_w)); + map(0x8, 0xf).rw(m_ide2, FUNC(bus_master_ide_controller_device::bmdma_r), FUNC(bus_master_ide_controller_device::bmdma_w)); +} + +void sis5513_ide_device::device_start() +{ + pci_device::device_start(); + + m_irq_pri_callback.resolve(); + m_irq_sec_callback.resolve(); + + add_map(8, M_IO, FUNC(sis5513_ide_device::ide1_command_map)); + add_map(4, M_IO, FUNC(sis5513_ide_device::ide1_control_map)); + add_map(8, M_IO, FUNC(sis5513_ide_device::ide2_command_map)); + add_map(4, M_IO, FUNC(sis5513_ide_device::ide2_control_map)); + add_map(16, M_IO, FUNC(sis5513_ide_device::bus_master_ide_control_map)); +} + + +void sis5513_ide_device::device_reset() +{ + pci_device::device_reset(); + + command = 0x0000; + status = 0x0000; + pclass = 0x01018a; + m_ide_ctrl0 = 0; + m_ide_misc = 0; + m_bar[0] = 0x1f0; + m_bar[1] = 0x3f4; + m_bar[2] = 0x170; + m_bar[3] = 0x374; + m_bar[4] = 0xf00; + for (int i = 0; i < 5; i++) + bank_infos[i].adr = m_bar[i]; + remap_cb(); +} + +inline bool sis5513_ide_device::ide1_mode() +{ + return (pclass & 0x3) == 3; +} + +inline bool sis5513_ide_device::ide2_mode() +{ + return (pclass & 0xc) == 0xc; +} + +// In compatible mode BARs with legacy addresses but can values written can still be readout. +// In practice we need to override writes and make sure we flush remapping accordingly +inline void sis5513_ide_device::flush_ide_mode() +{ + // Map Primary IDE Channel + if (ide1_mode()) + { + // PCI Mode + pci_device::address_base_w(0, m_bar[0]); + pci_device::address_base_w(1, m_bar[1]); + } + else + { + // Legacy Mode + pci_device::address_base_w(0, 0x1f0); + pci_device::address_base_w(1, 0x3f4); + } + + // Map Secondary IDE Channel + if (ide2_mode()) + { + // PCI Mode + pci_device::address_base_w(2, m_bar[2]); + pci_device::address_base_w(3, m_bar[3]); + } + else + { + // Legacy Mode + pci_device::address_base_w(2, 0x170); + pci_device::address_base_w(3, 0x374); + } +} + +void sis5513_ide_device::prog_if_w(u8 data) +{ + uint32_t oldVal = pclass; + pclass = (pclass & ~(0xff)) | (data & 0xff); + // Check for switch to/from compatibility (legacy) mode from/to pci mode + if ((oldVal ^ pclass) & 0xf) + flush_ide_mode(); +} + +u32 sis5513_ide_device::bar_r(offs_t offset) +{ + if (bank_reg_infos[offset].bank == -1) + return 0; + int bid = bank_reg_infos[offset].bank; + if (bank_reg_infos[offset].hi) + return bank_infos[bid].adr >> 32; + int flags = bank_infos[bid].flags; + return (m_bar[offset] & ~(bank_infos[bid].size - 1)) | (flags & M_IO ? 1 : 0) | (flags & M_64A ? 4 : 0) | (flags & M_PREF ? 8 : 0); +} + +void sis5513_ide_device::bar_w(offs_t offset, u32 data) +{ + m_bar[offset] = data; + // Bits 0 (primary) and 2 (secondary) control if the mapping is legacy or BAR + switch (offset) { + case 0 ... 1: + if (ide1_mode()) + pci_device::address_base_w(offset, data); + break; + case 2 ... 3: + if (ide2_mode()) + pci_device::address_base_w(offset, data); + break; + default: + // Only the first 4 bars are controlled by pif + pci_device::address_base_w(offset, data); + } + logerror("Mapping bar[%i] = %08x\n", offset, data); +} + +u8 sis5513_ide_device::ide_ctrl_0_r() +{ + LOGIO("IDE ctrl 0 read [$4a] %02x\n", m_ide_ctrl0); + return m_ide_ctrl0; +} + +void sis5513_ide_device::ide_ctrl_0_w(u8 data) +{ + LOGIO("IDE ctrl 0 write [$4a] %02x\n", data); + m_ide_ctrl0 = data; + // TODO: bit 1 disables IDE ch. 0, bit 2 ch. 1 +// remap_cb(); +} + +u8 sis5513_ide_device::ide_misc_ctrl_r() +{ + LOGIO("IDE misc ctrl read [$52] %02x\n", m_ide_misc); + return m_ide_misc; +} + +void sis5513_ide_device::ide_misc_ctrl_w(u8 data) +{ + LOGIO("IDE misc ctrl write [$52] %02x\n", data); + m_ide_misc = data; + + const bool compatible_mode = BIT(m_ide_misc, 2); + pclass &= 0xffff85; + + if (compatible_mode) + { + //LOGMAP("- Compatible Mode\n"); + intr_pin = 0; + } + else + { + // Native Mode + pclass |= 0xa; + intr_pin = 1; + } + + flush_ide_mode(); +} + +/* + * Debugging + */ + +u8 sis5513_ide_device::unmap_log_r(offs_t offset) +{ + LOGTODO("IDE Unemulated [%02x] R\n", offset + 0x40); + return 0; +} + +void sis5513_ide_device::unmap_log_w(offs_t offset, u8 data) +{ + LOGTODO("IDE Unemulated [%02x] %02x W\n", offset + 0x40, data); +} + +/* + * Start of legacy handling, to be moved out + */ + +uint32_t sis5513_ide_device::ide1_read32_cs0_r(offs_t offset, uint32_t mem_mask) +{ + if (!(command & 1)) + return 0xffffffff; + return m_ide1->read_cs0(offset, mem_mask); +} + +void sis5513_ide_device::ide1_write32_cs0_w(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + if (!(command & 1)) + return; + m_ide1->write_cs0(offset, data, mem_mask); +} + +uint32_t sis5513_ide_device::ide2_read32_cs0_r(offs_t offset, uint32_t mem_mask) +{ + if (!(command & 1)) + return 0xffffffff; + return m_ide2->read_cs0(offset, mem_mask); +} + +void sis5513_ide_device::ide2_write32_cs0_w(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + if (!(command & 1)) + return; + m_ide2->write_cs0(offset, data, mem_mask); +} + +uint8_t sis5513_ide_device::ide1_read_cs1_r() +{ + if (!(command & 1)) + return 0xff; + return m_ide1->read_cs1(1, 0xff0000) >> 16; +} + +void sis5513_ide_device::ide1_write_cs1_w(uint8_t data) +{ + if (!(command & 1)) + return; + m_ide1->write_cs1(1, data << 16, 0xff0000); +} + +uint8_t sis5513_ide_device::ide2_read_cs1_r() +{ + if (!(command & 1)) + return 0xff; + return m_ide2->read_cs1(1, 0xff0000) >> 16; +} + +void sis5513_ide_device::ide2_write_cs1_w(uint8_t data) +{ + if (!(command & 1)) + return; + m_ide2->write_cs1(1, data << 16, 0xff0000); +} diff --git a/src/devices/machine/sis5513_ide.h b/src/devices/machine/sis5513_ide.h new file mode 100644 index 00000000000..89d4916c47b --- /dev/null +++ b/src/devices/machine/sis5513_ide.h @@ -0,0 +1,89 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese + +#ifndef MAME_MACHINE_SIS5513_IDE_H +#define MAME_MACHINE_SIS5513_IDE_H + +#pragma once + +#include "pci.h" +#include "machine/pci-ide.h" + +class sis5513_ide_device : public pci_device +{ +public: + template sis5513_ide_device( + const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, + T &&host_tag, uint32_t bmspace = AS_PROGRAM + ) : sis5513_ide_device(mconfig, tag, owner, clock) + { + // IDE controller with 0xd0 as programming i/f "ATA Host Adapters standard" + // pclass bits 1-3 are actually 1 when controller is in native mode + // pclass bits 0-2 can be r/w from $09 + set_ids(0x10395513, 0xd0, 0x010180, 0x00); + m_bus_master_space.set_tag(host_tag, bmspace); + } + sis5513_ide_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + auto irq_pri() { return m_irq_pri_callback.bind(); } + auto irq_sec() { return m_irq_sec_callback.bind(); } + +protected: + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_add_mconfig(machine_config &config) override; + +// virtual void reset_all_mappings() override; + +// virtual void 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) override; + + virtual void config_map(address_map &map) override; + + void ide1_command_map(address_map &map); + void ide1_control_map(address_map &map); + void ide2_command_map(address_map &map); + void ide2_control_map(address_map &map); + void bus_master_ide_control_map(address_map &map); +private: + required_device m_ide1; + required_device m_ide2; + devcb_write_line m_irq_pri_callback; + devcb_write_line m_irq_sec_callback; + required_address_space m_bus_master_space; + + bool ide1_mode(); + bool ide2_mode(); + + u32 bar_r(offs_t offset); + void bar_w(offs_t offset, u32 data); + u32 m_bar[5]{}; + + void prog_if_w(u8 data); + u8 ide_ctrl_0_r(); + void ide_ctrl_0_w(u8 data); + u8 ide_misc_ctrl_r(); + void ide_misc_ctrl_w(u8 data); + + u8 m_ide_ctrl0 = 0; + u8 m_ide_misc = 0; + + uint32_t ide1_read32_cs0_r(offs_t offset, uint32_t mem_mask = ~0); + void ide1_write32_cs0_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); + uint32_t ide2_read32_cs0_r(offs_t offset, uint32_t mem_mask = ~0); + void ide2_write32_cs0_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); + uint8_t ide1_read_cs1_r(); + void ide1_write_cs1_w(uint8_t data); + uint8_t ide2_read_cs1_r(); + void ide2_write_cs1_w(uint8_t data); + +// void compatible_io_map(address_map &map); + void flush_ide_mode(); + + u8 unmap_log_r(offs_t offset); + void unmap_log_w(offs_t offset, u8 data); +}; + +DECLARE_DEVICE_TYPE(SIS5513_IDE, sis5513_ide_device) + +#endif diff --git a/src/devices/machine/sis630_gui.cpp b/src/devices/machine/sis630_gui.cpp new file mode 100644 index 00000000000..be5d6030612 --- /dev/null +++ b/src/devices/machine/sis630_gui.cpp @@ -0,0 +1,709 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese +/************************************************************************************************** + + SiS 630 Video GUI portion (SVGA-based) & 301 video bridge + + - 630 core is SVGA based: + \- has two sets of extended CRTC ($3c4) regs; + \- a dedicated MPEG-2 video playback interface; + \- a digital video interface to 301; + - 301 draws to a separate monitor, and it was originally tied to a SiS300 AGP card, + (which we don't have a dump of at the time of this writing): + \- can select VGA, NTSC, PAL or LCD sources; + \- Has separate set of VGA and RAMDAC regs; + \- Has TV encoder; + \- Has macrovision regs; + - GUI is the 630 PCI/AGP i/f + \- it's actually internal to the rest of 630; + \- 301 is external but closely tied to it: the digital i/f ports (RIO+$4) selects where it + should start drawing/sync etc. while the "VGA2 regs" (RIO+$14) seems to be a custom set + rather than be related at all (i.e. it most likely be just capable to have VGA-like + resolutions). + - sis_main.c portions refers to the correlated Linux driver at + https://github.com/torvalds/linux/blob/master/drivers/video/fbdev/sis/sis_main.c + + TODO: + - Backward port '630 GUI/PCI implementation to '300 and other flavours + (needs VGA mods to do this properly); + - 2d acceleration; + - Turbo queue stuff; + - AGP; + - interlace (cfr. xubuntu 6.10 splash screen on 1024x768x32); + - xubuntu 6.10 splash screen is decentered (zooming?) + - xubuntu 6.10 splash screen text is unreadable or not visible depending on res selected; + - Interface with '301 bridge (a lovely can of worms); + +**************************************************************************************************/ + +#include "emu.h" +#include "sis630_gui.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 LOG_SVGA (1U << 5) // log SVGA + +#define VERBOSE (LOG_GENERAL | LOG_IO | LOG_TODO | LOG_MAP | LOG_AGP | LOG_SVGA) +//#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 LOGSVGA(...) LOGMASKED(LOG_SVGA, __VA_ARGS__) + +/************************** + * + * SVGA implementation + * + *************************/ + +// TODO: later variant of 5598 +// (definitely doesn't have dual segment mode for instance) +DEFINE_DEVICE_TYPE(SIS630_SVGA, sis630_svga_device, "sis630_svga", "SiS 630 SVGA") + +sis630_svga_device::sis630_svga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : svga_device(mconfig, SIS630_SVGA, tag, owner, clock) +{ + +} + +void sis630_svga_device::device_start() +{ + svga_device::device_start(); + zero(); + + // Avoid an infinite loop when displaying. 0 is not possible anyway. + vga.crtc.maximum_scan_line = 1; + + // copy over interfaces + vga.read_dipswitch.set(nullptr); //read_dipswitch; + vga.svga_intf.seq_regcount = 0x05; + vga.svga_intf.crtc_regcount = 0x27; + vga.svga_intf.vram_size = 64*1024*1024; + //vga.memory = std::make_unique(vga.svga_intf.vram_size); +} + +void sis630_svga_device::device_reset() +{ + svga_device::device_reset(); + + m_svga_bank_reg_w = m_svga_bank_reg_r = 0; + m_unlock_reg = false; + //m_dual_seg_mode = false; +} + +// Page 144 +uint8_t sis630_svga_device::crtc_reg_read(uint8_t index) +{ + if (index < 0x19) + return svga_device::crtc_reg_read(index); + + // make sure '301 CRT2 is not enabled + if (index == 0x30) + return 0; + + if (index == 0x31) + return 0x60; + + if (index == 0x32) + return 0x20; + + // TODO: if one of these is 0xff then it enables a single port transfer to $b8000 + return m_crtc_ext_regs[index]; +} + +void sis630_svga_device::crtc_reg_write(uint8_t index, uint8_t data) +{ + if (index < 0x19) + svga_device::crtc_reg_write(index, data); + else + { + m_crtc_ext_regs[index] = data; + } +} + +uint8_t sis630_svga_device::seq_reg_read(uint8_t index) +{ + switch (index) + { + // extended id register + case 0x05: + return m_unlock_reg ? 0xa1 : 0x21; + case 0x06: + return m_ramdac_mode; + case 0x07: + return m_ext_misc_ctrl_0; + case 0x0a: + return m_ext_vert_overflow; + case 0x0b ... 0x0c: + return m_ext_horz_overflow[index - 0xb]; + case 0x0d: + return vga.crtc.start_addr_latch >> 16; + case 0x14: + // sis_main.c calculates VRAM size in two ways: + // 1. the legacy way ('300), by probing this register + // 2. by reading '630 PCI host register $63 (as shared DRAM?) + // Method 1 seems enough to enforce "64MB" message at POST, + // 2 is probably more correct but unsure about how to change the shared area in BIOS + // (shutms11 will always write a "0x41" on fresh CMOS then a "0x47" + // on successive boots no matter what) + const u8 bus_width = m_seq_ext_regs[index] & 0xc0; + return (bus_width) | ((vga.svga_intf.vram_size / (1024 * 1024) - 1) & 0x3f); + } + + //LOGSVGA("Unemulated index R [%02x]\n", index); + return m_seq_ext_regs[index]; +} + +std::tuple sis630_svga_device::flush_true_color_mode() +{ + // punt if extended or true color is off + if ((m_ramdac_mode & 0x12) != 0x12) + return std::make_tuple(0, 0); + + const u8 res = (m_ext_misc_ctrl_0 & 4) >> 2; + + return std::make_tuple(res, res ^ 1); +} + +void sis630_svga_device::recompute_params() +{ + // TODO: ext clock + recompute_params_clock(1, XTAL(25'174'800).value()); +} + + +void sis630_svga_device::seq_reg_write(uint8_t index, uint8_t data) +{ + if (index < vga.svga_intf.seq_regcount) + svga_device::seq_reg_write(index, data); + else + { + if (index == 0x05) + { + m_unlock_reg = (data == 0x86); + LOGSVGA("Unlock register write %02x (%s)\n", data, m_unlock_reg ? "unlocked" : "locked"); + } + else + { + if (!m_unlock_reg) + { + LOGSVGA("Attempt to write to extended SVGA while locked [$%02x] -> %02x\n", index, data); + return; + } + + m_seq_ext_regs[index] = data; + + switch(index) + { + /* + * x--- ---- GFX mode linear addressing enable + * -x-- ---- GFX hardware cursor display + * --x- ---- GFX mode interlace + * ---x ---- True Color enable (ties with index 0x07 bit 2) + * ---- x--- RGB16 enable + * ---- -x-- RGB15 enable + * ---- --x- enhanced GFX mode enable + * ---- ---x enhanced text mode enable + */ + case 0x06: + m_ramdac_mode = data; + LOGSVGA("RAMDAC mode %02x\n", data); + + if (!BIT(data, 1)) + { + svga.rgb8_en = svga.rgb15_en = svga.rgb16_en = svga.rgb24_en = svga.rgb32_en = 0; + } + else + { + if (BIT(data, 2)) + svga.rgb15_en = 1; + if (BIT(data, 3)) + svga.rgb16_en = 1; + std::tie(svga.rgb24_en, svga.rgb32_en) = flush_true_color_mode(); + } + break; + case 0x07: + LOGSVGA("Extended Misc. Control register 0 (%02x) %02x\n", index, data); + m_ext_misc_ctrl_0 = data; + std::tie(svga.rgb24_en, svga.rgb32_en) = flush_true_color_mode(); + break; + case 0x0a: + LOGSVGA("Extended vertical Overflow register (%02x) %02x\n", index, data); + m_ext_vert_overflow = data; + vga.crtc.vert_retrace_end = (vga.crtc.vert_retrace_end & 0xf) | ((data & 0x20) >> 1); + vga.crtc.vert_blank_end = (vga.crtc.vert_blank_end & 0x00ff) | ((data & 0x10) << 4); + vga.crtc.vert_retrace_start = (vga.crtc.vert_retrace_start & 0x03ff) | ((data & 0x08) << 7); + vga.crtc.vert_blank_start = (vga.crtc.vert_blank_start & 0x03ff) | ((data & 0x04) << 8); + vga.crtc.vert_disp_end = (vga.crtc.vert_disp_end & 0x03ff) | ((data & 0x02) << 9); + vga.crtc.vert_total = (vga.crtc.vert_total & 0x03ff) | ((data & 0x01) << 10); + recompute_params(); + break; + case 0x0b: + //m_dual_seg_mode = bool(BIT(data, 3)); + LOGSVGA("Extended horizontal Overflow 1 (%02x) %02x\n", index, data); + m_ext_horz_overflow[0] = data; + + vga.crtc.horz_retrace_start = (vga.crtc.horz_retrace_start & 0x00ff) | ((data & 0xc0) << 2); + vga.crtc.horz_blank_start = (vga.crtc.horz_blank_start & 0x00ff) | ((data & 0x30) << 4); + vga.crtc.horz_disp_end = (vga.crtc.horz_disp_end & 0x00ff) | ((data & 0x0c) << 6); + vga.crtc.horz_total = (vga.crtc.horz_total & 0x00ff) | ((data & 0x03) << 8); + + recompute_params(); + break; + case 0x0c: + LOGSVGA("Extended horizontal Overflow 2 (%02x) %02x\n", index, data); + m_ext_horz_overflow[1] = data; + + vga.crtc.horz_retrace_end = (vga.crtc.horz_retrace_end & 0x001f) | ((data & 0x04) << 3); + vga.crtc.horz_blank_end = (vga.crtc.horz_blank_end & 0x003f) | ((data & 0x03) << 6); + recompute_params(); + break; + case 0x0d: + LOGSVGA("Extended starting address register (%02x) %02x\n", index, data); + vga.crtc.start_addr_latch &= ~0xff0000; + vga.crtc.start_addr_latch |= data << 16; + break; + case 0x0e: + LOGSVGA("Extended pitch register (%02x) %02x\n", index, data); + // sis_main.c implicitly sets this with bits 0-3 granularity, assume being right + vga.crtc.offset = (vga.crtc.offset & 0x00ff) | ((data & 0x0f) << 8); + break; + case 0x1e: + if (data & 0x40) + popmessage("Warning: enable 2d engine"); + break; + case 0x20: + if (data & 0x81) + popmessage("Warning: %s %s", BIT(data, 7) ? "PCI address enabled" : "", BIT(data, 0) ? "memory map I/O enable" : ""); + break; + default: + LOGSVGA("Extended write %02x %02x\n", index, data); + break; + } + } + } +} + +uint16_t sis630_svga_device::offset() +{ + if (svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb24_en || svga.rgb32_en) + return vga.crtc.offset << 3; + return svga_device::offset(); +} + +// read by gamecstl Kontron BIOS +u8 sis630_svga_device::port_03c0_r(offs_t offset) +{ + if (offset == 0xd) + return m_svga_bank_reg_w; + if (offset == 0xb) + return m_svga_bank_reg_r; + + return svga_device::port_03c0_r(offset); +} + +void sis630_svga_device::port_03c0_w(offs_t offset, uint8_t data) +{ + // TODO: for '630 it's always with dual segment enabled? + + if (offset == 0xd) + { + //if (m_dual_seg_mode) + m_svga_bank_reg_w = (data & 0x3f) * 0x10000; + //else + { + // m_svga_bank_reg_w = (data >> 4) * 0x10000; + // m_svga_bank_reg_r = (data & 0xf) * 0x10000; + } + return; + } + + if (offset == 0xb) + { + //if (m_dual_seg_mode) + m_svga_bank_reg_r = (data & 0x3f) * 0x10000; + // otherwise ignored if dual segment mode disabled + return; + } + + svga_device::port_03c0_w(offset, data); +} + +uint8_t sis630_svga_device::mem_r(offs_t offset) +{ + if (svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb24_en || svga.rgb32_en) + return svga_device::mem_linear_r(offset + m_svga_bank_reg_r); + return svga_device::mem_r(offset); +} + +void sis630_svga_device::mem_w(offs_t offset, uint8_t data) +{ + if (svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb24_en || svga.rgb32_en) + { + svga_device::mem_linear_w(offset + m_svga_bank_reg_w, data); + return; + } + svga_device::mem_w(offset, data); +} + +/***************************** + * + * 630 GUI PCI implementation + * + ****************************/ + +DEFINE_DEVICE_TYPE(SIS630_GUI, sis630_gui_device, "sis630_gui", "SiS 630 GUI") + +sis630_gui_device::sis630_gui_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : pci_device(mconfig, SIS630_GUI, tag, owner, clock) + , m_svga(*this, "svga") + , m_gui_rom(*this, "gui_rom") +{ + set_ids(0x10396300, 0x00, 0x030000, 0x00); +} + +ROM_START( sis630gui ) + ROM_REGION32_LE( 0xc000, "gui_rom", ROMREGION_ERASEFF ) + // TODO: why the OEM ROM is 0xc000 in size? + // 0x8000-0xbfff mostly contains a charset, may be either programmable via a dedicated interface + // or the dump above is half size. + // gamecstl dump ver. 2.06.50 + // (which actually writes to VRAM with the actual expansion ROM enabled, uh?) + ROM_SYSTEM_BIOS( 0, "2.06.50", "Ver. 2.06.50 OEM" ) + ROMX_LOAD( "oemrom.bin", 0x0000, 0xc000, BAD_DUMP CRC(03d8df9d) SHA1(8fb80a2bf4067d9bebc90fb498448869ae795b2b), ROM_BIOS(0) ) + + // "SiS 630 (Ver. 2.02.1c) [AGP VGA] (Silicon Integrated Systems Corp.).bin" + ROM_SYSTEM_BIOS( 1, "2.02.1c", "Ver. 2.02.1c" ) + ROMX_LOAD( "sis630.bin", 0x0000, 0x8000, BAD_DUMP CRC(f04ef9b0) SHA1(2396a79cd4045362bfc511090b146daa85902b4d), ROM_BIOS(1) ) +ROM_END + +const tiny_rom_entry *sis630_gui_device::device_rom_region() const +{ + return ROM_NAME(sis630gui); +} + +void sis630_gui_device::device_add_mconfig(machine_config &config) +{ + screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER)); + screen.set_raw(XTAL(25'174'800), 900, 0, 640, 526, 0, 480); + screen.set_screen_update(m_svga, FUNC(sis630_svga_device::screen_update)); + + SIS630_SVGA(config, m_svga, 0); + m_svga->set_screen("screen"); + // 64MB according to POST + // documentation claims 128MB, assume being wrong + m_svga->set_vram_size(64*1024*1024); +} + +void sis630_gui_device::config_map(address_map &map) +{ + pci_device::config_map(map); + map(0x2c, 0x2d).r(FUNC(sis630_gui_device::subvendor_r)); + map(0x2e, 0x2f).r(FUNC(sis630_gui_device::subsystem_r)); + map(0x2c, 0x2f).w(FUNC(sis630_gui_device::subvendor_w)); + +// map(0x3c, 0x3d) irq line/pin + + map(0x34, 0x34).r(FUNC(sis630_gui_device::capptr_r)); + + map(0x50, 0x53).r(FUNC(sis630_gui_device::agp_id_r)); + map(0x54, 0x57).r(FUNC(sis630_gui_device::agp_status_r)); + map(0x58, 0x5b).rw(FUNC(sis630_gui_device::agp_command_r), FUNC(sis630_gui_device::agp_command_w)); + map(0x5c, 0x5c).lr8(NAME([] () { return 0; })); // NULL terminator +} + +u8 sis630_gui_device::capptr_r() +{ + return 0x50; +} + +// TODO: move to specific interface +u32 sis630_gui_device::agp_id_r() +{ + LOGAGP("Read AGP ID [$50]\n"); + // bits 23-16 AGP v1.0 + // bits 15-8 0x5c NEXT_PTR (which goes to NULL terminator, heh) + // bits 7-0 CAP_ID (0x02 for AGP) + return 0x00105c02; +} + +u32 sis630_gui_device::agp_status_r() +{ + LOGAGP("Read AGP status [$54]\n"); + // RQ (1 + 1), 2X and 1X capable + return 0x01000003; +} + +u32 sis630_gui_device::agp_command_r(offs_t offset, uint32_t mem_mask) +{ + LOGAGP("Read AGP command [$58] %d %d %08x\n", m_agp.enable, m_agp.data_rate, mem_mask); + // TODO: enable gets cleared by AGP_RESET, or even from PCI RST# + return m_agp.enable << 8 | (m_agp.data_rate & 7); +} + +void sis630_gui_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.enable = bool(BIT(m_agp.enable, 8)); + LOGAGP("- AGP_ENABLE = %d\n", m_agp.enable); + } + + if (ACCESSING_BITS_0_7) + { + // quick checker, to be translated into an AGP interface + std::map agp_transfer_rates = { + { 0, "(illegal 0)" }, + { 1, "1X" }, + { 2, "2X" }, + { 3, "(illegal 3)" } + }; + + // make sure the AGP DATA_RATE specs are honored + const u8 data_rate = data & 3; + LOGAGP("- DATA_RATE = %s enabled=%d\n", agp_transfer_rates.at(data_rate), m_agp.enable); + m_agp.data_rate = data_rate; + } +} + +// TODO: may be common to PCI base interface, verify +void sis630_gui_device::subvendor_w(offs_t offset, u32 data, u32 mem_mask) +{ + // write once + if (m_subsystem_logger_mask & mem_mask) + { + LOG("Warning: subvendor ID possible rewrite! old=%08x & %08x data=%08x & %08x\n" + , subsystem_id + , m_subsystem_logger_mask + , data + , mem_mask + ); + } + m_subsystem_logger_mask |= mem_mask; + + COMBINE_DATA(&subsystem_id); + LOGIO("subsystem ID write [$2c] %08x & %08x (%08x)\n", data, mem_mask, subsystem_id); +} + +void sis630_gui_device::memory_map(address_map &map) +{ + map(0x0000000, 0x3ffffff).rw(m_svga, FUNC(sis630_svga_device::mem_linear_r), FUNC(sis630_svga_device::mem_linear_w)).umask32(0xffffffff); +} + +void sis630_gui_device::io_map(address_map &map) +{ + +} + +// "Relocate I/O" -> RIO +void sis630_gui_device::space_io_map(address_map &map) +{ + // RIO + 0x00: video capture regs on '300, omitted or missing on '630 + // RIO + 0x02: MPEG-2 video playback + // RIO + 0x04: digital video interface (to '301 only?) + // RIO + 0x10: 301 TV encoder + // RIO + 0x12: 301 macrovision regs + // RIO + 0x14: 301 VGA2 regs + // RIO + 0x16: 301 RAMDAC + // RIO + 0x30/+0x40/+0x50: omitted, legacy '300/'630 VGA regs? + // (gamecstl definitely tries to access 0x44 index 5 for readback extension ID) + map(0x30, 0x3f).rw(FUNC(sis630_gui_device::vga_3b0_r), FUNC(sis630_gui_device::vga_3b0_w)); + map(0x40, 0x4f).rw(FUNC(sis630_gui_device::vga_3c0_r), FUNC(sis630_gui_device::vga_3c0_w)); + map(0x50, 0x5f).rw(FUNC(sis630_gui_device::vga_3d0_r), FUNC(sis630_gui_device::vga_3d0_w)); +} + +void sis630_gui_device::legacy_memory_map(address_map &map) +{ + map(0xa0000, 0xbffff).rw(FUNC(sis630_gui_device::vram_r), FUNC(sis630_gui_device::vram_w)); +} + +void sis630_gui_device::legacy_io_map(address_map &map) +{ + map(0x03b0, 0x03bf).rw(FUNC(sis630_gui_device::vga_3b0_r), FUNC(sis630_gui_device::vga_3b0_w)); + map(0x03c0, 0x03cf).rw(FUNC(sis630_gui_device::vga_3c0_r), FUNC(sis630_gui_device::vga_3c0_w)); + map(0x03d0, 0x03df).rw(FUNC(sis630_gui_device::vga_3d0_r), FUNC(sis630_gui_device::vga_3d0_w)); +} + +void sis630_gui_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) +{ + +} + +void sis630_gui_device::device_start() +{ + pci_device::device_start(); + + add_map(64*1024*1024, M_MEM, FUNC(sis630_gui_device::memory_map)); + // claims 128KB, which goes outside the pentium range. + // Assume memory mapped, given the size should be yet another VGA memory compatible window. + add_map(128*1024, M_MEM, FUNC(sis630_gui_device::io_map)); + add_map(128, M_IO, FUNC(sis630_gui_device::space_io_map)); + + add_rom((u8 *)m_gui_rom->base(), m_gui_rom->bytes()); + + // INTA# + intr_pin = 1; +} + +void sis630_gui_device::device_reset() +{ + pci_device::device_reset(); + + command = 0x0004; + status = 0x0220; + + m_subsystem_logger_mask = 0; +} + +// TODO: remove these trampolines +uint8_t sis630_gui_device::vram_r(offs_t offset) +{ + return downcast(m_svga.target())->mem_r(offset); +} + +void sis630_gui_device::vram_w(offs_t offset, uint8_t data) +{ + downcast(m_svga.target())->mem_w(offset, data); +} + +u32 sis630_gui_device::vga_3b0_r(offs_t offset, uint32_t mem_mask) +{ + uint32_t result = 0; + if (ACCESSING_BITS_0_7) + result |= downcast(m_svga.target())->port_03b0_r(offset * 4 + 0) << 0; + if (ACCESSING_BITS_8_15) + result |= downcast(m_svga.target())->port_03b0_r(offset * 4 + 1) << 8; + if (ACCESSING_BITS_16_23) + result |= downcast(m_svga.target())->port_03b0_r(offset * 4 + 2) << 16; + if (ACCESSING_BITS_24_31) + result |= downcast(m_svga.target())->port_03b0_r(offset * 4 + 3) << 24; + return result; +} + +void sis630_gui_device::vga_3b0_w(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + if (ACCESSING_BITS_0_7) + downcast(m_svga.target())->port_03b0_w(offset * 4 + 0, data >> 0); + if (ACCESSING_BITS_8_15) + downcast(m_svga.target())->port_03b0_w(offset * 4 + 1, data >> 8); + if (ACCESSING_BITS_16_23) + downcast(m_svga.target())->port_03b0_w(offset * 4 + 2, data >> 16); + if (ACCESSING_BITS_24_31) + downcast(m_svga.target())->port_03b0_w(offset * 4 + 3, data >> 24); +} + + +u32 sis630_gui_device::vga_3c0_r(offs_t offset, uint32_t mem_mask) +{ + uint32_t result = 0; + if (ACCESSING_BITS_0_7) + result |= downcast(m_svga.target())->port_03c0_r(offset * 4 + 0) << 0; + if (ACCESSING_BITS_8_15) + result |= downcast(m_svga.target())->port_03c0_r(offset * 4 + 1) << 8; + if (ACCESSING_BITS_16_23) + result |= downcast(m_svga.target())->port_03c0_r(offset * 4 + 2) << 16; + if (ACCESSING_BITS_24_31) + result |= downcast(m_svga.target())->port_03c0_r(offset * 4 + 3) << 24; + return result; +} + +void sis630_gui_device::vga_3c0_w(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + if (ACCESSING_BITS_0_7) + downcast(m_svga.target())->port_03c0_w(offset * 4 + 0, data >> 0); + if (ACCESSING_BITS_8_15) + downcast(m_svga.target())->port_03c0_w(offset * 4 + 1, data >> 8); + if (ACCESSING_BITS_16_23) + downcast(m_svga.target())->port_03c0_w(offset * 4 + 2, data >> 16); + if (ACCESSING_BITS_24_31) + downcast(m_svga.target())->port_03c0_w(offset * 4 + 3, data >> 24); +} + +u32 sis630_gui_device::vga_3d0_r(offs_t offset, uint32_t mem_mask) +{ + uint32_t result = 0; + if (ACCESSING_BITS_0_7) + result |= downcast(m_svga.target())->port_03d0_r(offset * 4 + 0) << 0; + if (ACCESSING_BITS_8_15) + result |= downcast(m_svga.target())->port_03d0_r(offset * 4 + 1) << 8; + if (ACCESSING_BITS_16_23) + result |= downcast(m_svga.target())->port_03d0_r(offset * 4 + 2) << 16; + if (ACCESSING_BITS_24_31) + result |= downcast(m_svga.target())->port_03d0_r(offset * 4 + 3) << 24; + return result; +} + +void sis630_gui_device::vga_3d0_w(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + if (ACCESSING_BITS_0_7) + downcast(m_svga.target())->port_03d0_w(offset * 4 + 0, data >> 0); + if (ACCESSING_BITS_8_15) + downcast(m_svga.target())->port_03d0_w(offset * 4 + 1, data >> 8); + if (ACCESSING_BITS_16_23) + downcast(m_svga.target())->port_03d0_w(offset * 4 + 2, data >> 16); + if (ACCESSING_BITS_24_31) + downcast(m_svga.target())->port_03d0_w(offset * 4 + 3, data >> 24); +} + +/***************************** + * + * 630 bridge PCI implementation + * + ****************************/ + +DEFINE_DEVICE_TYPE(SIS630_BRIDGE, sis630_bridge_device, "sis630_bridge", "SiS 630 Virtual PCI-to-PCI bridge") + +sis630_bridge_device::sis630_bridge_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : pci_bridge_device(mconfig, SIS630_BRIDGE, tag, owner, clock) + , m_vga(*this, finder_base::DUMMY_TAG) +{ + +} + +void sis630_bridge_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 +) +{ + // command extensions + // VGA control - forward legacy VGA addresses to AGP + // TODO: doc implies that is unaffected by base and limit? + if (BIT(bridge_control, 3)) + { + memory_space->install_device(0, 0xfffff, *m_vga, &sis630_gui_device::legacy_memory_map); + io_space->install_device(0, 0x0fff, *m_vga, &sis630_gui_device::legacy_io_map); + } + + // TODO: ISA control + // forward to "primary PCI" (host & LPC?) for A8 or A9 blocks for each 1KB blocks in I/O spaces, + // (i.e. $100-$3ff, $500-$7ff, $900-$bff etc.) + // even if I/O range is inside base and limits +// if (BIT(bridge_control, 2)) + // ... +} + +void sis630_bridge_device::bridge_control_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + pci_bridge_device::bridge_control_w(offset, data, mem_mask); + LOGMAP("- %s VGA control\n", bridge_control & 8 ? "Enable" : "Disable"); + remap_cb(); +} + +void sis630_bridge_device::device_start() +{ + pci_bridge_device::device_start(); +} + +void sis630_bridge_device::device_reset() +{ + pci_bridge_device::device_reset(); +} diff --git a/src/devices/machine/sis630_gui.h b/src/devices/machine/sis630_gui.h new file mode 100644 index 00000000000..79690f81575 --- /dev/null +++ b/src/devices/machine/sis630_gui.h @@ -0,0 +1,144 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese + +#ifndef MAME_MACHINE_SIS630_VGA_H +#define MAME_MACHINE_SIS630_VGA_H + +#pragma once + +#include "pci.h" +#include "video/pc_vga.h" + +class sis630_svga_device : public svga_device +{ +public: + sis630_svga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual uint8_t mem_r(offs_t offset) override; + virtual void mem_w(offs_t offset, uint8_t data) override; + + virtual u8 port_03c0_r(offs_t offset) override; + virtual void port_03c0_w(offs_t offset, uint8_t data) override; + +protected: + virtual void device_start() override; + virtual void device_reset() override; + virtual uint8_t crtc_reg_read(uint8_t index) override; + virtual void crtc_reg_write(uint8_t index, uint8_t data) override; + virtual uint8_t seq_reg_read(uint8_t index) override; + virtual void seq_reg_write(uint8_t index, uint8_t data) override; + virtual uint16_t offset() override; + virtual void recompute_params() override; + + u8 m_crtc_ext_regs[0x100]{}; + u8 m_seq_ext_regs[0x100]{}; + u8 m_ramdac_mode = 0; + u8 m_ext_misc_ctrl_0 = 0; + u8 m_ext_vert_overflow = 0; + u8 m_ext_horz_overflow[2]{}; + u32 m_svga_bank_reg_w = 0; + u32 m_svga_bank_reg_r = 0; + bool m_unlock_reg = false; + + std::tuple flush_true_color_mode(); +// bool m_dual_seg_mode = false; +}; + +DECLARE_DEVICE_TYPE(SIS630_SVGA, sis630_svga_device) + + +class sis630_gui_device : public pci_device +{ +public: + sis630_gui_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + void legacy_memory_map(address_map &map); + void legacy_io_map(address_map &map); + +protected: + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_add_mconfig(machine_config &config) override; + + virtual const tiny_rom_entry *device_rom_region() const override; + +// virtual void reset_all_mappings() override; + + virtual void 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) override; + + virtual void config_map(address_map &map) override; + + void memory_map(address_map &map); + void io_map(address_map &map); + void space_io_map(address_map &map); + +private: + required_device m_svga; + required_memory_region m_gui_rom; + + u8 vram_r(offs_t offset); + void vram_w(offs_t offset, uint8_t data); + u32 vga_3b0_r(offs_t offset, uint32_t mem_mask = ~0); + void vga_3b0_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); + u32 vga_3c0_r(offs_t offset, uint32_t mem_mask = ~0); + void vga_3c0_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); + u32 vga_3d0_r(offs_t offset, uint32_t mem_mask = ~0); + void vga_3d0_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); + + void subvendor_w(offs_t offset, u32 data, u32 mem_mask = ~0); + + virtual u8 capptr_r() override; + u32 agp_id_r(); + u32 agp_status_r(); + u32 agp_command_r(offs_t offset, uint32_t mem_mask); + void agp_command_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); + + struct { + bool enable = false; + u8 data_rate = 0; + } m_agp; + + u32 m_subsystem_logger_mask = 0; + + u8 unmap_log_r(offs_t offset); + void unmap_log_w(offs_t offset, u8 data); +}; + +DECLARE_DEVICE_TYPE(SIS630_GUI, sis630_gui_device) + +class sis630_bridge_device : public pci_bridge_device +{ +public: + template sis630_bridge_device( + const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, + T &&gui_tag + ) : sis630_bridge_device(mconfig, tag, owner, clock) + { + // either 0001 or 6001 as device ID + set_ids_bridge(0x10396001, 0x00); + //set_multifunction_device(true); + m_vga.set_tag(std::forward(gui_tag)); + } + + sis630_bridge_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + virtual void device_start() override; + virtual void device_reset() override; + + virtual void 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) override; + +private: + required_device m_vga; + + virtual void bridge_control_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0) override; + + +}; + +DECLARE_DEVICE_TYPE(SIS630_BRIDGE, sis630_bridge_device) + + +#endif 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(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 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))); + } +} diff --git a/src/devices/machine/sis630_host.h b/src/devices/machine/sis630_host.h new file mode 100644 index 00000000000..46efc0ed803 --- /dev/null +++ b/src/devices/machine/sis630_host.h @@ -0,0 +1,98 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese + +#ifndef MAME_MACHINE_SIS630_HOST_H +#define MAME_MACHINE_SIS630_HOST_H + +#pragma once + +#include "pci.h" +#include "sis630_gui.h" + +class sis630_host_device : public pci_host_device +{ +public: + template sis630_host_device( + const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, + T &&cpu_tag, int ram_size + ) : sis630_host_device(mconfig, tag, owner, clock) + { + // Revision 1 -> A1 + set_ids(0x10390630, 0x01, 0x060000, 0x00); + set_multifunction_device(true); + m_host_cpu.set_tag(std::forward(cpu_tag)); + set_ram_size(ram_size); + } + + sis630_host_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + void set_ram_size(int ram_size) { m_ram_size = ram_size; } + + +protected: + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_add_mconfig(machine_config &config) override; + + virtual bool map_first() const override { return true; } + +// virtual void reset_all_mappings() override; + + virtual void 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) override; + + virtual void config_map(address_map &map) override; + + void memory_map(address_map &map); + +private: + required_device m_host_cpu; + std::vector m_ram; + + void map_shadowram(address_space *memory_space, offs_t start_offs, offs_t end_offs, bool read_enable, bool write_enable); + + int m_ram_size = 0; + u8 m_dram_status = 0; + u32 m_shadow_ram_ctrl = 0; + u8 m_vga_control = 0; + u8 m_agp_mailbox[12]{}; + u8 m_smram = 0; + u32 m_agp_priority_timer = 0; + + u8 dram_status_r(); + void dram_status_w(u8 data); + + u8 pci_hole_r(); + void pci_hole_w(u8 data); + + u8 vga_control_r(); + void vga_control_w(u8 data); + + u32 shadow_ram_ctrl_r(offs_t offset, uint32_t mem_mask = ~0); + void shadow_ram_ctrl_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); + + u8 smram_r(); + void smram_w(u8 data); + + u32 agp_priority_timer_r(offs_t offset, uint32_t mem_mask = ~0); + void agp_priority_timer_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); + + u8 agp_mailbox_r(offs_t offset); + void agp_mailbox_w(offs_t offset, u8 data); + + virtual uint8_t capptr_r() override; + u32 agp_id_r(); + u32 agp_status_r(); + u32 agp_command_r(offs_t offset, uint32_t mem_mask); + void agp_command_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); + + struct { + bool sba_enable = false; + bool enable = false; + u8 data_rate = 0; + } m_agp; +}; + +DECLARE_DEVICE_TYPE(SIS630_HOST, sis630_host_device) + + +#endif diff --git a/src/devices/machine/sis7001_usb.cpp b/src/devices/machine/sis7001_usb.cpp new file mode 100644 index 00000000000..7703c777888 --- /dev/null +++ b/src/devices/machine/sis7001_usb.cpp @@ -0,0 +1,93 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese +/************************************************************************************************** + + SiS 7001 USB Host controller + + TODO: + - Stub interface, to be improved; + - PCI values omitted from docs, assumes same as OpenHCI; + +**************************************************************************************************/ + +#include "emu.h" +#include "sis7001_usb.h" + +#define LOG_IO (1U << 1) // log PCI register accesses +#define LOG_MAP (1U << 2) // log full remaps + +#define VERBOSE (LOG_GENERAL | LOG_IO | LOG_MAP) +//#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_DEVICE_TYPE(SIS7001_USB, sis7001_usb_device, "sis7001_usb", "SiS 7001 USB Host Controller") + +sis7001_usb_device::sis7001_usb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : pci_device(mconfig, SIS7001_USB, tag, owner, clock) + +{ + +} + +void sis7001_usb_device::device_add_mconfig(machine_config &config) +{ + +} + +void sis7001_usb_device::config_map(address_map &map) +{ + pci_device::config_map(map); +} + +void sis7001_usb_device::io_map(address_map &map) +{ + // operational mode + map(0x000, 0x003).lr32(NAME([]() { return 0x00000110; })); + // ... + // HcFmInterval (Windows OSes fails if this isn't r/w) + map(0x034, 0x037).lrw32( + NAME([this]() { return m_HcFmInterval; } ), + NAME([this](offs_t offset, u32 data, u32 mem_mask) { COMBINE_DATA(&m_HcFmInterval); LOG("Write HcFmInterval %08x & %08x\n", data, mem_mask); }) + ); + // ... + // HcRhDescriptorA, writeable except for 0x4ff + map(0x048, 0x04b).lr32(NAME([this]() { return 0x01000000 | m_downstream_ports; })); + // ... +// map(0x05c, 0x05c) last item for function 2, missing on function 3 + + // legacy support mode (8-bit each) +// map(0x100, 0x100) control, bit 0 enables emulation mode +// map(0x104, 0x104) input +// map(0x108, 0x108) output +// map(0x10c, 0x10f) status +} + +void sis7001_usb_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) +{ + // TODO: overrides I/O ports $0060-$0064 (emulation mode) +} + +void sis7001_usb_device::device_start() +{ + pci_device::device_start(); + + add_map(512, M_MEM, FUNC(sis7001_usb_device::io_map)); + + // INTD# + intr_pin = 4; +} + + +void sis7001_usb_device::device_reset() +{ + pci_device::device_reset(); + + command = 0x0000; + status = 0x0000; + m_HcFmInterval = 0; +} diff --git a/src/devices/machine/sis7001_usb.h b/src/devices/machine/sis7001_usb.h new file mode 100644 index 00000000000..e85a5285bdf --- /dev/null +++ b/src/devices/machine/sis7001_usb.h @@ -0,0 +1,53 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese + +#ifndef MAME_MACHINE_SIS7001_USB_H +#define MAME_MACHINE_SIS7001_USB_H + +#pragma once + +#include "pci.h" + +class sis7001_usb_device : public pci_device +{ +public: + sis7001_usb_device( + const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, + int num_ports + ) : sis7001_usb_device(mconfig, tag, owner, clock) + { + // 0x0c0310 - Serial Bus Controller, USB, OpenHCI Host + // Assume no rev. + set_ids(0x10397001, 0x00, 0x0c0310, 0x00); + // TODO: should really read from a std::list interface + m_downstream_ports = num_ports; + } + sis7001_usb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + static constexpr feature_type unemulated_features() { return feature::MEDIA; } + +protected: + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_add_mconfig(machine_config &config) override; + +// virtual void reset_all_mappings() override; + + virtual void 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) override; + + virtual void config_map(address_map &map) override; + + void io_map(address_map &map); + +private: + u8 m_downstream_ports; + u32 m_HcFmInterval = 0; + + u8 unmap_log_r(offs_t offset); + void unmap_log_w(offs_t offset, u8 data); +}; + +DECLARE_DEVICE_TYPE(SIS7001_USB, sis7001_usb_device) + +#endif diff --git a/src/devices/machine/sis7018_audio.cpp b/src/devices/machine/sis7018_audio.cpp new file mode 100644 index 00000000000..a9eb4416188 --- /dev/null +++ b/src/devices/machine/sis7018_audio.cpp @@ -0,0 +1,126 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese +/************************************************************************************************** + + SiS 7018 Audio device (AC97 complaint) + + TODO: + - Stub interface, to be improved; + - Should be easy to at least inherit SB16/MIDI/game port devices; + +**************************************************************************************************/ + +#include "emu.h" +#include "sis7018_audio.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_PMC (1U << 4) // log PMC access + +#define VERBOSE (LOG_GENERAL | LOG_IO | LOG_TODO | LOG_MAP | LOG_PMC) +//#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 LOGPMC(...) LOGMASKED(LOG_PMC, __VA_ARGS__) + +DEFINE_DEVICE_TYPE(SIS7018_AUDIO, sis7018_audio_device, "sis7018_audio", "SiS 7018 Audio AC97") + +sis7018_audio_device::sis7018_audio_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : pci_device(mconfig, SIS7018_AUDIO, tag, owner, clock) + +{ + // 0x040100 - Multimedia device, audio device (vendor specific i/f) + // 0x01 - Rev 1 + set_ids(0x10397018, 0x01, 0x040100, 0x00); +} + +void sis7018_audio_device::device_add_mconfig(machine_config &config) +{ + +} + +void sis7018_audio_device::config_map(address_map &map) +{ + pci_device::config_map(map); + // map(0x003e, 0x003f) max latency min=0x02, max=0x18 + + map(0x40, 0xe3).rw(FUNC(sis7018_audio_device::unmap_log_r), FUNC(sis7018_audio_device::unmap_log_w)); + + // PMC capability identifier + map(0xdc, 0xdf).r(FUNC(sis7018_audio_device::pmc_id_r)); +// map(0xe0, 0xe3).r(FUNC(sis7018_audio_device::pmc_status_r), FUNC(sis7018_audio_device::pmc_control_w)); +} + +u8 sis7018_audio_device::capptr_r() +{ + LOGIO("AUDIO Read capptr_r [$34]\n"); + return 0xdc; +} + +// TODO: move to specific interface +u32 sis7018_audio_device::pmc_id_r() +{ + LOGPMC("Read PMC ID [$dc]\n"); + // bits 31-16 PPMI v1.0, D1 / D2 supported, no PCI clock for PME# + // bits 15-8 0x00 no NEXT_PTR (NULL terminates here) + // bits 7-0 PM_CAP_ID (0x01 for PMC) + return 0xe6110001; +} + +void sis7018_audio_device::memory_map(address_map &map) +{ + +} + +void sis7018_audio_device::io_map(address_map &map) +{ + +} + +void sis7018_audio_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, 0x03ff, *this, &sis7018_audio_device::io_map); + // TODO: legacy handling, including game port +} + +void sis7018_audio_device::device_start() +{ + pci_device::device_start(); + add_map(256, M_IO, FUNC(sis7018_audio_device::io_map)); + // not explicitly stated, assume 4096 size from the MEM decoding + add_map(4096, M_MEM, FUNC(sis7018_audio_device::memory_map)); +} + + +void sis7018_audio_device::device_reset() +{ + pci_device::device_reset(); + + command = 0x0000; + status = 0x0000; + // INTB# + intr_pin = 2; + // TODO: can be written to with $46=1 + subsystem_id = 0x10397018; +} + +/* + * Debugging + */ + +u8 sis7018_audio_device::unmap_log_r(offs_t offset) +{ + LOGTODO("AUDIO Unemulated [%02x] R\n", offset + 0x40); + return 0; +} + +void sis7018_audio_device::unmap_log_w(offs_t offset, u8 data) +{ + LOGTODO("AUDIO Unemulated [%02x] %02x W\n", offset + 0x40, data); +} diff --git a/src/devices/machine/sis7018_audio.h b/src/devices/machine/sis7018_audio.h new file mode 100644 index 00000000000..c9e9a6918b5 --- /dev/null +++ b/src/devices/machine/sis7018_audio.h @@ -0,0 +1,46 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese + +#ifndef MAME_MACHINE_SIS7018_AUDIO_H +#define MAME_MACHINE_SIS7018_AUDIO_H + +#pragma once + +#include "pci.h" + +class sis7018_audio_device : public pci_device +{ +public: + sis7018_audio_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + static constexpr feature_type unemulated_features() { return feature::SOUND; } + +protected: + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_add_mconfig(machine_config &config) override; + +// virtual void reset_all_mappings() override; + + virtual void 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) override; + + virtual void config_map(address_map &map) override; + + void memory_map(address_map &map); + void io_map(address_map &map); + +private: + virtual u8 capptr_r() override; + + u32 pmc_id_r(); +// void pmc_status_r(); +// u32 pmc_control(offs_t offset, u32 data, u32 mem_mask = ~0); + + u8 unmap_log_r(offs_t offset); + void unmap_log_w(offs_t offset, u8 data); +}; + +DECLARE_DEVICE_TYPE(SIS7018_AUDIO, sis7018_audio_device) + +#endif diff --git a/src/devices/machine/sis900_eth.cpp b/src/devices/machine/sis900_eth.cpp new file mode 100644 index 00000000000..d960c4b0293 --- /dev/null +++ b/src/devices/machine/sis900_eth.cpp @@ -0,0 +1,161 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese +/************************************************************************************************** + + SiS 900 Fast Ethernet Controller / Adapter + + TODO: + - Stub interface, to be improved; + - Sensible defaults for EEPROM; + +**************************************************************************************************/ + +#include "emu.h" +#include "sis900_eth.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_PMC (1U << 4) // log PMC access + +#define VERBOSE (LOG_GENERAL | LOG_IO | LOG_TODO | LOG_MAP | LOG_PMC) +//#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 LOGPMC(...) LOGMASKED(LOG_PMC, __VA_ARGS__) + +DEFINE_DEVICE_TYPE(SIS900_ETH, sis900_eth_device, "sis900_eth", "SiS 900 Fast Ethernet Adapter") + +sis900_eth_device::sis900_eth_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : pci_device(mconfig, SIS900_ETH, tag, owner, clock) + , m_eeprom(*this, "eeprom") + , m_eth_rom(*this, "eth_rom") +{ + // 0x020000 - Network Ethernet controller + // 0x80 - "Silicon revision" (sic) + set_ids(0x10390900, 0x80, 0x020000, 0x00); +} + +void sis900_eth_device::device_add_mconfig(machine_config &config) +{ + EEPROM_93C66_16BIT(config, m_eeprom); // NM93Cxx +} + +void sis900_eth_device::config_map(address_map &map) +{ + pci_device::config_map(map); + map(0x40, 0x43).r(FUNC(sis900_eth_device::pmc_id_r)); +// map(0x44, 0x47).r(FUNC(sis900_eth_device::pmc_status_r), FUNC(sis900_eth_device::pmc_control_w)); +} + +void sis900_eth_device::memory_map(address_map &map) +{ + +} + +void sis900_eth_device::io_map(address_map &map) +{ + map(0x08, 0x08).rw(FUNC(sis900_eth_device::eromar_r), FUNC(sis900_eth_device::eromar_w)); +} + +void sis900_eth_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, 0x03ff, *this, &sis900_eth_device::io_map); +} + +ROM_START( sis900eth ) + ROM_REGION32_LE( 0x10000, "eth_rom", ROMREGION_ERASEFF ) + ROM_LOAD( "pxe_m.19", 0x0000, 0xa000, BAD_DUMP CRC(c8da34a6) SHA1(f11b4f5398176b7d924c63c77a1951cb83020e48) ) + // structure: + // [0x00] signature -> 0x55aa + // [0x08] MAC address + // [0x0b] checksum + // PCIR signature+[0x00] vendor ID -> 0x1039 + // PCIR signature+[0x02] device ID -> 0x0900 +ROM_END + +const tiny_rom_entry *sis900_eth_device::device_rom_region() const +{ + return ROM_NAME(sis900eth); +} + +void sis900_eth_device::device_start() +{ + pci_device::device_start(); + + add_map(256, M_IO, FUNC(sis900_eth_device::io_map)); + add_map(4096, M_MEM, FUNC(sis900_eth_device::memory_map)); + add_rom((u8 *)m_eth_rom->base(), m_eth_rom->bytes()); + + // INTC# + intr_pin = 3; + // TODO: "if auto load is enabled it is set by subvendor ID stored in EEPROM" (?) + subsystem_id = 0x10390900; +} + +void sis900_eth_device::device_reset() +{ + pci_device::device_reset(); + + command = 0x0000; + status = 0x0290; + + m_eromar_mode = false; +} + +uint8_t sis900_eth_device::capptr_r() +{ + return 0x40; +} + +// TODO: move to specific interface +u32 sis900_eth_device::pmc_id_r() +{ + LOGPMC("Read PMC ID [$40]\n"); + // bits 31-16 PPMI v1.0 / v1.0a, D1 / D2 supported, PME# D0/D1/D2/D3hot & optional D3cold + // bits 15-8 0x00 no NEXT_PTR (NULL terminates here) + // bits 7-0 PM_CAP_ID (0x01 for PMC) + // TODO: versioning may depend on ROM installed + return 0xfe010001; +} + +/* + * I/O space + */ + +u8 sis900_eth_device::eromar_r() +{ + // TODO: doc claims all bits are readable, looks unlikely? + u8 res = m_eromar_mode << 7; + if (m_eromar_mode) + { + // ... + } + else + res |= m_eeprom->do_read() << 1; + + return res; +} + +void sis900_eth_device::eromar_w(u8 data) +{ + m_eromar_mode = bool(BIT(data, 7)); + + LOGIO("eromar_w %s selected %02x\n", m_eromar_mode ? "HomePHY" : "eeprom", data); + + if (m_eromar_mode) + { + // ... + } + else + { + m_eeprom->cs_write(BIT(data, 3)); + m_eeprom->clk_write(BIT(data, 2)); + m_eeprom->di_write(BIT(data, 0)); + } +} diff --git a/src/devices/machine/sis900_eth.h b/src/devices/machine/sis900_eth.h new file mode 100644 index 00000000000..4d5fb46f2bd --- /dev/null +++ b/src/devices/machine/sis900_eth.h @@ -0,0 +1,53 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese + +#ifndef MAME_MACHINE_SIS900_ETH_H +#define MAME_MACHINE_SIS900_ETH_H + +#pragma once + +#include "pci.h" +#include "machine/eepromser.h" + +class sis900_eth_device : public pci_device +{ +public: + sis900_eth_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + static constexpr feature_type unemulated_features() { return feature::LAN; } + +protected: + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_add_mconfig(machine_config &config) override; + + virtual const tiny_rom_entry *device_rom_region() const override; + +// virtual void reset_all_mappings() override; + + virtual void 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) override; + + virtual void config_map(address_map &map) override; + + void memory_map(address_map &map); + void io_map(address_map &map); + +private: + required_device m_eeprom; + required_memory_region m_eth_rom; + + bool m_eromar_mode; + + virtual uint8_t capptr_r() override; + u32 pmc_id_r(); +// void pmc_status_r(); +// u32 pmc_control(offs_t offset, u32 data, u32 mem_mask = ~0); + + u8 eromar_r(); + void eromar_w(u8 data); +}; + +DECLARE_DEVICE_TYPE(SIS900_ETH, sis900_eth_device) + +#endif diff --git a/src/devices/machine/sis950_lpc.cpp b/src/devices/machine/sis950_lpc.cpp new file mode 100644 index 00000000000..3a75f35156d --- /dev/null +++ b/src/devices/machine/sis950_lpc.cpp @@ -0,0 +1,764 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese +/************************************************************************************************** + + SiS950 LPC implementation (Super I/O & southbridge) + + TODO: + - Convert most stuff declared here to generic interfaces; + - Flash ROM handling + \- Doesn't survive a soft reset; + - Fix EISA; + - INIT register (reset & A20 control + fast gates + fast reset timing control); + - Override PS/2 ports if USB legacy mode is enabled; + - NMI & SMI handling; + - SMBus handling; + - RTC extended bank enable; + \- Doesn't survive a CMOS write after fast reset; + - Shadow registers for PIC and PIT; + - IRQ remaps + \- INTA GUI + \- INTB AUDIO and MODEM + \- INTC ethernet + \- INTD USB + - IRQ software traps ($6e-$6f); + \- Documentation mentions that those can be read-back too, huh? + - Understand what's the caveat of "changing device ID number" via BIOS control $40 bit 6; + +**************************************************************************************************/ + +#include "emu.h" +#include "sis950_lpc.h" +#include "bus/pc_kbd/keyboards.h" +#include "speaker.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_LPC (1U << 4) // log LPC legacy regs +#define LOG_IRQ (1U << 5) // log IRQ remaps + +#define VERBOSE (LOG_GENERAL | LOG_IO | LOG_TODO | LOG_IRQ) +//#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 LOGLPC(...) LOGMASKED(LOG_LPC, __VA_ARGS__) +#define LOGIRQ(...) LOGMASKED(LOG_IRQ, __VA_ARGS__) + +DEFINE_DEVICE_TYPE(SIS950_LPC, sis950_lpc_device, "sis950_lpc", "SiS 950 LPC Super-South Bridge") + +sis950_lpc_device::sis950_lpc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : pci_device(mconfig, SIS950_LPC, tag, owner, clock) + , m_host_cpu(*this, finder_base::DUMMY_TAG) + , m_flash_rom(*this, finder_base::DUMMY_TAG) + , m_pic_master(*this, "pic_master") + , m_pic_slave(*this, "pic_slave") + , m_dmac_master(*this, "dmac_master") + , m_dmac_slave(*this, "dmac_slave") + , m_pit(*this, "pit") + , m_keybc(*this, "keybc") + , m_speaker(*this, "speaker") + , m_rtc(*this, "rtc") + , m_ps2_con(*this, "ps2_con") + , m_aux_con(*this, "aux_con") + , m_uart(*this, "uart") + , m_acpi(*this, "acpi") + , m_smbus(*this, "smbus") + , m_fast_reset_cb(*this) +{ +} + +void sis950_lpc_device::device_start() +{ + pci_device::device_start(); + + m_fast_reset_cb.resolve_safe(); +} + +void sis950_lpc_device::device_reset() +{ + pci_device::device_reset(); + + command = 0x000c; + status = 0x0200; + + m_bios_control = 1; + m_acpi_base = 0; + m_flash_control = 0x40; + m_keybc_reg = 0x51; + m_dma_channel = -1; +// m_cur_eop = false; + m_dma_high_byte = 0; + m_init_reg = 0; + m_rtc_reg = 0x10; + // remapping is disabled for all as default + std::fill(std::begin(m_irq_remap), std::end(m_irq_remap), 0x80); + + m_lpc_legacy.fast_init = 0; + remap_cb(); +} + +WRITE_LINE_MEMBER(sis950_lpc_device::cpu_a20_w) +{ + // TODO: confirm "A20M# being always high" +// if (BIT(m_init_reg, 1)) +// state = ASSERT_LINE; + m_host_cpu->set_input_line(INPUT_LINE_A20, state); +} + +WRITE_LINE_MEMBER(sis950_lpc_device::cpu_reset_w) +{ + // TODO: masked via INIT $46 bit 0 + m_host_cpu->set_input_line(INPUT_LINE_RESET, state); +} + +void sis950_lpc_device::device_add_mconfig(machine_config &config) +{ + constexpr XTAL lpc_pit_clock = XTAL(14'318'181); + + // confirmed 82C54 + PIT8254(config, m_pit, 0); + // heartbeat IRQ + m_pit->set_clk<0>(lpc_pit_clock / 12); + m_pit->out_handler<0>().set(FUNC(sis950_lpc_device::pit_out0)); + // DRAM refresh + m_pit->set_clk<1>(lpc_pit_clock / 12); + m_pit->out_handler<1>().set(FUNC(sis950_lpc_device::pit_out1)); + // PIO port C pin 4, and speaker polling enough + m_pit->set_clk<2>(lpc_pit_clock / 12); + m_pit->out_handler<2>().set(FUNC(sis950_lpc_device::pit_out2)); + + // TODO: unknown part # + AM9517A(config, m_dmac_master, lpc_pit_clock / 3); + m_dmac_master->out_hreq_callback().set(m_dmac_slave, FUNC(am9517a_device::dreq0_w)); +// m_dmac_master->out_eop_callback().set(FUNC(sis950_lpc_device::at_dma8237_out_eop)); + m_dmac_master->in_memr_callback().set(FUNC(sis950_lpc_device::pc_dma_read_byte)); + m_dmac_master->out_memw_callback().set(FUNC(sis950_lpc_device::pc_dma_write_byte)); + // TODO: ior/iow/dack/eop callbacks + + AM9517A(config, m_dmac_slave, lpc_pit_clock / 3); + m_dmac_slave->out_hreq_callback().set(FUNC(sis950_lpc_device::pc_dma_hrq_changed)); + m_dmac_slave->in_memr_callback().set(FUNC(sis950_lpc_device::pc_dma_read_word)); + m_dmac_slave->out_memw_callback().set(FUNC(sis950_lpc_device::pc_dma_write_word)); + // TODO: ior/iow/dack callbacks + + // Confirmed 82C59s + PIC8259(config, m_pic_master, 0); + m_pic_master->out_int_callback().set_inputline(m_host_cpu, 0); + m_pic_master->in_sp_callback().set_constant(1); + m_pic_master->read_slave_ack_callback().set( + [this](offs_t offset) -> u8 + { + if (offset == 2) + return m_pic_slave->acknowledge(); + + return 0; + }); + + PIC8259(config, m_pic_slave, 0); + m_pic_slave->out_int_callback().set(m_pic_master, FUNC(pic8259_device::ir2_w)); + m_pic_slave->in_sp_callback().set_constant(0); + + // TODO: EISA, from virtual bridge + + PC_KBDC(config, m_ps2_con, pc_at_keyboards, STR_KBD_MICROSOFT_NATURAL); + m_ps2_con->out_clock_cb().set(m_keybc, FUNC(ps2_keyboard_controller_device::kbd_clk_w)); + m_ps2_con->out_data_cb().set(m_keybc, FUNC(ps2_keyboard_controller_device::kbd_data_w)); + + PC_KBDC(config, m_aux_con, ps2_mice, STR_HLE_PS2_MOUSE); + m_aux_con->out_clock_cb().set(m_keybc, FUNC(ps2_keyboard_controller_device::aux_clk_w)); + m_aux_con->out_data_cb().set(m_keybc, FUNC(ps2_keyboard_controller_device::aux_data_w)); + + // TODO: selectable between PCI clock / 4 (33 MHz) or 7.159 MHz, via reg $47 bit 5 + PS2_KEYBOARD_CONTROLLER(config, m_keybc, DERIVED_CLOCK(1, 4)); + // TODO: default ibm BIOS doesn't cope with this too well + m_keybc->set_default_bios_tag("compaq"); + m_keybc->hot_res().set(FUNC(sis950_lpc_device::cpu_reset_w)); + m_keybc->gate_a20().set(FUNC(sis950_lpc_device::cpu_a20_w)); + m_keybc->kbd_irq().set(m_pic_master, FUNC(pic8259_device::ir1_w)); + m_keybc->kbd_clk().set(m_ps2_con, FUNC(pc_kbdc_device::clock_write_from_mb)); + m_keybc->kbd_data().set(m_ps2_con, FUNC(pc_kbdc_device::data_write_from_mb)); + m_keybc->aux_irq().set(m_pic_slave, FUNC(pic8259_device::ir4_w)); + m_keybc->aux_clk().set(m_aux_con, FUNC(pc_kbdc_device::clock_write_from_mb)); + m_keybc->aux_data().set(m_aux_con, FUNC(pc_kbdc_device::data_write_from_mb)); + + // TODO: unknown RTC type + // Has external RTC bank select at $48, using this one as convenience + DS12885EXT(config, m_rtc, XTAL(32'768)); + m_rtc->irq().set(m_pic_slave, FUNC(pic8259_device::ir0_w)); + m_rtc->set_century_index(0x32); + + // serial fragment + // TODO: unconfirmed type / clock + INS8250(config, m_uart, XTAL(18'432'000) / 10); + m_uart->out_tx_callback().set("com1", FUNC(rs232_port_device::write_txd)); + m_uart->out_dtr_callback().set("com1", FUNC(rs232_port_device::write_dtr)); + m_uart->out_rts_callback().set("com1", FUNC(rs232_port_device::write_rts)); +// m_uart->out_int_callback().set() +// m_uart->out_baudout_callback().set([this](int state){ if (m_8251dtr_state) m_uart->rclk_w(state); }); // TODO: Fix INS8250 BAUDOUT pin support + + rs232_port_device &rs232(RS232_PORT(config, "com1", default_rs232_devices, nullptr)); + rs232.rxd_handler().set(m_uart, FUNC(ins8250_uart_device::rx_w)); + rs232.dcd_handler().set(m_uart, FUNC(ins8250_uart_device::dcd_w)); + rs232.dsr_handler().set(m_uart, FUNC(ins8250_uart_device::dsr_w)); + rs232.ri_handler().set(m_uart, FUNC(ins8250_uart_device::ri_w)); + rs232.cts_handler().set(m_uart, FUNC(ins8250_uart_device::cts_w)); + + // TODO: left/right speaker connection + SPEAKER(config, "mono").front_center(); + SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "mono", 0.50); +} + +void sis950_lpc_device::config_map(address_map &map) +{ + pci_device::config_map(map); + map(0x10, 0x4f).unmaprw(); + map(0x10, 0x75).rw(FUNC(sis950_lpc_device::unmap_log_r), FUNC(sis950_lpc_device::unmap_log_w)); + + // LPC control regs + map(0x40, 0x40).rw(FUNC(sis950_lpc_device::bios_control_r), FUNC(sis950_lpc_device::bios_control_w)); + map(0x41, 0x41).rw(FUNC(sis950_lpc_device::irq_remap_r), FUNC(sis950_lpc_device::irq_remap_w)); + map(0x42, 0x42).rw(FUNC(sis950_lpc_device::irq_remap_r), FUNC(sis950_lpc_device::irq_remap_w)); + map(0x43, 0x43).rw(FUNC(sis950_lpc_device::irq_remap_r), FUNC(sis950_lpc_device::irq_remap_w)); + map(0x44, 0x44).rw(FUNC(sis950_lpc_device::irq_remap_r), FUNC(sis950_lpc_device::irq_remap_w)); + + map(0x45, 0x45).rw(FUNC(sis950_lpc_device::flash_ctrl_r), FUNC(sis950_lpc_device::flash_ctrl_w)); + map(0x46, 0x46).rw(FUNC(sis950_lpc_device::init_enable_r), FUNC(sis950_lpc_device::init_enable_w)); + map(0x47, 0x47).rw(FUNC(sis950_lpc_device::keybc_reg_r), FUNC(sis950_lpc_device::keybc_reg_w)); + map(0x48, 0x48).rw(FUNC(sis950_lpc_device::rtc_reg_r), FUNC(sis950_lpc_device::rtc_reg_w)); + + // DMA control regs +// map(0x49, 0x49) Distributed DMA channel enable +// map(0x4a, 0x4b) Distributed DMA Master config + + // Shadow regs (r/o) +// map(0x4c, 0x4f) PIC master ICW* +// map(0x50, 0x53) PIC slave ICW* +// map(0x54, 0x55) PIC master OCW2-3 +// map(0x56, 0x57) PIC slave OCW2-3 (NB: assume documentation 0x54-0x55 to be a typo) +// map(0x58, 0x5f) PIT counters 0-1-2 low/high, $5e -> control 43h, $5f -> read count pointer statuses +// map(0x60, 0x60) EISA port $70 + + map(0x61, 0x61).rw(FUNC(sis950_lpc_device::irq_remap_r), FUNC(sis950_lpc_device::irq_remap_w)); +// map(0x62, 0x62) , hardwired to 0x80 (PIT irq remap?) + map(0x62, 0x62).lr8(NAME([] () { return 0x80; })); + map(0x63, 0x63).rw(FUNC(sis950_lpc_device::irq_remap_r), FUNC(sis950_lpc_device::irq_remap_w)); + +// map(0x64, 0x64) PCI bus priority timer +// map(0x65, 0x65) PHOLD# timer + +// map(0x66, 0x66) +// map(0x67, 0x67) Serial IRQ 1 & 12 latch control (FDC super I/O) +// map(0x68, 0x69) + + map(0x63, 0x63).rw(FUNC(sis950_lpc_device::irq_remap_r), FUNC(sis950_lpc_device::irq_remap_w)); +// map(0x6b, 0x6b) + map(0x6c, 0x6c).rw(FUNC(sis950_lpc_device::irq_remap_r), FUNC(sis950_lpc_device::irq_remap_w)); + map(0x6d, 0x6d).rw(FUNC(sis950_lpc_device::irq_remap_r), FUNC(sis950_lpc_device::irq_remap_w)); + +// map(0x6e, 0x6f) SW irq triggers +// map(0x70, 0x70) Serial irq control +// map(0x71, 0x73) Serial irq enable + + // $74 should be ACPI lower base bank, but marked as regardless + // (by logic that should go to NOP too) + map(0x74, 0x74).lr8(NAME([] () { return 0; })); + map(0x75, 0x75).rw(FUNC(sis950_lpc_device::acpi_base_r), FUNC(sis950_lpc_device::acpi_base_w)); +} + +u8 sis950_lpc_device::bios_control_r() +{ + LOGIO("Read BIOS control [$40] %02x\n", m_bios_control); + return m_bios_control; +} + +void sis950_lpc_device::bios_control_w(u8 data) +{ + // Mostly 0x9a or 0x9b + LOGIO("Write BIOS control [$40] %02x\n", data); + m_bios_control = data; + remap_cb(); +} + +template u8 sis950_lpc_device::irq_remap_r() +{ + return m_irq_remap[N]; +} + +template void sis950_lpc_device::irq_remap_w(u8 data) +{ + m_irq_remap[N] = data; + LOGIRQ("%s IRQ remap write %02x (%s)\n", std::array {{ + "INTA", + "INTB", + "INTC", + "INTD", + "IDEIRQ", + "GPEIRQ", + "ACPI/SCI", + "SMBus", + "Software Watchdog" + }}[N], data, BIT(data, 7) ? "disable" : "enable"); +} + +u8 sis950_lpc_device::flash_ctrl_r() +{ + LOGIO("Read Flash control [$45] %02x\n", m_flash_control); + return m_flash_control; +} + +void sis950_lpc_device::flash_ctrl_w(u8 data) +{ + LOGIO("Write Flash control [$45] %02x\n", data); + m_flash_control = data; + remap_cb(); +} + +u8 sis950_lpc_device::init_enable_r() +{ + LOGIO("Read INIT enable [$46] %02x\n", m_init_reg); + return m_init_reg; +} + +/* + * 11-- ---- HW (fast?) reset + * --x- ---- INIT enable + * ---x ---- Fast Gate A20 emulation + * ---- x--- Fast Reset latency control + * ---- -x-- Fast Reset emulation + * ---- --x- (0) enable A20M# (1) A20M# always high (?) + * ---- ---x Keyboard HW reset + */ +void sis950_lpc_device::init_enable_w(u8 data) +{ + LOGIO("Write INIT enable [$46] %02x\n", data); + // HW fast reset + // TODO: is 0->1 implementation correct? + // it will otherwise keep resetting itself, which may be a side effect of something else + // (perhaps PS/2 controller can intercept this? Or it's a full on LPC reset like using an actual MAME soft reset implies?) + if ((data & 0xc0) == 0xc0)// && (m_init_reg & 0xc0) == 0) + { + //const int fast_reset_time = BIT(data, 3) ? 6 : 2; + LOGIO("Fast reset issued\n"); + //m_host_cpu->pulse_input_line(INPUT_LINE_RESET, attotime::from_usec(fast_reset_time)); + m_fast_reset_cb(1); + } + + m_init_reg = data; +} + +u8 sis950_lpc_device::keybc_reg_r() +{ + LOGIO("Read keyboard register [$47] %02x\n", m_keybc_reg); + return m_keybc_reg; +} + +/* + * x--- ---- legacy USB (ports $60-$64 overrides) + * -x-- ---- PS/2 mouse lock enable + * --x- ---- Keyboard controller clock select (0) PCI Clock / 4 (1) 7.159 MHz + * ---x ---- Keyboard lock enable + * ---- x--- Integrated keyboard controller enable + * ---- -x-- Integrated PS/2 mouse enable (needs bit 3 enabled) + * ---- --x- Keyboard hot key status (needs bit 3 enabled, ctrl+alt+backspace) + * ---- ---x Keyboard hot key control + */ +void sis950_lpc_device::keybc_reg_w(u8 data) +{ + LOGIO("Write keyboard register [$47] %02x\n", data); + m_keybc_reg = data; +} + +u8 sis950_lpc_device::rtc_reg_r() +{ + LOGIO("Read RTC register [$48] %02x\n", m_keybc_reg); + return m_rtc_reg | 0x10; +} + +/* + * x--- ---- RTC extended bank enable + * -x-- ---- APC enable + * --x- ---- Instant Power-Off enable (thru APC) + * ---x ---- Internal RTC status (r/o, always on?) + * ---- xxxx + */ +void sis950_lpc_device::rtc_reg_w(u8 data) +{ + LOGIO("Write RTC register [$48] %02x\n", data); + m_rtc_reg = data; +} + +u8 sis950_lpc_device::acpi_base_r() +{ + LOGIO("Read ACPI base [$75] %04x\n", m_acpi_base); + return m_acpi_base >> 8; +} + +void sis950_lpc_device::acpi_base_w(u8 data) +{ + u16 new_value = data << 8; + LOGIO("Write ACPI base [$75] %04x\n", new_value); + m_acpi_base = new_value; + remap_cb(); +} + +template void sis950_lpc_device::memory_map(address_map &map) +{ + map(0x00000000, 0x0001ffff).lrw8( + NAME([this] (offs_t offset) { return m_flash_rom->read(offset | N * 0x20000); }), + NAME([this] (offs_t offset, u8 data) { m_flash_rom->write(offset | N * 0x20000, data); }) + ); +} + +void sis950_lpc_device::io_map(address_map &map) +{ + // Legacy ISA (page 177) + // map(0x0000, 0x000f) DMA1 + map(0x0000, 0x001f).rw(m_dmac_master, FUNC(am9517a_device::read), FUNC(am9517a_device::write)); + // map(0x0020, 0x0021) INT1 + map(0x0020, 0x003f).rw(m_pic_master, FUNC(pic8259_device::read), FUNC(pic8259_device::write)); + // map(0x0040, 0x0043) PIT + map(0x0040, 0x0043).rw(m_pit, FUNC(pit8254_device::read), FUNC(pit8254_device::write)); + map(0x0060, 0x0060).rw(m_keybc, FUNC(ps2_keyboard_controller_device::data_r), FUNC(ps2_keyboard_controller_device::data_w)); + // map(0x0061, 0x0061) NMI Status Register + map(0x0061, 0x0061).rw(FUNC(sis950_lpc_device::nmi_status_r), FUNC(sis950_lpc_device::nmi_control_w)); + // undocumented but read, assume LPC complaint + map(0x0064, 0x0064).rw(m_keybc, FUNC(ps2_keyboard_controller_device::status_r), FUNC(ps2_keyboard_controller_device::command_w)); + // map(0x0070, 0x0070) CMOS and NMI Mask + map(0x0070, 0x0070).w(FUNC(sis950_lpc_device::rtc_index_w)); + map(0x0071, 0x0071).rw(FUNC(sis950_lpc_device::rtc_data_r), FUNC(sis950_lpc_device::rtc_data_w)); + // map(0x0080, 0x008f) DMA low page registers + map(0x0080, 0x008f).rw(FUNC(sis950_lpc_device::at_page8_r), FUNC(sis950_lpc_device::at_page8_w)); + // map(0x0092, 0x0092) INIT and A20 + map(0x0092, 0x0092).rw(FUNC(sis950_lpc_device::lpc_fast_init_r), FUNC(sis950_lpc_device::lpc_fast_init_w)); + // map(0x00a0, 0x00a1) INT2 + map(0x00a0, 0x00bf).rw(m_pic_slave, FUNC(pic8259_device::read), FUNC(pic8259_device::write)); + // map(0x00c0, 0x00df) DMA2 + map(0x00c0, 0x00df).lrw8( + NAME([this] (offs_t offset) { return m_dmac_slave->read( offset / 2 ); }), + NAME([this] (offs_t offset, u8 data) { m_dmac_slave->write( offset / 2, data ); }) + ); + + map(0x00e0, 0x00ef).noprw(); + // map(0x00f0, 0x00f0) COPRO error + // map(0x0480, 0x048f) DMA high page registers + // map(0x04d0, 0x04d1) IRQ edge/level control registers + + // http://bxr.su/DragonFly/share/man/man4/it.4 + // 0x0290, 0xc00, 0xd00, 0x228: Motherboard Super I/O HW monitoring + + // map(0x0295, 0x0295) - index register, $d-$e lower/upper RPM readback for fans (alternating on read) + // map(0x0296, 0x0296) - data ^ + + // Intel LPC interface specs (legacy host decode ranges, not necessarily present on '950) + + // map(0x002e, 0x002f) Super I/O config (config-index & data ports) + // map(0x004e, 0x004f) alt Super I/O config (ISA converter index-data ports) + // map(0x0062, 0x0062) - ACPI embedded controller + // map(0x0066, 0x0066) / + + // map(0x0200, 0x020f) game ports ($201 as shutms11 default) + + // map(0x0220, 0x0227) serial 2 + // map(0x0228, 0x022f) serial 2 + // map(0x0220, 0x0233) sb compatible i/f 1 + // map(0x0240, 0x0253) sb compatible i/f 2 + // map(0x0260, 0x0273) sb compatible i/f 3 + // map(0x0280, 0x0293) sb compatible i/f 4 + + // map(0x0238, 0x023f) serial 3 + + // map(0x0278, 0x027f) parallel port 2 & PnP + // map(0x02e8, 0x02ef) serial 3 + // map(0x02f8, 0x02ff) serial 1 + + // map(0x0300, 0x0301) - MIDI ($330 as shutms11 default) + // map(0x0310, 0x0311) / + // map(0x0320, 0x0321) / + // map(0x0330, 0x0331) / + + // map(0x0338, 0x033f) serial 4 + // map(0x0370, 0x0377) FDC 2 + + // map(0x0378, 0x037f) parallel port 1 + // map(0x0388, 0x0389) ADLIB + // map(0x03bc, 0x03bf) parallel port 3 + // map(0x03e8, 0x03ef) serial 4 + // map(0x03f0, 0x03f7) FDC 1 + map(0x03f8, 0x03ff).rw(m_uart, FUNC(ins8250_device::ins8250_r), FUNC(ins8250_device::ins8250_w)); // COM1 + + // map(0x0530, 0x0537) - MSS (TCP Maximum Segment Size?) + // map(0x0604, 0x060b) / + // map(0x0e80, 0x0e87) / + // map(0x0f40, 0x0f47) / + + // map(0x0678, 0x067f) ECP parallel port 1 + // map(0x0778, 0x0779) ECP parallel port 2 & PnP + // map(0x07bc, 0x07bf) ECP parallel port 3 +} + +void sis950_lpc_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, 0x07ff, *this, &sis950_lpc_device::io_map); + + LOGMAP("LPC Remapping table (BIOS: %02x, flash: %02x)\n", m_bios_control, m_flash_control); + + // ACPI enable + if (BIT(m_bios_control, 7)) + { + LOGMAP("- ACPI enable (%02x) %04x-%04x\n", m_bios_control, m_acpi_base, m_acpi_base + 0xff); + // shutms11 BIOS POST maps this at $5000 + m_acpi->map_device(memory_window_start, memory_window_end, 0, memory_space, io_window_start, io_window_end, m_acpi_base, io_space); + io_space->install_device(m_acpi_base | 0x80, m_acpi_base | 0xff, *m_smbus, &sis950_smbus_device::map); + } + + // TODO: disable flash access write thru reg $45 + // TODO: BIOS positive decode + // (bios_control bit 1), which should disable BIOS mapping to E and F segment + + memory_space->install_device(0x000e0000, 0x000fffff, *this, &sis950_lpc_device::memory_map<3>); + // extended BIOS enable + if (m_bios_control & 1) + { + LOGMAP("- Extend BIOS on\n"); + memory_space->install_device(0xfff80000, 0xfff9ffff, *this, &sis950_lpc_device::memory_map<0>); + memory_space->install_device(0xfffa0000, 0xfffbffff, *this, &sis950_lpc_device::memory_map<1>); + memory_space->install_device(0xfffc0000, 0xfffdffff, *this, &sis950_lpc_device::memory_map<2>); + } + memory_space->install_device(0xfffe0000, 0xffffffff, *this, &sis950_lpc_device::memory_map<3>); +} + +u8 sis950_lpc_device::lpc_fast_init_r() +{ + LOGLPC("LPC fast init read [$92]\n"); + return m_lpc_legacy.fast_init; +} + +void sis950_lpc_device::lpc_fast_init_w(offs_t offset, u8 data) +{ + LOGLPC("LPC fast init write [$92] %02x\n", data); + if (data & 0xfd) + LOG("Warning: unemulated LPC fast init type %02x", data); + + // TODO: pinpoint exact disable INIT condition and if that will be reflected on reading reg too + m_host_cpu->set_input_line(INPUT_LINE_A20, BIT(data, 1)); + + m_lpc_legacy.fast_init = data; +} + +/* + * Debugging + */ +u8 sis950_lpc_device::unmap_log_r(offs_t offset) +{ + LOGTODO("LPC Unemulated [%02x] R\n", offset + 0x10); + return 0; +} + +void sis950_lpc_device::unmap_log_w(offs_t offset, u8 data) +{ + LOGTODO("LPC Unemulated [%02x] %02x W\n", offset + 0x10, data); +} + +/* + * Start of legacy handling, to be moved out + */ + +WRITE_LINE_MEMBER( sis950_lpc_device::pit_out0 ) +{ + m_pic_master->ir0_w(state); +} + +WRITE_LINE_MEMBER( sis950_lpc_device::pit_out1 ) +{ + if(state) + m_refresh = !m_refresh; +} + +WRITE_LINE_MEMBER( sis950_lpc_device::pit_out2 ) +{ + m_pit_out2 = state ? 1 : 0; + m_speaker->level_w(m_at_spkrdata & m_pit_out2); +} + +/* + * x--- ---- Set if a PCI device or main memory module asserts PERR#/SERR# line + * -x-- ---- Set when IOCHK# is asserted on ISA bus + * --x- ---- Counter 2 out signal state (PIT ch. 2) + * ---x ---- Refresh bit toggle (PIT ch. 1) + * ---- xxxx + */ +uint8_t sis950_lpc_device::nmi_status_r() +{ + uint8_t data = m_at_speaker; + data &= ~0xd0; // AT BIOS don't likes this being set + + data |= m_refresh ? 0x10 : 0; + + if (m_pit_out2) + data |= 0x20; + else + data &= ~0x20; // ps2m30 wants this + + return data; +} + +void sis950_lpc_device::at_speaker_set_spkrdata(uint8_t data) +{ + m_at_spkrdata = data ? 1 : 0; + m_speaker->level_w(m_at_spkrdata & m_pit_out2); +} + +/* + * xxxx ---- + * ---- x--- (0) enable IOCHK# NMI (1) clear and disable IOCHK# NMI + * ---- -x-- (0) enable PCI SERR# (1) clear and disable PCI SERR# + * ---- --x- Speaker output enable + * ---- ---x Timer counter 2 enable + */ +void sis950_lpc_device::nmi_control_w(uint8_t data) +{ + m_at_speaker = data; + m_pit->write_gate2(BIT(data, 0)); + at_speaker_set_spkrdata(BIT(data, 1)); + m_channel_check = BIT(data, 3); + if (m_channel_check) + m_host_cpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE); +} + +void sis950_lpc_device::rtc_index_w(uint8_t data) +{ + m_rtc_index = data & 0x7f; + // bit 7: NMI enable +} + +u8 sis950_lpc_device::rtc_data_r() +{ + const u8 rtc_address = m_rtc_index | (m_rtc_reg & 0x80); + return m_rtc->read_direct(rtc_address); +} + +void sis950_lpc_device::rtc_data_w(u8 data) +{ + const u8 rtc_address = m_rtc_index | (m_rtc_reg & 0x80); + m_rtc->write_direct(rtc_address, data); +} + +uint8_t sis950_lpc_device::at_page8_r(offs_t offset) +{ + uint8_t data = m_at_pages[offset % 0x10]; + + switch(offset % 8) + { + case 1: + data = m_dma_offset[BIT(offset, 3)][2]; + break; + case 2: + data = m_dma_offset[BIT(offset, 3)][3]; + break; + case 3: + data = m_dma_offset[BIT(offset, 3)][1]; + break; + case 7: + data = m_dma_offset[BIT(offset, 3)][0]; + break; + } + return data; +} + + +void sis950_lpc_device::at_page8_w(offs_t offset, uint8_t data) +{ + m_at_pages[offset % 0x10] = data; + + switch(offset % 8) + { + case 0: + // matches boot_state_infos_phoenix + //m_boot_state_hook((offs_t)0, data); + break; + case 1: + m_dma_offset[BIT(offset, 3)][2] = data; + break; + case 2: + m_dma_offset[BIT(offset, 3)][3] = data; + break; + case 3: + m_dma_offset[BIT(offset, 3)][1] = data; + break; + case 7: + m_dma_offset[BIT(offset, 3)][0] = data; + break; + } +} + +WRITE_LINE_MEMBER( sis950_lpc_device::pc_dma_hrq_changed ) +{ + m_host_cpu->set_input_line(INPUT_LINE_HALT, state ? ASSERT_LINE : CLEAR_LINE); + + // Assert HLDA + m_dmac_slave->hack_w( state ); +} + +#if 0 +WRITE_LINE_MEMBER( sis950_lpc_device::iochck_w ) +{ +// if (!state && !m_channel_check && m_nmi_enabled) + if (!state && !m_channel_check) + m_host_cpu->set_input_line(INPUT_LINE_NMI, ASSERT_LINE); +} +#endif + +uint8_t sis950_lpc_device::pc_dma_read_byte(offs_t offset) +{ + address_space& prog_space = m_host_cpu->space(AS_PROGRAM); // get the right address space + if(m_dma_channel == -1) + return 0xff; + uint8_t result; + offs_t page_offset = ((offs_t) m_dma_offset[0][m_dma_channel]) << 16; + + result = prog_space.read_byte(page_offset + offset); + return result; +} + + +void sis950_lpc_device::pc_dma_write_byte(offs_t offset, uint8_t data) +{ + address_space& prog_space = m_host_cpu->space(AS_PROGRAM); // get the right address space + if(m_dma_channel == -1) + return; + offs_t page_offset = ((offs_t) m_dma_offset[0][m_dma_channel]) << 16; + + prog_space.write_byte(page_offset + offset, data); +} + + +uint8_t sis950_lpc_device::pc_dma_read_word(offs_t offset) +{ + address_space& prog_space = m_host_cpu->space(AS_PROGRAM); // get the right address space + if(m_dma_channel == -1) + return 0xff; + uint16_t result; + offs_t page_offset = ((offs_t) m_dma_offset[1][m_dma_channel & 3]) << 16; + + result = prog_space.read_word((page_offset & 0xfe0000) | (offset << 1)); + m_dma_high_byte = result & 0xFF00; + + return result & 0xFF; +} + + +void sis950_lpc_device::pc_dma_write_word(offs_t offset, uint8_t data) +{ + address_space& prog_space = m_host_cpu->space(AS_PROGRAM); // get the right address space + if(m_dma_channel == -1) + return; + offs_t page_offset = ((offs_t) m_dma_offset[1][m_dma_channel & 3]) << 16; + + prog_space.write_word((page_offset & 0xfe0000) | (offset << 1), m_dma_high_byte | data); +} diff --git a/src/devices/machine/sis950_lpc.h b/src/devices/machine/sis950_lpc.h new file mode 100644 index 00000000000..4e994110b9b --- /dev/null +++ b/src/devices/machine/sis950_lpc.h @@ -0,0 +1,176 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese + +#ifndef MAME_MACHINE_SIS950_LPC_H +#define MAME_MACHINE_SIS950_LPC_H + +#pragma once + +#include "pci.h" + +#include "bus/ata/ataintf.h" +#include "bus/isa/isa.h" +#include "bus/pc_kbd/pc_kbdc.h" +#include "bus/rs232/rs232.h" +#include "lpc-acpi.h" +#include "sis950_smbus.h" + +#include "cpu/i386/i386.h" + +#include "machine/am9517a.h" +#include "machine/at.h" +#include "machine/at_keybc.h" +#include "machine/ds128x.h" +#include "machine/ins8250.h" +#include "machine/intelfsh.h" +#include "machine/pc_lpt.h" +#include "machine/pic8259.h" +#include "machine/pit8253.h" +#include "machine/ram.h" +#include "machine/nvram.h" + +#include "sound/spkrdev.h" + + +class sis950_lpc_device : public pci_device +{ +public: + template sis950_lpc_device( + const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, + T &&cpu_tag, U &&flash_tag + ) : sis950_lpc_device(mconfig, tag, owner, clock) + { + // Revision 0 -> A0 + set_ids(0x10390008, 0x00, 0x060100, 0x00); + //set_multifunction_device(true); + m_host_cpu.set_tag(std::forward(cpu_tag)); + m_flash_rom.set_tag(std::forward(flash_tag)); + } + + sis950_lpc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + static constexpr feature_type unemulated_features() { return feature::MOUSE; } + + auto fast_reset_cb() { return m_fast_reset_cb.bind(); } + +protected: + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_add_mconfig(machine_config &config) override; + +// virtual void reset_all_mappings() override; + + virtual void 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) override; + + virtual void config_map(address_map &map) override; + + template void memory_map(address_map &map); + void io_map(address_map &map); + +private: + required_device m_host_cpu; + required_device m_flash_rom; + required_device m_pic_master; + required_device m_pic_slave; + required_device m_dmac_master; + required_device m_dmac_slave; + required_device m_pit; + required_device m_keybc; + required_device m_speaker; + required_device m_rtc; + required_device m_ps2_con; + required_device m_aux_con; + required_device m_uart; + required_device m_acpi; + required_device m_smbus; + + devcb_write_line m_fast_reset_cb; + + // PCI interface + u8 bios_control_r(); + void bios_control_w(u8 data); + u8 flash_ctrl_r(); + void flash_ctrl_w(u8 data); + u8 acpi_base_r(); + void acpi_base_w(u8 data); + u8 init_enable_r(); + void init_enable_w(u8 data); + u8 keybc_reg_r(); + void keybc_reg_w(u8 data); + u8 rtc_reg_r(); + void rtc_reg_w(u8 data); + void rtc_index_w(u8 data); + u8 rtc_data_r(); + void rtc_data_w(u8 data); + template u8 irq_remap_r(); + template void irq_remap_w(u8 data); + u8 unmap_log_r(offs_t offset); + void unmap_log_w(offs_t offset, u8 data); + + u8 m_bios_control = 0; + u8 m_flash_control = 0; + u16 m_acpi_base = 0x0000; + u8 m_init_reg = 0; + u8 m_keybc_reg = 0; + u8 m_rtc_reg = 0; + u8 m_rtc_index = 0; + + enum { + IRQ_INTA = 0, + IRQ_INTB, + IRQ_INTC, + IRQ_INTD, + IRQ_IDE, + IRQ_GPE, + // or SCI + IRQ_ACPI, + IRQ_SMBUS, + IRQ_SWDOG + }; + u8 m_irq_remap[9]{}; + + // LPC vendor specific, verify if it's common for all + u8 lpc_fast_init_r(); + void lpc_fast_init_w(offs_t offset, u8 data); + struct { + u8 fast_init; + } m_lpc_legacy; + + // SB implementation, to be moved out + DECLARE_WRITE_LINE_MEMBER(pit_out0); + DECLARE_WRITE_LINE_MEMBER(pit_out1); + DECLARE_WRITE_LINE_MEMBER(pit_out2); + uint8_t pc_dma_read_byte(offs_t offset); + void pc_dma_write_byte(offs_t offset, uint8_t data); + uint8_t pc_dma_read_word(offs_t offset); + void pc_dma_write_word(offs_t offset, uint8_t data); + DECLARE_WRITE_LINE_MEMBER(pc_dma_hrq_changed); + void pc_select_dma_channel(int channel, bool state); + + uint8_t m_at_pages[0x10]{}; + uint8_t m_dma_offset[2][4]{}; + uint8_t m_at_speaker = 0; + uint8_t m_refresh = 0; + bool m_pit_out2 = 0; + bool m_at_spkrdata = 0; + uint8_t m_channel_check = 0; + int m_dma_channel = -1; +// bool m_cur_eop = false; + uint16_t m_dma_high_byte = 0; + + DECLARE_WRITE_LINE_MEMBER(cpu_a20_w); + DECLARE_WRITE_LINE_MEMBER(cpu_reset_w); + + uint8_t at_page8_r(offs_t offset); + void at_page8_w(offs_t offset, uint8_t data); + u8 nmi_status_r(); + void nmi_control_w(uint8_t data); + + void at_speaker_set_spkrdata(uint8_t data); +}; + +DECLARE_DEVICE_TYPE(SIS950_LPC, sis950_lpc_device) + + +#endif diff --git a/src/devices/machine/sis950_smbus.cpp b/src/devices/machine/sis950_smbus.cpp new file mode 100644 index 00000000000..b96898cbbe0 --- /dev/null +++ b/src/devices/machine/sis950_smbus.cpp @@ -0,0 +1,108 @@ +// license:BSD-3-Clause +// copyright-holders:Angelo Salese +/************************************************************************************************** + + SiS 950 SMBus implementation + + TODO: + - Stub, needs an smbus_interface, bare minimum to make shutms11 happy; + +**************************************************************************************************/ +#include "emu.h" +#include "sis950_smbus.h" + +#define LOG_CMD (1U << 1) // log commands + +#define VERBOSE (LOG_GENERAL | LOG_CMD) +//#define LOG_OUTPUT_FUNC osd_printf_warning + +#include "logmacro.h" + +#define LOGCMD(...) LOGMASKED(LOG_CMD, __VA_ARGS__) + +DEFINE_DEVICE_TYPE(SIS950_SMBUS, sis950_smbus_device, "sis950_smbus", "SiS950 SMBus interface") + +void sis950_smbus_device::map(address_map &map) +{ + map(0x00, 0x00).rw(FUNC(sis950_smbus_device::smb_sts_r), FUNC(sis950_smbus_device::smb_sts_w)); + + map(0x03, 0x03).rw(FUNC(sis950_smbus_device::smbhost_cnt_r), FUNC(sis950_smbus_device::smbhost_cnt_w)); + +#if 0 + map(0x02, 0x02).rw(FUNC(sis950_smbus_device::hst_cnt_r), FUNC(sis950_smbus_device::hst_cnt_w)); + map(0x03, 0x03).rw(FUNC(sis950_smbus_device::hst_cmd_r), FUNC(sis950_smbus_device::hst_cmd_w)); + map(0x04, 0x04).rw(FUNC(sis950_smbus_device::xmit_slva_r), FUNC(sis950_smbus_device::xmit_slva_w)); + map(0x05, 0x05).rw(FUNC(sis950_smbus_device::hst_d0_r), FUNC(sis950_smbus_device::hst_d0_w)); + map(0x06, 0x06).rw(FUNC(sis950_smbus_device::hst_d1_r), FUNC(sis950_smbus_device::hst_d1_w)); + map(0x07, 0x07).rw(FUNC(sis950_smbus_device::host_block_db_r), FUNC(sis950_smbus_device::host_block_db_w)); + map(0x08, 0x08).rw(FUNC(sis950_smbus_device::pec_r), FUNC(sis950_smbus_device::pec_w)); + map(0x09, 0x09).rw(FUNC(sis950_smbus_device::rcv_slva_r), FUNC(sis950_smbus_device::rcv_slva_w)); + map(0x0a, 0x0b).rw(FUNC(sis950_smbus_device::slv_data_r), FUNC(sis950_smbus_device::slv_data_w)); + map(0x0c, 0x0c).rw(FUNC(sis950_smbus_device::aux_sts_r), FUNC(sis950_smbus_device::aux_sts_w)); + map(0x0d, 0x0d).rw(FUNC(sis950_smbus_device::aux_ctl_r), FUNC(sis950_smbus_device::aux_ctl_w)); + map(0x0e, 0x0e).rw(FUNC(sis950_smbus_device::smlink_pin_ctl_r), FUNC(sis950_smbus_device::smlink_pin_ctl_w)); + map(0x0f, 0x0f).rw(FUNC(sis950_smbus_device::smbus_pin_ctl_r), FUNC(sis950_smbus_device::smbus_pin_ctl_w)); + map(0x10, 0x10).rw(FUNC(sis950_smbus_device::slv_sts_r), FUNC(sis950_smbus_device::slv_sts_w)); + map(0x11, 0x11).rw(FUNC(sis950_smbus_device::slv_cmd_r), FUNC(sis950_smbus_device::slv_cmd_w)); + map(0x14, 0x14).r(FUNC(sis950_smbus_device::notify_daddr_r)); + map(0x16, 0x16).r(FUNC(sis950_smbus_device::notify_dlow_r)); + map(0x17, 0x17).r(FUNC(sis950_smbus_device::notify_dhigh_r)); +#endif +} + +sis950_smbus_device::sis950_smbus_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, SIS950_SMBUS, tag, owner, clock) +{ +} + +void sis950_smbus_device::device_start() +{ + +} + +void sis950_smbus_device::device_reset() +{ + +} + +u8 sis950_smbus_device::smb_sts_r() +{ + LOGCMD("%s: smb_sts_r (%02x)\n", tag(), m_status); + + return m_status; +} + +void sis950_smbus_device::smb_sts_w(u8 data) +{ + m_status &= ~data; + LOGCMD("%s: smb_sts_w = %02x\n", tag(), data); +} + +// reads back bits 0-2 only +u8 sis950_smbus_device::smbhost_cnt_r() +{ + return m_cmd; +} + +/* + * --x- ---- kill (reset state, TODO) + * ---x ---- start transaction + * ---- -xxx command protocol + * ---- -000 quick command + * ---- -001 send/receive byte + * ---- -010 read/write byte data + * ---- -011 read/write word data + * ---- -100 process call + * ---- -101 read/write block data + * ---- -11x + */ +void sis950_smbus_device::smbhost_cnt_w(u8 data) +{ + m_cmd = data & 7; + LOGCMD("%s: smbhost_cnt_w = %02x\n", tag(), data); + + // TODO: process commands properly + // For now we just reflect shutms11 wanting bit 3 on after each transaction + if (BIT(data, 4)) + m_status |= 8; +} diff --git a/src/devices/machine/sis950_smbus.h b/src/devices/machine/sis950_smbus.h new file mode 100644 index 00000000000..a474fe10914 --- /dev/null +++ b/src/devices/machine/sis950_smbus.h @@ -0,0 +1,32 @@ +// license:BSD-3-Clause +// copyright-holders:Angelo Salese + +#ifndef MAME_MACHINE_SIS950_SMBUS_H +#define MAME_MACHINE_SIS950_SMBUS_H + +#include "emu.h" + +class sis950_smbus_device : public device_t { +public: + + sis950_smbus_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + void map(address_map &map); + +protected: + virtual void device_start() override; + virtual void device_reset() override; + +private: + u8 smb_sts_r(); + void smb_sts_w(u8 data); + u8 smbhost_cnt_r(); + void smbhost_cnt_w(u8 data); + + u8 m_status = 0; + u8 m_cmd = 0; +}; + +DECLARE_DEVICE_TYPE(SIS950_SMBUS, sis950_smbus_device) + +#endif // MAME_MACHINE_PCI_SMBUS_H diff --git a/src/devices/video/pc_vga.cpp b/src/devices/video/pc_vga.cpp index d1d20c70c14..a553813a8d7 100644 --- a/src/devices/video/pc_vga.cpp +++ b/src/devices/video/pc_vga.cpp @@ -1698,6 +1698,12 @@ uint8_t vga_device::gc_reg_read(uint8_t index) return res; } +uint8_t vga_device::seq_reg_read(uint8_t index) +{ + logerror("Reading unmapped sequencer read register %02x (SVGA?)\n", index); + return 0; +} + uint8_t vga_device::port_03c0_r(offs_t offset) { uint8_t data = 0xff; @@ -1758,6 +1764,8 @@ uint8_t vga_device::port_03c0_r(offs_t offset) case 5: if (vga.sequencer.index < vga.svga_intf.seq_regcount) data = vga.sequencer.data[vga.sequencer.index]; + else + data = seq_reg_read(vga.sequencer.index); break; case 6: diff --git a/src/devices/video/pc_vga.h b/src/devices/video/pc_vga.h index 717d965330f..2c32c25cbb0 100644 --- a/src/devices/video/pc_vga.h +++ b/src/devices/video/pc_vga.h @@ -73,10 +73,11 @@ protected: void vga_vh_mono(bitmap_rgb32 &bitmap, const rectangle &cliprect); virtual uint8_t pc_vga_choosevideomode(); void recompute_params_clock(int divisor, int xtal); - uint8_t crtc_reg_read(uint8_t index); + virtual uint8_t crtc_reg_read(uint8_t index); virtual void recompute_params(); - void crtc_reg_write(uint8_t index, uint8_t data); - void seq_reg_write(uint8_t index, uint8_t data); + virtual void crtc_reg_write(uint8_t index, uint8_t data); + virtual uint8_t seq_reg_read(uint8_t index); + virtual void seq_reg_write(uint8_t index, uint8_t data); uint8_t vga_vblank(); uint8_t vga_crtc_r(offs_t offset); void vga_crtc_w(offs_t offset, uint8_t data); diff --git a/src/mame/arcade.flt b/src/mame/arcade.flt index 0589ffba92d..f41a4f14f0a 100644 --- a/src/mame/arcade.flt +++ b/src/mame/arcade.flt @@ -473,7 +473,6 @@ galpanic.cpp galpanic_ms.cpp galspnbl.cpp gambl186.cpp -gamecstl.cpp gamemasters.cpp gameplan.cpp gammagic.cpp @@ -1193,6 +1192,7 @@ silvmil.cpp simpl156.cpp simple_st0016.cpp simpsons.cpp +sis630.cpp skeetsht.cpp skimaxx.cpp skopro.cpp diff --git a/src/mame/drivers/gamecstl.cpp b/src/mame/drivers/gamecstl.cpp deleted file mode 100644 index 77e76cd389d..00000000000 --- a/src/mame/drivers/gamecstl.cpp +++ /dev/null @@ -1,506 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:R. Belmont -// thanks-to: Diego Nappino -/* - Cristaltec "Game Cristal" (MAME bootleg) - - Skeleton driver by R. Belmont, based on taitowlf.cpp by Ville Linde - - Notes: - - Specs: P3-866, SiS 630 motherboard + integrated graphics card, - SiS 7018 sound, Windows 98SE, DirectX 8.1. - - Windows image can be booted with m55hipl driver. - It will try to install an "unnamed card" (svga_et4k?) then uses its own shell - "ialoader.exe" to boot the frontend, located in C:\WINDOWS. - It will eventually hang after throwing a "DirectX missing" error, trying to install - the ET4K drivers won't work (will BSoD at start of boot sequence). - - In order to bypass the shell launcher, you should: - 1. edit C:\WINDOWS\system.ini and change shell property to explorer.exe - 2. remove the autoexec.bat contents, it will otherwise copy a bunch of .ini - files from C:\dat to C:\WINDOWS, and replacing the system.ini shell launcher. - - (gamecstl) Device Manager installed devices: - - two Samsung SyncMaster 900SL monitors (?); - - SiS 630 display adapter; - - Samsung CD-ROM SC-152L; - - SiS 5513 Dual PCI IDE Controller; - - COM1, COM2, LPT1 enabled; - - a QDI USBDisk USB Mass Storage SCSI driver; - - a SiS 7001 PCI to USB Open Host Controller + USB root hub x 2; - - C:\drvs contains a collection of drivers, mostly the ones described above. - - Other parts of Windows are otherwise more or less stock, except for a footprint - inside C:\WINDOWS\temp: - 1. has a Portuguese version of the Intel Processor Identification Utility, - most likely used for binding the emulator to the CPU serial via CPUID; - 2. has u3spwd.exe (USB Flash Disk), likely used to copy the necessary files for - making the frontend to work; - - Input is via a custom COM1 port JAMMA adaptor. - - The custom emulator is a heavily modified version of MAME32. If you extract the - disk image, it's in C:\GH4\GH4.EXE. It's UPX compressed, so unpack it before doing - any forensics. The emulator does run on Windows as new as XP Pro SP2 but you can't - control it due to the lack of the custom input. - - C:\GH4\mvs contains movie clips of the emulated games. - These are MS-CRAM encoded, 288x208 at 20 fps, stereo MS ADPCM with 11025 Hz sample rate, - 36 seconds length. - Mentioning this because SiS 630 has several HW registers dedicated to video playback, - which will be most likely used once we get there. - - Updates 27/11/2007 (Diego Nappino): - The COM1 port is opened at 19200 bps, No parity, 8 bit data, 1 stop bit. - The protocol is based on a 6 bytes frame with a leading byte valued 0x05 and a trailing one at 0x02 - The four middle bytes are used, in negative logic (0xFF = No button pressed), to implement the inputs. - Each bit meaning as follows: - - Byte 1 Byte 2 Byte 3 Byte 4 - Bit 0 P1-Credit P1-Button C P2-Left UNUSED - Bit 1 P1-Start P1-Button D P2-Right UNUSED - Bit 2 P1-Down P1-Button E P2-Button A SERVICE - Bit 3 P1-Up TEST P2-Button B UNUSED - Bit 4 P1-Left P2-Credit P2-Button C UNUSED - Bit 5 P1-Right P2-Start P2-Button D UNUSED - Bit 6 P1-Button A P2-Down P2-Button E UNUSED - Bit 7 P1-Button B P2-Up VIDEO-MODE UNUSED - - The JAMMA adaptor sends a byte frame each time an input changes. - So for example, if the P1-Button A and P1-Button B are both pressed, it will send: - - 0x05 0xFC 0xFF 0xFF 0xFF 0x02 - - And when the buttons are both released - - 0x05 0xFF 0xFF 0xFF 0xFF 0x02 - - CPUID info: - - Original set: - CPUID Level: EAX: EBX: ECX: EDX: - 00000000 00000003 756E6547 6C65746E 49656E69 - 00000001 0000068A 00000002 00000000 0387F9FF - 00000002 03020101 00000000 00000000 0C040882 - 00000003 00000000 00000000 CA976D2E 000082F6 - 80000000 00000000 00000000 CA976D2E 000082F6 - C0000000 00000000 00000000 CA976D2E 000082F6 - - Version 2: - CPUID Level: EAX: EBX: ECX: EDX: - 00000000 00000003 756E6547 6C65746E 49656E69 - 00000001 0000068A 00000002 00000000 0387F9FF - 00000002 03020101 00000000 00000000 0C040882 - 00000003 00000000 00000000 B8BA1941 00038881 - 80000000 00000000 00000000 B8BA1941 00038881 - C0000000 00000000 00000000 B8BA1941 00038881 - -*/ - -#include "emu.h" -#include "cpu/i386/i386.h" -#include "machine/idectrl.h" -#include "machine/lpci.h" -#include "machine/pckeybrd.h" -#include "machine/pcshare.h" -#include "emupal.h" -#include "screen.h" - - -class gamecstl_state : public pcat_base_state -{ -public: - gamecstl_state(const machine_config &mconfig, device_type type, const char *tag) - : pcat_base_state(mconfig, type, tag) - , m_cga_ram(*this, "cga_ram") - , m_gfxdecode(*this, "gfxdecode") - , m_palette(*this, "palette") - { } - - void gamecstl(machine_config &config); - - void init_gamecstl(); - -private: - required_shared_ptr m_cga_ram; - required_device m_gfxdecode; - required_device m_palette; - std::unique_ptr m_bios_ram; - uint8_t m_mtxc_config_reg[256]; - uint8_t m_piix4_config_reg[4][256]; - - void pnp_config_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); - void pnp_data_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); - void bios_ram_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); - virtual void machine_start() override; - virtual void machine_reset() override; - virtual void video_start() override; - uint32_t screen_update_gamecstl(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); - void draw_char(bitmap_ind16 &bitmap, const rectangle &cliprect, gfx_element *gfx, int ch, int att, int x, int y); - void intel82439tx_init(); - void gamecstl_io(address_map &map); - void gamecstl_map(address_map &map); - - uint8_t mtxc_config_r(int function, int reg); - void mtxc_config_w(int function, int reg, uint8_t data); - uint32_t intel82439tx_pci_r(int function, int reg, uint32_t mem_mask); - void intel82439tx_pci_w(int function, int reg, uint32_t data, uint32_t mem_mask); - uint8_t piix4_config_r(int function, int reg); - void piix4_config_w(int function, int reg, uint8_t data); - uint32_t intel82371ab_pci_r(int function, int reg, uint32_t mem_mask); - void intel82371ab_pci_w(int function, int reg, uint32_t data, uint32_t mem_mask); - uint32_t pci_3dfx_r(int function, int reg, uint32_t mem_mask); - void pci_3dfx_w(int function, int reg, uint32_t data, uint32_t mem_mask); -}; - - -static const rgb_t cga_palette[16] = -{ - rgb_t( 0x00, 0x00, 0x00 ), rgb_t( 0x00, 0x00, 0xaa ), rgb_t( 0x00, 0xaa, 0x00 ), rgb_t( 0x00, 0xaa, 0xaa ), - rgb_t( 0xaa, 0x00, 0x00 ), rgb_t( 0xaa, 0x00, 0xaa ), rgb_t( 0xaa, 0x55, 0x00 ), rgb_t( 0xaa, 0xaa, 0xaa ), - rgb_t( 0x55, 0x55, 0x55 ), rgb_t( 0x55, 0x55, 0xff ), rgb_t( 0x55, 0xff, 0x55 ), rgb_t( 0x55, 0xff, 0xff ), - rgb_t( 0xff, 0x55, 0x55 ), rgb_t( 0xff, 0x55, 0xff ), rgb_t( 0xff, 0xff, 0x55 ), rgb_t( 0xff, 0xff, 0xff ), -}; - -void gamecstl_state::video_start() -{ - int i; - for (i=0; i < 16; i++) - m_palette->set_pen_color(i, cga_palette[i]); -} - -void gamecstl_state::draw_char(bitmap_ind16 &bitmap, const rectangle &cliprect, gfx_element *gfx, int ch, int att, int x, int y) -{ - int index = 0; - uint8_t const *const dp = gfx->get_data(ch); - - for (int j=y; j < y+8; j++) - { - uint16_t *const p = &bitmap.pix(j); - - for (int i=x; i < x+8; i++) - { - uint8_t pen = dp[index++]; - if (pen) - p[i] = gfx->colorbase() + (att & 0xf); - else - p[i] = gfx->colorbase() + ((att >> 4) & 0x7); - } - } -} - -uint32_t gamecstl_state::screen_update_gamecstl(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) -{ - gfx_element *gfx = m_gfxdecode->gfx(0); - uint32_t const *const cga = m_cga_ram; - int index = 0; - - bitmap.fill(0, cliprect); - - for (int j=0; j < 25; j++) - { - for (int i=0; i < 80; i+=2) - { - int att0 = (cga[index] >> 8) & 0xff; - int ch0 = (cga[index] >> 0) & 0xff; - int att1 = (cga[index] >> 24) & 0xff; - int ch1 = (cga[index] >> 16) & 0xff; - - draw_char(bitmap, cliprect, gfx, ch0, att0, i*8, j*8); - draw_char(bitmap, cliprect, gfx, ch1, att1, (i*8)+8, j*8); - index++; - } - } - return 0; -} - -// Intel 82439TX System Controller (MTXC) - -uint8_t gamecstl_state::mtxc_config_r(int function, int reg) -{ - logerror("MTXC: read %d, %02X\n", function, reg); - return m_mtxc_config_reg[reg]; -} - -void gamecstl_state::mtxc_config_w(int function, int reg, uint8_t data) -{ - logerror("%s:MTXC: write %d, %02X, %02X\n", machine().describe_context(), function, reg, data); - - switch(reg) - { - case 0x59: // PAM0 - { - if (data & 0x10) // enable RAM access to region 0xf0000 - 0xfffff - { - membank("bank1")->set_base(m_bios_ram.get()); - } - else // disable RAM access (reads go to BIOS ROM) - { - membank("bank1")->set_base(memregion("bios")->base() + 0x30000); - } - break; - } - } - - m_mtxc_config_reg[reg] = data; -} - -void gamecstl_state::intel82439tx_init() -{ - m_mtxc_config_reg[0x60] = 0x02; - m_mtxc_config_reg[0x61] = 0x02; - m_mtxc_config_reg[0x62] = 0x02; - m_mtxc_config_reg[0x63] = 0x02; - m_mtxc_config_reg[0x64] = 0x02; - m_mtxc_config_reg[0x65] = 0x02; -} - -uint32_t gamecstl_state::intel82439tx_pci_r(int function, int reg, uint32_t mem_mask) -{ - uint32_t r = 0; - if (ACCESSING_BITS_24_31) - { - r |= mtxc_config_r(function, reg + 3) << 24; - } - if (ACCESSING_BITS_16_23) - { - r |= mtxc_config_r(function, reg + 2) << 16; - } - if (ACCESSING_BITS_8_15) - { - r |= mtxc_config_r(function, reg + 1) << 8; - } - if (ACCESSING_BITS_0_7) - { - r |= mtxc_config_r(function, reg + 0) << 0; - } - return r; -} - -void gamecstl_state::intel82439tx_pci_w(int function, int reg, uint32_t data, uint32_t mem_mask) -{ - if (ACCESSING_BITS_24_31) - { - mtxc_config_w(function, reg + 3, (data >> 24) & 0xff); - } - if (ACCESSING_BITS_16_23) - { - mtxc_config_w(function, reg + 2, (data >> 16) & 0xff); - } - if (ACCESSING_BITS_8_15) - { - mtxc_config_w(function, reg + 1, (data >> 8) & 0xff); - } - if (ACCESSING_BITS_0_7) - { - mtxc_config_w(function, reg + 0, (data >> 0) & 0xff); - } -} - -// Intel 82371AB PCI-to-ISA / IDE bridge (PIIX4) - -uint8_t gamecstl_state::piix4_config_r(int function, int reg) -{ - logerror("PIIX4: read %d, %02X\n", function, reg); - return m_piix4_config_reg[function][reg]; -} - -void gamecstl_state::piix4_config_w(int function, int reg, uint8_t data) -{ - logerror("%s:PIIX4: write %d, %02X, %02X\n", machine().describe_context(), function, reg, data); - m_piix4_config_reg[function][reg] = data; -} - -uint32_t gamecstl_state::intel82371ab_pci_r(int function, int reg, uint32_t mem_mask) -{ - uint32_t r = 0; - if (ACCESSING_BITS_24_31) - { - r |= piix4_config_r(function, reg + 3) << 24; - } - if (ACCESSING_BITS_16_23) - { - r |= piix4_config_r(function, reg + 2) << 16; - } - if (ACCESSING_BITS_8_15) - { - r |= piix4_config_r(function, reg + 1) << 8; - } - if (ACCESSING_BITS_0_7) - { - r |= piix4_config_r(function, reg + 0) << 0; - } - return r; -} - -void gamecstl_state::intel82371ab_pci_w(int function, int reg, uint32_t data, uint32_t mem_mask) -{ - if (ACCESSING_BITS_24_31) - { - piix4_config_w(function, reg + 3, (data >> 24) & 0xff); - } - if (ACCESSING_BITS_16_23) - { - piix4_config_w(function, reg + 2, (data >> 16) & 0xff); - } - if (ACCESSING_BITS_8_15) - { - piix4_config_w(function, reg + 1, (data >> 8) & 0xff); - } - if (ACCESSING_BITS_0_7) - { - piix4_config_w(function, reg + 0, (data >> 0) & 0xff); - } -} - -// ISA Plug-n-Play -void gamecstl_state::pnp_config_w(offs_t offset, uint32_t data, uint32_t mem_mask) -{ - if (ACCESSING_BITS_8_15) - { -// osd_printf_debug("PNP Config: %02X\n", (data >> 8) & 0xff); - } -} - -void gamecstl_state::pnp_data_w(offs_t offset, uint32_t data, uint32_t mem_mask) -{ - if (ACCESSING_BITS_8_15) - { -// osd_printf_debug("PNP Data: %02X\n", (data >> 8) & 0xff); - } -} - - - -void gamecstl_state::bios_ram_w(offs_t offset, uint32_t data, uint32_t mem_mask) -{ - if (m_mtxc_config_reg[0x59] & 0x20) // write to RAM if this region is write-enabled - { - COMBINE_DATA(m_bios_ram.get() + offset); - } -} - -/*****************************************************************************/ - -void gamecstl_state::gamecstl_map(address_map &map) -{ - map(0x00000000, 0x0009ffff).ram(); - map(0x000a0000, 0x000affff).ram(); - map(0x000b0000, 0x000b7fff).ram().share("cga_ram"); - map(0x000e0000, 0x000effff).ram(); - map(0x000f0000, 0x000fffff).bankr("bank1"); - map(0x000f0000, 0x000fffff).w(FUNC(gamecstl_state::bios_ram_w)); - map(0x00100000, 0x01ffffff).ram(); - map(0xfffc0000, 0xffffffff).rom().region("bios", 0); /* System BIOS */ -} - -void gamecstl_state::gamecstl_io(address_map &map) -{ - pcat32_io_common(map); - map(0x00e8, 0x00eb).noprw(); - map(0x00ec, 0x00ef).noprw(); - map(0x01f0, 0x01f7).rw("ide", FUNC(ide_controller_device::cs0_r), FUNC(ide_controller_device::cs0_w)); - map(0x0300, 0x03af).noprw(); - map(0x03b0, 0x03df).noprw(); - map(0x0278, 0x027b).w(FUNC(gamecstl_state::pnp_config_w)); - map(0x03f0, 0x03f7).rw("ide", FUNC(ide_controller_device::cs1_r), FUNC(ide_controller_device::cs1_w)); - map(0x0a78, 0x0a7b).w(FUNC(gamecstl_state::pnp_data_w)); - map(0x0cf8, 0x0cff).rw("pcibus", FUNC(pci_bus_legacy_device::read), FUNC(pci_bus_legacy_device::write)); -} - -/*****************************************************************************/ - -static const gfx_layout CGA_charlayout = -{ - 8,8, /* 8 x 16 characters */ - 256, /* 256 characters */ - 1, /* 1 bits per pixel */ - { 0 }, /* no bitplanes; 1 bit per pixel */ - /* x offsets */ - { 0,1,2,3,4,5,6,7 }, - /* y offsets */ - { 0*8,1*8,2*8,3*8, - 4*8,5*8,6*8,7*8 }, - 8*8 /* every char takes 8 bytes */ -}; - -static GFXDECODE_START( gfx_cga ) -/* Support up to four CGA fonts */ - GFXDECODE_ENTRY( "gfx1", 0x0000, CGA_charlayout, 0, 256 ) /* Font 0 */ - GFXDECODE_ENTRY( "gfx1", 0x0800, CGA_charlayout, 0, 256 ) /* Font 1 */ - GFXDECODE_ENTRY( "gfx1", 0x1000, CGA_charlayout, 0, 256 ) /* Font 2 */ - GFXDECODE_ENTRY( "gfx1", 0x1800, CGA_charlayout, 0, 256 ) /* Font 3*/ -GFXDECODE_END - -static INPUT_PORTS_START(gamecstl) -INPUT_PORTS_END - -void gamecstl_state::machine_start() -{ -} - -void gamecstl_state::machine_reset() -{ - membank("bank1")->set_base(memregion("bios")->base() + 0x30000); -} - -void gamecstl_state::gamecstl(machine_config &config) -{ - PENTIUM3(config, m_maincpu, 200000000); - m_maincpu->set_addrmap(AS_PROGRAM, &gamecstl_state::gamecstl_map); - m_maincpu->set_addrmap(AS_IO, &gamecstl_state::gamecstl_io); - m_maincpu->set_irq_acknowledge_callback("pic8259_1", FUNC(pic8259_device::inta_cb)); - - pcat_common(config); - - // TODO: wrong, needs SiS 630 instead - pci_bus_legacy_device &pcibus(PCI_BUS_LEGACY(config, "pcibus", 0, 0)); - pcibus.set_device(0, FUNC(gamecstl_state::intel82439tx_pci_r), FUNC(gamecstl_state::intel82439tx_pci_w)); - pcibus.set_device(7, FUNC(gamecstl_state::intel82371ab_pci_r), FUNC(gamecstl_state::intel82371ab_pci_w)); - - ide_controller_device &ide(IDE_CONTROLLER(config, "ide").options(ata_devices, "hdd", nullptr, true)); - ide.irq_handler().set("pic8259_2", FUNC(pic8259_device::ir6_w)); - - screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER)); - screen.set_refresh_hz(60); - screen.set_vblank_time(ATTOSECONDS_IN_USEC(0)); - screen.set_size(640, 480); - screen.set_visarea(0, 639, 0, 199); - screen.set_screen_update(FUNC(gamecstl_state::screen_update_gamecstl)); - screen.set_palette(m_palette); - - GFXDECODE(config, m_gfxdecode, m_palette, gfx_cga); - PALETTE(config, m_palette).set_entries(16); -} - -void gamecstl_state::init_gamecstl() -{ - m_bios_ram = std::make_unique(0x10000/4); - - intel82439tx_init(); -} - -/*****************************************************************************/ - -// not the correct BIOS, f205v owes me a dump of it... -ROM_START(gamecstl) - ROM_REGION32_LE(0x40000, "bios", 0) - ROM_LOAD( "bios.bin", 0x000000, 0x040000, BAD_DUMP CRC(27834ce9) SHA1(134c546dd75138c6f4bc5729b40e20e118454df9) ) - - ROM_REGION(0x08100, "gfx1", 0) - ROM_LOAD( "cga.chr", 0x00000, 0x01000, BAD_DUMP CRC(42009069) SHA1(ed08559ce2d7f97f68b9f540bddad5b6295294dd)) - - DISK_REGION( "ide:0:hdd:image" ) - // Note: has filled NVRAM directory - DISK_IMAGE( "gamecstl", 0, SHA1(b431af3c42c48ba07972d77a3d24e60ee1e4359e) ) -ROM_END - -ROM_START(gamecst2) - ROM_REGION32_LE(0x40000, "bios", 0) - ROM_LOAD( "bios.bin", 0x000000, 0x040000, BAD_DUMP CRC(27834ce9) SHA1(134c546dd75138c6f4bc5729b40e20e118454df9) ) - - ROM_REGION(0x08100, "gfx1", 0) - ROM_LOAD( "cga.chr", 0x00000, 0x01000, BAD_DUMP CRC(42009069) SHA1(ed08559ce2d7f97f68b9f540bddad5b6295294dd)) - - DISK_REGION( "ide:0:hdd:image" ) - DISK_IMAGE( "gamecst2", 0, SHA1(14e1b311cb474801c7bdda3164a0c220fb102159) ) -ROM_END - -/*****************************************************************************/ - -GAME(2002, gamecstl, 0, gamecstl, gamecstl, gamecstl_state, init_gamecstl, ROT0, "Cristaltec", "GameCristal", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) -GAME(2002, gamecst2, gamecstl, gamecstl, gamecstl, gamecstl_state, init_gamecstl, ROT0, "Cristaltec", "GameCristal (version 2.613)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) diff --git a/src/mame/drivers/sis630.cpp b/src/mame/drivers/sis630.cpp new file mode 100644 index 00000000000..e0ba8fb8df0 --- /dev/null +++ b/src/mame/drivers/sis630.cpp @@ -0,0 +1,305 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese, R. Belmont +// thanks-to: Diego Nappino +/************************************************************************************************** + + SiS 630 chipset based PC + + TODO (main): + - PS/2 loses IRQs, mouse is unusable, "ibm" BIOS doesn't work at all; + - '900 Ethernet (missing ROM dump); + - USB controllers (OpenHCI complaint); + - Floppy drive, unsupported SMC37C673 default; + - ACPI is not fully lpc-acpi complaint; + - EISA slots; + - PnP from LPC; + - SMBus; + - Super I/O handling in LPC (HW motherboard monitor, cfr. I/O $294 reads in shutms11 fan tests); + + TODO (usability, to be moved in a SW list): + - windows xp sp3: tests HW then does an ACPI devtrap write ($48), will eventually BSoD with + ACPI STOP #a5 error with param $11 + \- To bypass hold F7 while the "to install SCSI drivers [...] press F6" appears. + And by F7 I really mean it :shrug: + + - windows xp sp3: BSoD during install with a STOP #0a IRQL_NOT_LESS_OR_EQUAL; + + - windows neptune: BSoD during ethernet check (after time clock setup) + with a STOP #a0 INTERNAL_POWER_ERROR with param1 0x5 ("reserved"!?) + + - gamecstl Kontron BIOS: + \- hangs at PC=0xf3cf2, again wanting a SMI# from devtrap_en_w; + \- No PS/2 inputs; + + - gamecstl dump (tested from shutms11, also see notes below): + \- Currently black screens before booting normal Windows, reading $5004 from the LPC ACPI + (flip EAX to non-zero to bypass). + NB: it also writes to $5048 once (devtrap_en_w), which should generate a SMI# event; + \- Doesn't accept any PS/2 input, tries to install a "PCI standard CPU Host Bridge" (?), + hangs there; + \- GUI is never recognized no matter what, punts with DirectX not installed; + + - xubuntu 6.10: throws several SCSIDEV unhandled $46 & $51 commands + (get configuration/read disc information), + eventually punts to prompt with a "can't access tty: job control turned off" (on live CD) or + hangs at "Configuring network interfaces" (on actual install); + + - xubuntu 10.10: stalls after '900 ethernet check; + + - Haiku 0.1: hangs throwing an "unhandled READ TOC format 2", + serial COM1 prints a "vm_mark_page_range_inuse: page 0x9f in non-free state 7!" + + - Red Hat 6.2: Triple Faults on x87 exception check + \- prints the type of mounted floating point exception if bypassed. + +=================================================================================================== + + Cristaltec "Game Cristal" (MAME bootleg) + + Skeleton driver by R. Belmont, based on taitowlf.cpp by Ville Linde + + Notes: + - Specs: P3-866, SiS 630 motherboard + integrated graphics card, + SiS 7018 sound, DirectX 8.1. + - Image is just a more or less stock Windows 98SE with a customized shell + "Ialoader.exe" (sic) to boot the frontend, located in C:\WINDOWS + It will eventually hang after throwing a "DirectX missing" error. + - In order to bypass the shell launcher, you should: + 1. edit C:\WINDOWS\system.ini and change shell property to explorer.exe + 2. remove the autoexec.bat contents, it will otherwise copy a bunch of .ini + files from C:\dat to C:\WINDOWS, and replacing the system.ini shell launcher. + Alternatively you can also execute "open.exe" from MS-DOS, that removes above customization + too. + - (gamecstl) Device Manager installed devices: + - two Samsung SyncMaster 900SL monitors ('630 + '301?); + - SiS 630 display adapter; + - Samsung CD-ROM SC-152L; + - SiS 5513 Dual PCI IDE Controller; + - COM1, COM2, LPT1 enabled; + - a QDI USBDisk USB Mass Storage SCSI driver; + - a SiS 7001 PCI to USB Open Host Controller + USB root hub x 2; + - C:\drvs contains a collection of drivers, mostly the ones described above. + - C:\WINDOWS\temp has a couple footprints: + 1. has a Portuguese version of the Intel Processor Identification Utility, + most likely used for binding the emulator to the CPU serial via CPUID; + 2. has u3spwd.exe (USB Flash Disk), likely used to copy the necessary files for + making the frontend to work; + - Input is via a custom COM1 port JAMMA adaptor. + - The custom emulator is a heavily modified version of MAME32. If you extract the + disk image, it's in C:\GH4\GH4.EXE. It's UPX compressed, so unpack it before doing + any forensics. The emulator does run on Windows as new as XP Pro SP2 but you can't + control it due to the lack of the custom input. + - C:\GH4\mvs contains movie clips of the emulated games. + These are MS-CRAM encoded, 288x208 at 20 fps, stereo MS ADPCM with 11025 Hz sample rate, + 36 seconds length. + Mentioning this because SiS 630 has several HW registers dedicated to video playback, + which will be most likely used once we get there. + - C:\GH4\rdir contains filled NVRAM directory of the supported games. + These are probably copied from a factory default (like skipping NVRAM errors in spang & mk), + needs to be extensively checked if they can be flushed and given a working state with no + arbitrary user data (i.e. the mk games sports about 3 hours of playtime each) + + Updates 27/11/2007 (Diego Nappino): + The COM1 port is opened at 19200 bps, No parity, 8 bit data, 1 stop bit. + The protocol is based on a 6 bytes frame with a leading byte valued 0x05 and a trailing one at 0x02 + The four middle bytes are used, in negative logic (0xFF = No button pressed), to implement the inputs. + Each bit meaning as follows: + + Byte 1 Byte 2 Byte 3 Byte 4 + Bit 0 P1-Credit P1-Button C P2-Left UNUSED + Bit 1 P1-Start P1-Button D P2-Right UNUSED + Bit 2 P1-Down P1-Button E P2-Button A SERVICE + Bit 3 P1-Up TEST P2-Button B UNUSED + Bit 4 P1-Left P2-Credit P2-Button C UNUSED + Bit 5 P1-Right P2-Start P2-Button D UNUSED + Bit 6 P1-Button A P2-Down P2-Button E UNUSED + Bit 7 P1-Button B P2-Up VIDEO-MODE UNUSED + + The JAMMA adaptor sends a byte frame each time an input changes. + So for example, if the P1-Button A and P1-Button B are both pressed, it will send: + + 0x05 0xFC 0xFF 0xFF 0xFF 0x02 + + And when the buttons are both released + + 0x05 0xFF 0xFF 0xFF 0xFF 0x02 + + CPUID info: + + Original set: + CPUID Level: EAX: EBX: ECX: EDX: + 00000000 00000003 756E6547 6C65746E 49656E69 + 00000001 0000068A 00000002 00000000 0387F9FF + 00000002 03020101 00000000 00000000 0C040882 + 00000003 00000000 00000000 CA976D2E 000082F6 + 80000000 00000000 00000000 CA976D2E 000082F6 + C0000000 00000000 00000000 CA976D2E 000082F6 + + Version 2: + CPUID Level: EAX: EBX: ECX: EDX: + 00000000 00000003 756E6547 6C65746E 49656E69 + 00000001 0000068A 00000002 00000000 0387F9FF + 00000002 03020101 00000000 00000000 0C040882 + 00000003 00000000 00000000 B8BA1941 00038881 + 80000000 00000000 00000000 B8BA1941 00038881 + C0000000 00000000 00000000 B8BA1941 00038881 + +**************************************************************************************************/ + +#include "emu.h" +#include "cpu/i386/i386.h" +#include "bus/isa/isa_cards.h" +#include "bus/pc_kbd/keyboards.h" +#include "machine/intelfsh.h" +#include "machine/pci.h" +#include "machine/sis5513_ide.h" +#include "machine/sis630_host.h" +#include "machine/sis630_gui.h" +#include "machine/sis7001_usb.h" +#include "machine/sis7018_audio.h" +#include "machine/sis900_eth.h" +#include "machine/sis950_lpc.h" +#include "machine/sis950_smbus.h" +//#include "machine/fdc37c93x.h" + +class sis630_state : public driver_device +{ +public: + sis630_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag) + , m_maincpu(*this, "maincpu") + , m_ide_00_1(*this, "pci:00.1") + , m_lpc_01_0(*this, "pci:01.0") + { } + + void sis630(machine_config &config); + void gamecstl(machine_config &config); + +private: + + required_device m_maincpu; + required_device m_ide_00_1; + required_device m_lpc_01_0; + +// void main_io(address_map &map); +// void main_map(address_map &map); +}; + + +static INPUT_PORTS_START(sis630) +INPUT_PORTS_END + +void sis630_state::sis630(machine_config &config) +{ + // Slot 1/Socket 370, Coppermine FC-PGA @ 500~850+/100 MHz or Celeron PPGA 300~600+ MHz + // TODO: lowered rate for debugging aid, needs a slot option anyway + PENTIUM3(config, m_maincpu, 100'000'000); +// m_maincpu->set_addrmap(AS_PROGRAM, &sis630_state::main_map); +// m_maincpu->set_addrmap(AS_IO, &sis630_state::main_io); + m_maincpu->set_irq_acknowledge_callback("pci:01.0:pic_master", FUNC(pic8259_device::inta_cb)); +// m_maincpu->smiact().set("pci:00.0", FUNC(sis950_lpc_device::smi_act_w)); + + // TODO: unknown flash ROM types + // Needs a $80000 sized ROM + AMD_29F400T(config, "flash"); + + PCI_ROOT(config, "pci", 0); + // up to 512MB, 2 x DIMM sockets + SIS630_HOST(config, "pci:00.0", 0, "maincpu", 256*1024*1024); + SIS5513_IDE(config, m_ide_00_1, 0, "maincpu"); + // TODO: both on same line as default, should also trigger towards LPC + m_ide_00_1->irq_pri().set("pci:01.0:pic_slave", FUNC(pic8259_device::ir6_w)); + //FUNC(sis950_lpc_device::pc_irq14_w)); + m_ide_00_1->irq_sec().set("pci:01.0:pic_slave", FUNC(pic8259_device::ir7_w)); + //FUNC(sis950_lpc_device::pc_mirq0_w)); + + SIS950_LPC (config, m_lpc_01_0, XTAL(33'000'000), "maincpu", "flash"); + m_lpc_01_0->fast_reset_cb().set([this] (int state) { + if (state) + machine().schedule_soft_reset(); + }); + LPC_ACPI (config, "pci:01.0:acpi", 0); + SIS950_SMBUS(config, "pci:01.0:smbus", 0); + + SIS900_ETH(config, "pci:01.1", 0); + // USB config: 2 on back, 3 on front. Front is fn 2 + SIS7001_USB(config, "pci:01.2", 0, 3); + SIS7001_USB(config, "pci:01.3", 0, 2); + SIS7018_AUDIO(config, "pci:01.4", 0); + // documentation doesn't mention modem part #, derived from Shuttle MS11 MB manual +// SIS7013_MODEM_AC97(config, "pci:01.6" + + // "Virtual PCI-to-PCI Bridge" + SIS630_BRIDGE(config, "pci:02.0", 0, "pci:02.0:00.0"); + // GUI must go under the virtual bridge + // This will be correctly identified as bus #1-dev #0-func #0 by the Award BIOS + SIS630_GUI(config, "pci:02.0:00.0", 0); + + // optional stuff (according to Kontron 786LCD manual) +// "pci:08.0" SCSI controller (vendor=1000 NCR / LSI Logic / Symbios Logic device=0012 53C895A) +// "pci:09.0" IEEE1394 controller (vendor=1033 NEC device=00ce uPD72872 / μPD72872) + + // TODO: 3 expansion PCI slots (PC104+) + // "pci:09.x" to "pci:12.x"? + // (PIC-MG) + // "pci:20.x" to "pci:17.x"? + + // TODO: 1 parallel + 2 serial ports + // TODO: 1 game port ('7018?) + + // TODO: AMR (Audio/modem riser) + UPT (Panel Link-TV out), assume [E]ISA complaint, needs specific slot options +// ISA16_SLOT(config, "isa1", 0, "pci:01.0:isabus", pc_isa16_cards, nullptr, false); +// ISA16_SLOT(config, "isa2", 0, "pci:01.0:isabus", pc_isa16_cards, nullptr, false); +} + +// Kontron 786LCD/3.5 based +void sis630_state::gamecstl(machine_config &config) +{ + sis630_state::sis630(config); + // TODO: Actually Celeron, as also stated by the BIOS + PENTIUM3(config.replace(), m_maincpu, 100'000'000); + + // tries to install '900 on Windows boot, which implies it doesn't have it + // (leave it on for now since it has specific option in Setup BIOS) + //config.device_remove("pci:01.1"); + + // TODO: mapped RAM config + // TODO: add custom inputs + // TODO: eventually remove PS/2 connector defaults +// subdevice("pci:01.0:ps2_con")->set_default_option(nullptr); +// subdevice("pci:01.0:aux_con")->set_default_option(nullptr); +} + +ROM_START(shutms11) + ROM_REGION32_LE(0x80000, "flash", ROMREGION_ERASEFF ) + ROM_SYSTEM_BIOS(0, "ms11s11d", "ms11s11d") + ROMX_LOAD( "ms11s11d.bin", 0x040000, 0x040000, CRC(27077a58) SHA1(32327ebf328cb0c2dec819c3710acc83527803c5), ROM_BIOS(0) ) + ROM_SYSTEM_BIOS(1, "ms11s134", "ms11s134") + ROMX_LOAD( "ms11s134.bin", 0x040000, 0x040000, CRC(d739c4f3) SHA1(2301e57163ac4d9b7eddcabce52fa7d01b22330e), ROM_BIOS(1) ) +ROM_END + +ROM_START(gamecstl) + ROM_REGION32_LE(0x80000, "flash", ROMREGION_ERASEFF ) + // from gamecstl HDD dump, under "C:\drvs\bios\bios1_9" + ROM_LOAD( "prod19.rom", 0x040000, 0x040000, BAD_DUMP CRC(9262306c) SHA1(5cd805622ecb4d326591b5f2cf918fe5cb1bce8e) ) + ROM_CONTINUE( 0x000000, 0x040000 ) + + DISK_REGION( "pci:00.1:ide1:0:hdd:image" ) + DISK_IMAGE( "gamecstl", 0, SHA1(b431af3c42c48ba07972d77a3d24e60ee1e4359e) ) +ROM_END + +ROM_START(gamecst2) + ROM_REGION32_LE(0x80000, "pci:01.0:flash", ROMREGION_ERASEFF ) + ROM_LOAD( "prod19.rom", 0x040000, 0x040000, BAD_DUMP CRC(9262306c) SHA1(5cd805622ecb4d326591b5f2cf918fe5cb1bce8e) ) + ROM_CONTINUE( 0x000000, 0x040000 ) + + DISK_REGION( "pci:00.1:ide1:0:hdd:image" ) + DISK_IMAGE( "gamecst2", 0, SHA1(14e1b311cb474801c7bdda3164a0c220fb102159) ) +ROM_END + + +COMP( 2000, shutms11, 0, 0, sis630, sis630, sis630_state, empty_init, "Shuttle", "MS11 PC", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS ) + +// Arcade based games +GAME( 2002, gamecstl, 0, gamecstl, sis630, sis630_state, empty_init, ROT0, "Cristaltec", "GameCristal", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS ) +GAME( 2002, gamecst2, gamecstl, gamecstl, sis630, sis630_state, empty_init, ROT0, "Cristaltec", "GameCristal (version 2.613)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS ) diff --git a/src/mame/mame.lst b/src/mame/mame.lst index 0a33a1f9197..9df3c8f97dd 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -14952,10 +14952,6 @@ gambl186d // EGD @source:gamecom.cpp gamecom // Tiger Game.com -@source:gamecstl.cpp -gamecst2 // MAME based bootleg, version 2.613 -gamecstl // MAME based bootleg - @source:gamecube.cpp gcjp // (c) 2001 Nintendo gcus // (c) 2001 Nintendo @@ -38979,6 +38975,11 @@ simpsons2pj // GX072 (c) 1991 (Japan) simpsons4pa // GX072 (c) 1991 (Asia) simpsons4pe // GX072 (c) 1991 (World) +@source:sis630.cpp +gamecst2 // MAME based bootleg, version 2.613 +gamecstl // MAME based bootleg +shutms11 // (c) 2000 + @source:sitcom.cpp sitcom // sitcomtmr // diff --git a/src/mame/mess.flt b/src/mame/mess.flt index 30bfc685e68..e28189af733 100644 --- a/src/mame/mess.flt +++ b/src/mame/mess.flt @@ -967,6 +967,7 @@ sg1000.cpp sh4robot.cpp shine.cpp si5500.cpp +sis630.cpp sitcom.cpp sk1.cpp sk101bl.cpp