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]
This commit is contained in:
Angelo Salese 2022-05-23 17:27:33 +02:00 committed by GitHub
parent 09062b24a3
commit e6180e3510
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 3853 additions and 518 deletions

View File

@ -2737,6 +2737,22 @@ if (MACHINES["PCI"]~=null) then
MAME_DIR .. "src/devices/machine/vrc5074.h", MAME_DIR .. "src/devices/machine/vrc5074.h",
MAME_DIR .. "src/devices/machine/gt64xxx.cpp", MAME_DIR .. "src/devices/machine/gt64xxx.cpp",
MAME_DIR .. "src/devices/machine/gt64xxx.h", 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.cpp",
MAME_DIR .. "src/devices/machine/sis85c496.h", MAME_DIR .. "src/devices/machine/sis85c496.h",
} }

View File

@ -2116,6 +2116,7 @@ files {
MAME_DIR .. "src/mame/drivers/pcxt.cpp", MAME_DIR .. "src/mame/drivers/pcxt.cpp",
MAME_DIR .. "src/mame/drivers/quakeat.cpp", MAME_DIR .. "src/mame/drivers/quakeat.cpp",
MAME_DIR .. "src/mame/drivers/queen.cpp", MAME_DIR .. "src/mame/drivers/queen.cpp",
MAME_DIR .. "src/mame/drivers/sis630.cpp",
} }
createMAMEProjects(_target, _subtarget, "igs") createMAMEProjects(_target, _subtarget, "igs")
@ -4844,7 +4845,6 @@ files {
MAME_DIR .. "src/mame/drivers/gambl186.cpp", MAME_DIR .. "src/mame/drivers/gambl186.cpp",
MAME_DIR .. "src/mame/drivers/galaxi.cpp", MAME_DIR .. "src/mame/drivers/galaxi.cpp",
MAME_DIR .. "src/mame/drivers/galgame.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/gamemasters.cpp",
MAME_DIR .. "src/mame/drivers/gammagic.cpp", MAME_DIR .. "src/mame/drivers/gammagic.cpp",
MAME_DIR .. "src/mame/drivers/gamtor.cpp", MAME_DIR .. "src/mame/drivers/gamtor.cpp",

View File

@ -3390,6 +3390,7 @@ files {
MAME_DIR .. "src/mame/drivers/nforcepc.cpp", MAME_DIR .. "src/mame/drivers/nforcepc.cpp",
MAME_DIR .. "src/mame/drivers/pc.cpp", MAME_DIR .. "src/mame/drivers/pc.cpp",
MAME_DIR .. "src/mame/drivers/pcipc.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/tandy1t.cpp",
MAME_DIR .. "src/mame/drivers/tosh1000.cpp", MAME_DIR .. "src/mame/drivers/tosh1000.cpp",
MAME_DIR .. "src/mame/machine/tosh1000_bram.cpp", MAME_DIR .. "src/mame/machine/tosh1000_bram.cpp",

View File

@ -3333,12 +3333,38 @@ void pentium3_device::device_reset()
// [ 0:0] FPU on chip // [ 0:0] FPU on chip
// [ 4:4] Time Stamp Counter // [ 4:4] Time Stamp Counter
// [ 8:8] CMPXCHG8B instruction
// [ D:D] PTE Global Bit // [ 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); 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 */ /* Intel Pentium 4 */
@ -3402,7 +3428,9 @@ void pentium4_device::device_reset()
m_cpu_version = REG32(EDX); m_cpu_version = REG32(EDX);
// [ 0:0] FPU on chip // [ 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); CHANGE_PC(m_eip);
} }

View File

@ -1650,6 +1650,8 @@ public:
protected: protected:
virtual void device_start() override; virtual void device_start() override;
virtual void device_reset() override; virtual void device_reset() override;
virtual void opcode_cpuid() override;
}; };

View File

