summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/wd_fdc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/wd_fdc.cpp')
-rw-r--r--src/devices/machine/wd_fdc.cpp807
1 files changed, 492 insertions, 315 deletions
diff --git a/src/devices/machine/wd_fdc.cpp b/src/devices/machine/wd_fdc.cpp
index dcba2b3f5ce..3ba43855aa9 100644
--- a/src/devices/machine/wd_fdc.cpp
+++ b/src/devices/machine/wd_fdc.cpp
@@ -5,10 +5,7 @@
#include "imagedev/floppy.h"
-#include "debugger.h"
-
-//#define LOG_GENERAL (1U << 0) //defined in logmacro.h already
-#define LOG_SETUP (1U << 1) // Shows register setup
+#define LOG_DATA (1U << 1) // Shows data reads and writes
#define LOG_SHIFT (1U << 2) // Shows shift register contents
#define LOG_COMP (1U << 3) // Shows operations on the CPU side
#define LOG_COMMAND (1U << 4) // Shows command invocation
@@ -22,13 +19,15 @@
#define LOG_STATE (1U << 12) // Show state machine
#define LOG_LIVE (1U << 13) // Live states
#define LOG_FUNC (1U << 14) // Function calls
+#define LOG_CRC (1U << 15) // CRC errors
-#define VERBOSE (LOG_GENERAL )
+#define VERBOSE (LOG_DESC)
+//#define VERBOSE (LOG_DESC | LOG_COMMAND | LOG_MATCH | LOG_WRITE | LOG_STATE | LOG_LINES | LOG_COMP | LOG_CRC )
//#define LOG_OUTPUT_STREAM std::cout
#include "logmacro.h"
-#define LOGSETUP(...) LOGMASKED(LOG_SETUP, __VA_ARGS__)
+#define LOGDATA(...) LOGMASKED(LOG_DATA, __VA_ARGS__)
#define LOGSHIFT(...) LOGMASKED(LOG_SHIFT, __VA_ARGS__)
#define LOGCOMP(...) LOGMASKED(LOG_COMP, __VA_ARGS__)
#define LOGCOMMAND(...) LOGMASKED(LOG_COMMAND, __VA_ARGS__)
@@ -42,6 +41,7 @@
#define LOGSTATE(...) LOGMASKED(LOG_STATE, __VA_ARGS__)
#define LOGLIVE(...) LOGMASKED(LOG_LIVE, __VA_ARGS__)
#define LOGFUNC(...) LOGMASKED(LOG_FUNC, __VA_ARGS__)
+#define LOGCRC(...) LOGMASKED(LOG_CRC, __VA_ARGS__)
#ifdef _MSC_VER
#define FUNCNAME __func__
@@ -79,6 +79,70 @@ DEFINE_DEVICE_TYPE(WD1770, wd1770_device, "wd1770", "Western Digital
DEFINE_DEVICE_TYPE(WD1772, wd1772_device, "wd1772", "Western Digital WD1772 FDC")
DEFINE_DEVICE_TYPE(WD1773, wd1773_device, "wd1773", "Western Digital WD1773 FDC")
+static const char *const states[] =
+{
+ "IDLE",
+ "RESTORE",
+ "SEEK",
+ "STEP",
+ "READ_SECTOR",
+ "READ_TRACK",
+ "READ_ID",
+ "WRITE_TRACK",
+ "WRITE_SECTOR",
+ "SPINUP",
+ "SPINUP_WAIT",
+ "SPINUP_DONE",
+ "SETTLE_WAIT",
+ "SETTLE_DONE",
+ "WRITE_PROTECT_WAIT",
+ "WRITE_PROTECT_DONE",
+ "DATA_LOAD_WAIT",
+ "DATA_LOAD_WAIT_DONE",
+ "SEEK_MOVE",
+ "SEEK_WAIT_STEP_TIME",
+ "SEEK_WAIT_STEP_TIME_DONE",
+ "SEEK_WAIT_STABILIZATION_TIME",
+ "SEEK_WAIT_STABILIZATION_TIME_DONE",
+ "SEEK_DONE",
+ "WAIT_INDEX",
+ "WAIT_INDEX_DONE",
+ "SCAN_ID",
+ "SCAN_ID_FAILED",
+ "SECTOR_READ",
+ "SECTOR_WRITE",
+ "TRACK_DONE",
+ "INITIAL_RESTORE",
+ "DUMMY",
+ "SEARCH_ADDRESS_MARK_HEADER",
+ "READ_HEADER_BLOCK_HEADER",
+ "READ_DATA_BLOCK_HEADER",
+ "READ_ID_BLOCK_TO_LOCAL",
+ "READ_ID_BLOCK_TO_DMA",
+ "READ_ID_BLOCK_TO_DMA_BYTE",
+ "SEARCH_ADDRESS_MARK_DATA",
+ "SEARCH_ADDRESS_MARK_DATA_FAILED",
+ "READ_SECTOR_DATA",
+ "READ_SECTOR_DATA_BYTE",
+ "READ_TRACK_DATA",
+ "READ_TRACK_DATA_BYTE",
+ "WRITE_TRACK_DATA",
+ "WRITE_BYTE",
+ "WRITE_BYTE_DONE",
+ "WRITE_SECTOR_PRE",
+ "WRITE_SECTOR_PRE_BYTE"
+};
+
+template <unsigned B> inline uint32_t wd_fdc_device_base::live_info::shift_reg_low() const
+{
+ return shift_reg & make_bitmask<uint32_t>(B);
+}
+
+inline uint8_t wd_fdc_device_base::live_info::shift_reg_data() const
+{
+ return bitswap<8>(shift_reg, 14, 12, 10, 8, 6, 4, 2, 0);
+}
+
wd_fdc_device_base::wd_fdc_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, type, tag, owner, clock),
intrq_cb(*this),
@@ -87,10 +151,14 @@ wd_fdc_device_base::wd_fdc_device_base(const machine_config &mconfig, device_typ
enp_cb(*this),
sso_cb(*this),
ready_cb(*this), // actually output by the drive, not by the FDC
- enmf_cb(*this)
+ enmf_cb(*this, 0),
+ mon_cb(*this)
{
force_ready = false;
disable_motor_control = false;
+ spinup_on_interrupt = false;
+ extended_ddam = false;
+ hlt = true; // assume tied to VCC
}
void wd_fdc_device_base::set_force_ready(bool _force_ready)
@@ -105,27 +173,23 @@ void wd_fdc_device_base::set_disable_motor_control(bool _disable_motor_control)
void wd_fdc_device_base::device_start()
{
- intrq_cb.resolve();
- drq_cb.resolve();
- hld_cb.resolve();
- enp_cb.resolve();
- sso_cb.resolve();
- ready_cb.resolve();
- enmf_cb.resolve();
-
- if (!has_enmf && !enmf_cb.isnull())
+ if (!has_enmf && !enmf_cb.isunset())
logerror("Warning, this chip doesn't have an ENMF line.\n");
- t_gen = timer_alloc(TM_GEN);
- t_cmd = timer_alloc(TM_CMD);
- t_track = timer_alloc(TM_TRACK);
- t_sector = timer_alloc(TM_SECTOR);
+ t_gen = timer_alloc(FUNC(wd_fdc_device_base::generic_tick), this);
+ t_cmd = timer_alloc(FUNC(wd_fdc_device_base::cmd_w_tick), this);
+ t_track = timer_alloc(FUNC(wd_fdc_device_base::track_w_tick), this);
+ t_sector = timer_alloc(FUNC(wd_fdc_device_base::sector_w_tick), this);
dden = disable_mfm;
enmf = false;
floppy = nullptr;
status = 0x00;
+ data = 0x00;
+ track = 0x00;
mr = true;
+ delay_int = false;
+
save_item(NAME(status));
save_item(NAME(command));
save_item(NAME(main_state));
@@ -142,6 +206,10 @@ void wd_fdc_device_base::device_start()
if (!disable_mfm)
save_item(NAME(dden));
save_item(NAME(mr));
+ save_item(NAME(intrq));
+ save_item(NAME(drq));
+ if (head_control)
+ save_item(NAME(hld));
}
void wd_fdc_device_base::device_reset()
@@ -157,17 +225,15 @@ void wd_fdc_device_base::soft_reset()
}
}
-WRITE_LINE_MEMBER(wd_fdc_device_base::mr_w)
+void wd_fdc_device_base::mr_w(int state)
{
if(mr && !state) {
- command = 0x00;
+ command = 0x03;
main_state = IDLE;
sub_state = IDLE;
cur_live.state = IDLE;
- track = 0x00;
sector = 0x01;
status = 0x00;
- data = 0x00;
cmd_buffer = track_buffer = sector_buffer = -1;
counter = 0;
status_type_1 = true;
@@ -175,26 +241,30 @@ WRITE_LINE_MEMBER(wd_fdc_device_base::mr_w)
mr = false;
// gnd == enmf enabled, otherwise disabled (default)
- if (!enmf_cb.isnull() && has_enmf)
+ if (!enmf_cb.isunset() && has_enmf)
enmf = enmf_cb() ? false : true;
intrq = false;
- if (!intrq_cb.isnull())
- {
- intrq_cb(intrq);
- }
+ intrq_cb(intrq);
drq = false;
- if (!drq_cb.isnull())
- {
- drq_cb(drq);
+ drq_cb(drq);
+ if(head_control) {
+ hld = false;
+ hld_cb(hld);
}
- hld = false;
+
+ mon_cb(1); // Clear the MON* line
+
intrq_cond = 0;
live_abort();
} else if(state && !mr) {
- // trigger a restore after everything else is reset too, in particular the floppy device itself
- sub_state = INITIAL_RESTORE;
- t_gen->adjust(attotime::zero);
+ // WD1770/72 (supposedly) not perform RESTORE after reset
+ if (!motor_control) {
+ // trigger a restore after everything else is reset too, in particular the floppy device itself
+ status |= S_BUSY;
+ sub_state = INITIAL_RESTORE;
+ t_gen->adjust(attotime::zero);
+ }
mr = true;
}
}
@@ -216,6 +286,9 @@ void wd_fdc_device_base::set_floppy(floppy_image_device *_floppy)
int next_ready = floppy ? floppy->ready_r() : 1;
+ if (motor_control)
+ mon_cb(status & S_MON ? 0 : 1);
+
if(floppy) {
if(motor_control && !disable_motor_control)
floppy->mon_w(status & S_MON ? 0 : 1);
@@ -227,7 +300,7 @@ void wd_fdc_device_base::set_floppy(floppy_image_device *_floppy)
ready_callback(floppy, next_ready);
}
-WRITE_LINE_MEMBER(wd_fdc_device_base::dden_w)
+void wd_fdc_device_base::dden_w(int state)
{
if(disable_mfm) {
logerror("Error, this chip does not have a dden line\n");
@@ -240,31 +313,35 @@ WRITE_LINE_MEMBER(wd_fdc_device_base::dden_w)
}
}
-std::string wd_fdc_device_base::tts(const attotime &t)
+TIMER_CALLBACK_MEMBER(wd_fdc_device_base::generic_tick)
{
- char buf[256];
- int nsec = t.attoseconds() / ATTOSECONDS_PER_NANOSECOND;
- sprintf(buf, "%4d.%03d,%03d,%03d", int(t.seconds()), nsec/1000000, (nsec/1000)%1000, nsec % 1000);
- return buf;
+ LOGEVENT("Event fired for TM_GEN\n");
+ live_sync();
+ do_generic();
+ general_continue();
}
-std::string wd_fdc_device_base::ttsn()
+TIMER_CALLBACK_MEMBER(wd_fdc_device_base::cmd_w_tick)
{
- return tts(machine().time());
+ LOGEVENT("Event fired for TM_CMD\n");
+ live_sync();
+ do_cmd_w();
+ general_continue();
}
-void wd_fdc_device_base::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(wd_fdc_device_base::track_w_tick)
{
- LOGEVENT("Event fired for timer %s\n", (id==TM_GEN)? "TM_GEN" : (id==TM_CMD)? "TM_CMD" : (id==TM_TRACK)? "TM_TRACK" : "TM_SECTOR");
+ LOGEVENT("Event fired for TM_TRACK\n");
live_sync();
+ do_track_w();
+ general_continue();
+}
- switch(id) {
- case TM_GEN: do_generic(); break;
- case TM_CMD: do_cmd_w(); break;
- case TM_TRACK: do_track_w(); break;
- case TM_SECTOR: do_sector_w(); break;
- }
-
+TIMER_CALLBACK_MEMBER(wd_fdc_device_base::sector_w_tick)
+{
+ LOGEVENT("Event fired for TM_SECTOR\n");
+ live_sync();
+ do_sector_w();
general_continue();
}
@@ -274,28 +351,28 @@ void wd_fdc_device_base::command_end()
main_state = sub_state = IDLE;
motor_timeout = 0;
- if (!drq) {
- status &= ~S_BUSY;
+ if(status & S_BUSY) {
+ if (!t_cmd->enabled()) {
+ status &= ~S_BUSY;
+ }
intrq = true;
- if(!intrq_cb.isnull())
- intrq_cb(intrq);
+ intrq_cb(intrq);
}
}
void wd_fdc_device_base::seek_start(int state)
{
- LOGCOMMAND("cmd: seek %d %x (track=%d)\n", state, data, track);
+ LOGCOMMAND("cmd: seek %d %x (track=%u)\n", state, data, track);
main_state = state;
status &= ~(S_CRC|S_RNF|S_SPIN);
+ sub_state = motor_control ? SPINUP : SPINUP_DONE;
+ status_type_1 = true;
if(head_control) {
- // TODO get value from HLT callback
- if(command & 8)
- status |= S_HLD;
+ if(BIT(command, 3))
+ set_hld();
else
- status &= ~S_HLD;
+ drop_hld();
}
- sub_state = motor_control ? SPINUP : SPINUP_DONE;
- status_type_1 = true;
seek_continue();
}
@@ -326,8 +403,14 @@ void wd_fdc_device_base::seek_continue()
}
if(main_state == SEEK && track == data) {
- sub_state = SEEK_WAIT_STABILIZATION_TIME;
- delay_cycles(t_gen, 30000);
+ if (command & 0x04) {
+ set_hld();
+ sub_state = SEEK_WAIT_STABILIZATION_TIME;
+ delay_cycles(t_gen, 30000);
+ return;
+ }
+ else
+ sub_state = SEEK_DONE;
}
if(sub_state == SPINUP_DONE) {
@@ -377,6 +460,7 @@ void wd_fdc_device_base::seek_continue()
track = 0;
if(command & 0x04) {
+ set_hld();
sub_state = SEEK_WAIT_STABILIZATION_TIME;
delay_cycles(t_gen, 30000);
return;
@@ -395,15 +479,12 @@ void wd_fdc_device_base::seek_continue()
case SEEK_WAIT_STABILIZATION_TIME_DONE:
LOGSTATE("SEEK_WAIT_STABILIZATION_TIME_DONE\n");
+ // TODO: here should be HLT wait
sub_state = SEEK_DONE;
break;
case SEEK_DONE:
LOGSTATE("SEEK_DONE\n");
- status |= S_HLD;
- hld = true;
- if (!hld_cb.isnull())
- hld_cb(hld);
if(command & 0x04) {
if(!is_ready()) {
status |= S_RNF;
@@ -427,6 +508,7 @@ void wd_fdc_device_base::seek_continue()
if(cur_live.crc) {
status |= S_CRC;
live_start(SEARCH_ADDRESS_MARK_HEADER);
+ LOGCRC("CRC error in seek\n");
return;
}
command_end();
@@ -439,7 +521,7 @@ void wd_fdc_device_base::seek_continue()
return;
default:
- logerror("seek unknown sub-state %d\n", ttsn().c_str(), sub_state);
+ logerror("%s: seek unknown sub-state %d\n", machine().time().to_string(), sub_state);
return;
}
}
@@ -476,9 +558,8 @@ void wd_fdc_device_base::read_sector_start()
main_state = READ_SECTOR;
status &= ~(S_CRC|S_LOST|S_RNF|S_WP|S_DDM);
- drop_drq();
- if(side_control)
- update_sso();
+ update_sso();
+ set_hld();
sub_state = motor_control ? SPINUP : SPINUP_DONE;
status_type_1 = false;
read_sector_continue();
@@ -532,6 +613,7 @@ void wd_fdc_device_base::read_sector_continue()
if(cur_live.crc) {
status |= S_CRC;
live_start(SEARCH_ADDRESS_MARK_HEADER);
+ LOGCRC("CRC error in readsector\n");
return;
}
sector_size = calc_sector_size(cur_live.idbuf[3], command);
@@ -547,8 +629,10 @@ void wd_fdc_device_base::read_sector_continue()
case SECTOR_READ:
LOGSTATE("SECTOR_READ\n");
- if(cur_live.crc)
+ if(cur_live.crc) {
status |= S_CRC;
+ LOGCRC("CRC error in readsector %04X\n",cur_live.crc);
+ }
if(command & 0x10 && !(status & S_RNF)) {
sector++;
@@ -560,7 +644,7 @@ void wd_fdc_device_base::read_sector_continue()
break;
default:
- logerror("read sector unknown sub-state %d\n", ttsn().c_str(), sub_state);
+ logerror("%s: read sector unknown sub-state %d\n", machine().time().to_string(), sub_state);
return;
}
}
@@ -577,9 +661,8 @@ void wd_fdc_device_base::read_track_start()
main_state = READ_TRACK;
status &= ~(S_LOST|S_RNF);
- drop_drq();
- if(side_control)
- update_sso();
+ update_sso();
+ set_hld();
sub_state = motor_control ? SPINUP : SPINUP_DONE;
status_type_1 = false;
read_track_continue();
@@ -639,7 +722,7 @@ void wd_fdc_device_base::read_track_continue()
return;
default:
- logerror("read track unknown sub-state %d\n", ttsn().c_str(), sub_state);
+ logerror("%s: read track unknown sub-state %d\n", machine().time().to_string(), sub_state);
return;
}
}
@@ -656,9 +739,8 @@ void wd_fdc_device_base::read_id_start()
main_state = READ_ID;
status &= ~(S_WP|S_DDM|S_LOST|S_RNF);
- drop_drq();
- if(side_control)
- update_sso();
+ update_sso();
+ set_hld();
sub_state = motor_control ? SPINUP : SPINUP_DONE;
status_type_1 = false;
read_id_continue();
@@ -716,7 +798,7 @@ void wd_fdc_device_base::read_id_continue()
return;
default:
- logerror("read id unknown sub-state %d\n", ttsn().c_str(), sub_state);
+ logerror("%s: read id unknown sub-state %d\n", machine().time().to_string(), sub_state);
return;
}
}
@@ -733,9 +815,8 @@ void wd_fdc_device_base::write_track_start()
main_state = WRITE_TRACK;
status &= ~(S_WP|S_DDM|S_LOST|S_RNF);
- drop_drq();
- if(side_control)
- update_sso();
+ update_sso();
+ set_hld();
sub_state = motor_control ? SPINUP : SPINUP_DONE;
status_type_1 = false;
@@ -780,11 +861,27 @@ void wd_fdc_device_base::write_track_continue()
case SETTLE_DONE:
LOGSTATE("SETTLE_DONE\n");
+ if (floppy && floppy->wpt_r()) {
+ LOGSTATE("WRITE_PROT\n");
+ sub_state = WRITE_PROTECT_WAIT;
+ delay_cycles(t_gen, 145);
+ return;
+ }
set_drq();
sub_state = DATA_LOAD_WAIT;
delay_cycles(t_gen, 192);
return;
+ case WRITE_PROTECT_WAIT:
+ LOGSTATE("WRITE_PROTECT_WAIT\n");
+ return;
+
+ case WRITE_PROTECT_DONE:
+ LOGSTATE("WRITE_PROTECT_DONE\n");
+ status |= S_WP;
+ command_end();
+ return;
+
case DATA_LOAD_WAIT:
LOGSTATE("DATA_LOAD_WAIT\n");
return;
@@ -816,17 +913,18 @@ void wd_fdc_device_base::write_track_continue()
if(format_last_byte_count) {
char buf[32];
if(format_last_byte_count > 1)
- sprintf(buf, "%dx%02x", format_last_byte_count, format_last_byte);
+ snprintf(buf, 32, "%dx%02x", format_last_byte_count, format_last_byte);
else
- sprintf(buf, "%02x", format_last_byte);
+ snprintf(buf, 32, "%02x", format_last_byte);
format_description_string += buf;
}
LOGDESC("track description %s\n", format_description_string.c_str());
+ drop_drq();
command_end();
return;
default:
- logerror("write track unknown sub-state %d\n", ttsn().c_str(), sub_state);
+ logerror("%s: write track unknown sub-state %d\n", machine().time().to_string(), sub_state);
return;
}
}
@@ -844,9 +942,8 @@ void wd_fdc_device_base::write_sector_start()
main_state = WRITE_SECTOR;
status &= ~(S_CRC|S_LOST|S_RNF|S_WP|S_DDM);
- drop_drq();
- if(side_control)
- update_sso();
+ update_sso();
+ set_hld();
sub_state = motor_control ? SPINUP : SPINUP_DONE;
status_type_1 = false;
write_sector_continue();
@@ -886,11 +983,27 @@ void wd_fdc_device_base::write_sector_continue()
case SETTLE_DONE:
LOGSTATE("SETTLE_DONE\n");
+ if (floppy && floppy->wpt_r()) {
+ LOGSTATE("WRITE_PROT\n");
+ sub_state = WRITE_PROTECT_WAIT;
+ delay_cycles(t_gen, 145);
+ return;
+ }
sub_state = SCAN_ID;
counter = 0;
live_start(SEARCH_ADDRESS_MARK_HEADER);
return;
+ case WRITE_PROTECT_WAIT:
+ LOGSTATE("WRITE_PROTECT_WAIT\n");
+ return;
+
+ case WRITE_PROTECT_DONE:
+ LOGSTATE("WRITE_PROTECT_DONE\n");
+ status |= S_WP;
+ command_end();
+ return;
+
case SCAN_ID:
LOGSTATE("SCAN_ID\n");
if(!sector_matches()) {
@@ -900,6 +1013,7 @@ void wd_fdc_device_base::write_sector_continue()
if(cur_live.crc) {
status |= S_CRC;
live_start(SEARCH_ADDRESS_MARK_HEADER);
+ LOGCRC("CRC error in writesector\n");
return;
}
sector_size = calc_sector_size(cur_live.idbuf[3], command);
@@ -925,7 +1039,7 @@ void wd_fdc_device_base::write_sector_continue()
break;
default:
- logerror("write sector unknown sub-state %d\n", ttsn().c_str(), sub_state);
+ logerror("%s: write sector unknown sub-state %d\n", machine().time().to_string(), sub_state);
return;
}
}
@@ -933,43 +1047,60 @@ void wd_fdc_device_base::write_sector_continue()
void wd_fdc_device_base::interrupt_start()
{
+ // technically we should re-execute this (at chip-specific rate) all the time while interrupt command code is in command register
+
LOGCOMMAND("cmd: forced interrupt (c=%02x)\n", command);
+ // If writing a byte to a sector, then wait until it's written before terminating
+ // This behavior is required by the RM nimbus driver, otherwise the forced interrupt
+ // at the end of a multiple sector write occasionally prevents the CRC byte being
+ // written, causing the disk to be corrupted.
+ if(/*((main_state == READ_SECTOR) && (cur_live.state == READ_SECTOR_DATA)) ||*/
+ ((main_state == WRITE_SECTOR) && (cur_live.state == WRITE_BYTE))) {
+ delay_int = true;
+ return;
+ } else {
+ delay_int = false;
+ }
+
+ //logerror("main_state=%s, cur_live.state=%s\n",states[main_state],states[cur_live.state]);
+
if(status & S_BUSY) {
main_state = sub_state = cur_live.state = IDLE;
cur_live.tm = attotime::never;
status &= ~S_BUSY;
- drop_drq();
motor_timeout = 0;
- }
- else
- {
+ } else {
// when a force interrupt command is issued and there is no
// currently running command, return the status type 1 bits
status_type_1 = true;
+ drop_drq();
}
- int intcond = command & 0x0f;
- if (!nonsticky_immint) {
- if(intcond == 0)
- intrq_cond = 0;
- else
- intrq_cond = (intrq_cond & I_IMM) | intcond;
- } else {
- if (intcond < 8)
- intrq_cond = intcond;
- else
- intrq_cond = 0;
- }
+ intrq_cond = command & 0x0f;
- if(command & I_IMM) {
+ if(!intrq && (command & I_IMM)) {
intrq = true;
- if(!intrq_cb.isnull())
- intrq_cb(intrq);
+ intrq_cb(intrq);
+ }
+
+ if(spinup_on_interrupt) { // see notes in FD1771 and WD1772 constructors, might be true for other FDC types as well.
+ motor_timeout = 0;
+
+ if (head_control)
+ set_hld();
+
+ if(motor_control) {
+ status |= S_MON | S_SPIN;
+
+ mon_cb(0);
+ if (floppy && !disable_motor_control)
+ floppy->mon_w(0);
+ }
}
if(command & 0x03) {
- logerror("%s: unhandled interrupt generation (%02x)\n", ttsn().c_str(), command);
+ logerror("%s: unhandled interrupt generation (%02x)\n", machine().time().to_string(), command);
}
}
@@ -1004,7 +1135,7 @@ void wd_fdc_device_base::general_continue()
write_sector_continue();
break;
default:
- logerror("%s: general_continue on unknown main-state %d\n", ttsn().c_str(), main_state);
+ logerror("%s: general_continue on unknown main-state %d\n", machine().time().to_string(), main_state);
break;
}
}
@@ -1021,6 +1152,10 @@ void wd_fdc_device_base::do_generic()
sub_state = SETTLE_DONE;
break;
+ case WRITE_PROTECT_WAIT:
+ sub_state = WRITE_PROTECT_DONE;
+ break;
+
case SEEK_WAIT_STEP_TIME:
sub_state = SEEK_WAIT_STEP_TIME_DONE;
break;
@@ -1040,23 +1175,28 @@ void wd_fdc_device_base::do_generic()
default:
if(cur_live.tm.is_never())
- logerror("%s: do_generic on unknown sub-state %d\n", ttsn().c_str(), sub_state);
+ logerror("%s: do_generic on unknown sub-state %d\n", machine().time().to_string(), sub_state);
break;
}
}
void wd_fdc_device_base::do_cmd_w()
{
+ // it is actually possible to send another command even while in busy state.
+ // currently we simply accept any commands, but chip logic is probably more complex
+ // (presumably it is only possible change to a command of the same type).
+#if 0
// Only available command when busy is interrupt
if(main_state != IDLE && (cmd_buffer & 0xf0) != 0xd0) {
cmd_buffer = -1;
return;
}
+#endif
command = cmd_buffer;
cmd_buffer = -1;
- LOGCOMMAND("%s %02x: %s\n", FUNCNAME, cmd_buffer, std::array<char const *, 16>
- {{"RESTORE", "SEEK", "STEP", "STEP", "STEP", "STEP", "STEP", "STEP",
+ LOGCOMMAND("%s %02x: %s\n", FUNCNAME, command, std::array<char const *, 16>
+ {{"RESTORE", "SEEK", "STEP", "STEP", "STEP in", "STEP in", "STEP out", "STEP out",
"READ sector start", "READ sector start", "WRITE sector start", "WRITE sector start",
"READ ID start", "INTERRUPT start", "READ track start", "WRITE track start"}}[(command >> 4) & 0x0f]);
switch(command & 0xf0) {
@@ -1107,7 +1247,7 @@ void wd_fdc_device_base::do_cmd_w()
void wd_fdc_device_base::cmd_w(uint8_t val)
{
- if (inverted_bus) val ^= 0xff;
+ val ^= bus_invert_value;
if (!mr) {
logerror("Not initiating command %02x during master reset\n", val);
return;
@@ -1115,10 +1255,17 @@ void wd_fdc_device_base::cmd_w(uint8_t val)
LOGCOMP("Initiating command %02x\n", val);
- if(intrq && !(intrq_cond & I_IMM)) {
+ // INTRQ flip-flop logic from die schematics:
+ // Reset conditions:
+ // - Command register write
+ // - Status register read
+ // Setting conditions:
+ // - While command register contain Dx (interrupt cmd) and one or more I0-I3 conditions met
+ // - Command-specific based on PLL microprogram
+ // No other logic present in real chips, descriptions of "Forced interrupt" (Dx) command in datasheets are wrong.
+ if (intrq) {
intrq = false;
- if(!intrq_cb.isnull())
- intrq_cb(intrq);
+ intrq_cb(intrq);
}
// No more than one write in flight, but interrupts take priority
@@ -1129,11 +1276,13 @@ void wd_fdc_device_base::cmd_w(uint8_t val)
if ((val & 0xf0) == 0xd0)
{
- // force interrupt is executed instantly (?)
- delay_cycles(t_cmd, 0);
+ // checkme timings
+ delay_cycles(t_cmd, dden ? delay_register_commit * 2 : delay_register_commit);
}
else
{
+ intrq_cond = 0;
+ drop_drq();
// set busy, then set a timer to process the command
status |= S_BUSY;
delay_cycles(t_cmd, dden ? delay_command_commit*2 : delay_command_commit);
@@ -1144,8 +1293,7 @@ uint8_t wd_fdc_device_base::status_r()
{
if(intrq && !(intrq_cond & I_IMM) && !machine().side_effects_disabled()) {
intrq = false;
- if(!intrq_cb.isnull())
- intrq_cb(intrq);
+ intrq_cb(intrq);
}
if(status_type_1) {
@@ -1160,6 +1308,14 @@ uint8_t wd_fdc_device_base::status_r()
status &= ~S_DRQ;
}
+ if (status_type_1 && head_control)
+ { // note: this status bit is AND of HLD latch and HLT input line
+ if (hld && hlt)
+ status |= S_HLD;
+ else
+ status &= ~S_HLD;
+ }
+
if(status_type_1) {
status &= ~(S_TR00|S_WP);
if(floppy) {
@@ -1177,8 +1333,9 @@ uint8_t wd_fdc_device_base::status_r()
status &= ~S_NRDY;
}
- uint8_t val = status;
- if (inverted_bus) val ^= 0xff;
+ uint8_t val = status ^ bus_invert_value;
+
+ LOGCOMP("Status value: %02X\n",val);
return val;
}
@@ -1191,22 +1348,17 @@ void wd_fdc_device_base::do_track_w()
void wd_fdc_device_base::track_w(uint8_t val)
{
- if (inverted_bus) val ^= 0xff;
-
// No more than one write in flight
if(track_buffer != -1 || !mr)
return;
- track_buffer = val;
+ track_buffer = val ^ bus_invert_value;
delay_cycles(t_track, dden ? delay_register_commit*2 : delay_register_commit);
}
uint8_t wd_fdc_device_base::track_r()
{
- uint8_t val = track;
- if (inverted_bus) val ^= 0xff;
-
- return val;
+ return track ^ bus_invert_value;
}
void wd_fdc_device_base::do_sector_w()
@@ -1219,15 +1371,13 @@ void wd_fdc_device_base::sector_w(uint8_t val)
{
if (!mr) return;
- if (inverted_bus) val ^= 0xff;
-
// No more than one write in flight
// C1581 accesses this register with an INC opcode,
// i.e. write old value, write new value, and the new value gets ignored by this
//if(sector_buffer != -1)
// return;
- sector_buffer = val;
+ sector_buffer = val ^ bus_invert_value;
// set a timer to write the new value to the register, but only if we aren't in
// the middle of an already occurring update
@@ -1237,31 +1387,27 @@ void wd_fdc_device_base::sector_w(uint8_t val)
uint8_t wd_fdc_device_base::sector_r()
{
- uint8_t val = sector;
- if (inverted_bus) val ^= 0xff;
-
- return val;
+ return sector ^ bus_invert_value;
}
void wd_fdc_device_base::data_w(uint8_t val)
{
if (!mr) return;
- if (inverted_bus) val ^= 0xff;
-
- data = val;
+ data = val ^ bus_invert_value;
+ LOGDATA("%s: Write %02X to data register (DRQ=%d)\n", machine().describe_context(), data, drq);
drop_drq();
}
uint8_t wd_fdc_device_base::data_r()
{
if (!machine().side_effects_disabled())
+ {
+ LOGDATA("%s: Read %02X from data register (DRQ=%d)\n", machine().describe_context(), data, drq);
drop_drq();
+ }
- uint8_t val = data;
- if (inverted_bus) val ^= 0xff;
-
- return val;
+ return data ^ bus_invert_value;
}
void wd_fdc_device_base::write(offs_t reg, uint8_t val)
@@ -1301,14 +1447,15 @@ void wd_fdc_device_base::spinup()
}
status |= S_MON|S_SPIN;
+
+ mon_cb(0);
if(floppy && !disable_motor_control)
floppy->mon_w(0);
}
void wd_fdc_device_base::ready_callback(floppy_image_device *floppy, int state)
{
- if(!ready_cb.isnull())
- ready_cb(state);
+ ready_cb(state);
// why is this even possible?
if (!floppy)
@@ -1320,8 +1467,7 @@ void wd_fdc_device_base::ready_callback(floppy_image_device *floppy, int state)
if(!intrq && (((intrq_cond & I_RDY) && !state) || ((intrq_cond & I_NRDY) && state))) {
intrq = true;
- if(!intrq_cb.isnull())
- intrq_cb(intrq);
+ intrq_cb(intrq);
}
}
@@ -1330,7 +1476,7 @@ void wd_fdc_device_base::index_callback(floppy_image_device *floppy, int state)
live_sync();
if(!state) {
- general_continue();
+ //general_continue();
return;
}
@@ -1338,28 +1484,21 @@ void wd_fdc_device_base::index_callback(floppy_image_device *floppy, int state)
case IDLE:
if(motor_control || head_control) {
motor_timeout ++;
- if(motor_control && motor_timeout >= 5) {
+ // Spindown delay is 9 revs according to spec
+ if(motor_control && motor_timeout >= 8) {
status &= ~S_MON;
+ mon_cb(1);
if(floppy && !disable_motor_control)
floppy->mon_w(1);
}
- if (head_control && motor_timeout >= 3)
- {
- hld = false;
-
- // signal drive to unload head
- if (!hld_cb.isnull())
- hld_cb(hld);
-
- status &= ~S_HLD; // todo: should get this value from the drive
- }
+ if(head_control && motor_timeout >= hld_timeout)
+ drop_hld();
}
if(!intrq && (intrq_cond & I_IDX)) {
intrq = true;
- if(!intrq_cb.isnull())
- intrq_cb(intrq);
+ intrq_cb(intrq);
}
break;
@@ -1378,6 +1517,8 @@ void wd_fdc_device_base::index_callback(floppy_image_device *floppy, int state)
case SPINUP_DONE:
case SETTLE_WAIT:
case SETTLE_DONE:
+ case WRITE_PROTECT_WAIT:
+ case WRITE_PROTECT_DONE:
case DATA_LOAD_WAIT:
case DATA_LOAD_WAIT_DONE:
case SEEK_MOVE:
@@ -1408,35 +1549,38 @@ void wd_fdc_device_base::index_callback(floppy_image_device *floppy, int state)
live_abort();
break;
+ case DUMMY:
+ return;
+
default:
- logerror("%s: Index pulse on unknown sub-state %d\n", ttsn().c_str(), sub_state);
+ logerror("%s: Index pulse on unknown sub-state %d\n", machine().time().to_string(), sub_state);
break;
}
general_continue();
}
-READ_LINE_MEMBER(wd_fdc_device_base::intrq_r)
+int wd_fdc_device_base::intrq_r()
{
return intrq;
}
-READ_LINE_MEMBER(wd_fdc_device_base::drq_r)
+int wd_fdc_device_base::drq_r()
{
return drq;
}
-READ_LINE_MEMBER(wd_fdc_device_base::hld_r)
+int wd_fdc_device_base::hld_r()
{
return hld;
}
-WRITE_LINE_MEMBER(wd_fdc_device_base::hlt_w)
+void wd_fdc_device_base::hlt_w(int state)
{
hlt = bool(state);
}
-READ_LINE_MEMBER(wd_fdc_device_base::enp_r)
+int wd_fdc_device_base::enp_r()
{
return enp;
}
@@ -1456,7 +1600,7 @@ void wd_fdc_device_base::live_start(int state)
cur_live.data_bit_context = false;
cur_live.byte_counter = 0;
- if (!enmf_cb.isnull() && has_enmf)
+ if (!enmf_cb.isunset() && has_enmf)
enmf = enmf_cb() ? false : true;
pll_reset(dden, enmf, cur_live.tm);
@@ -1490,12 +1634,12 @@ void wd_fdc_device_base::live_sync()
{
if(!cur_live.tm.is_never()) {
if(cur_live.tm > machine().time()) {
- LOGSYNC("%s: Rolling back and replaying (%s)\n", ttsn().c_str(), tts(cur_live.tm).c_str());
+ LOGSYNC("%s: Rolling back and replaying (%s)\n", machine().time().to_string(), cur_live.tm.to_string());
rollback();
live_run(machine().time());
pll_commit(floppy, cur_live.tm);
} else {
- LOGSYNC("%s: Committing (%s)\n", ttsn().c_str(), tts(cur_live.tm).c_str());
+ LOGSYNC("%s: Committing (%s)\n", machine().time().to_string(), cur_live.tm.to_string());
pll_commit(floppy, cur_live.tm);
if(cur_live.next_state != -1) {
cur_live.state = cur_live.next_state;
@@ -1542,6 +1686,14 @@ bool wd_fdc_device_base::read_one_bit(const attotime &limit)
return false;
}
+void wd_fdc_device_base::reset_data_sync()
+{
+ cur_live.data_separator_phase = false;
+ cur_live.bit_counter = 0;
+
+ cur_live.data_reg = cur_live.shift_reg_data();
+}
+
bool wd_fdc_device_base::write_one_bit(const attotime &limit)
{
bool bit = cur_live.shift_reg & 0x8000;
@@ -1616,7 +1768,7 @@ void wd_fdc_device_base::live_run(attotime limit)
}
}
- // fprintf(stderr, "%s: live_run(%s)\n", ttsn().c_str(), tts(limit).c_str());
+ // logerror("%s: live_run(%s)\n", machine().time().to_string(), limit.to_string());
for(;;) {
switch(cur_live.state) {
@@ -1625,28 +1777,19 @@ void wd_fdc_device_base::live_run(attotime limit)
if(read_one_bit(limit))
return;
- LOGSHIFT("%s: shift = %04x data=%02x c=%d\n", tts(cur_live.tm).c_str(), cur_live.shift_reg,
- (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) |
- (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) |
- (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) |
- (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) |
- (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) |
- (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) |
- (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) |
- (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00),
+ LOGSHIFT("%s: shift = %08x data=%02x c=%d\n", cur_live.tm.to_string(), cur_live.shift_reg,
+ cur_live.shift_reg_data(),
cur_live.bit_counter);
- if(!dden && cur_live.shift_reg == 0x4489) {
+ if(!dden && cur_live.shift_reg_low<16>() == 0x4489) {
cur_live.crc = 0x443b;
- cur_live.data_separator_phase = false;
- cur_live.bit_counter = 0;
+ reset_data_sync();
cur_live.state = READ_HEADER_BLOCK_HEADER;
}
- if(dden && cur_live.shift_reg == 0xf57e) {
+ if(dden && cur_live.shift_reg_low<23>() == 0x2af57e) {
cur_live.crc = 0xef21;
- cur_live.data_separator_phase = false;
- cur_live.bit_counter = 0;
+ reset_data_sync();
if(main_state == READ_ID)
cur_live.state = READ_ID_BLOCK_TO_DMA;
else
@@ -1659,15 +1802,8 @@ void wd_fdc_device_base::live_run(attotime limit)
if(read_one_bit(limit))
return;
- LOGSHIFT("%s: shift = %04x data=%02x counter=%d\n", tts(cur_live.tm).c_str(), cur_live.shift_reg,
- (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) |
- (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) |
- (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) |
- (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) |
- (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) |
- (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) |
- (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) |
- (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00),
+ LOGSHIFT("%s: shift = %08x data=%02x counter=%d\n", cur_live.tm.to_string(), cur_live.shift_reg,
+ cur_live.shift_reg_data(),
cur_live.bit_counter);
if(cur_live.bit_counter & 15)
@@ -1676,7 +1812,7 @@ void wd_fdc_device_base::live_run(attotime limit)
int slot = cur_live.bit_counter >> 4;
if(slot < 3) {
- if(cur_live.shift_reg != 0x4489)
+ if(cur_live.shift_reg_low<16>() != 0x4489)
cur_live.state = SEARCH_ADDRESS_MARK_HEADER;
break;
}
@@ -1702,7 +1838,7 @@ void wd_fdc_device_base::live_run(attotime limit)
if(cur_live.bit_counter & 15)
break;
int slot = (cur_live.bit_counter >> 4)-1;
- // fprintf(stderr, "%s: slot[%d] = %02x crc = %04x\n", tts(cur_live.tm).c_str(), slot, cur_live.data_reg, cur_live.crc);
+ // logerror("%s: slot[%d] = %02x crc = %04x\n", cur_live.tm.to_string(), slot, cur_live.data_reg, cur_live.crc);
cur_live.idbuf[slot] = cur_live.data_reg;
if(slot == 5) {
live_delay(IDLE);
@@ -1730,6 +1866,7 @@ void wd_fdc_device_base::live_run(attotime limit)
if(cur_live.bit_counter == 16*6) {
if(cur_live.crc) {
status |= S_CRC;
+ LOGCRC("CRC error in live_run\n");
}
// Already synchronous
@@ -1746,15 +1883,8 @@ void wd_fdc_device_base::live_run(attotime limit)
if(read_one_bit(limit))
return;
- LOGSHIFT("%s: shift = %04x data=%02x c=%d.%x\n", tts(cur_live.tm).c_str(), cur_live.shift_reg,
- (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) |
- (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) |
- (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) |
- (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) |
- (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) |
- (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) |
- (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) |
- (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00),
+ LOGSHIFT("%s: shift = %08x data=%02x c=%d.%x\n", cur_live.tm.to_string(), cur_live.shift_reg,
+ cur_live.shift_reg_data(),
cur_live.bit_counter >> 4, cur_live.bit_counter & 15);
if(!dden) {
@@ -1763,10 +1893,9 @@ void wd_fdc_device_base::live_run(attotime limit)
return;
}
- if(cur_live.bit_counter >= 28*16 && cur_live.shift_reg == 0x4489) {
+ if(cur_live.bit_counter >= 28*16 && cur_live.shift_reg_low<16>() == 0x4489) {
cur_live.crc = 0x443b;
- cur_live.data_separator_phase = false;
- cur_live.bit_counter = 0;
+ reset_data_sync();
cur_live.state = READ_DATA_BLOCK_HEADER;
}
} else {
@@ -1775,19 +1904,24 @@ void wd_fdc_device_base::live_run(attotime limit)
return;
}
- if(cur_live.bit_counter >= 11*16 && (cur_live.shift_reg == 0xf56a || cur_live.shift_reg == 0xf56b ||
- cur_live.shift_reg == 0xf56e || cur_live.shift_reg == 0xf56f)) {
+ if(cur_live.bit_counter >= 11*16 && (cur_live.shift_reg_low<16>() == 0xf56a || cur_live.shift_reg_low<16>() == 0xf56b ||
+ cur_live.shift_reg_low<16>() == 0xf56e || cur_live.shift_reg_low<16>() == 0xf56f)) {
cur_live.crc =
- cur_live.shift_reg == 0xf56a ? 0x8fe7 :
- cur_live.shift_reg == 0xf56b ? 0x9fc6 :
- cur_live.shift_reg == 0xf56e ? 0xafa5 :
+ cur_live.shift_reg_low<16>() == 0xf56a ? 0x8fe7 :
+ cur_live.shift_reg_low<16>() == 0xf56b ? 0x9fc6 :
+ cur_live.shift_reg_low<16>() == 0xf56e ? 0xafa5 :
0xbf84;
- if((cur_live.data_reg & 0xfe) == 0xf8)
+ reset_data_sync();
+
+ if(extended_ddam) {
+ if(!(cur_live.data_reg & 1))
+ status |= S_DDM;
+ if(!(cur_live.data_reg & 2))
+ status |= S_DDM << 1;
+ } else if((cur_live.data_reg & 0xfe) == 0xf8)
status |= S_DDM;
- cur_live.data_separator_phase = false;
- cur_live.bit_counter = 0;
cur_live.state = READ_SECTOR_DATA;
}
}
@@ -1798,15 +1932,8 @@ void wd_fdc_device_base::live_run(attotime limit)
if(read_one_bit(limit))
return;
- LOGSHIFT("%s: shift = %04x data=%02x counter=%d\n", tts(cur_live.tm).c_str(), cur_live.shift_reg,
- (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) |
- (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) |
- (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) |
- (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) |
- (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) |
- (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) |
- (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) |
- (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00),
+ LOGSHIFT("%s: shift = %08x data=%02x counter=%d\n", cur_live.tm.to_string(), cur_live.shift_reg,
+ cur_live.shift_reg_data(),
cur_live.bit_counter);
if(cur_live.bit_counter & 15)
@@ -1815,7 +1942,7 @@ void wd_fdc_device_base::live_run(attotime limit)
int slot = cur_live.bit_counter >> 4;
if(slot < 3) {
- if(cur_live.shift_reg != 0x4489) {
+ if(cur_live.shift_reg_low<16>() != 0x4489) {
live_delay(SEARCH_ADDRESS_MARK_DATA_FAILED);
return;
}
@@ -1854,7 +1981,12 @@ void wd_fdc_device_base::live_run(attotime limit)
} else if(slot < sector_size+2) {
// CRC
if(slot == sector_size+1) {
- live_delay(IDLE);
+ // act on delayed interrupt if active
+/* if(delay_int) {
+ interrupt_start();
+ return;
+ }
+*/ live_delay(IDLE);
return;
}
}
@@ -1874,14 +2006,26 @@ void wd_fdc_device_base::live_run(attotime limit)
if(read_one_bit(limit))
return;
+ if(dden) {
+ //FM Prefix match
+ if(cur_live.shift_reg_low<17>() == 0xabd5) { // 17-bit match
+ cur_live.data_separator_phase = false;
+ cur_live.bit_counter = 5*2; // prefix is 5 of 8 bits
+ cur_live.data_reg = 0xff;
+ break;
+ } else if(cur_live.bit_counter == 16) {
+ cur_live.data_separator_phase = false;
+ cur_live.bit_counter = 0;
+ live_delay(READ_TRACK_DATA_BYTE);
+ return;
+ }
+ break;
+ }
+ // !dden
if(cur_live.bit_counter != 16
// MFM resyncs
- && !(!dden && (cur_live.shift_reg == 0x4489
- || cur_live.shift_reg == 0x5224))
- // FM resyncs
- && !(dden && (cur_live.shift_reg == 0xf57e // FM IDAM
- || cur_live.shift_reg == 0xf56f // FM DAM
- || cur_live.shift_reg == 0xf56a)) // FM DDAM
+ && !((cur_live.shift_reg_low<16>() == 0x4489
+ || cur_live.shift_reg_low<16>() == 0x5224))
)
break;
@@ -1898,8 +2042,7 @@ void wd_fdc_device_base::live_run(attotime limit)
// MZ: TI99 "DISkASSEMBLER" copy protection requires a threshold of 8
bool output_byte = cur_live.bit_counter > 8;
- cur_live.data_separator_phase = false;
- cur_live.bit_counter = 0;
+ reset_data_sync();
if(output_byte) {
live_delay(READ_TRACK_DATA_BYTE);
@@ -1925,9 +2068,9 @@ void wd_fdc_device_base::live_run(attotime limit)
if(format_last_byte_count) {
char buf[32];
if(format_last_byte_count > 1)
- sprintf(buf, "%dx%02x ", format_last_byte_count, format_last_byte);
+ snprintf(buf, 32, "%dx%02x ", format_last_byte_count, format_last_byte);
else
- sprintf(buf, "%02x ", format_last_byte);
+ snprintf(buf, 32, "%02x ", format_last_byte);
format_description_string += buf;
}
format_last_byte = data;
@@ -2048,7 +2191,11 @@ void wd_fdc_device_base::live_run(attotime limit)
live_write_fm(0x00);
else if(cur_live.byte_counter < 7) {
cur_live.crc = 0xffff;
- live_write_raw(command & 1 ? 0xf56a : 0xf56f);
+ if(extended_ddam) {
+ static const uint16_t dam[4] = { 0xf56f, 0xf56e, 0xf56b, 0xf56a };
+ live_write_raw(dam[command & 3]);
+ } else
+ live_write_raw(command & 1 ? 0xf56a : 0xf56f);
} else if(cur_live.byte_counter < sector_size + 7-1) {
if(drq) {
status |= S_LOST;
@@ -2069,6 +2216,11 @@ void wd_fdc_device_base::live_run(attotime limit)
else {
pll_stop_writing(floppy, cur_live.tm);
cur_live.state = IDLE;
+
+ // Act on delayed interrupt if set.
+ if(delay_int)
+ interrupt_start();
+
return;
}
@@ -2098,9 +2250,15 @@ void wd_fdc_device_base::live_run(attotime limit)
live_write_mfm(cur_live.crc >> 8);
else if(cur_live.byte_counter < sector_size + 16+3)
live_write_mfm(0xff);
+// live_write_mfm(0x4e);
else {
pll_stop_writing(floppy, cur_live.tm);
cur_live.state = IDLE;
+
+ // Act on delayed interrupt if set.
+ if(delay_int)
+ interrupt_start();
+
return;
}
}
@@ -2110,7 +2268,7 @@ void wd_fdc_device_base::live_run(attotime limit)
break;
default:
- logerror("%s: Unknown sub state %d in WRITE_BYTE_DONE\n", tts(cur_live.tm).c_str(), sub_state);
+ logerror("%s: Unknown sub state %d in WRITE_BYTE_DONE\n", cur_live.tm.to_string(), sub_state);
live_abort();
return;
}
@@ -2173,7 +2331,7 @@ void wd_fdc_device_base::live_run(attotime limit)
break;
default:
- logerror("%s: Unknown live state %d\n", tts(cur_live.tm).c_str(), cur_live.state);
+ logerror("%s: Unknown live state %d\n", cur_live.tm.to_string(), cur_live.state);
return;
}
}
@@ -2183,13 +2341,9 @@ void wd_fdc_device_base::set_drq()
{
if(drq) {
status |= S_LOST;
- drq = false;
- if(!drq_cb.isnull())
- drq_cb(false);
} else if(!(status & S_LOST)) {
drq = true;
- if(!drq_cb.isnull())
- drq_cb(true);
+ drq_cb(true);
}
}
@@ -2197,14 +2351,29 @@ void wd_fdc_device_base::drop_drq()
{
if(drq) {
drq = false;
- if(!drq_cb.isnull())
- drq_cb(false);
- if (main_state == IDLE) {
- status &= ~S_BUSY;
- intrq = true;
- if(!intrq_cb.isnull())
- intrq_cb(intrq);
- }
+ drq_cb(false);
+ }
+}
+
+void wd_fdc_device_base::set_hld()
+{
+ if(head_control && !hld) {
+ hld = true;
+ int temp = sub_state;
+ sub_state = DUMMY;
+ hld_cb(hld);
+ sub_state = temp;
+ }
+}
+
+void wd_fdc_device_base::drop_hld()
+{
+ if(head_control && hld) {
+ hld = false;
+ int temp = sub_state;
+ sub_state = DUMMY;
+ hld_cb(hld);
+ sub_state = temp;
}
}
@@ -2220,7 +2389,7 @@ void wd_fdc_device_base::update_sso()
// If a SSO callback is defined then it is assumed that this callback
// will update the floppy side if that is the connection. There are
// some machines that use the SSO output for other purposes.
- if(!sso_cb.isnull()) {
+ if(!sso_cb.isunset()) {
sso_cb(side);
return;
}
@@ -2377,12 +2546,12 @@ int wd_fdc_digital_device_base::digital_pll_t::get_next_bit(attotime &tm, floppy
/*
if(!when.is_never())
- LOGTRANSITION("transition_time=%s\n", tts(when).c_str());
+ LOGTRANSITION("transition_time=%s\n", when.to_string());
*/
for(;;) {
// LOGTRANSITION("slot=%2d, counter=%03x\n", slot, counter);
attotime etime = ctime+delays[slot];
- // LOGTRANSITION("etime=%s\n", tts(etime).c_str());
+ // LOGTRANSITION("etime=%s\n", etime.to_string());
if(etime > limit)
return -1;
if(transition_time == 0xffff && !when.is_never() && etime >= when)
@@ -2477,7 +2646,7 @@ bool wd_fdc_digital_device_base::digital_pll_t::write_next_bit(bool bit, attotim
uint16_t pre_counter = counter;
counter += increment;
if(bit && !(pre_counter & 0x400) && (counter & 0x400))
- if(write_position < ARRAY_LENGTH(write_buffer))
+ if(write_position < std::size(write_buffer))
write_buffer[write_position++] = etime;
slot++;
tm = etime;
@@ -2509,16 +2678,18 @@ fd1771_device::fd1771_device(const machine_config &mconfig, const char *tag, dev
constexpr static int fd1771_step_times[4] = { 12000, 12000, 20000, 40000 };
step_times = fd1771_step_times;
- delay_register_commit = 16;
- delay_command_commit = 20; // x2 due to fm
+ delay_register_commit = 16/2; // will became x2 later due to FM
+ delay_command_commit = 20/2; // same as above
disable_mfm = true;
- inverted_bus = true;
+ bus_invert_value = 0xff;
side_control = false;
side_compare = false;
head_control = true;
+ hld_timeout = 3;
motor_control = false;
ready_hooked = true;
- nonsticky_immint = false;
+ spinup_on_interrupt = true; // ZX-Spectrum Beta-disk V2 require this, or ReadSector command should set HLD before RDY check
+ extended_ddam = true;
}
int fd1771_device::calc_sector_size(uint8_t size, uint8_t command) const
@@ -2537,13 +2708,13 @@ fd1781_device::fd1781_device(const machine_config &mconfig, const char *tag, dev
delay_register_commit = 16;
delay_command_commit = 12;
disable_mfm = false;
- inverted_bus = true;
+ bus_invert_value = 0xff;
side_control = false;
side_compare = false;
head_control = true;
+ hld_timeout = 3;
motor_control = false;
ready_hooked = true;
- nonsticky_immint = false;
}
int fd1781_device::calc_sector_size(uint8_t size, uint8_t command) const
@@ -2564,13 +2735,13 @@ fd1791_device::fd1791_device(const machine_config &mconfig, const char *tag, dev
delay_command_commit = 12;
disable_mfm = false;
has_enmf = false;
- inverted_bus = true;
+ bus_invert_value = 0xff;
side_control = false;
side_compare = true;
head_control = true;
+ hld_timeout = 15;
motor_control = false;
ready_hooked = true;
- nonsticky_immint = false;
}
fd1792_device::fd1792_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : wd_fdc_analog_device_base(mconfig, FD1792, tag, owner, clock)
@@ -2580,13 +2751,13 @@ fd1792_device::fd1792_device(const machine_config &mconfig, const char *tag, dev
delay_command_commit = 12;
disable_mfm = true;
has_enmf = false;
- inverted_bus = true;
+ bus_invert_value = 0xff;
side_control = false;
side_compare = true;
head_control = true;
+ hld_timeout = 15;
motor_control = false;
ready_hooked = true;
- nonsticky_immint = false;
}
fd1793_device::fd1793_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : wd_fdc_analog_device_base(mconfig, FD1793, tag, owner, clock)
@@ -2596,13 +2767,13 @@ fd1793_device::fd1793_device(const machine_config &mconfig, const char *tag, dev
delay_command_commit = 12;
disable_mfm = false;
has_enmf = false;
- inverted_bus = false;
+ bus_invert_value = 0x00;
side_control = false;
side_compare = true;
head_control = true;
+ hld_timeout = 15;
motor_control = false;
ready_hooked = true;
- nonsticky_immint = false;
}
kr1818vg93_device::kr1818vg93_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : wd_fdc_analog_device_base(mconfig, KR1818VG93, tag, owner, clock)
@@ -2612,13 +2783,13 @@ kr1818vg93_device::kr1818vg93_device(const machine_config &mconfig, const char *
delay_command_commit = 12;
disable_mfm = false;
has_enmf = false;
- inverted_bus = false;
+ bus_invert_value = 0x00;
side_control = false;
side_compare = true;
head_control = true;
+ hld_timeout = 15;
motor_control = false;
ready_hooked = true;
- nonsticky_immint = true;
}
fd1794_device::fd1794_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : wd_fdc_analog_device_base(mconfig, FD1794, tag, owner, clock)
@@ -2628,13 +2799,13 @@ fd1794_device::fd1794_device(const machine_config &mconfig, const char *tag, dev
delay_command_commit = 12;
disable_mfm = true;
has_enmf = false;
- inverted_bus = false;
+ bus_invert_value = 0x00;
side_control = false;
side_compare = true;
head_control = true;
+ hld_timeout = 15;
motor_control = false;
ready_hooked = true;
- nonsticky_immint = false;
}
fd1795_device::fd1795_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : wd_fdc_analog_device_base(mconfig, FD1795, tag, owner, clock)
@@ -2644,13 +2815,13 @@ fd1795_device::fd1795_device(const machine_config &mconfig, const char *tag, dev
delay_command_commit = 12;
disable_mfm = false;
has_enmf = false;
- inverted_bus = true;
+ bus_invert_value = 0xff;
side_control = true;
side_compare = false;
head_control = true;
+ hld_timeout = 15;
motor_control = false;
ready_hooked = true;
- nonsticky_immint = false;
}
int fd1795_device::calc_sector_size(uint8_t size, uint8_t command) const
@@ -2668,13 +2839,13 @@ fd1797_device::fd1797_device(const machine_config &mconfig, const char *tag, dev
delay_command_commit = 12;
disable_mfm = false;
has_enmf = false;
- inverted_bus = false;
+ bus_invert_value = 0x00;
side_control = true;
side_compare = false;
head_control = true;
+ hld_timeout = 15;
motor_control = false;
ready_hooked = true;
- nonsticky_immint = false;
}
int fd1797_device::calc_sector_size(uint8_t size, uint8_t command) const
@@ -2692,13 +2863,13 @@ mb8866_device::mb8866_device(const machine_config &mconfig, const char *tag, dev
delay_command_commit = 12;
disable_mfm = false;
has_enmf = false;
- inverted_bus = true;
+ bus_invert_value = 0xff;
side_control = false;
side_compare = true;
head_control = true;
+ hld_timeout = 15;
motor_control = false;
ready_hooked = true;
- nonsticky_immint = false;
}
mb8876_device::mb8876_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : wd_fdc_analog_device_base(mconfig, MB8876, tag, owner, clock)
@@ -2708,13 +2879,13 @@ mb8876_device::mb8876_device(const machine_config &mconfig, const char *tag, dev
delay_command_commit = 12;
disable_mfm = false;
has_enmf = false;
- inverted_bus = true;
+ bus_invert_value = 0xff;
side_control = false;
side_compare = true;
head_control = true;
+ hld_timeout = 15;
motor_control = false;
ready_hooked = true;
- nonsticky_immint = false;
}
mb8877_device::mb8877_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : wd_fdc_analog_device_base(mconfig, MB8877, tag, owner, clock)
@@ -2724,13 +2895,13 @@ mb8877_device::mb8877_device(const machine_config &mconfig, const char *tag, dev
delay_command_commit = 12;
disable_mfm = false;
has_enmf = false;
- inverted_bus = false;
+ bus_invert_value = 0x00;
side_control = false;
side_compare = true;
head_control = true;
+ hld_timeout = 15;
motor_control = false;
ready_hooked = true;
- nonsticky_immint = false;
}
fd1761_device::fd1761_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : wd_fdc_analog_device_base(mconfig, FD1761, tag, owner, clock)
@@ -2740,13 +2911,13 @@ fd1761_device::fd1761_device(const machine_config &mconfig, const char *tag, dev
delay_command_commit = 12;
disable_mfm = false;
has_enmf = false;
- inverted_bus = true;
+ bus_invert_value = 0xff;
side_control = false;
side_compare = true;
head_control = true;
+ hld_timeout = 15;
motor_control = false;
ready_hooked = true;
- nonsticky_immint = false;
}
fd1763_device::fd1763_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : wd_fdc_analog_device_base(mconfig, FD1763, tag, owner, clock)
@@ -2756,13 +2927,13 @@ fd1763_device::fd1763_device(const machine_config &mconfig, const char *tag, dev
delay_command_commit = 12;
disable_mfm = false;
has_enmf = false;
- inverted_bus = false;
+ bus_invert_value = 0x00;
side_control = false;
side_compare = true;
head_control = true;
+ hld_timeout = 15;
motor_control = false;
ready_hooked = true;
- nonsticky_immint = false;
}
fd1765_device::fd1765_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : wd_fdc_analog_device_base(mconfig, FD1765, tag, owner, clock)
@@ -2772,13 +2943,13 @@ fd1765_device::fd1765_device(const machine_config &mconfig, const char *tag, dev
delay_command_commit = 12;
disable_mfm = false;
has_enmf = false;
- inverted_bus = true;
+ bus_invert_value = 0xff;
side_control = true;
side_compare = false;
head_control = true;
+ hld_timeout = 15;
motor_control = false;
ready_hooked = true;
- nonsticky_immint = false;
}
int fd1765_device::calc_sector_size(uint8_t size, uint8_t command) const
@@ -2796,13 +2967,13 @@ fd1767_device::fd1767_device(const machine_config &mconfig, const char *tag, dev
delay_command_commit = 12;
disable_mfm = false;
has_enmf = false;
- inverted_bus = false;
+ bus_invert_value = 0x00;
side_control = true;
side_compare = false;
head_control = true;
+ hld_timeout = 15;
motor_control = false;
ready_hooked = true;
- nonsticky_immint = false;
}
int fd1767_device::calc_sector_size(uint8_t size, uint8_t command) const
@@ -2820,29 +2991,30 @@ wd2791_device::wd2791_device(const machine_config &mconfig, const char *tag, dev
delay_command_commit = 12;
disable_mfm = false;
has_enmf = true;
- inverted_bus = true;
+ bus_invert_value = 0xff;
side_control = false;
side_compare = true;
head_control = true;
+ hld_timeout = 15;
motor_control = false;
ready_hooked = true;
- nonsticky_immint = false;
}
wd2793_device::wd2793_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : wd_fdc_analog_device_base(mconfig, WD2793, tag, owner, clock)
{
step_times = fd179x_step_times;
+
delay_register_commit = 16;
delay_command_commit = 12;
disable_mfm = false;
has_enmf = true;
- inverted_bus = false;
+ bus_invert_value = 0x00;
side_control = false;
side_compare = true;
head_control = true;
+ hld_timeout = 15;
motor_control = false;
ready_hooked = true;
- nonsticky_immint = false;
}
wd2795_device::wd2795_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : wd_fdc_analog_device_base(mconfig, WD2795, tag, owner, clock)
@@ -2852,13 +3024,13 @@ wd2795_device::wd2795_device(const machine_config &mconfig, const char *tag, dev
delay_command_commit = 12;
disable_mfm = false;
has_enmf = false;
- inverted_bus = true;
+ bus_invert_value = 0xff;
side_control = true;
side_compare = false;
head_control = true;
+ hld_timeout = 15;
motor_control = false;
ready_hooked = true;
- nonsticky_immint = false;
}
int wd2795_device::calc_sector_size(uint8_t size, uint8_t command) const
@@ -2876,13 +3048,13 @@ wd2797_device::wd2797_device(const machine_config &mconfig, const char *tag, dev
delay_command_commit = 12;
disable_mfm = false;
has_enmf = false;
- inverted_bus = false;
+ bus_invert_value = 0x00;
side_control = true;
side_compare = false;
head_control = true;
+ hld_timeout = 15;
motor_control = false;
ready_hooked = true;
- nonsticky_immint = false;
}
int wd2797_device::calc_sector_size(uint8_t size, uint8_t command) const
@@ -2896,17 +3068,17 @@ int wd2797_device::calc_sector_size(uint8_t size, uint8_t command) const
wd1770_device::wd1770_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : wd_fdc_digital_device_base(mconfig, WD1770, tag, owner, clock)
{
step_times = wd_digital_step_times;
- delay_register_commit = 32;
+ delay_register_commit = 16;
delay_command_commit = 36; // official 48 is too high for oric jasmin boot
disable_mfm = false;
has_enmf = false;
- inverted_bus = false;
+ bus_invert_value = 0x00;
side_control = false;
side_compare = false;
head_control = false;
+ hld_timeout = 0;
motor_control = true;
ready_hooked = false;
- nonsticky_immint = false;
}
wd1772_device::wd1772_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : wd_fdc_digital_device_base(mconfig, WD1772, tag, owner, clock)
@@ -2914,17 +3086,22 @@ wd1772_device::wd1772_device(const machine_config &mconfig, const char *tag, dev
const static int wd1772_step_times[4] = { 12000, 24000, 4000, 6000 };
step_times = wd1772_step_times;
- delay_register_commit = 32;
+ delay_register_commit = 16;
delay_command_commit = 48;
disable_mfm = false;
has_enmf = false;
- inverted_bus = false;
+ bus_invert_value = 0x00;
side_control = false;
side_compare = false;
head_control = false;
+ hld_timeout = 0;
motor_control = true;
ready_hooked = false;
- nonsticky_immint = false;
+
+ /* Sam Coupe/+D/Disciple expect a 0xd0 force interrupt command to cause a spin-up.
+ eg. +D issues 2x 0xd0, then waits for index pulses to start, bails out with no disk error if that doesn't happen.
+ Not sure if other chips should do this too? */
+ spinup_on_interrupt = true;
}
int wd1772_device::settle_time() const
@@ -2935,15 +3112,15 @@ int wd1772_device::settle_time() const
wd1773_device::wd1773_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : wd_fdc_digital_device_base(mconfig, WD1773, tag, owner, clock)
{
step_times = wd_digital_step_times;
- delay_register_commit = 32;
+ delay_register_commit = 16;
delay_command_commit = 48;
disable_mfm = false;
has_enmf = false;
- inverted_bus = false;
+ bus_invert_value = 0x00;
side_control = false;
side_compare = true;
head_control = false;
+ hld_timeout = 0;
motor_control = false;
ready_hooked = true;
- nonsticky_immint = false;
}