diff options
-rw-r--r-- | src/devices/machine/wd1010.cpp | 222 | ||||
-rw-r--r-- | src/devices/machine/wd1010.h | 20 |
2 files changed, 168 insertions, 74 deletions
diff --git a/src/devices/machine/wd1010.cpp b/src/devices/machine/wd1010.cpp index 96fb4b5fdd0..a330d6c7671 100644 --- a/src/devices/machine/wd1010.cpp +++ b/src/devices/machine/wd1010.cpp @@ -16,7 +16,7 @@ #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,7 +46,11 @@ 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_out_dirin_cb(*this), + m_out_wg_cb(*this), m_in_data_cb(*this), m_out_data_cb(*this), m_intrq(0), @@ -83,13 +87,18 @@ void wd1010_device::device_start() // resolve callbacks m_out_intrq_cb.resolve_safe(); + m_out_bdrq_cb.resolve_safe(); + m_out_bcs_cb.resolve_safe(); m_out_bcr_cb.resolve_safe(); + m_out_dirin_cb.resolve_safe(); + m_out_wg_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_read_timer = timer_alloc(TIMER_READ); + m_write_timer = timer_alloc(TIMER_WRITE); // register for save states save_item(NAME(m_intrq)); @@ -156,14 +165,12 @@ void wd1010_device::device_timer(emu_timer &timer, device_timer_id tid, int para break; - case TIMER_DATA: - - // check if data is ready or continue waiting - if (m_brdy) - cmd_write_sector(); - else - m_data_timer->adjust(attotime::from_usec(35)); + case TIMER_READ: + cmd_read_sector(); + break; + case TIMER_WRITE: + cmd_write_sector(); break; } } @@ -207,6 +214,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 //------------------------------------------------- @@ -305,6 +332,16 @@ void wd1010_device::brdy_w(int state) m_brdy = state; } +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 @@ -423,13 +460,13 @@ void wd1010_device::write(offs_t offset, uint8_t data) 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 +474,17 @@ void wd1010_device::write(offs_t offset, uint8_t data) 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,12 +504,30 @@ void wd1010_device::cmd_restore() void wd1010_device::cmd_read_sector() { + if (m_status & STATUS_DRQ) + { + if (m_brdy) + { + set_bdrq(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; + } + } + hard_disk_file *file = m_drives[drive()].drive->get_hard_disk_file(); hard_disk_info *info = hard_disk_get_info(file); - m_out_bcr_cb(1); - m_out_bcr_cb(0); - // verify that we can read if (head() > info->heads) { @@ -479,91 +536,112 @@ void wd1010_device::cmd_read_sector() 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; + hard_disk_read(file, 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(); 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); + hard_disk_write(file, 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; - if (BIT(m_command, 2)) + // multi-sector write + if (BIT(m_command, 2) && m_sector_count > 0) + { + m_sector_number++; + m_sector_count--; + + // 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(); } diff --git a/src/devices/machine/wd1010.h b/src/devices/machine/wd1010.h index b6a637c99e9..17ebd9606de 100644 --- a/src/devices/machine/wd1010.h +++ b/src/devices/machine/wd1010.h @@ -27,7 +27,11 @@ public: wd1010_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); auto out_intrq_callback() { return m_out_intrq_cb.bind(); } + auto out_bdrq_callback() { return m_out_bdrq_cb.bind(); } + auto out_bcs_callback() { return m_out_bcs_cb.bind(); } auto out_bcr_callback() { return m_out_bcr_cb.bind(); } + auto out_dirin_callback() { return m_out_dirin_cb.bind(); } + auto out_wg_callback() { return m_out_wg_cb.bind(); } auto in_data_callback() { return m_in_data_cb.bind(); } auto out_data_callback() { return m_out_data_cb.bind(); } @@ -37,6 +41,10 @@ public: void drdy_w(int state); void brdy_w(int state); + // actually inputs to the controller from the drive + int sc_r(); + int tk000_r(); + protected: // device-level overrides virtual void device_start() override; @@ -81,11 +89,13 @@ private: enum { TIMER_SEEK, - TIMER_DATA + TIMER_READ, + TIMER_WRITE }; void set_error(int error); void set_intrq(int state); + void set_bdrq(int state); attotime get_stepping_rate(); void start_command(); void end_command(); @@ -107,7 +117,11 @@ private: void cmd_seek(); devcb_write_line m_out_intrq_cb; + devcb_write_line m_out_bdrq_cb; + devcb_write_line m_out_bcs_cb; devcb_write_line m_out_bcr_cb; + devcb_write_line m_out_dirin_cb; + devcb_write_line m_out_wg_cb; devcb_read8 m_in_data_cb; devcb_write8 m_out_data_cb; @@ -120,9 +134,11 @@ private: } m_drives[4]; emu_timer *m_seek_timer; - emu_timer *m_data_timer; + emu_timer *m_read_timer; + emu_timer *m_write_timer; int m_intrq; + int m_bdrq; int m_brdy; uint8_t m_stepping_rate; uint8_t m_command; |