summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/wd1010.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/wd1010.cpp')
-rw-r--r--src/devices/machine/wd1010.cpp341
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();
}