diff options
author | smf- <smf-@users.noreply.github.com> | 2013-06-10 08:42:39 +0000 |
---|---|---|
committer | smf- <smf-@users.noreply.github.com> | 2013-06-10 08:42:39 +0000 |
commit | 407e3b88829eedb3f85b07622d459048e091b05a (patch) | |
tree | 374a8cce7832f1b84e735e7f74c01a37d5efca85 | |
parent | c4deaaf91a66360659b37d35df59217b17269cb2 (diff) |
Decoupled the IDE bus master emulation from the hard drive emulation [smf]
-rw-r--r-- | src/emu/machine/idectrl.c | 682 | ||||
-rw-r--r-- | src/emu/machine/idectrl.h | 44 |
2 files changed, 343 insertions, 383 deletions
diff --git a/src/emu/machine/idectrl.c b/src/emu/machine/idectrl.c index f38787d5fa9..c2cfe391879 100644 --- a/src/emu/machine/idectrl.c +++ b/src/emu/machine/idectrl.c @@ -90,29 +90,21 @@ #define IDE_ERROR_BAD_LOCATION 0x10 #define IDE_ERROR_BAD_SECTOR 0x80 -#define IDE_BUSMASTER_STATUS_ACTIVE 0x01 -#define IDE_BUSMASTER_STATUS_ERROR 0x02 -#define IDE_BUSMASTER_STATUS_IRQ 0x04 - -void ide_controller_device::signal_interrupt() +void ide_controller_device::set_irq(int state) { - LOG(("IDE interrupt assert\n")); - + if (state == ASSERT_LINE) + LOG(("IDE interrupt assert\n")); + else + LOG(("IDE interrupt clear\n")); + /* signal an interrupt */ - m_irq_handler(ASSERT_LINE); - interrupt_pending = 1; - bus_master_status |= IDE_BUSMASTER_STATUS_IRQ; + m_irq_handler(state); + interrupt_pending = state; } - -void ide_controller_device::clear_interrupt() +void ide_controller_device::set_dmarq(int state) { - LOG(("IDE interrupt clear\n")); - - /* clear an interrupt */ - m_irq_handler(CLEAR_LINE); - interrupt_pending = 0; } @@ -125,7 +117,7 @@ static TIMER_CALLBACK( delayed_interrupt ) { ide_controller_device *ide = (ide_controller_device *)ptr; ide->status &= ~IDE_STATUS_BUSY; - ide->signal_interrupt(); + ide->set_irq(ASSERT_LINE); } @@ -134,7 +126,7 @@ static TIMER_CALLBACK( delayed_interrupt_buffer_ready ) ide_controller_device *ide = (ide_controller_device *)ptr; ide->status &= ~IDE_STATUS_BUSY; ide->status |= IDE_STATUS_BUFFER_READY; - ide->signal_interrupt(); + ide->set_irq(ASSERT_LINE); } @@ -265,7 +257,7 @@ void ide_controller_device::security_error() * *************************************/ -void ide_controller_device::continue_read() +void ide_controller_device::read_buffer_empty() { /* reset the totals */ buffer_offset = 0; @@ -273,14 +265,14 @@ void ide_controller_device::continue_read() /* clear the buffer ready and busy flag */ status &= ~IDE_STATUS_BUFFER_READY; status &= ~IDE_STATUS_BUSY; + error = IDE_ERROR_DEFAULT; + set_dmarq(0); if (master_password_enable || user_password_enable) { security_error(); sector_count = 0; - bus_master_status &= ~IDE_BUSMASTER_STATUS_ACTIVE; - dma_active = 0; return; } @@ -290,63 +282,6 @@ void ide_controller_device::continue_read() sector_count--; if (sector_count > 0) read_next_sector(); - else - { - bus_master_status &= ~IDE_BUSMASTER_STATUS_ACTIVE; - dma_active = 0; - } -} - - -void ide_controller_device::write_buffer_to_dma() -{ - int bytesleft = IDE_DISK_SECTOR_SIZE; - UINT16 data = 0; - -// LOG(("Writing sector to %08X\n", dma_address)); - - /* loop until we've consumed all bytes */ - while (bytesleft--) - { - data >>= 8; - - if (bytesleft & 1) - data = read_dma(); - - /* if we're out of space, grab the next descriptor */ - if (dma_bytes_left == 0) - { - /* if we're out of buffer space, that's bad */ - if (dma_last_buffer) - { - LOG(("DMA Out of buffer space!\n")); - return; - } - - /* fetch the address */ - dma_address = dma_space->read_byte(dma_descriptor++ ^ dma_address_xor); - dma_address |= dma_space->read_byte(dma_descriptor++ ^ dma_address_xor) << 8; - dma_address |= dma_space->read_byte(dma_descriptor++ ^ dma_address_xor) << 16; - dma_address |= dma_space->read_byte(dma_descriptor++ ^ dma_address_xor) << 24; - dma_address &= 0xfffffffe; - - /* fetch the length */ - dma_bytes_left = dma_space->read_byte(dma_descriptor++ ^ dma_address_xor); - dma_bytes_left |= dma_space->read_byte(dma_descriptor++ ^ dma_address_xor) << 8; - dma_bytes_left |= dma_space->read_byte(dma_descriptor++ ^ dma_address_xor) << 16; - dma_bytes_left |= dma_space->read_byte(dma_descriptor++ ^ dma_address_xor) << 24; - dma_last_buffer = (dma_bytes_left >> 31) & 1; - dma_bytes_left &= 0xfffe; - if (dma_bytes_left == 0) - dma_bytes_left = 0x10000; - -// LOG(("New DMA descriptor: address = %08X bytes = %04X last = %d\n", dma_address, dma_bytes_left, dma_last_buffer)); - } - - /* write the next byte */ - dma_space->write_byte(dma_address++, data & 0xff); - dma_bytes_left--; - } } @@ -390,16 +325,16 @@ void ide_controller_device::read_sector_done() if (sectors_until_int == 0 || sector_count == 1) { sectors_until_int = ((command == IDE_COMMAND_READ_MULTIPLE_BLOCK) ? block_count : 1); - signal_interrupt(); + set_irq(ASSERT_LINE); } /* handle DMA */ if (dma_active) - write_buffer_to_dma(); + set_dmarq(1); /* if we're just verifying we can read the next sector */ if (verify_only) - continue_read(); + read_buffer_empty(); } /* if we got an error, we need to report it */ @@ -408,11 +343,9 @@ void ide_controller_device::read_sector_done() /* set the error flag and the error */ status |= IDE_STATUS_ERROR; error = IDE_ERROR_BAD_SECTOR; - bus_master_status |= IDE_BUSMASTER_STATUS_ERROR; - bus_master_status &= ~IDE_BUSMASTER_STATUS_ACTIVE; /* signal an interrupt */ - signal_interrupt(); + set_irq(ASSERT_LINE); } } @@ -509,54 +442,69 @@ void ide_controller_device::continue_write() } -void ide_controller_device::read_buffer_from_dma() +void ide_controller_device::write_buffer_full() { - int bytesleft = IDE_DISK_SECTOR_SIZE; - UINT16 data = 0; - -// LOG(("Reading sector from %08X\n", dma_address)); + ide_device_interface *dev = slot[cur_drive]->dev(); - /* loop until we've consumed all bytes */ - while (bytesleft--) + set_dmarq(0); + if (command == IDE_COMMAND_SECURITY_UNLOCK) { - /* if we're out of space, grab the next descriptor */ - if (dma_bytes_left == 0) + if (user_password_enable && memcmp(buffer, user_password, 2 + 32) == 0) { - /* if we're out of buffer space, that's bad */ - if (dma_last_buffer) - { - LOG(("DMA Out of buffer space!\n")); - return; - } - - /* fetch the address */ - dma_address = dma_space->read_byte(dma_descriptor++ ^ dma_address_xor); - dma_address |= dma_space->read_byte(dma_descriptor++ ^ dma_address_xor) << 8; - dma_address |= dma_space->read_byte(dma_descriptor++ ^ dma_address_xor) << 16; - dma_address |= dma_space->read_byte(dma_descriptor++ ^ dma_address_xor) << 24; - dma_address &= 0xfffffffe; + LOGPRINT(("IDE Unlocked user password\n")); + user_password_enable = 0; + } + if (master_password_enable && memcmp(buffer, master_password, 2 + 32) == 0) + { + LOGPRINT(("IDE Unlocked master password\n")); + master_password_enable = 0; + } + if (PRINTF_IDE_PASSWORD) + { + int i; - /* fetch the length */ - dma_bytes_left = dma_space->read_byte(dma_descriptor++ ^ dma_address_xor); - dma_bytes_left |= dma_space->read_byte(dma_descriptor++ ^ dma_address_xor) << 8; - dma_bytes_left |= dma_space->read_byte(dma_descriptor++ ^ dma_address_xor) << 16; - dma_bytes_left |= dma_space->read_byte(dma_descriptor++ ^ dma_address_xor) << 24; - dma_last_buffer = (dma_bytes_left >> 31) & 1; - dma_bytes_left &= 0xfffe; - if (dma_bytes_left == 0) - dma_bytes_left = 0x10000; + for (i = 0; i < 34; i += 2) + { + if (i % 8 == 2) + mame_printf_debug("\n"); -// LOG(("New DMA descriptor: address = %08X bytes = %04X last = %d\n", dma_address, dma_bytes_left, dma_last_buffer)); + mame_printf_debug("0x%02x, 0x%02x, ", buffer[i], buffer[i + 1]); + //mame_printf_debug("0x%02x%02x, ", buffer[i], buffer[i + 1]); + } + mame_printf_debug("\n"); } - /* read the next byte */ - data |= dma_space->read_byte(dma_address++) << 8; - dma_bytes_left --; + /* clear the busy and error flags */ + status &= ~IDE_STATUS_ERROR; + status &= ~IDE_STATUS_BUSY; + status &= ~IDE_STATUS_BUFFER_READY; - if((bytesleft & 1) == 0) - write_dma(data); + if (master_password_enable || user_password_enable) + security_error(); + else + status |= IDE_STATUS_DRIVE_READY; + } + else if (command == IDE_COMMAND_TAITO_GNET_UNLOCK_2) + { + UINT8 key[5] = { 0 }; + int i, bad = 0; + dev->read_key(key); + + for (i=0; !bad && i<512; i++) + bad = ((i < 2 || i >= 7) && buffer[i]) || ((i >= 2 && i < 7) && buffer[i] != key[i-2]); - data >>= 8; + status &= ~IDE_STATUS_BUSY; + status &= ~IDE_STATUS_BUFFER_READY; + if (bad) + status |= IDE_STATUS_ERROR; + else { + status &= ~IDE_STATUS_ERROR; + gnetreadlock= 0; + } + } + else + { + continue_write(); } } @@ -592,7 +540,7 @@ void ide_controller_device::write_sector_done() if (--sectors_until_int == 0 || sector_count == 1) { sectors_until_int = ((command == IDE_COMMAND_WRITE_MULTIPLE_BLOCK) ? block_count : 1); - signal_interrupt(); + set_irq(ASSERT_LINE); } /* signal an interrupt if there's more data needed */ @@ -604,10 +552,8 @@ void ide_controller_device::write_sector_done() /* keep going for DMA */ if (dma_active && sector_count != 0) { - read_buffer_from_dma(); + set_dmarq(1); } - else - dma_active = 0; } /* if we got an error, we need to report it */ @@ -616,11 +562,9 @@ void ide_controller_device::write_sector_done() /* set the error flag and the error */ status |= IDE_STATUS_ERROR; error = IDE_ERROR_BAD_SECTOR; - bus_master_status |= IDE_BUSMASTER_STATUS_ERROR; - bus_master_status &= ~IDE_BUSMASTER_STATUS_ACTIVE; /* signal an interrupt */ - signal_interrupt(); + set_irq(ASSERT_LINE); } } @@ -644,8 +588,9 @@ void ide_controller_device::handle_command(UINT8 _command) UINT8 key[5]; ide_device_interface *dev = slot[cur_drive]->dev(); - /* implicitly clear interrupts here */ - clear_interrupt(); + /* implicitly clear interrupts & dmarq here */ + set_irq(CLEAR_LINE); + set_dmarq(0); command = _command; switch (command) { @@ -704,8 +649,7 @@ void ide_controller_device::handle_command(UINT8 _command) verify_only = 0; /* start the read going */ - if (bus_master_command & 1) - read_first_sector(); + read_first_sector(); break; case IDE_COMMAND_WRITE_MULTIPLE: @@ -745,10 +689,7 @@ void ide_controller_device::handle_command(UINT8 _command) dma_active = 1; /* start the read going */ - if (bus_master_command & 1) - { - read_buffer_from_dma(); - } + set_dmarq(1); break; case IDE_COMMAND_SECURITY_UNLOCK: @@ -761,7 +702,7 @@ void ide_controller_device::handle_command(UINT8 _command) /* mark the buffer ready */ status |= IDE_STATUS_BUFFER_READY; - signal_interrupt(); + set_irq(ASSERT_LINE); break; case IDE_COMMAND_GET_INFO: @@ -811,7 +752,7 @@ void ide_controller_device::handle_command(UINT8 _command) /* for timeout disabled value is 0 */ sector_count = 0; /* signal an interrupt */ - signal_interrupt(); + set_irq(ASSERT_LINE); break; case IDE_COMMAND_SET_CONFIG: @@ -829,7 +770,7 @@ void ide_controller_device::handle_command(UINT8 _command) LOGPRINT(("IDE unknown command (F9)\n")); /* signal an interrupt */ - signal_interrupt(); + set_irq(ASSERT_LINE); break; case IDE_COMMAND_SET_FEATURES: @@ -847,7 +788,7 @@ void ide_controller_device::handle_command(UINT8 _command) status |= IDE_STATUS_DRIVE_READY; /* signal an interrupt */ - signal_interrupt(); + set_irq(ASSERT_LINE); break; case IDE_COMMAND_TAITO_GNET_UNLOCK_1: @@ -856,7 +797,7 @@ void ide_controller_device::handle_command(UINT8 _command) sector_count = 1; status |= IDE_STATUS_DRIVE_READY; status &= ~IDE_STATUS_ERROR; - signal_interrupt(); + set_irq(ASSERT_LINE); break; case IDE_COMMAND_TAITO_GNET_UNLOCK_2: @@ -869,7 +810,7 @@ void ide_controller_device::handle_command(UINT8 _command) /* mark the buffer ready */ status |= IDE_STATUS_BUFFER_READY; - signal_interrupt(); + set_irq(ASSERT_LINE); break; case IDE_COMMAND_TAITO_GNET_UNLOCK_3: @@ -885,7 +826,7 @@ void ide_controller_device::handle_command(UINT8 _command) /* update flags */ status |= IDE_STATUS_DRIVE_READY; status &= ~IDE_STATUS_ERROR; - signal_interrupt(); + set_irq(ASSERT_LINE); break; case IDE_COMMAND_SEEK: @@ -900,7 +841,7 @@ void ide_controller_device::handle_command(UINT8 _command) /* for timeout disabled value is 0 */ sector_count = 0; /* signal an interrupt */ - signal_interrupt(); + set_irq(ASSERT_LINE); break; @@ -908,7 +849,7 @@ void ide_controller_device::handle_command(UINT8 _command) LOGPRINT(("IDE unknown command (%02X)\n", command)); status |= IDE_STATUS_ERROR; error = IDE_ERROR_UNKNOWN_COMMAND; - signal_interrupt(); + set_irq(ASSERT_LINE); //debugger_break(device->machine()); break; } @@ -1066,8 +1007,8 @@ READ16_MEMBER( ide_controller_device::read_cs0 ) result |= IDE_STATUS_HIT_INDEX; last_status_timer->adjust(attotime::never); } - if (interrupt_pending) - clear_interrupt(); + if (interrupt_pending == ASSERT_LINE) + set_irq(CLEAR_LINE); break; /* log anything else */ @@ -1083,75 +1024,6 @@ READ16_MEMBER( ide_controller_device::read_cs0 ) } -void ide_controller_device::write_buffer_full() -{ - ide_device_interface *dev = slot[cur_drive]->dev(); - - if (command == IDE_COMMAND_SECURITY_UNLOCK) - { - if (user_password_enable && memcmp(buffer, user_password, 2 + 32) == 0) - { - LOGPRINT(("IDE Unlocked user password\n")); - user_password_enable = 0; - } - if (master_password_enable && memcmp(buffer, master_password, 2 + 32) == 0) - { - LOGPRINT(("IDE Unlocked master password\n")); - master_password_enable = 0; - } - if (PRINTF_IDE_PASSWORD) - { - int i; - - for (i = 0; i < 34; i += 2) - { - if (i % 8 == 2) - mame_printf_debug("\n"); - - mame_printf_debug("0x%02x, 0x%02x, ", buffer[i], buffer[i + 1]); - //mame_printf_debug("0x%02x%02x, ", buffer[i], buffer[i + 1]); - } - mame_printf_debug("\n"); - } - - /* clear the busy and error flags */ - status &= ~IDE_STATUS_ERROR; - status &= ~IDE_STATUS_BUSY; - status &= ~IDE_STATUS_BUFFER_READY; - - if (master_password_enable || user_password_enable) - security_error(); - else - status |= IDE_STATUS_DRIVE_READY; - } - else if (command == IDE_COMMAND_TAITO_GNET_UNLOCK_2) - { - UINT8 key[5] = { 0 }; - int i, bad = 0; - dev->read_key(key); - - for (i=0; !bad && i<512; i++) - bad = ((i < 2 || i >= 7) && buffer[i]) || ((i >= 2 && i < 7) && buffer[i] != key[i-2]); - - status &= ~IDE_STATUS_BUSY; - status &= ~IDE_STATUS_BUFFER_READY; - if (bad) - status |= IDE_STATUS_ERROR; - else { - status &= ~IDE_STATUS_ERROR; - gnetreadlock= 0; - } - } - else - continue_write(); -} - -void ide_controller_device::read_buffer_empty() -{ - continue_read(); - error = IDE_ERROR_DEFAULT; -} - READ16_MEMBER( ide_controller_device::read_cs1_pc ) { if (mem_mask == 0xff00) @@ -1389,101 +1261,6 @@ WRITE16_MEMBER( ide_controller_device::write_cs1 ) } -/************************************* - * - * Bus master read - * - *************************************/ - -READ32_MEMBER( bus_master_ide_controller_device::ide_bus_master32_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 bus_master_command | (bus_master_status << 16); - - case 1: - /* descriptor table register */ - return bus_master_descriptor; - } - - return 0xffffffff; -} - - - -/************************************* - * - * Bus master write - * - *************************************/ - -WRITE32_MEMBER( bus_master_ide_controller_device::ide_bus_master32_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 ) - { - /* command register */ - UINT8 old = bus_master_command; - UINT8 val = data & 0xff; - - /* save the read/write bit and the start/stop bit */ - bus_master_command = (old & 0xf6) | (val & 0x09); - bus_master_status = (bus_master_status & ~IDE_BUSMASTER_STATUS_ACTIVE) | (val & 0x01); - - /* handle starting a transfer */ - if (!(old & 1) && (val & 1)) - { - /* reset all the DMA data */ - dma_bytes_left = 0; - dma_last_buffer = 0; - dma_descriptor = bus_master_descriptor; - - /* if we're going live, start the pending read/write */ - if (dma_active) - { - if (bus_master_command & 8) - read_next_sector(); - else - { - read_buffer_from_dma(); - } - } - } - } - - if( ACCESSING_BITS_16_23 ) - { - /* status register */ - UINT8 old = bus_master_status; - UINT8 val = (data >> 16) & 0xff; - - /* save the DMA capable bits */ - bus_master_status = (old & 0x9f) | (val & 0x60); - - /* clear interrupt and error bits */ - if (val & IDE_BUSMASTER_STATUS_IRQ) - bus_master_status &= ~IDE_BUSMASTER_STATUS_IRQ; - if (val & IDE_BUSMASTER_STATUS_ERROR) - bus_master_status &= ~IDE_BUSMASTER_STATUS_ERROR; - } - break; - - case 1: - /* descriptor table register */ - bus_master_descriptor = data & 0xfffffffc; - break; - } -} - - SLOT_INTERFACE_START(ide_devices) SLOT_INTERFACE("hdd", IDE_HARDDISK) SLOT_INTERFACE_END @@ -1491,18 +1268,6 @@ SLOT_INTERFACE_END ide_controller_device::ide_controller_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) : device_t(mconfig, type, name, tag, owner, clock), status(0), - bmcpu(NULL), - bmspace(0), - dma_space(NULL), - dma_active(0), - dma_address_xor(0), - dma_last_buffer(0), - dma_address(0), - dma_descriptor(0), - dma_bytes_left(0), - bus_master_command(0), - bus_master_status(0), - bus_master_descriptor(0), adapter_control(0), error(0), command(0), @@ -1530,18 +1295,6 @@ 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) : device_t(mconfig, IDE_CONTROLLER, "IDE Controller", tag, owner, clock), - bmcpu(NULL), - bmspace(0), - dma_space(NULL), - dma_active(0), - dma_address_xor(0), - dma_last_buffer(0), - dma_address(0), - dma_descriptor(0), - dma_bytes_left(0), - bus_master_command(0), - bus_master_status(0), - bus_master_descriptor(0), adapter_control(0), error(0), command(0), @@ -1564,13 +1317,6 @@ ide_controller_device::ide_controller_device(const machine_config &mconfig, cons { } -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_device(mconfig, BUS_MASTER_IDE_CONTROLLER, "Bus Master IDE Controller", tag, owner, clock) -{ -} - //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- @@ -1583,19 +1329,6 @@ void ide_controller_device::device_start() slot[0] = owner()->subdevice<ide_slot_device>("drive_0"); slot[1] = owner()->subdevice<ide_slot_device>("drive_1"); - /* find the bus master space */ - if (bmcpu != NULL) - { - device_t *bmtarget = machine().device(bmcpu); - if (bmtarget == NULL) - throw emu_fatalerror("IDE controller '%s' bus master target '%s' doesn't exist!", tag(), bmcpu); - device_memory_interface *memory; - if (!bmtarget->interface(memory)) - throw emu_fatalerror("IDE controller '%s' bus master target '%s' has no memory!", tag(), bmcpu); - dma_space = &memory->space(bmspace); - dma_address_xor = (dma_space->endianness() == ENDIANNESS_LITTLE) ? 0 : 3; - } - /* create a timer for timing status */ last_status_timer = machine().scheduler().timer_alloc(FUNC_NULL); reset_timer = machine().scheduler().timer_alloc(FUNC(reset_callback), this); @@ -1616,14 +1349,6 @@ void ide_controller_device::device_start() save_item(NAME(sectors_until_int)); save_item(NAME(dma_active)); - save_item(NAME(dma_last_buffer)); - save_item(NAME(dma_address)); - save_item(NAME(dma_descriptor)); - save_item(NAME(dma_bytes_left)); - - save_item(NAME(bus_master_command)); - save_item(NAME(bus_master_status)); - save_item(NAME(bus_master_descriptor)); save_item(NAME(config_unknown)); save_item(NAME(config_register)); @@ -1650,7 +1375,8 @@ void ide_controller_device::device_reset() gnetreadlock = 0; master_password_enable = (master_password != NULL); user_password_enable = (user_password != NULL); - clear_interrupt(); + set_irq(CLEAR_LINE); + set_dmarq(0); } @@ -1691,3 +1417,227 @@ void ide_slot_device::device_config_complete() void ide_slot_device::device_start() { } + + + +#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_device(mconfig, BUS_MASTER_IDE_CONTROLLER, "Bus Master IDE Controller", tag, owner, clock), + dma_address(0), + dma_bytes_left(0), + dma_descriptor(0), + dma_last_buffer(0), + bus_master_command(0), + bus_master_status(0), + bus_master_descriptor(0) +{ +} + +void bus_master_ide_controller_device::device_start() +{ + ide_controller_device::device_start(); + + /* find the bus master space */ + if (bmcpu != NULL) + { + device_t *bmtarget = machine().device(bmcpu); + if (bmtarget == NULL) + throw emu_fatalerror("IDE controller '%s' bus master target '%s' doesn't exist!", tag(), bmcpu); + device_memory_interface *memory; + if (!bmtarget->interface(memory)) + throw emu_fatalerror("IDE controller '%s' bus master target '%s' has no memory!", tag(), bmcpu); + dma_space = &memory->space(bmspace); + dma_address_xor = (dma_space->endianness() == ENDIANNESS_LITTLE) ? 0 : 3; + } + + save_item(NAME(dma_address)); + save_item(NAME(dma_bytes_left)); + save_item(NAME(dma_descriptor)); + save_item(NAME(dma_last_buffer)); + save_item(NAME(bus_master_command)); + save_item(NAME(bus_master_status)); + save_item(NAME(bus_master_descriptor)); +} + +void bus_master_ide_controller_device::set_irq(int state) +{ + ide_controller_device::set_irq(state); + + if (m_irq != state) + { + m_irq = state; + + if( m_irq ) + bus_master_status |= IDE_BUSMASTER_STATUS_IRQ; + } +} + +void bus_master_ide_controller_device::set_dmarq(int state) +{ + if (m_dmarq != state) + { + m_dmarq = state; + + execute_dma(); + } +} + +/************************************* + * + * Bus master read + * + *************************************/ + +READ32_MEMBER( bus_master_ide_controller_device::ide_bus_master32_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 bus_master_command | (bus_master_status << 16); + + case 1: + /* descriptor table register */ + return bus_master_descriptor; + } + + return 0xffffffff; +} + + + +/************************************* + * + * Bus master write + * + *************************************/ + +WRITE32_MEMBER( bus_master_ide_controller_device::ide_bus_master32_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 ) + { + /* command register */ + UINT8 old = bus_master_command; + UINT8 val = data & 0xff; + + /* save the read/write bit and the start/stop bit */ + bus_master_command = (old & 0xf6) | (val & 0x09); + + if ((old ^ bus_master_command) & 1) + { + if (bus_master_command & 1) + { + /* handle starting a transfer */ + bus_master_status |= IDE_BUSMASTER_STATUS_ACTIVE; + + /* reset all the DMA data */ + dma_bytes_left = 0; + dma_descriptor = bus_master_descriptor; + + /* if we're going live, start the pending read/write */ + execute_dma(); + } + else if (bus_master_status & IDE_BUSMASTER_STATUS_ACTIVE) + { + bus_master_status &= ~IDE_BUSMASTER_STATUS_ACTIVE; + + LOG(("DMA Aborted!\n")); + } + } + } + + if( ACCESSING_BITS_16_23 ) + { + /* status register */ + UINT8 old = bus_master_status; + UINT8 val = data >> 16; + + /* save the DMA capable bits */ + bus_master_status = (old & 0x9f) | (val & 0x60); + + /* clear interrupt and error bits */ + if (val & IDE_BUSMASTER_STATUS_IRQ) + bus_master_status &= ~IDE_BUSMASTER_STATUS_IRQ; + if (val & IDE_BUSMASTER_STATUS_ERROR) + bus_master_status &= ~IDE_BUSMASTER_STATUS_ERROR; + } + break; + + case 1: + /* descriptor table register */ + bus_master_descriptor = data & 0xfffffffc; + break; + } +} + +void bus_master_ide_controller_device::execute_dma() +{ + while (m_dmarq && (bus_master_status & IDE_BUSMASTER_STATUS_ACTIVE)) + { + /* if we're out of space, grab the next descriptor */ + if (dma_bytes_left == 0) + { + /* fetch the address */ + dma_address = dma_space->read_byte(dma_descriptor++ ^ dma_address_xor); + dma_address |= dma_space->read_byte(dma_descriptor++ ^ dma_address_xor) << 8; + dma_address |= dma_space->read_byte(dma_descriptor++ ^ dma_address_xor) << 16; + dma_address |= dma_space->read_byte(dma_descriptor++ ^ dma_address_xor) << 24; + dma_address &= 0xfffffffe; + + /* fetch the length */ + dma_bytes_left = dma_space->read_byte(dma_descriptor++ ^ dma_address_xor); + dma_bytes_left |= dma_space->read_byte(dma_descriptor++ ^ dma_address_xor) << 8; + dma_bytes_left |= dma_space->read_byte(dma_descriptor++ ^ dma_address_xor) << 16; + dma_bytes_left |= dma_space->read_byte(dma_descriptor++ ^ dma_address_xor) << 24; + dma_last_buffer = (dma_bytes_left >> 31) & 1; + dma_bytes_left &= 0xfffe; + if (dma_bytes_left == 0) + dma_bytes_left = 0x10000; + +// LOG(("New DMA descriptor: address = %08X bytes = %04X last = %d\n", dma_address, dma_bytes_left, dma_last_buffer)); + } + + if (bus_master_command & 8) + { + // read from ata bus + UINT16 data = read_dma(); + + // write to memory + dma_space->write_byte(dma_address++, data & 0xff); + dma_space->write_byte(dma_address++, data >> 8); + } + else + { + // read from memory; + UINT16 data = dma_space->read_byte(dma_address++); + data |= dma_space->read_byte(dma_address++) << 8; + + // write to ata bus + write_dma(data); + } + + dma_bytes_left -= 2; + + if (dma_bytes_left == 0 && dma_last_buffer) + { + bus_master_status &= ~IDE_BUSMASTER_STATUS_ACTIVE; + + if (m_dmarq) + { + LOG(("DMA Out of buffer space!\n")); + } + } + } +} diff --git a/src/emu/machine/idectrl.h b/src/emu/machine/idectrl.h index 69ea768dba4..df47e39ad48 100644 --- a/src/emu/machine/idectrl.h +++ b/src/emu/machine/idectrl.h @@ -101,8 +101,8 @@ public: DECLARE_WRITE16_MEMBER(write_cs0_pc); DECLARE_WRITE16_MEMBER(write_cs1_pc); - void signal_interrupt(); - void clear_interrupt(); + virtual void set_irq(int state); + virtual void set_dmarq(int state); void read_sector_done(); void write_sector_done(); @@ -113,21 +113,7 @@ protected: virtual void device_start(); virtual void device_reset(); - const char *bmcpu; - UINT32 bmspace; - address_space * dma_space; - UINT8 dma_active; - UINT8 dma_address_xor; - UINT8 dma_last_buffer; - offs_t dma_address; - offs_t dma_descriptor; - UINT32 dma_bytes_left; - UINT8 bus_master_command; - UINT8 bus_master_status; - UINT32 bus_master_descriptor; - void read_next_sector(); - void read_buffer_from_dma(); void continue_write(); private: @@ -135,12 +121,12 @@ private: void next_sector(); void security_error(); void continue_read(); - void write_buffer_to_dma(); void read_first_sector(); void handle_command(UINT8 _command); void read_buffer_empty(); void write_buffer_full(); + UINT8 dma_active; UINT8 adapter_control; UINT8 error; UINT8 command; @@ -194,6 +180,30 @@ public: DECLARE_READ32_MEMBER( ide_bus_master32_r ); DECLARE_WRITE32_MEMBER( ide_bus_master32_w ); + + virtual void set_irq(int state); + virtual void set_dmarq(int state); + +protected: + virtual void device_start(); + +private: + void execute_dma(); + + const char *bmcpu; + UINT32 bmspace; + address_space * dma_space; + UINT8 dma_address_xor; + + offs_t dma_address; + UINT32 dma_bytes_left; + offs_t dma_descriptor; + UINT8 dma_last_buffer; + UINT8 bus_master_command; + UINT8 bus_master_status; + UINT32 bus_master_descriptor; + int m_irq; + int m_dmarq; }; extern const device_type BUS_MASTER_IDE_CONTROLLER; |