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/idectrl.cpp | |
| parent | a57b46ae933badd7441ce1644711dbb851e2b504 (diff) | |
Rename *.c -> *.cpp in our source (nw)
Diffstat (limited to 'src/devices/machine/idectrl.cpp')
| -rw-r--r-- | src/devices/machine/idectrl.cpp | 393 |
1 files changed, 393 insertions, 0 deletions
diff --git a/src/devices/machine/idectrl.cpp b/src/devices/machine/idectrl.cpp new file mode 100644 index 00000000000..bebfcc09d0d --- /dev/null +++ b/src/devices/machine/idectrl.cpp @@ -0,0 +1,393 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + + idectrl.c + + Generic (PC-style) IDE controller implementation. + +***************************************************************************/ + +#include "idectrl.h" + + +/*************************************************************************** + DEBUGGING +***************************************************************************/ + +#define VERBOSE 0 + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +const device_type IDE_CONTROLLER = &device_creator<ide_controller_device>; + +ide_controller_device::ide_controller_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + ata_interface_device(mconfig, IDE_CONTROLLER, "IDE Controller", tag, owner, clock, "ide_controller", __FILE__) +{ +} + +ide_controller_device::ide_controller_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + ata_interface_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +READ16_MEMBER( ide_controller_device::read_cs0 ) +{ + if (mem_mask == 0xffff && offset == 1 ){ offset = 0; popmessage( "requires ide_controller_32_device" ); } + if (mem_mask == 0xff00) + { + return ata_interface_device::read_cs0(space, (offset * 2) + 1, 0xff) << 8; + } + else + { + return ata_interface_device::read_cs0(space, offset * 2, mem_mask); + } +} + +READ16_MEMBER( ide_controller_device::read_cs1 ) +{ + if (mem_mask == 0xff00) + { + return ata_interface_device::read_cs1(space, (offset * 2) + 1, 0xff) << 8; + } + else + { + return ata_interface_device::read_cs1(space, offset * 2, mem_mask); + } +} + +WRITE16_MEMBER( ide_controller_device::write_cs0 ) +{ + if (mem_mask == 0xffff && offset == 1 ){ offset = 0; popmessage( "requires ide_controller_32_device" ); } + if (mem_mask == 0xff00) + { + return ata_interface_device::write_cs0(space, (offset * 2) + 1, data >> 8, 0xff); + } + else + { + return ata_interface_device::write_cs0(space, offset * 2, data, mem_mask); + } +} + +WRITE16_MEMBER( ide_controller_device::write_cs1 ) +{ + if (mem_mask == 0xff00) + { + return ata_interface_device::write_cs1(space, (offset * 2) + 1, data >> 8, 0xff); + } + else + { + return ata_interface_device::write_cs1(space, offset * 2, data, mem_mask); + } +} + + +const device_type IDE_CONTROLLER_32 = &device_creator<ide_controller_32_device>; + +ide_controller_32_device::ide_controller_32_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + ide_controller_device(mconfig, IDE_CONTROLLER, "IDE Controller (32 bit)", tag, owner, clock, "ide_controller32", __FILE__) +{ +} + +ide_controller_32_device::ide_controller_32_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + ide_controller_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +READ32_MEMBER(ide_controller_32_device::read_cs0) +{ + UINT32 data = 0; + + if (ACCESSING_BITS_0_15) + { + data = ide_controller_device::read_cs0(space, (offset * 2), mem_mask); + + if (offset == 0 && ACCESSING_BITS_16_31) + data |= ide_controller_device::read_cs0(space, (offset * 2), mem_mask >> 16) << 16; + } + else if (ACCESSING_BITS_16_31) + { + data = ide_controller_device::read_cs0(space, (offset * 2) + 1, mem_mask >> 16) << 16; + } + + return data; +} + +READ32_MEMBER(ide_controller_32_device::read_cs1) +{ + UINT32 data = 0; + + if (ACCESSING_BITS_0_15) + { + data = ide_controller_device::read_cs1(space, (offset * 2), mem_mask); + } + else if (ACCESSING_BITS_16_23) + { + data = ide_controller_device::read_cs1(space, (offset * 2) + 1, mem_mask >> 16) << 16; + } + + return data; +} + +WRITE32_MEMBER(ide_controller_32_device::write_cs0) +{ + if (ACCESSING_BITS_0_15) + { + ide_controller_device::write_cs0(space, (offset * 2), data, mem_mask); + + if (offset == 0 && ACCESSING_BITS_16_31) + ata_interface_device::write_cs0(space, (offset * 2), data >> 16, mem_mask >> 16); + } + else if (ACCESSING_BITS_16_31) + { + ide_controller_device::write_cs0(space, (offset * 2) + 1, data >> 16, mem_mask >> 16); + } +} + +WRITE32_MEMBER(ide_controller_32_device::write_cs1) +{ + if (ACCESSING_BITS_0_15) + { + ide_controller_device::write_cs1(space, (offset * 2), data, mem_mask); + } + else if (ACCESSING_BITS_16_31) + { + ide_controller_device::write_cs1(space, (offset * 2) + 1, data >> 16, mem_mask >> 16); + } +} + + +#define IDE_BUSMASTER_STATUS_ACTIVE 0x01 +#define IDE_BUSMASTER_STATUS_ERROR 0x02 +#define IDE_BUSMASTER_STATUS_IRQ 0x04 + +const device_type BUS_MASTER_IDE_CONTROLLER = &device_creator<bus_master_ide_controller_device>; + +bus_master_ide_controller_device::bus_master_ide_controller_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + ide_controller_32_device(mconfig, BUS_MASTER_IDE_CONTROLLER, "Bus Master IDE Controller", tag, owner, clock, "bus_master_ide_controller", __FILE__), + m_dma_address(0), + m_dma_bytes_left(0), + m_dma_descriptor(0), + m_dma_last_buffer(0), + m_bus_master_command(0), + m_bus_master_status(0), + m_bus_master_descriptor(0), + m_irq(0), + m_dmarq(0) +{ +} + +void bus_master_ide_controller_device::device_start() +{ + ide_controller_32_device::device_start(); + + /* find the bus master space */ + if (m_bmcpu != NULL) + { + device_t *bmtarget = machine().device(m_bmcpu); + if (bmtarget == NULL) + throw emu_fatalerror("IDE controller '%s' bus master target '%s' doesn't exist!", tag(), m_bmcpu); + device_memory_interface *memory; + if (!bmtarget->interface(memory)) + throw emu_fatalerror("IDE controller '%s' bus master target '%s' has no memory!", tag(), m_bmcpu); + m_dma_space = &memory->space(m_bmspace); + m_dma_address_xor = (m_dma_space->endianness() == ENDIANNESS_LITTLE) ? 0 : 3; + } + + save_item(NAME(m_dma_address)); + save_item(NAME(m_dma_bytes_left)); + save_item(NAME(m_dma_descriptor)); + save_item(NAME(m_dma_last_buffer)); + save_item(NAME(m_bus_master_command)); + save_item(NAME(m_bus_master_status)); + save_item(NAME(m_bus_master_descriptor)); +} + +void bus_master_ide_controller_device::set_irq(int state) +{ + ata_interface_device::set_irq(state); + + if (m_irq != state) + { + m_irq = state; + + if( m_irq ) + m_bus_master_status |= IDE_BUSMASTER_STATUS_IRQ; + } +} + +void bus_master_ide_controller_device::set_dmarq(int state) +{ + ata_interface_device::set_dmarq(state); + + if (m_dmarq != state) + { + m_dmarq = state; + + execute_dma(); + } +} + +/************************************* + * + * Bus master read + * + *************************************/ + +READ32_MEMBER( bus_master_ide_controller_device::bmdma_r ) +{ + LOG(("%s:ide_bus_master32_r(%d, %08x)\n", machine().describe_context(), offset, mem_mask)); + + switch( offset ) + { + case 0: + /* command register/status register */ + return m_bus_master_command | (m_bus_master_status << 16); + + case 1: + /* descriptor table register */ + return m_bus_master_descriptor; + } + + return 0xffffffff; +} + + + +/************************************* + * + * Bus master write + * + *************************************/ + +WRITE32_MEMBER( bus_master_ide_controller_device::bmdma_w ) +{ + LOG(("%s:ide_bus_master32_w(%d, %08x, %08X)\n", machine().describe_context(), offset, mem_mask, data)); + + switch( offset ) + { + case 0: + if( ACCESSING_BITS_0_7 ) + { + /* Bus Master IDE Command register */ + UINT8 old = m_bus_master_command; + UINT8 val = data & 0xff; + + /* save the "Read or Write Control" bit 3 and the "Start/Stop Bus Master" bit 0 */ + m_bus_master_command = (old & 0xf6) | (val & 0x09); + + if ((old ^ m_bus_master_command) & 1) + { + if (m_bus_master_command & 1) + { + /* handle starting a transfer */ + m_bus_master_status |= IDE_BUSMASTER_STATUS_ACTIVE; + + /* reset all the DMA data */ + m_dma_bytes_left = 0; + m_dma_descriptor = m_bus_master_descriptor; + + /* if we're going live, start the pending read/write */ + execute_dma(); + } + else if (m_bus_master_status & IDE_BUSMASTER_STATUS_ACTIVE) + { + m_bus_master_status &= ~IDE_BUSMASTER_STATUS_ACTIVE; + + LOG(("DMA Aborted!\n")); + } + } + } + + if( ACCESSING_BITS_16_23 ) + { + /* Bus Master IDE Status register */ + UINT8 old = m_bus_master_status; + UINT8 val = data >> 16; + + /* save the DMA capable bits */ + m_bus_master_status = (old & 0x9f) | (val & 0x60); + + /* clear interrupt and error bits */ + if (val & IDE_BUSMASTER_STATUS_IRQ) + m_bus_master_status &= ~IDE_BUSMASTER_STATUS_IRQ; + if (val & IDE_BUSMASTER_STATUS_ERROR) + m_bus_master_status &= ~IDE_BUSMASTER_STATUS_ERROR; + } + break; + + case 1: + /* descriptor table register */ + m_bus_master_descriptor = data & 0xfffffffc; + break; + } +} + +void bus_master_ide_controller_device::execute_dma() +{ + write_dmack(ASSERT_LINE); + + while (m_dmarq && (m_bus_master_status & IDE_BUSMASTER_STATUS_ACTIVE)) + { + /* if we're out of space, grab the next Physical Region Descriptor */ + if (m_dma_bytes_left == 0) + { + /* fetch the address */ + m_dma_address = m_dma_space->read_byte(m_dma_descriptor++ ^ m_dma_address_xor); + m_dma_address |= m_dma_space->read_byte(m_dma_descriptor++ ^ m_dma_address_xor) << 8; + m_dma_address |= m_dma_space->read_byte(m_dma_descriptor++ ^ m_dma_address_xor) << 16; + m_dma_address |= m_dma_space->read_byte(m_dma_descriptor++ ^ m_dma_address_xor) << 24; + m_dma_address &= 0xfffffffe; + + /* fetch the length */ + m_dma_bytes_left = m_dma_space->read_byte(m_dma_descriptor++ ^ m_dma_address_xor); + m_dma_bytes_left |= m_dma_space->read_byte(m_dma_descriptor++ ^ m_dma_address_xor) << 8; + m_dma_bytes_left |= m_dma_space->read_byte(m_dma_descriptor++ ^ m_dma_address_xor) << 16; + m_dma_bytes_left |= m_dma_space->read_byte(m_dma_descriptor++ ^ m_dma_address_xor) << 24; + m_dma_last_buffer = (m_dma_bytes_left >> 31) & 1; + m_dma_bytes_left &= 0xfffe; + if (m_dma_bytes_left == 0) + m_dma_bytes_left = 0x10000; + +// LOG(("New DMA descriptor: address = %08X bytes = %04X last = %d\n", m_dma_address, m_dma_bytes_left, m_dma_last_buffer)); + } + + if (m_bus_master_command & 8) + { + // read from ata bus + UINT16 data = read_dma(); + + // write to memory + m_dma_space->write_byte(m_dma_address++, data & 0xff); + m_dma_space->write_byte(m_dma_address++, data >> 8); + } + else + { + // read from memory; + UINT16 data = m_dma_space->read_byte(m_dma_address++); + data |= m_dma_space->read_byte(m_dma_address++) << 8; + + // write to ata bus + write_dma(data); + } + + m_dma_bytes_left -= 2; + + if (m_dma_bytes_left == 0 && m_dma_last_buffer) + { + m_bus_master_status &= ~IDE_BUSMASTER_STATUS_ACTIVE; + + if (m_dmarq) + { + LOG(("DMA Out of buffer space!\n")); + } + } + } + + write_dmack(CLEAR_LINE); +} |