@ -1,5 +1,10 @@
// license:BSD-3-Clause // license:BSD-3-Clause
// copyright-holders:Olivier Galibert // copyright-holders:Olivier Galibert
/*
* References:
* - PCI local bus (rev 2.x)
* - https://wiki.osdev.org/PCI
*/
#include "emu.h" #include "emu.h"
#include "pci.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) void pci_device::set_ids(uint32_t _main_id, uint8_t _revision, uint32_t _pclass, uint32_t _subsystem_id)
{ {
main_id = _main_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(); 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 <capability dependant, usually revision and supported sub-features>
// 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() uint8_t pci_device::capptr_r()
{ {
return 0x00; return 0x00;

View File

@ -193,7 +193,7 @@ public:
uint16_t iolimitu_r(); uint16_t iolimitu_r();
void iolimitu_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); void iolimitu_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint16_t bridge_control_r(); 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: protected:
enum enum

View File

@ -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);
}

View File

@ -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 <typename T> 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<bus_master_ide_controller_device> m_ide1;
required_device<bus_master_ide_controller_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

View File

@ -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<uint8_t []>(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<u8, u8> 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<u8, std::string> 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<sis630_svga_device *>(m_svga.target())->mem_r(offset);
}
void sis630_gui_device::vram_w(offs_t offset, uint8_t data)
{
downcast<sis630_svga_device *>(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<sis630_svga_device *>(m_svga.target())->port_03b0_r(offset * 4 + 0) << 0;
if (ACCESSING_BITS_8_15)
result |= downcast<sis630_svga_device *>(m_svga.target())->port_03b0_r(offset * 4 + 1) << 8;
if (ACCESSING_BITS_16_23)
result |= downcast<sis630_svga_device *>(m_svga.target())->port_03b0_r(offset * 4 + 2) << 16;
if (ACCESSING_BITS_24_31)
result |= downcast<sis630_svga_device *>(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<sis630_svga_device *>(m_svga.target())->port_03b0_w(offset * 4 + 0, data >> 0);
if (ACCESSING_BITS_8_15)
downcast<sis630_svga_device *>(m_svga.target())->port_03b0_w(offset * 4 + 1, data >> 8);
if (ACCESSING_BITS_16_23)
downcast<sis630_svga_device *>(m_svga.target())->port_03b0_w(offset * 4 + 2, data >> 16);
if (ACCESSING_BITS_24_31)
downcast<sis630_svga_device *>(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<sis630_svga_device *>(m_svga.target())->port_03c0_r(offset * 4 + 0) << 0;
if (ACCESSING_BITS_8_15)
result |= downcast<sis630_svga_device *>(m_svga.target())->port_03c0_r(offset * 4 + 1) << 8;
if (ACCESSING_BITS_16_23)
result |= downcast<sis630_svga_device *>(m_svga.target())->port_03c0_r(offset * 4 + 2) << 16;
if (ACCESSING_BITS_24_31)
result |= downcast<sis630_svga_device *>(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<sis630_svga_device *>(m_svga.target())->port_03c0_w(offset * 4 + 0, data >> 0);
if (ACCESSING_BITS_8_15)
downcast<sis630_svga_device *>(m_svga.target())->port_03c0_w(offset * 4 + 1, data >> 8);
if (ACCESSING_BITS_16_23)
downcast<sis630_svga_device *>(m_svga.target())->port_03c0_w(offset * 4 + 2, data >> 16);
if (ACCESSING_BITS_24_31)
downcast<sis630_svga_device *>(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<sis630_svga_device *>(m_svga.target())->port_03d0_r(offset * 4 + 0) << 0;
if (ACCESSING_BITS_8_15)
result |= downcast<sis630_svga_device *>(m_svga.target())->port_03d0_r(offset * 4 + 1) << 8;
if (ACCESSING_BITS_16_23)
result |= downcast<sis630_svga_device *>(m_svga.target())->port_03d0_r(offset * 4 + 2) << 16;
if (ACCESSING_BITS_24_31)
result |= downcast<sis630_svga_device *>(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<sis630_svga_device *>(m_svga.target())->port_03d0_w(offset * 4 + 0, data >> 0);
if (ACCESSING_BITS_8_15)
downcast<sis630_svga_device *>(m_svga.target())->port_03d0_w(offset * 4 + 1, data >> 8);
if (ACCESSING_BITS_16_23)
downcast<sis630_svga_device *>(m_svga.target())->port_03d0_w(offset * 4 + 2, data >> 16);
if (ACCESSING_BITS_24_31)
downcast<sis630_svga_device *>(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();
}

View File

@ -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<u8, u8> 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<sis630_svga_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 <typename T> 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<T>(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<sis630_gui_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

View File

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

View File

@ -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 <typename T> 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<T>(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<cpu_device> m_host_cpu;
std::vector<uint32_t> 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

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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));
}
}

View File

@ -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<eeprom_serial_93cxx_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

View File

@ -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<IRQ_INTA>), FUNC(sis950_lpc_device::irq_remap_w<IRQ_INTA>));
map(0x42, 0x42).rw(FUNC(sis950_lpc_device::irq_remap_r<IRQ_INTB>), FUNC(sis950_lpc_device::irq_remap_w<IRQ_INTB>));
map(0x43, 0x43).rw(FUNC(sis950_lpc_device::irq_remap_r<IRQ_INTC>), FUNC(sis950_lpc_device::irq_remap_w<IRQ_INTC>));
map(0x44, 0x44).rw(FUNC(sis950_lpc_device::irq_remap_r<IRQ_INTD>), FUNC(sis950_lpc_device::irq_remap_w<IRQ_INTD>));
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<IRQ_IDE>), FUNC(sis950_lpc_device::irq_remap_w<IRQ_IDE>));
// map(0x62, 0x62) <reserved>, hardwired to 0x80 (PIT irq remap?)
map(0x62, 0x62).lr8(NAME([] () { return 0x80; }));
map(0x63, 0x63).rw(FUNC(sis950_lpc_device::irq_remap_r<IRQ_GPE>), FUNC(sis950_lpc_device::irq_remap_w<IRQ_GPE>));
// map(0x64, 0x64) PCI bus priority timer
// map(0x65, 0x65) PHOLD# timer
// map(0x66, 0x66) <reserved>
// map(0x67, 0x67) Serial IRQ 1 & 12 latch control (FDC super I/O)
// map(0x68, 0x69) <reserved>
map(0x63, 0x63).rw(FUNC(sis950_lpc_device::irq_remap_r<IRQ_ACPI>), FUNC(sis950_lpc_device::irq_remap_w<IRQ_ACPI>));
// map(0x6b, 0x6b) <reserved>
map(0x6c, 0x6c).rw(FUNC(sis950_lpc_device::irq_remap_r<IRQ_SMBUS>), FUNC(sis950_lpc_device::irq_remap_w<IRQ_SMBUS>));
map(0x6d, 0x6d).rw(FUNC(sis950_lpc_device::irq_remap_r<IRQ_SWDOG>), FUNC(sis950_lpc_device::irq_remap_w<IRQ_SWDOG>));
// 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 <reserved> 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 <unsigned N> u8 sis950_lpc_device::irq_remap_r()
{
return m_irq_remap[N];
}
template <unsigned N> void sis950_lpc_device::irq_remap_w(u8 data)
{
m_irq_remap[N] = data;
LOGIRQ("%s IRQ remap write %02x (%s)\n", std::array<char const *, 9> {{
"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 <reserved>
*/
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 <unsigned N> 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 <reads back NMI control enable>
*/
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 ---- <must be zero when writing to this port>
* ---- 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);
}

View File

@ -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 <typename T, typename U> 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<T>(cpu_tag));
m_flash_rom.set_tag(std::forward<U>(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 <unsigned N> void memory_map(address_map &map);
void io_map(address_map &map);
private:
required_device<cpu_device> m_host_cpu;
required_device<intelfsh8_device> m_flash_rom;
required_device<pic8259_device> m_pic_master;
required_device<pic8259_device> m_pic_slave;
required_device<am9517a_device> m_dmac_master;
required_device<am9517a_device> m_dmac_slave;
required_device<pit8254_device> m_pit;
required_device<ps2_keyboard_controller_device> m_keybc;
required_device<speaker_sound_device> m_speaker;
required_device<ds12885ext_device> m_rtc;
required_device<pc_kbdc_device> m_ps2_con;
required_device<pc_kbdc_device> m_aux_con;
required_device<ins8250_device> m_uart;
required_device<lpc_acpi_device> m_acpi;
required_device<sis950_smbus_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 <unsigned N> u8 irq_remap_r();
template <unsigned N> 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

View File

@ -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 <reserved>
*/
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;
}

View File

@ -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

View File

@ -1698,6 +1698,12 @@ uint8_t vga_device::gc_reg_read(uint8_t index)
return res; 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 vga_device::port_03c0_r(offs_t offset)
{ {
uint8_t data = 0xff; uint8_t data = 0xff;
@ -1758,6 +1764,8 @@ uint8_t vga_device::port_03c0_r(offs_t offset)
case 5: case 5:
if (vga.sequencer.index < vga.svga_intf.seq_regcount) if (vga.sequencer.index < vga.svga_intf.seq_regcount)
data = vga.sequencer.data[vga.sequencer.index]; data = vga.sequencer.data[vga.sequencer.index];
else
data = seq_reg_read(vga.sequencer.index);
break; break;
case 6: case 6:

View File

@ -73,10 +73,11 @@ protected:
void vga_vh_mono(bitmap_rgb32 &bitmap, const rectangle &cliprect); void vga_vh_mono(bitmap_rgb32 &bitmap, const rectangle &cliprect);
virtual uint8_t pc_vga_choosevideomode(); virtual uint8_t pc_vga_choosevideomode();
void recompute_params_clock(int divisor, int xtal); 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(); virtual void recompute_params();
void crtc_reg_write(uint8_t index, uint8_t data); virtual void crtc_reg_write(uint8_t index, uint8_t data);
void seq_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_vblank();
uint8_t vga_crtc_r(offs_t offset); uint8_t vga_crtc_r(offs_t offset);
void vga_crtc_w(offs_t offset, uint8_t data); void vga_crtc_w(offs_t offset, uint8_t data);

View File

@ -473,7 +473,6 @@ galpanic.cpp
galpanic_ms.cpp galpanic_ms.cpp
galspnbl.cpp galspnbl.cpp
gambl186.cpp gambl186.cpp
gamecstl.cpp
gamemasters.cpp gamemasters.cpp
gameplan.cpp gameplan.cpp
gammagic.cpp gammagic.cpp
@ -1193,6 +1192,7 @@ silvmil.cpp
simpl156.cpp simpl156.cpp
simple_st0016.cpp simple_st0016.cpp
simpsons.cpp simpsons.cpp
sis630.cpp
skeetsht.cpp skeetsht.cpp
skimaxx.cpp skimaxx.cpp
skopro.cpp skopro.cpp

View File

@ -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<uint32_t> m_cga_ram;
required_device<gfxdecode_device> m_gfxdecode;
required_device<palette_device> m_palette;
std::unique_ptr<uint32_t[]> 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<uint32_t[]>(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)

305
src/mame/drivers/sis630.cpp Normal file
View File

@ -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<pentium3_device> m_maincpu;
required_device<sis5513_ide_device> m_ide_00_1;
required_device<sis950_lpc_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<pc_kbdc_device>("pci:01.0:ps2_con")->set_default_option(nullptr);
// subdevice<pc_kbdc_device>("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 )

View File

@ -14952,10 +14952,6 @@ gambl186d // EGD
@source:gamecom.cpp @source:gamecom.cpp
gamecom // Tiger Game.com gamecom // Tiger Game.com
@source:gamecstl.cpp
gamecst2 // MAME based bootleg, version 2.613
gamecstl // MAME based bootleg
@source:gamecube.cpp @source:gamecube.cpp
gcjp // (c) 2001 Nintendo gcjp // (c) 2001 Nintendo
gcus // (c) 2001 Nintendo gcus // (c) 2001 Nintendo
@ -38979,6 +38975,11 @@ simpsons2pj // GX072 (c) 1991 (Japan)
simpsons4pa // GX072 (c) 1991 (Asia) simpsons4pa // GX072 (c) 1991 (Asia)
simpsons4pe // GX072 (c) 1991 (World) 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 @source:sitcom.cpp
sitcom // sitcom //
sitcomtmr // sitcomtmr //

View File

@ -967,6 +967,7 @@ sg1000.cpp
sh4robot.cpp sh4robot.cpp
shine.cpp shine.cpp
si5500.cpp si5500.cpp
sis630.cpp
sitcom.cpp sitcom.cpp
sk1.cpp sk1.cpp
sk101bl.cpp sk101bl.cpp