mirror of
https://github.com/holub/mame
synced 2025-04-16 13:34:55 +03:00

- 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]
765 lines
25 KiB
C++
765 lines
25 KiB
C++
// 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);
|
|
}
|