diff options
author | 2015-11-08 12:56:12 +0100 | |
---|---|---|
committer | 2015-11-08 12:56:12 +0100 | |
commit | 7c19aac60e12d6f5ea301bdb34d7826a01e0b06f (patch) | |
tree | f310d86aa2c6bfc19d115307dedde4eb0cd52dad /src/devices/machine/cs4031.cpp | |
parent | a57b46ae933badd7441ce1644711dbb851e2b504 (diff) |
Rename *.c -> *.cpp in our source (nw)
Diffstat (limited to 'src/devices/machine/cs4031.cpp')
-rw-r--r-- | src/devices/machine/cs4031.cpp | 969 |
1 files changed, 969 insertions, 0 deletions
diff --git a/src/devices/machine/cs4031.cpp b/src/devices/machine/cs4031.cpp new file mode 100644 index 00000000000..b6d8de1acd8 --- /dev/null +++ b/src/devices/machine/cs4031.cpp @@ -0,0 +1,969 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Chips & Technologies CS4031 chipset + + Chipset for 486 based PC/AT compatible systems. Consists of two + individual chips: + + * F84031 + - DRAM controller + - ISA-bus controller + - VESA VL-BUS controller + + * F84035 (82C206 IPC core) + - 2x 8257 DMA controller + - 2x 8259 interrupt controller + - 8254 timer + - MC14818 RTC + + TODO: + - No emulation of memory parity checks + - Move IPC core to its own file so it can be shared with + other chipsets + +***************************************************************************/ + +#include "emu.h" +#include "machine/ram.h" +#include "machine/cs4031.h" + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define LOG_REGISTER 1 +#define LOG_MEMORY 1 +#define LOG_IO 1 +#define LOG_KEYBOARD 0 + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type CS4031 = &device_creator<cs4031_device>; + +const char* cs4031_device::m_register_names[] = +{ + /* 00 */ "RESERVED", + /* 01 */ "DMA WAIT STATE CONTROL", + /* 02 */ "RESERVED", + /* 03 */ "RESERVED", + /* 04 */ "RESERVED", + /* 05 */ "ISA BUS COMMAND DELAY", + /* 06 */ "ISA BUS WAIT STATES AND ADDRESS HOLD", + /* 07 */ "ISA BUS CLOCK SELECTION", + /* 08 */ "PERFORMANCE CONTROL", + /* 09 */ "84035 MISC CONTROL", + /* 0a */ "DMA CLOCK SELECTION", + /* 0b */ "RESERVED", + /* 0c */ "RESERVED", + /* 0d */ "RESERVED", + /* 0e */ "RESERVED", + /* 0f */ "RESERVED", + /* 10 */ "DRAM TIMING", + /* 11 */ "DRAM SETUP", + /* 12 */ "DRAM CONFIGURATION 0 AND 1", + /* 13 */ "DRAM CONFIGURATION 2 AND 3", + /* 14 */ "DRAM BLOCK 0 STARTING ADDRESS", + /* 15 */ "DRAM BLOCK 1 STARTING ADDRESS", + /* 16 */ "DRAM BLOCK 2 STARTING ADDRESS", + /* 17 */ "DRAM BLOCK 3 STARTING ADDRESS", + /* 18 */ "VIDEO AREA SHADOW AND LOCAL BUS CONTROL", + /* 19 */ "DRAM SHADOW READ ENABLE", + /* 1a */ "DRAM SHADOW WRITE ENABLE", + /* 1b */ "ROMCS ENABLE", + /* 1c */ "SOFT RESET AND GATEA20", + /* 1d */ "RESERVED", + /* 1e */ "RESERVED", + /* 1f */ "RESERVED" +}; + +const float cs4031_device::m_dma_clock_divider[] = +{ + 10, 8, 6, 0, 0, 0, 0, 0, 5, 4, 3, 2.5, 2, 1.5, 0, 0 +}; + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( cs4031 ) + MCFG_DEVICE_ADD("dma1", AM9517A, 0) + MCFG_I8237_OUT_HREQ_CB(DEVWRITELINE("dma2", am9517a_device, dreq0_w)) + MCFG_I8237_OUT_EOP_CB(WRITELINE(cs4031_device, dma1_eop_w)) + MCFG_I8237_IN_MEMR_CB(READ8(cs4031_device, dma_read_byte)) + MCFG_I8237_OUT_MEMW_CB(WRITE8(cs4031_device, dma_write_byte)) + MCFG_I8237_IN_IOR_0_CB(READ8(cs4031_device, dma1_ior0_r)) + MCFG_I8237_IN_IOR_1_CB(READ8(cs4031_device, dma1_ior1_r)) + MCFG_I8237_IN_IOR_2_CB(READ8(cs4031_device, dma1_ior2_r)) + MCFG_I8237_IN_IOR_3_CB(READ8(cs4031_device, dma1_ior3_r)) + MCFG_I8237_OUT_IOW_0_CB(WRITE8(cs4031_device, dma1_iow0_w)) + MCFG_I8237_OUT_IOW_1_CB(WRITE8(cs4031_device, dma1_iow1_w)) + MCFG_I8237_OUT_IOW_2_CB(WRITE8(cs4031_device, dma1_iow2_w)) + MCFG_I8237_OUT_IOW_3_CB(WRITE8(cs4031_device, dma1_iow3_w)) + MCFG_I8237_OUT_DACK_0_CB(WRITELINE(cs4031_device, dma1_dack0_w)) + MCFG_I8237_OUT_DACK_1_CB(WRITELINE(cs4031_device, dma1_dack1_w)) + MCFG_I8237_OUT_DACK_2_CB(WRITELINE(cs4031_device, dma1_dack2_w)) + MCFG_I8237_OUT_DACK_3_CB(WRITELINE(cs4031_device, dma1_dack3_w)) + MCFG_DEVICE_ADD("dma2", AM9517A, 0) + MCFG_I8237_OUT_HREQ_CB(WRITELINE(cs4031_device, dma2_hreq_w)) + MCFG_I8237_IN_MEMR_CB(READ8(cs4031_device, dma_read_word)) + MCFG_I8237_OUT_MEMW_CB(WRITE8(cs4031_device, dma_write_word)) + MCFG_I8237_IN_IOR_1_CB(READ8(cs4031_device, dma2_ior1_r)) + MCFG_I8237_IN_IOR_2_CB(READ8(cs4031_device, dma2_ior2_r)) + MCFG_I8237_IN_IOR_3_CB(READ8(cs4031_device, dma2_ior3_r)) + MCFG_I8237_OUT_IOW_1_CB(WRITE8(cs4031_device, dma2_iow1_w)) + MCFG_I8237_OUT_IOW_2_CB(WRITE8(cs4031_device, dma2_iow2_w)) + MCFG_I8237_OUT_IOW_3_CB(WRITE8(cs4031_device, dma2_iow3_w)) + MCFG_I8237_OUT_DACK_0_CB(WRITELINE(cs4031_device, dma2_dack0_w)) + MCFG_I8237_OUT_DACK_1_CB(WRITELINE(cs4031_device, dma2_dack1_w)) + MCFG_I8237_OUT_DACK_2_CB(WRITELINE(cs4031_device, dma2_dack2_w)) + MCFG_I8237_OUT_DACK_3_CB(WRITELINE(cs4031_device, dma2_dack3_w)) + MCFG_PIC8259_ADD("intc1", WRITELINE(cs4031_device, intc1_int_w), VCC, READ8(cs4031_device, intc1_slave_ack_r)) + MCFG_PIC8259_ADD("intc2", DEVWRITELINE("intc1", pic8259_device, ir2_w), GND, NULL) + + MCFG_DEVICE_ADD("ctc", PIT8254, 0) + MCFG_PIT8253_CLK0(XTAL_14_31818MHz / 12) + MCFG_PIT8253_OUT0_HANDLER(DEVWRITELINE("intc1", pic8259_device, ir0_w)) + MCFG_PIT8253_CLK1(XTAL_14_31818MHz / 12) + MCFG_PIT8253_OUT1_HANDLER(WRITELINE(cs4031_device, ctc_out1_w)) + MCFG_PIT8253_CLK2(XTAL_14_31818MHz / 12) + MCFG_PIT8253_OUT2_HANDLER(WRITELINE(cs4031_device, ctc_out2_w)) + + MCFG_DS12885_ADD("rtc") + MCFG_MC146818_IRQ_HANDLER(WRITELINE(cs4031_device, rtc_irq_w)) + MCFG_MC146818_CENTURY_INDEX(0x32) +MACHINE_CONFIG_END + +machine_config_constructor cs4031_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cs4031 ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// cs4031_device - constructor +//------------------------------------------------- + +cs4031_device::cs4031_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CS4031, "CS4031", tag, owner, clock, "cs4031", __FILE__), + m_read_ior(*this), + m_write_iow(*this), + m_write_tc(*this), + m_write_hold(*this), + m_write_nmi(*this), + m_write_intr(*this), + m_write_cpureset(*this), + m_write_a20m(*this), + m_write_spkr(*this), + m_dma1(*this, "dma1"), + m_dma2(*this, "dma2"), + m_intc1(*this, "intc1"), + m_intc2(*this, "intc2"), + m_ctc(*this, "ctc"), + m_rtc(*this, "rtc"), + m_dma_eop(0), + m_dma_high_byte(0xff), + m_dma_channel(-1), + m_portb(0x0f), + m_refresh_toggle(0), + m_iochck(1), + m_nmi_mask(1), + m_cpureset(0), + m_kbrst(1), + m_ext_gatea20(0), + m_fast_gatea20(0), + m_emu_gatea20(0), + m_keybc_d1_written(false), + m_keybc_data_blocked(false), + m_address(0), + m_address_valid(false) +{ +} + +void cs4031_device::static_set_cputag(device_t &device, const char *tag) +{ + cs4031_device &cs4031 = downcast<cs4031_device &>(device); + cs4031.m_cputag = tag; +} + +void cs4031_device::static_set_isatag(device_t &device, const char *tag) +{ + cs4031_device &cs4031 = downcast<cs4031_device &>(device); + cs4031.m_isatag = tag; +} + +void cs4031_device::static_set_biostag(device_t &device, const char *tag) +{ + cs4031_device &cs4031 = downcast<cs4031_device &>(device); + cs4031.m_biostag = tag; +} + +void cs4031_device::static_set_keybctag(device_t &device, const char *tag) +{ + cs4031_device &cs4031 = downcast<cs4031_device &>(device); + cs4031.m_keybctag = tag; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cs4031_device::device_start() +{ + ram_device *ram_dev = machine().device<ram_device>(RAM_TAG); + + // make sure the ram device is already running + if (!ram_dev->started()) + throw device_missing_dependencies(); + + // resolve callbacks + m_read_ior.resolve_safe(0); + m_write_iow.resolve_safe(); + m_write_tc.resolve_safe(); + m_write_hold.resolve_safe(); + m_write_nmi.resolve_safe(); + m_write_intr.resolve_safe(); + m_write_cpureset.resolve_safe(); + m_write_a20m.resolve_safe(); + m_write_spkr.resolve_safe(); + + // register for state saving + save_item(NAME(m_dma_eop)); + save_item(NAME(m_dma_page)); + save_item(NAME(m_dma_high_byte)); + save_item(NAME(m_dma_channel)); + save_item(NAME(m_portb)); + save_item(NAME(m_refresh_toggle)); + save_item(NAME(m_iochck)); + save_item(NAME(m_nmi_mask)); + save_item(NAME(m_cpureset)); + save_item(NAME(m_kbrst)); + save_item(NAME(m_ext_gatea20)); + save_item(NAME(m_fast_gatea20)); + save_item(NAME(m_address)); + save_item(NAME(m_address_valid)); + save_item(NAME(m_registers)); + + device_t *cpu = machine().device(m_cputag); + m_space = &cpu->memory().space(AS_PROGRAM); + m_space_io = &cpu->memory().space(AS_IO); + + m_isa = machine().root_device().memregion(m_isatag)->base(); + m_bios = machine().root_device().memregion(m_biostag)->base(); + m_keybc = downcast<at_keyboard_controller_device *>(machine().device(m_keybctag)); + + m_ram = ram_dev->pointer(); + UINT32 ram_size = ram_dev->size(); + + // install base memory + m_space->install_ram(0x000000, 0x09ffff, m_ram); + + // install extended memory + if (ram_size > 0x100000) + m_space->install_ram(0x100000, ram_size - 1, m_ram + 0x100000); + + // install bios rom at cpu inital pc + m_space->install_rom(0xffff0000, 0xffffffff, m_bios + 0xf0000); + + // install i/o accesses + m_space_io->install_readwrite_handler(0x0000, 0x000f, read8_delegate(FUNC(am9517a_device::read), &(*m_dma1)), write8_delegate(FUNC(am9517a_device::write), &(*m_dma1)), 0xffffffff); + m_space_io->install_readwrite_handler(0x0020, 0x0023, read8_delegate(FUNC(pic8259_device::read), &(*m_intc1)), write8_delegate(FUNC(pic8259_device::write), &(*m_intc1)), 0x0000ffff); + m_space_io->install_write_handler(0x0020, 0x0023, write8_delegate(FUNC(cs4031_device::config_address_w), this), 0x00ff0000); + m_space_io->install_readwrite_handler(0x0020, 0x0023, read8_delegate(FUNC(cs4031_device::config_data_r), this), write8_delegate(FUNC(cs4031_device::config_data_w), this), 0xff000000); + m_space_io->install_readwrite_handler(0x0040, 0x0043, read8_delegate(FUNC(pit8254_device::read), &(*m_ctc)), write8_delegate(FUNC(pit8254_device::write), &(*m_ctc)), 0xffffffff); + m_space_io->install_readwrite_handler(0x0060, 0x0063, read8_delegate(FUNC(cs4031_device::keyb_data_r), this), write8_delegate(FUNC(cs4031_device::keyb_data_w), this), 0x000000ff); + m_space_io->install_readwrite_handler(0x0060, 0x0063, read8_delegate(FUNC(cs4031_device::portb_r), this), write8_delegate(FUNC(cs4031_device::portb_w), this), 0x0000ff00); + m_space_io->install_readwrite_handler(0x0064, 0x0067, read8_delegate(FUNC(cs4031_device::keyb_status_r), this), write8_delegate(FUNC(cs4031_device::keyb_command_w), this), 0x000000ff); + m_space_io->install_readwrite_handler(0x0070, 0x0073, read8_delegate(FUNC(mc146818_device::read), &(*m_rtc)), write8_delegate(FUNC(cs4031_device::rtc_w), this), 0x0000ffff); + m_space_io->install_readwrite_handler(0x0080, 0x008f, read8_delegate(FUNC(cs4031_device::dma_page_r), this), write8_delegate(FUNC(cs4031_device::dma_page_w), this), 0xffffffff); + m_space_io->install_readwrite_handler(0x0090, 0x0093, read8_delegate(FUNC(cs4031_device::sysctrl_r), this), write8_delegate(FUNC(cs4031_device::sysctrl_w), this), 0x00ff0000); + m_space_io->install_readwrite_handler(0x00a0, 0x00a3, read8_delegate(FUNC(pic8259_device::read), &(*m_intc2)), write8_delegate(FUNC(pic8259_device::write), &(*m_intc2)), 0x0000ffff); + m_space_io->install_readwrite_handler(0x00c0, 0x00df, read8_delegate(FUNC(cs4031_device::dma2_r),this), write8_delegate(FUNC(cs4031_device::dma2_w),this), 0xffffffff); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void cs4031_device::device_reset() +{ + // setup default values + memset(&m_registers, 0x00, sizeof(m_registers)); + m_registers[ROMCS] = 0x60; + + // update rom/ram regions below 1mb + update_read_regions(); + update_write_regions(); + + // initialize dma controller clocks + update_dma_clock(); +} + +//------------------------------------------------- +// device_reset_after_children +//------------------------------------------------- + +void cs4031_device::device_reset_after_children() +{ + // timer 2 default state + m_ctc->write_gate2(1); +} + + +//************************************************************************** +// DMA CONTROLLER +//************************************************************************** + +offs_t cs4031_device::page_offset() +{ + switch (m_dma_channel) + { + case 0: return (offs_t) m_dma_page[0x07] << 16; + case 1: return (offs_t) m_dma_page[0x03] << 16; + case 2: return (offs_t) m_dma_page[0x01] << 16; + case 3: return (offs_t) m_dma_page[0x02] << 16; + case 5: return (offs_t) m_dma_page[0x0b] << 16; + case 6: return (offs_t) m_dma_page[0x09] << 16; + case 7: return (offs_t) m_dma_page[0x0a] << 16; + } + + // should never get here + return 0xff0000; +} + +READ8_MEMBER( cs4031_device::dma_read_byte ) +{ + if (m_dma_channel == -1) + return 0xff; + + return m_space->read_byte(page_offset() + offset); +} + +WRITE8_MEMBER( cs4031_device::dma_write_byte ) +{ + if (m_dma_channel == -1) + return; + + m_space->write_byte(page_offset() + offset, data); +} + +READ8_MEMBER( cs4031_device::dma_read_word ) +{ + if (m_dma_channel == -1) + return 0xff; + + UINT16 result = m_space->read_word(page_offset() + (offset << 1)); + m_dma_high_byte = result >> 8; + + return result; +} + +WRITE8_MEMBER( cs4031_device::dma_write_word ) +{ + if (m_dma_channel == -1) + return; + + m_space->write_word(page_offset() + (offset << 1), (m_dma_high_byte << 8) | data); +} + +WRITE_LINE_MEMBER( cs4031_device::dma2_dack0_w ) +{ + m_dma1->hack_w(state ? 0 : 1); // inverted? +} + +WRITE_LINE_MEMBER( cs4031_device::dma1_eop_w ) +{ + m_dma_eop = state; + if (m_dma_channel != -1) + m_write_tc(m_dma_channel, state, 0xff); +} + +void cs4031_device::set_dma_channel(int channel, bool state) +{ + if (!state) + { + m_dma_channel = channel; + if (m_dma_eop) + m_write_tc(channel, 1, 0xff); + } + else + { + if (m_dma_channel == channel) + { + m_dma_channel = -1; + if (m_dma_eop) + m_write_tc(channel, 0, 0xff); + } + } +} + +void cs4031_device::update_dma_clock() +{ + if (m_dma_clock_divider[m_registers[DMA_CLOCK] & 0x0f] != 0) + { + UINT32 dma_clock = clock() / m_dma_clock_divider[m_registers[DMA_CLOCK] & 0x0f]; + + if (!BIT(m_registers[DMA_WAIT_STATE], 0)) + dma_clock /= 2; + + logerror("cs4031_device::update_dma_clock: dma clock is now %u\n", dma_clock); + + m_dma1->set_unscaled_clock(dma_clock); + m_dma2->set_unscaled_clock(dma_clock); + } +} + + +//************************************************************************** +// INTERRUPTS +//************************************************************************** + +/* + Check NMI sources and generate NMI if needed + + Not emulated here: Parity check NMI + */ +void cs4031_device::nmi() +{ + if (m_nmi_mask & BIT(m_portb, 6)) + { + m_write_nmi(1); + m_write_nmi(0); + } +} + +READ8_MEMBER( cs4031_device::intc1_slave_ack_r ) +{ + if (offset == 2) // IRQ 2 + return m_intc2->acknowledge(); + + return 0x00; +} + +WRITE_LINE_MEMBER( cs4031_device::rtc_irq_w ) +{ + m_intc2->ir0_w(state ? 0 : 1); // inverted? +} + +WRITE_LINE_MEMBER( cs4031_device::iochck_w ) +{ + if (LOG_IO) + logerror("cs4031_device::iochck_w: %u\n", state); + + if (BIT(m_portb, 3) == 0) + { + if (m_iochck && state == 0) + { + // set channel check latch + m_portb |= 1 << 6; + nmi(); + } + + m_iochck = state; + } +} + + +//************************************************************************** +// TIMER +//************************************************************************** + +WRITE_LINE_MEMBER( cs4031_device::ctc_out1_w ) +{ + m_refresh_toggle ^= state; + m_portb = (m_portb & 0xef) | (m_refresh_toggle << 4); +} + +WRITE_LINE_MEMBER( cs4031_device::ctc_out2_w ) +{ + m_write_spkr(!(state & BIT(m_portb, 1))); + m_portb = (m_portb & 0xdf) | (state << 5); +} + + +//************************************************************************** +// CHIPSET CONFIGURATION +//************************************************************************** + +WRITE8_MEMBER( cs4031_device::config_address_w ) +{ + m_address = data; + m_address_valid = (m_address < 0x20) ? true : false; +} + +READ8_MEMBER( cs4031_device::config_data_r ) +{ + UINT8 result = 0xff; + + if (m_address_valid) + { + if (LOG_REGISTER) + logerror("cs4031_device: read %s = %02x\n", m_register_names[m_address], m_registers[m_address]); + + result = m_registers[m_address]; + } + + // after a read the selected address needs to be reset + m_address_valid = false; + + return result; +} + +WRITE8_MEMBER( cs4031_device::config_data_w ) +{ + if (m_address_valid) + { + if (LOG_REGISTER) + logerror("cs4031_device: write %s = %02x\n", m_register_names[m_address], data); + + // update register with new data + m_registers[m_address] = data; + + // execute command + switch (m_address) + { + case DMA_WAIT_STATE: + update_dma_clock(); + break; + + case 0x05: break; + case 0x06: break; + case 0x07: break; + case 0x08: break; + case 0x09: break; + + case DMA_CLOCK: + update_dma_clock(); + break; + + case 0x10: break; + case 0x11: break; + case 0x12: break; + case 0x13: break; + case 0x14: break; + case 0x15: break; + case 0x16: break; + case 0x17: break; + case 0x18: break; + + case SHADOW_READ: + update_read_regions(); + break; + + case SHADOW_WRITE: + update_write_regions(); + break; + + case ROMCS: + update_read_regions(); + update_write_regions(); + break; + + case SOFT_RESET_AND_GATEA20: + a20m(); + break; + } + } + + // after a write the selected address needs to be reset + m_address_valid = false; +} + + +//************************************************************************** +// MEMORY MAPPER +//************************************************************************** + +void cs4031_device::update_read_region(int index, const char *region, offs_t start, offs_t end) +{ + if (!BIT(m_registers[SHADOW_READ], index) && BIT(m_registers[ROMCS], index)) + { + if (LOG_MEMORY) + logerror("ROM read from %x to %x\n", start, end); + + m_space->install_read_bank(start, end, region); + machine().root_device().membank(region)->set_base(m_bios + start); + } + else if (!BIT(m_registers[SHADOW_READ], index) && !BIT(m_registers[ROMCS], index)) + { + if (LOG_MEMORY) + logerror("ISA read from %x to %x\n", start, end); + + m_space->install_read_bank(start, end, region); + machine().root_device().membank(region)->set_base(m_isa + start - 0xc0000); + } + else if (BIT(m_registers[SHADOW_READ], index)) + { + if (LOG_MEMORY) + logerror("RAM read from %x to %x\n", start, end); + + m_space->install_read_bank(start, end, region); + machine().root_device().membank(region)->set_base(m_ram + start); + } + else + { + if (LOG_MEMORY) + logerror("NOP read from %x to %x\n", start, end); + + m_space->nop_read(start, end); + } +} + +void cs4031_device::update_write_region(int index, const char *region, offs_t start, offs_t end) +{ + if (!BIT(m_registers[SHADOW_WRITE], index) && BIT(m_registers[ROMCS], index) && BIT(m_registers[ROMCS], 7)) + { + if (LOG_MEMORY) + logerror("ROM write from %x to %x\n", start, end); + + m_space->install_write_bank(start, end, region); + machine().root_device().membank(region)->set_base(m_bios + start); + } + else if (!BIT(m_registers[SHADOW_WRITE], index) && !BIT(m_registers[ROMCS], index)) + { + if (LOG_MEMORY) + logerror("ISA write from %x to %x\n", start, end); + + m_space->install_write_bank(start, end, region); + machine().root_device().membank(region)->set_base(m_isa + start - 0xc0000); + } + else if (BIT(m_registers[SHADOW_WRITE], index)) + { + if (LOG_MEMORY) + logerror("RAM write from %x to %x\n", start, end); + + m_space->install_write_bank(start, end, region); + machine().root_device().membank(region)->set_base(m_ram + start); + } + else + { + if (LOG_MEMORY) + logerror("NOP write from %x to %x\n", start, end); + + m_space->nop_write(start, end); + } +} + +void cs4031_device::update_read_regions() +{ + update_read_region(0, "read_c0000", 0xc0000, 0xc3fff); + update_read_region(1, "read_c4000", 0xc4000, 0xc7fff); + update_read_region(2, "read_c8000", 0xc8000, 0xcbfff); + update_read_region(3, "read_cc000", 0xcc000, 0xcffff); + update_read_region(4, "read_d0000", 0xd0000, 0xdffff); + update_read_region(5, "read_e0000", 0xe0000, 0xeffff); + update_read_region(6, "read_f0000", 0xf0000, 0xfffff); +} + +void cs4031_device::update_write_regions() +{ + update_write_region(0, "write_c0000", 0xc0000, 0xc3fff); + update_write_region(1, "write_c4000", 0xc4000, 0xc7fff); + update_write_region(2, "write_c8000", 0xc8000, 0xcbfff); + update_write_region(3, "write_cc000", 0xcc000, 0xcffff); + update_write_region(4, "write_d0000", 0xd0000, 0xdffff); + update_write_region(5, "write_e0000", 0xe0000, 0xeffff); + update_write_region(6, "write_f0000", 0xf0000, 0xfffff); +} + + +//************************************************************************** +// KEYBOARD / 8042 +//************************************************************************** + +void cs4031_device::a20m() +{ + // external signal is ignored when emulation is on + if (BIT(m_registers[SOFT_RESET_AND_GATEA20], 5)) + m_write_a20m(m_fast_gatea20 | m_emu_gatea20); + else + m_write_a20m(m_fast_gatea20 | m_ext_gatea20); +} + +void cs4031_device::emulated_kbreset(int state) +{ + if (BIT(m_registers[SOFT_RESET_AND_GATEA20], 4)) + { + // kbreset (input) is active low + // cpureset (output) is active high + m_write_cpureset(!state); + } +} + +void cs4031_device::emulated_gatea20(int state) +{ + if (BIT(m_registers[SOFT_RESET_AND_GATEA20], 5)) + { + m_emu_gatea20 = state; + a20m(); + } +} + +void cs4031_device::fast_gatea20(int state) +{ + m_fast_gatea20 = state; + a20m(); +} + +void cs4031_device::keyboard_gatea20(int state) +{ + m_ext_gatea20 = state; + a20m(); +} + +READ8_MEMBER( cs4031_device::keyb_status_r ) +{ + if (LOG_KEYBOARD) + logerror("cs4031_device::keyb_status_r\n"); + + return m_keybc->status_r(space, 0); +} + +WRITE8_MEMBER( cs4031_device::keyb_command_blocked_w ) +{ + // command is optionally blocked + if (!BIT(m_registers[SOFT_RESET_AND_GATEA20], 7)) + m_keybc->command_w(space, 0, data); +} + +WRITE8_MEMBER( cs4031_device::keyb_command_w ) +{ + if (LOG_KEYBOARD) + logerror("cs4031_device::keyb_command_w: %02x\n", data); + + m_keybc_d1_written = false; + + switch (data) + { + // self-test + case 0xaa: + emulated_kbreset(1); + emulated_gatea20(1); + + // self-test is never blocked + m_keybc->command_w(space, 0, data); + break; + + case 0xd1: + m_keybc_d1_written = true; + keyb_command_blocked_w(space, 0, data); + break; + + case 0xf0: + case 0xf1: + case 0xf2: + case 0xf4: + case 0xf5: + case 0xf6: + case 0xf8: + case 0xf9: + case 0xfa: + case 0xfc: + case 0xfd: + case 0xfe: + // toggle keyboard reset? + if (!BIT(data, 0)) + { + emulated_kbreset(0); + emulated_kbreset(1); + } + + // toggle gatea20? + if (!BIT(data, 1)) + { + emulated_gatea20(0); + emulated_gatea20(1); + } + + keyb_command_blocked_w(space, 0, data); + + break; + + case 0xff: + // last data write was blocked? + if (m_keybc_data_blocked) + { + m_keybc_data_blocked = false; + keyb_command_blocked_w(space, 0, data); + } + else + m_keybc->command_w(space, 0, data); + + break; + + // everything else goes directly to the keyboard controller + default: + m_keybc->command_w(space, 0, data); + break; + } +} + +READ8_MEMBER( cs4031_device::keyb_data_r ) +{ + if (LOG_KEYBOARD) + logerror("cs4031_device::keyb_data_r\n"); + + return m_keybc->data_r(space, 0); +} + +WRITE8_MEMBER( cs4031_device::keyb_data_w ) +{ + if (LOG_KEYBOARD) + logerror("cs4031_device::keyb_data_w: %02x\n", data); + + // data is blocked only for d1 command + if (BIT(m_registers[SOFT_RESET_AND_GATEA20], 7) && m_keybc_d1_written) + { + m_keybc_data_blocked = true; + emulated_kbreset(BIT(data, 0)); + emulated_gatea20(BIT(data, 1)); + } + else + { + m_keybc_data_blocked = false; + m_keybc->data_w(space, 0, data); + } +} + +WRITE_LINE_MEMBER( cs4031_device::gatea20_w ) +{ + if (LOG_KEYBOARD) + logerror("cs4031_device::gatea20_w: %u\n", state); + + keyboard_gatea20(state); +} + +WRITE_LINE_MEMBER( cs4031_device::kbrst_w ) +{ + if (LOG_KEYBOARD) + logerror("cs4031_device::kbrst_w: %u\n", state); + + // convert to active low signal (gets inverted in at_keybc.c) + state = (state == ASSERT_LINE ? 0 : 1); + + // external kbreset is ignored when emulation enabled + if (!BIT(m_registers[SOFT_RESET_AND_GATEA20], 4)) + { + // detect transition + if (m_kbrst == 1 && state == 0) + { + m_write_cpureset(1); + m_write_cpureset(0); + } + } + + m_kbrst = state; +} + +/* + Fast CPU reset and Gate A20 + + 0 - Fast CPU reset + 1 - Fast Gate A20 + + */ +WRITE8_MEMBER( cs4031_device::sysctrl_w ) +{ + if (LOG_IO) + logerror("cs4031_device::sysctrl_w: %u\n", data); + + fast_gatea20(BIT(data, 1)); + + if (m_cpureset == 0 && BIT(data, 0)) + { + // pulse reset line + m_write_cpureset(1); + m_write_cpureset(0); + } + + m_cpureset = BIT(data, 0); +} + +READ8_MEMBER( cs4031_device::sysctrl_r ) +{ + UINT8 result = 0; // reserved bits read as 0? + + result |= m_cpureset << 0; + result |= m_fast_gatea20 << 1; + + if (LOG_IO) + logerror("cs4031_device::sysctrl_r: %u\n", result); + + return result; +} + + +//************************************************************************** +// MISCELLANEOUS +//************************************************************************** + +/* + "Port B" - AT-compatible port with miscellaneous information + + 0 - Timer 2 gate (rw) + 1 - Speaker data (rw) + 2 - Enable parity check (rw) [not emulated] + 3 - Enable IOCHECK (rw) + 4 - Refresh detect (r) + 5 - Timer 2 output (r) + 6 - Channel check latch (r) + 7 - Parity check latch (r) [not emulated] +*/ + +READ8_MEMBER( cs4031_device::portb_r ) +{ + if (0) + logerror("cs4031_device::portb_r: %02x\n", m_portb); + + return m_portb; +} + +WRITE8_MEMBER( cs4031_device::portb_w ) +{ + if (0) + logerror("cs4031_device::portb_w: %02x\n", data); + + m_portb = (m_portb & 0xf0) | (data & 0x0f); + + // bit 5 forced to 1 if timer disabled + if (!BIT(m_portb, 0)) + m_portb |= 1 << 5; + + m_ctc->write_gate2(BIT(m_portb, 0)); + + m_write_spkr(!BIT(m_portb, 1)); + + // clear channel check latch? + if (BIT(m_portb, 3)) + m_portb &= 0xbf; +} + +/* + NMI mask and RTC address + + 7 - NMI mask + 6:0 - RTC address + */ +WRITE8_MEMBER( cs4031_device::rtc_w ) +{ + if (0) + logerror("cs4031_device::rtc_w: %02x\n", data); + + if (offset == 0) + { + m_nmi_mask = !BIT(data, 7); + data &= 0x7f; + } + + m_rtc->write(space, offset, data); +} |