diff options
Diffstat (limited to 'src/devices/machine/wd1010.cpp')
-rw-r--r-- | src/devices/machine/wd1010.cpp | 341 |
1 files changed, 210 insertions, 131 deletions
diff --git a/src/devices/machine/wd1010.cpp b/src/devices/machine/wd1010.cpp index c093c11319b..5a01446c946 100644 --- a/src/devices/machine/wd1010.cpp +++ b/src/devices/machine/wd1010.cpp @@ -1,4 +1,4 @@ -// license:GPL-2.0+ +// license:BSD-3-Clause // copyright-holders:Dirk Best /*************************************************************************** @@ -9,14 +9,13 @@ #include "emu.h" #include "wd1010.h" -//#define LOG_GENERAL (1U << 0) -#define LOG_CMD (1U << 1) -#define LOG_INT (1U << 2) -#define LOG_SEEK (1U << 3) -#define LOG_REGS (1U << 4) -#define LOG_DATA (1U << 5) +#define LOG_CMD (1U << 1) +#define LOG_INT (1U << 2) +#define LOG_SEEK (1U << 3) +#define LOG_REGS (1U << 4) +#define LOG_DATA (1U << 5) -//#define VERBOSE (LOG_CMD | LOG_INT | LOG_SEEK | LOG_REGS | LOG_DATA) +#define VERBOSE (LOG_CMD | LOG_INT | LOG_SEEK | LOG_REGS | LOG_DATA) //#define LOG_OUTPUT_STREAM std::cout #include "logmacro.h" @@ -46,8 +45,12 @@ DEFINE_DEVICE_TYPE(WD1010, wd1010_device, "wd1010", "Western Digital WD1010-05") wd1010_device::wd1010_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, WD1010, tag, owner, clock), m_out_intrq_cb(*this), + m_out_bdrq_cb(*this), + m_out_bcs_cb(*this), m_out_bcr_cb(*this), - m_in_data_cb(*this), + m_out_dirin_cb(*this), + m_out_wg_cb(*this), + m_in_data_cb(*this, 0), m_out_data_cb(*this), m_intrq(0), m_brdy(0), @@ -81,15 +84,10 @@ void wd1010_device::device_start() m_drives[i].sector = 0; } - // resolve callbacks - m_out_intrq_cb.resolve_safe(); - m_out_bcr_cb.resolve_safe(); - m_in_data_cb.resolve_safe(0); - m_out_data_cb.resolve_safe(); - // allocate timer - m_seek_timer = timer_alloc(TIMER_SEEK); - m_data_timer = timer_alloc(TIMER_DATA); + m_seek_timer = timer_alloc(FUNC(wd1010_device::update_seek), this); + m_read_timer = timer_alloc(FUNC(wd1010_device::delayed_read), this); + m_write_timer = timer_alloc(FUNC(wd1010_device::delayed_write), this); // register for save states save_item(NAME(m_intrq)); @@ -103,6 +101,7 @@ void wd1010_device::device_start() save_item(NAME(m_cylinder)); save_item(NAME(m_sdh)); save_item(NAME(m_status)); + save_item(NAME(m_head)); } //------------------------------------------------- @@ -114,61 +113,62 @@ void wd1010_device::device_reset() } //------------------------------------------------- -// device_timer - device-specific timer +// update_seek - //------------------------------------------------- -void wd1010_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) +TIMER_CALLBACK_MEMBER(wd1010_device::update_seek) { - switch (tid) + if ((m_command >> 4) != CMD_SCAN_ID) { - case TIMER_SEEK: - - if ((m_command >> 4) != CMD_SCAN_ID) - { - LOGSEEK("Seek complete\n"); - m_drives[drive()].cylinder = param; - m_status |= STATUS_SC; - } + LOGSEEK("Seek complete\n"); + m_drives[drive()].cylinder = param; + m_status |= STATUS_SC; + } - switch (m_command >> 4) - { - case CMD_RESTORE: - cmd_restore(); - break; - - case CMD_SEEK: - cmd_seek(); - break; - - case CMD_READ_SECTOR: - cmd_read_sector(); - break; - - case CMD_WRITE_SECTOR: - case CMD_WRITE_FORMAT: - cmd_write_sector(); - break; - - case CMD_SCAN_ID: - cmd_scan_id(); - break; - } + switch (m_command >> 4) + { + case CMD_RESTORE: + cmd_restore(); + break; + case CMD_SEEK: + cmd_seek(); break; - case TIMER_DATA: + case CMD_READ_SECTOR: + cmd_read_sector(); + break; - // check if data is ready or continue waiting - if (m_brdy) - cmd_write_sector(); - else - m_data_timer->adjust(attotime::from_usec(35)); + case CMD_WRITE_SECTOR: + case CMD_WRITE_FORMAT: + cmd_write_sector(); + break; + case CMD_SCAN_ID: + cmd_scan_id(); break; } } //------------------------------------------------- +// delayed_read - +//------------------------------------------------- + +TIMER_CALLBACK_MEMBER(wd1010_device::delayed_read) +{ + cmd_read_sector(); +} + +//------------------------------------------------- +// delayed_write - +//------------------------------------------------- + +TIMER_CALLBACK_MEMBER(wd1010_device::delayed_write) +{ + cmd_write_sector(); +} + +//------------------------------------------------- // set_error - set error and adjust status //------------------------------------------------- @@ -207,6 +207,26 @@ void wd1010_device::set_intrq(int state) } //------------------------------------------------- +// set_bdrq - set drq status +//------------------------------------------------- + +void wd1010_device::set_bdrq(int state) +{ + if ((!(m_status & STATUS_DRQ)) && state == 1) + { + LOGINT("DRQ 1\n"); + m_status |= STATUS_DRQ; + m_out_bdrq_cb(1); + } + else if ((m_status & STATUS_DRQ) && state == 0) + { + LOGINT("DRQ 0\n"); + m_status &= ~STATUS_DRQ; + m_out_bdrq_cb(0); + } +} + +//------------------------------------------------- // get_stepping_rate - calculate stepping rate //------------------------------------------------- @@ -274,14 +294,14 @@ void wd1010_device::end_command() int wd1010_device::get_lbasector() { - hard_disk_file *file = m_drives[drive()].drive->get_hard_disk_file(); - hard_disk_info *info = hard_disk_get_info(file); + harddisk_image_device *file = m_drives[drive()].drive; + const auto &info = file->get_info(); int lbasector; lbasector = m_cylinder; - lbasector *= info->heads; + lbasector *= info.heads; lbasector += head(); - lbasector *= info->sectors; + lbasector *= info.sectors; lbasector += m_sector_number; return lbasector; @@ -292,7 +312,7 @@ int wd1010_device::get_lbasector() // INTERFACE //************************************************************************** -WRITE_LINE_MEMBER( wd1010_device::drdy_w ) +void wd1010_device::drdy_w(int state) { if (state) m_status |= STATUS_RDY; @@ -300,12 +320,30 @@ WRITE_LINE_MEMBER( wd1010_device::drdy_w ) m_status &= ~STATUS_RDY; } -WRITE_LINE_MEMBER( wd1010_device::brdy_w ) +void wd1010_device::brdy_w(int state) { m_brdy = state; } -READ8_MEMBER( wd1010_device::read ) +void wd1010_device::sc_w(int state) +{ + if (state) + m_status |= STATUS_SC; + else + m_status &= ~STATUS_SC; +} + +int wd1010_device::sc_r() +{ + return m_status & STATUS_SC ? 1 : 0; +} + +int wd1010_device::tk000_r() +{ + return m_drives[drive()].cylinder == 0 ? 1 : 0; +} + +uint8_t wd1010_device::read(offs_t offset) { // if the controller is busy all reads return the status register if (m_status & STATUS_BSY) @@ -358,7 +396,7 @@ READ8_MEMBER( wd1010_device::read ) return 0xff; } -WRITE8_MEMBER( wd1010_device::write ) +void wd1010_device::write(offs_t offset, uint8_t data) { switch (offset & 0x07) { @@ -423,13 +461,13 @@ WRITE8_MEMBER( wd1010_device::write ) if ((m_command >> 4) != CMD_SCAN_ID) m_status &= ~STATUS_SC; - int amount = 0; + int seek = 0; int target = 0; switch (m_command >> 4) { case CMD_RESTORE: - amount = m_drives[drive()].cylinder; + seek = m_drives[drive()].cylinder; target = 0; break; @@ -437,15 +475,17 @@ WRITE8_MEMBER( wd1010_device::write ) case CMD_READ_SECTOR: case CMD_WRITE_SECTOR: case CMD_WRITE_FORMAT: - amount = abs(m_drives[drive()].cylinder - m_cylinder); + seek = m_drives[drive()].cylinder - m_cylinder; target = m_cylinder; break; } + m_out_dirin_cb(seek > 0 ? 1 : 0); + if ((m_command >> 4) != CMD_SCAN_ID) - LOGSEEK("Seeking %d cylinders to %d\n", amount, target); + LOGSEEK("Seeking %d cylinders to %d\n", seek, target); - m_seek_timer->adjust(get_stepping_rate() * amount, target); + m_seek_timer->adjust(get_stepping_rate() * abs(seek), target); } break; @@ -465,105 +505,144 @@ void wd1010_device::cmd_restore() void wd1010_device::cmd_read_sector() { - hard_disk_file *file = m_drives[drive()].drive->get_hard_disk_file(); - hard_disk_info *info = hard_disk_get_info(file); + if (m_status & STATUS_DRQ) + { + if (m_brdy) + { + set_bdrq(0); - m_out_bcr_cb(1); - m_out_bcr_cb(0); + // if there's nothing left we're done + if (m_sector_count == 0) + { + end_command(); + return; + } + } + else + { + // continue waiting for the buffer to be ready + m_read_timer->adjust(attotime::from_usec(35)); + return; + } + } + + harddisk_image_device *file = m_drives[drive()].drive; + const auto &info = file->get_info(); // verify that we can read - if (head() > info->heads) + if (head() > info.heads) { // out of range LOG("--> Head out of range, aborting\n"); set_error(ERR_AC); end_command(); + return; } - else - { - uint8_t buffer[512]; - while (m_sector_count > 0) - { - LOGDATA("--> Transferring sector to buffer (lba = %08x)\n", get_lbasector()); + uint8_t buffer[512]; - hard_disk_read(file, get_lbasector(), buffer); + m_out_bcr_cb(1); + m_out_bcr_cb(0); - for (int i = 0; i < 512; i++) - m_out_data_cb(buffer[i]); + m_out_bcs_cb(1); - m_out_bcr_cb(1); - m_out_bcr_cb(0); + LOGDATA("--> Transferring sector to buffer (lba = %08x)\n", get_lbasector()); - // save last read head and sector number - m_drives[drive()].head = head(); - m_drives[drive()].sector = m_sector_number; + file->read(get_lbasector(), buffer); - if (BIT(m_command, 2)) - { - m_sector_number++; - m_sector_count--; - } - else - break; - } + for (int i = 0; i < 512; i++) + m_out_data_cb(buffer[i]); - end_command(); + // multi-sector read + if (BIT(m_command, 2)) + { + m_sector_number++; + m_sector_count--; + } + else + { + m_sector_count = 0; + } + + if (m_sector_count == 0) + { + m_out_bcr_cb(1); + m_out_bcr_cb(0); } + + m_out_bcs_cb(0); + + set_bdrq(1); + + // interrupt at bdrq time? + if (BIT(m_command, 3) == 0) + set_intrq(1); + + // now wait for brdy + m_read_timer->adjust(attotime::from_usec(35)); } void wd1010_device::cmd_write_sector() { - if (!(m_status & STATUS_DRQ)) - { - LOGDATA("Setting DATA REQUEST\n"); - m_status |= STATUS_DRQ; - m_data_timer->adjust(attotime::from_usec(35)); - return; - } + set_bdrq(1); + // wait if the buffer isn't ready if (m_brdy == 0) { - m_data_timer->adjust(attotime::from_usec(35)); + m_write_timer->adjust(attotime::from_usec(35)); return; } - LOGDATA("Clearing DATA REQUEST\n"); - m_status &= ~STATUS_DRQ; - - hard_disk_file *file = m_drives[drive()].drive->get_hard_disk_file(); + harddisk_image_device *file = m_drives[drive()].drive; uint8_t buffer[512]; - while (m_sector_count > 0) + set_bdrq(0); + + m_out_bcr_cb(1); + m_out_bcr_cb(0); + + m_out_bcs_cb(1); + + m_out_wg_cb(1); + + if ((m_command >> 4) == CMD_WRITE_FORMAT) { - if ((m_command >> 4) == CMD_WRITE_FORMAT) - { - // we ignore the format specification and fill everything with 0xe5 - std::fill(std::begin(buffer), std::end(buffer), 0xe5); - } - else - { - // get data for sector from buffer chip - for (int i = 0; i < 512; i++) - buffer[i] = m_in_data_cb(); - } + // we ignore the format specification and fill everything with 0xe5 + std::fill(std::begin(buffer), std::end(buffer), 0xe5); + } + else + { + // get data for sector from buffer chip + for (int i = 0; i < 512; i++) + buffer[i] = m_in_data_cb(); + } - hard_disk_write(file, get_lbasector(), buffer); + file->write(get_lbasector(), buffer); - // save last read head and sector number - m_drives[drive()].head = head(); - m_drives[drive()].sector = m_sector_number; + // save last read head and sector number + m_drives[drive()].head = head(); + m_drives[drive()].sector = m_sector_number; + + // multi-sector write + if (BIT(m_command, 2) && m_sector_count > 0) + { + m_sector_number++; + m_sector_count--; - if (BIT(m_command, 2)) + // schedule another run if we aren't finished yet + if (m_sector_count > 0) { - m_sector_number++; - m_sector_count--; + m_out_bcs_cb(0); + m_out_wg_cb(0); + m_write_timer->adjust(attotime::from_usec(35)); + return; } - else - break; } + m_out_bcs_cb(0); + m_out_wg_cb(0); + end_command(); } |