--- xmil/io/fdc.c 2004/08/11 16:09:04 1.9 +++ xmil/io/fdc.c 2009/03/23 15:02:25 1.24 @@ -1,95 +1,364 @@ #include "compiler.h" -#include "dosio.h" #include "z80core.h" #include "pccore.h" #include "iocore.h" #include "nevent.h" #include "fddfile.h" -#include "fdd_2d.h" -#include "fdd_d88.h" #include "fdd_mtr.h" +enum { + FDCCTYPE_CMD1 = 0x01, + FDCCTYPE_CMD2 = 0x02, + FDCCTYPE_CMD3 = 0x04, + FDCCTYPE_CMD4 = 0x08, + + FDCCTYPE_RO = 0x10, + FDCCTYPE_DATA = 0x80 +}; + + +static const UINT8 fdctype[] = { + FDCCTYPE_CMD1, + FDCCTYPE_CMD1, + FDCCTYPE_CMD1, + FDCCTYPE_CMD1, + FDCCTYPE_CMD1, + FDCCTYPE_CMD1, + FDCCTYPE_CMD1, + FDCCTYPE_CMD1, + FDCCTYPE_CMD2 + FDCCTYPE_RO, + FDCCTYPE_CMD2 + FDCCTYPE_RO, + FDCCTYPE_CMD2, + FDCCTYPE_CMD2, + FDCCTYPE_CMD3 + FDCCTYPE_RO, + FDCCTYPE_CMD4, + FDCCTYPE_CMD3 + FDCCTYPE_RO, + FDCCTYPE_CMD3}; + + +/* write track */ + +#if !defined(CONST_DISKIMAGE) +enum { + TAO_MODE_GAP = 0x4e, + TAO_MODE_SYNC = 0x00, + TAO_MODE_AM = 0xf5, + TAO_MODE_IM = 0xf6, + TAO_MODE_ID = 0xfe, + TAO_MODE_DATA = 0xfb, + TAO_ENDOFDATA = 0xf7, + + TAO_CMD_GAP = 0x4e, + TAO_CMD_SYNC = 0x00, + TAO_CMD_IM_IN = 0xf6, + TAO_CMD_IM = 0xfc, + TAO_CMD_AM_IN = 0xf5, + TAO_CMD_IAM = 0xfe, + TAO_CMD_DAM = 0xfb, + TAO_CMD_DDAM = 0xf8, + TAO_CMD_CRC = 0xf7 +}; -static const UINT8 fdctype[] = {1,1,1,1,1,1,1,1,2,2,2,2,3,4,3,3}; +static REG8 wrtrkstart(FDC *f) { -void nvitem_fdcbusy(UINT id) { + FDDFILE fdd; + + fdd = fddfile + f->s.drv; + if ((fdd->type == DISKTYPE_NOTREADY) || (fdd->protect)) { + return(0); + } + f->s.bufdir = FDCDIR_TAO; + f->s.bufpos = 0; + f->s.bufmedia = f->s.media; + f->s.bufunit = f->s.drv; + f->s.buftrack = (f->s.c << 1) + f->s.h; + + f->s.wt_mode = TAO_ENDOFDATA; + f->s.wt_sectors = 0; + f->s.wt_ptr = 0; + f->s.wt_datpos = 0; + f->s.wt_datsize = 0; + ZeroMemory(f->s.buffer, sizeof(f->s.buffer)); + + return(0); +} + +static void wrtrkdata(FDC *f, REG8 data) { + + TAOSEC *t; + REG8 n; + UINT datsize; + FDDFILE fdd; + + switch(f->s.wt_mode) { + case TAO_ENDOFDATA: + if (data == TAO_MODE_GAP) { + f->s.wt_mode = TAO_MODE_GAP; + f->s.wt_ptr = 0; + } + break; + + case TAO_MODE_GAP: + if (data == TAO_MODE_GAP) { + f->s.wt_ptr++; + if (f->s.wt_ptr >= 256) { + goto wtd_done; + } + } + else if (data == TAO_CMD_SYNC) { + f->s.wt_mode = TAO_MODE_SYNC; + } + else if (data == 0xf4) { + goto wtd_done; + } + else { + goto wtd_err; + } + break; + + case TAO_MODE_SYNC: + if (data == TAO_CMD_AM_IN) { + f->s.wt_mode = TAO_MODE_AM; + } + else if (data == TAO_CMD_IM_IN) { + f->s.wt_mode = TAO_MODE_IM; + } + else if (data) { + goto wtd_err; + } + break; + + case TAO_MODE_IM: + if (data == TAO_CMD_IM) { + f->s.wt_mode = TAO_ENDOFDATA; + } + else if (data != TAO_CMD_IM_IN) { + goto wtd_err; + } + break; + + case TAO_MODE_AM: + if (data == TAO_CMD_IAM) { + f->s.wt_mode = TAO_MODE_ID; + f->s.wt_ptr = 0; + } + else if ((data == TAO_CMD_DAM) || (data == TAO_CMD_DDAM)) { + f->s.wt_mode = TAO_MODE_DATA; + f->s.wt_ptr = 0; + if (f->s.wt_datsize) { + t = (TAOSEC *)(f->s.buffer + f->s.wt_datpos); + t[-1].flag = (UINT8)(data == TAO_CMD_DDAM); + } + } + break; + + case TAO_MODE_ID: + if ((f->s.wt_ptr == 0) && (data == TAO_CMD_IAM)) { + break; + } + else if (f->s.wt_ptr < 4) { + f->s.buffer[f->s.bufpos + f->s.wt_ptr] = data; + f->s.wt_ptr++; + } + else if (data == TAO_CMD_CRC) { + f->s.wt_mode = TAO_ENDOFDATA; + n = f->s.buffer[f->s.bufpos + 3]; + if (n > 3) { + n = 3; + } + datsize = 128 << n; + if ((f->s.bufpos + (sizeof(TAOSEC) * 2) + datsize) + <= sizeof(f->s.buffer)) { + t = (TAOSEC *)(f->s.buffer + f->s.bufpos); + STOREINTELWORD(t->size, datsize); + f->s.wt_datpos = f->s.bufpos + sizeof(TAOSEC); + f->s.wt_datsize = datsize; + f->s.bufpos = f->s.wt_datpos + datsize; + f->s.wt_sectors += 1; + } + else { + goto wtd_err; + } + } + break; + + case TAO_MODE_DATA: /* DATA WRITE */ + if ((f->s.wt_ptr == 0) && + ((data == TAO_CMD_DAM) || (data == TAO_CMD_DDAM))) { + break; + } + else if (f->s.wt_ptr < f->s.wt_datsize) { + f->s.buffer[f->s.wt_datpos + f->s.wt_ptr] = data; + f->s.wt_ptr++; + } + else if (data == TAO_CMD_CRC) { + f->s.wt_mode = TAO_ENDOFDATA; + f->s.wt_datsize = 0; + } + break; + } + return; + +wtd_done: + fdd = fddfile + f->s.bufunit; + TRACEOUT(("write! %d %dbytes", f->s.wt_sectors, f->s.bufpos)); + f->s.stat = (*fdd->wrtrk)(fdd, f->s.bufmedia, f->s.buftrack, + f->s.wt_sectors, f->s.buffer, f->s.bufpos); + f->s.bufdir = FDCDIR_NONE; + dmac_sendready(FALSE); + return; + +wtd_err: + f->s.stat = FDDSTAT_LOSTDATA; + f->s.bufdir = FDCDIR_NONE; + dmac_sendready(FALSE); +} +#endif + + +/* ---- */ + +void neitem_fdcbusy(UINT id) { - fdc.s.busy = FALSE; + fdc.s.busy = 0; if (fdc.s.bufdir) { - TRACEOUT(("dma ready!")); + /* TRACEOUT(("dma ready!")); */ dmac_sendready(TRUE); } + (void)id; } -static void setbusy(UINT clock) { +static void setbusy(FDC *f, SINT32 clock) { - fdc.s.busy = TRUE; - nevent_set(NEVENT_FDC, clock, nvitem_fdcbusy, NEVENT_ABSOLUTE); + if (clock > 0) { + f->s.busy = FDDSTAT_BUSY; + nevent_set(NEVENT_FDC, clock, neitem_fdcbusy, NEVENT_ABSOLUTE); + } + else { + f->s.busy = 0; + nevent_reset(NEVENT_FDC); + } +} + +#if defined(SUPPORT_MOTORRISEUP) +static void setmotor(FDC *f, REG8 drvcmd) { + + UINT drv; + SINT32 clock; + + drv = drvcmd & 3; + clock = CPU_CLOCK + CPU_BASECLOCK - CPU_REMCLOCK; + if (drvcmd & 0x80) { + if (f->s.motorevent[drv] == FDCMOTOR_STOP) { + f->s.motorevent[drv] = FDCMOTOR_STARTING; + f->s.motorclock[drv] = clock; + } + else if (f->s.motorevent[drv] == FDCMOTOR_STOPING) { + f->s.motorevent[drv] = FDCMOTOR_READY; + } + } + else { + if ((f->s.motorevent[drv] == FDCMOTOR_STARTING) || + (f->s.motorevent[drv] == FDCMOTOR_READY)) { + f->s.motorevent[drv] = FDCMOTOR_STOPING; + f->s.motorclock[drv] = clock; + } + } +} + +void fdc_callback(void) { + + SINT32 clock; + UINT i; + + clock = CPU_CLOCK + CPU_BASECLOCK - CPU_REMCLOCK; + for (i=0; i<4; i++) { + if (fdc.s.motorevent[i] == FDCMOTOR_STARTING) { + if ((clock - fdc.s.motorclock[i]) >= (SINT32)pccore.realclock) { + fdc.s.motorevent[i] = FDCMOTOR_READY; + } + } + else if (fdc.s.motorevent[i] == FDCMOTOR_STOPING) { + if ((clock - fdc.s.motorclock[i]) >= (SINT32)pccore.realclock) { + fdc.s.motorevent[i] = FDCMOTOR_STOP; + } + } + } +} + +static SINT32 motorwait(const FDC *f) { + + SINT32 curclock; + SINT32 nextclock; + + if (f->s.motorevent[f->s.drv] == FDCMOTOR_STARTING) { + curclock = CPU_CLOCK + CPU_BASECLOCK - CPU_REMCLOCK; + curclock -= f->s.motorclock[f->s.drv]; + if (curclock < (SINT32)pccore.realclock) { + nextclock = pccore.realclock - curclock; + /* TRACEOUT(("motor starting busy %d", nextclock)); */ + return(nextclock); + } + } + return(0); } +#endif + -static REG8 getstat(void) { +static REG8 getstat(FDC *f) { FDDFILE fdd; - REG8 cmd; - REG8 type; + REG8 ctype; REG8 ret; - fdd = fddfile + fdc.s.drv; - cmd = (REG8)(fdc.s.cmd >> 4); - type = fdc.s.type; + fdd = fddfile + f->s.drv; + ctype = f->s.ctype; if (fdd->type == DISKTYPE_NOTREADY) { ret = FDDSTAT_NOTREADY; } - else if (type != 0) { - ret = fdc.s.stat; - } else { - ret = 0; + ret = f->s.stat; } - if ((type == 1) && (fdc.s.c == 0)) { + if ((ctype & FDCCTYPE_CMD1) && (f->s.c == 0)) { ret |= FDDSTAT_TRACK00; } - if ((type == 0) || (type == 1) || (type == 4) || - (cmd == 0x0a) || (cmd == 0x0b) || (cmd == 0x0f)) { + if (!(ctype & FDCCTYPE_RO)) { if (fdd->protect) { ret |= FDDSTAT_WRITEP; } } - if ((type == 1) || (type == 4)) { - fdc.s.hole++; - if (fdc.s.hole < 8) { + if (ctype & (FDCCTYPE_CMD1 | FDCCTYPE_CMD4)) { + f->s.hole++; + if (f->s.hole < 8) { ret |= FDDSTAT_INDEX; } } else if (!(ret & 0xf0)) { - if (FDDMTR_BUSY) { + if (fddmtr_isbusy()) { ret |= FDDSTAT_BUSY; } - if (fdc.s.bufdir) { + if (f->s.bufdir) { ret |= FDDSTAT_DRQ | FDDSTAT_BUSY; } - else if (cmd == 0x0f) { - ret |= FDDSTAT_LOSTDATA; - } } return(ret); } -static void seekcmd(void) { +static void seekcmd(FDC *f) { FDDFILE fdd; UINT track; - fdc.s.crcnum = 0; - fdc.s.creg = fdc.s.c; - fdd = fddfile + fdc.s.drv; - track = (fdc.s.c << 1) + fdc.s.h; - fdc.s.stat = fdd->seek(fdd, fdc.s.media, track) | FDDSTAT_HEADENG; - FDDMTR_MOVE; + f->s.crcnum = 0; + f->s.creg = f->s.c; + fdd = fddfile + f->s.drv; + track = (f->s.c << 1) + f->s.h; + f->s.stat = fdd->seek(fdd, f->s.media, track) | FDDSTAT_HEADENG; + fddmtr_motormove(); } -static REG8 type2cmd(REG8 sc) { +static REG8 type2cmd(FDC *f, REG8 sc) { REG8 dir; UINT track; @@ -97,341 +366,486 @@ static REG8 type2cmd(REG8 sc) { FDDFILE fdd; UINT size; REG8 stat; + SINT32 clock; +#if defined(SUPPORT_DISKEXT) + SINT32 curclock; + SINT32 nextclock; + UINT32 secinfo; +#endif - track = (fdc.s.c << 1) + fdc.s.h; - if (!(fdc.s.cmd & 0x20)) { - p = fdc.s.buffer; + track = (f->s.c << 1) + f->s.h; + fdd = fddfile + f->s.drv; +#if !defined(CONST_DISKIMAGE) + if (!(f->s.cmd & 0x20)) { + p = f->s.buffer; dir = FDCDIR_IN; } else { p = NULL; dir = FDCDIR_OUT; } - size = sizeof(fdc.s.buffer); - fdd = fddfile + fdc.s.drv; - TRACEOUT(("read %.2x %d %d", fdc.s.drv, track, sc)); - stat = fdd->read(fdd, fdc.s.media, track, sc, p, &size); + size = sizeof(f->s.buffer); + stat = fdd->read(fdd, f->s.media, track, sc, p, &size); if (stat & FDDSTAT_RECNFND) { size = 0; dir = FDCDIR_NONE; } else if (dir == FDCDIR_OUT) { if (size) { - ZeroMemory(fdc.s.buffer, size); + ZeroMemory(f->s.buffer, size); } stat = stat & (~FDDSTAT_RECTYPE); } - fdc.s.bufmedia = fdc.s.media; - fdc.s.bufunit = fdc.s.drv; - fdc.s.buftrack = track; - fdc.s.bufsc = sc; - fdc.s.bufwrite = FALSE; - fdc.s.bufdir = dir; - fdc.s.bufmark = fdc.s.cmd & 1; - fdc.s.bufpos = 0; - fdc.s.bufsize = size; +#else + size = 0; + dir = FDCDIR_NONE; + if (!(f->s.cmd & 0x20)) { + stat = fdd->readp(fdd, f->s.media, track, sc, (void **)&p, &size); + if (!(stat & FDDSTAT_RECNFND)) { + f->e.buffer = p; + dir = FDCDIR_IN; + } + } + else { + stat = FDDSTAT_RECNFND | FDDSTAT_WRITEFAULT; + } +#endif + f->s.bufmedia = f->s.media; + f->s.bufunit = f->s.drv; + f->s.buftrack = track; + f->s.bufsc = sc; + f->s.bufwrite = FALSE; + f->s.bufdir = dir; + f->s.bufmark = f->s.cmd & 1; + f->s.bufpos = 0; + f->s.bufsize = size; + f->s.curtime = 0; + + clock = 0; +#if defined(SUPPORT_MOTORRISEUP) + clock += motorwait(f); +#endif +#if defined(SUPPORT_DISKEXT) + secinfo = fdd->sec(fdd, f->s.media, track, sc); + if (secinfo) { + nextclock = LOW16(secinfo); + nextclock *= f->s.loopclock; + nextclock /= LOW16(secinfo >> 16); + curclock = nevent_getwork(NEVENT_RTC); + nextclock -= curclock; + if (nextclock < 0) { + nextclock += f->s.loopclock; + } + /* TRACEOUT(("wait clock -> %d [%d/%d]", nextclock, + LOW16(secinfo), LOW16(secinfo >> 16))); */ + clock += nextclock; + } +#endif + setbusy(f, max(clock, 500)); return(stat); } -static REG8 type2flash(void) { +static REG8 type2flash(FDC *f) { +#if !defined(CONST_DISKIMAGE) FDDFILE fdd; - fdc.s.bufwrite = FALSE; - fdd = fddfile + fdc.s.bufunit; + f->s.bufwrite = FALSE; + fdd = fddfile + f->s.bufunit; if (fdd->protect) { return(FDDSTAT_WRITEFAULT); } - return(fdd->write(fdd, fdc.s.bufmedia, fdc.s.buftrack, - fdc.s.bufsc, fdc.s.buffer, fdc.s.bufpos)); + return(fdd->write(fdd, f->s.bufmedia, f->s.buftrack, + f->s.bufsc, f->s.buffer, f->s.bufpos)); +#else + (void)f; + return(FDDSTAT_RECNFND | FDDSTAT_WRITEFAULT); +#endif } -static REG8 crccmd(void) { +static REG8 crccmd(FDC *f) { + UINT8 *crcbuf; UINT track; FDDFILE fdd; REG8 stat; - track = (fdc.s.c << 1) + fdc.s.h; - fdd = fddfile + fdc.s.drv; - stat = fdd->crc(fdd, fdc.s.media, track, fdc.s.crcnum, fdc.s.buffer); +#if !defined(CONST_DISKIMAGE) + crcbuf = f->s.buffer; +#else + crcbuf = f->s.crcbuf; + f->e.buffer = crcbuf; +#endif + + track = (f->s.c << 1) + f->s.h; + fdd = fddfile + f->s.drv; + /* TRACEOUT(("fdd->crc %d %d %d", f->s.drv, track, f->s.crcnum)); */ + stat = fdd->crc(fdd, f->s.media, track, f->s.crcnum, crcbuf); if (stat & FDDSTAT_RECNFND) { - fdc.s.crcnum = 0; - stat = fdd->crc(fdd, fdc.s.media, track, 0, fdc.s.buffer); + f->s.crcnum = 0; + stat = fdd->crc(fdd, f->s.media, track, 0, crcbuf); } if (!(stat & FDDSTAT_RECNFND)) { - fdc.s.bufdir = FDCDIR_IN; - fdc.s.bufsize = 6; - fdc.s.rreg = fdc.s.buffer[0]; + f->s.bufdir = FDCDIR_IN; + f->s.bufsize = 6; + f->s.rreg = crcbuf[0]; + f->s.crcnum++; } else { - fdc.s.bufdir = FDCDIR_NONE; - fdc.s.bufsize = 0; + f->s.bufdir = FDCDIR_NONE; + f->s.bufsize = 0; } - fdc.s.bufwrite = FALSE; + f->s.bufwrite = FALSE; + f->s.curtime = 0; return(stat); } -static void bufposinc(void) { +static void fdcenddata(FDC *f) { BRESULT r; REG8 stat; - if (fdc.s.busy) { - return; - } - fdc.s.bufpos++; - if (fdc.s.bufpos >= fdc.s.bufsize) { - r = FALSE; - if (fdc.s.type == 2) { - stat = 0; - if (fdc.s.cmd & 0x10) { - r = TRUE; - } - if ((fdc.s.cmd & 0x20) && (fdc.s.bufwrite)) { - stat = type2flash(); - if (stat & (FDDSTAT_RECNFND | FDDSTAT_WRITEFAULT)) { - r = FALSE; - } - fdc.s.stat = stat; - } - if (r) { - fdc.s.rreg = fdc.s.r + 1; - stat = type2cmd(fdc.s.rreg); - if (!(stat & FDDSTAT_RECNFND)) { - fdc.s.r = fdc.s.r + 1; - fdc.s.stat = stat; - } - else { - r = FALSE; - } + r = FALSE; + if (f->s.ctype & FDCCTYPE_CMD2) { + stat = 0; + if (f->s.cmd & 0x10) { + r = TRUE; + } + if ((f->s.cmd & 0x20) && (f->s.bufwrite)) { + stat = type2flash(f); + if (stat & (FDDSTAT_RECNFND | FDDSTAT_WRITEFAULT)) { + r = FALSE; } + f->s.stat = stat; } - if (!r) { - fdc.s.bufdir = FDCDIR_NONE; - dmac_sendready(FALSE); + } + f->s.bufdir = FDCDIR_NONE; + dmac_sendready(FALSE); + if (r) { + f->s.rreg = f->s.r + 1; + stat = type2cmd(f, f->s.rreg); + if (!(stat & FDDSTAT_RECNFND)) { + f->s.r = f->s.r + 1; + f->s.stat = stat; } } } -void IOOUTCALL fdc_o(UINT port, REG8 value) { + + +/* IO-Sub */ + +static void IOOUTCALL fdc_o0ff8(FDC *f, REG8 value) { REG8 cmd; - if ((port & (~7)) != 0x0ff8) { - return; - } - TRACEOUT(("fdc %.4x,%.2x [%.4x]", port, value, Z80_PC)); - switch(port & 7) { - case 0: // コマンド - fdc.s.cmd = value; - cmd = (REG8)(value >> 4); - fdc.s.type = fdctype[cmd]; - TRACEOUT(("fdc cmd: %.2x", value)); - if (fdc.s.bufwrite) { - fdc.s.stat = type2flash(); - } - fdc.s.bufdir = FDCDIR_NONE; - setbusy(20); - switch(cmd) { - case 0x00: // リストア - if (value & 8) { // LAYDOCK - setbusy(0); - } - fdc.s.motor = 0x80; // モーターOn? - fdc.s.c = 0; - fdc.s.step = 1; - fdc.s.r = 0; // デゼニワールド - seekcmd(); - fdc.s.rreg = 0; - break; - - case 0x01: // シーク - fdc.s.motor = 0x80; // モーターOn - fdc.s.step = (SINT8)((fdc.s.c<=fdc.s.data)?1:-1); - fdc.s.c = fdc.s.data; - seekcmd(); - break; - - case 0x02: // ステップ - case 0x03: - if (fdc.s.motor) { - fdc.s.c += fdc.s.step; - if (cmd & 1) { - seekcmd(); - } - } - break; - - case 0x04: // ステップイン - case 0x05: - if (fdc.s.motor) { - fdc.s.step = 1; - fdc.s.c++; - if (cmd & 1) { - seekcmd(); - } - } - break; - - case 0x06: // ステップアウト - case 0x07: - if (fdc.s.motor) { - fdc.s.step = -1; - fdc.s.c--; - if (cmd & 1) { - seekcmd(); - } - } - break; - - case 0x08: // リードデータ - case 0x09: - case 0x0a: // ライトデータ - case 0x0b: - setbusy(500); - fdc.s.stat = type2cmd(fdc.s.r); - break; - - case 0xc: // リードアドレス - setbusy(200); - fdc.s.stat = crccmd(); - break; - - case 0x0d: // フォースインタラプト - setbusy(0); // 必要ない? -// fdc.s.skip = 0; // 000330 - dmac_sendready(FALSE); - break; - - case 0x0e: // リードトラック - setbusy(200); - ZeroMemory(fdc.s.buffer, 0x1a00); - fdc.s.bufpos = 0; - fdc.s.bufsize = 0x1a00; - fdc.s.bufdir = FDCDIR_IN; - break; - - case 0x0f: // ライトトラック - break; - } - break; - - case 1: // トラック - fdc.s.c = value; - break; - - case 2: // セクタ - FDDMTR_WAITSEC(value); - fdc.s.r = value; - fdc.s.rreg = value; - break; - - case 3: // データ - fdc.s.data = value; - if ((fdc.s.motor) && (fdc.s.bufdir == FDCDIR_OUT)) { - fdc.s.buffer[fdc.s.bufpos] = value; - fdc.s.bufwrite = TRUE; - bufposinc(); - } - break; - - case 4: // ドライブ・サイド - fdc.s.ctbl[fdc.s.drv] = fdc.s.c; - fdc.s.c = fdc.s.ctbl[value & 0x03]; - fdc.s.motor = (UINT8)(value & 0x80); - fdc.s.drv = (UINT8)(value & 0x03); - fdc.s.h = (UINT8)((value >> 4) & 1); - fdc.s.cmd = 0; // T&E SORCERIAN - fdc.s.type = 0; - - FDDMTR_DRVSET; - if (!fdc.s.motor) { - fdc.s.r = 0; // SACOM TELENET - fdc.s.rreg = 0; + /* コマンド */ + if (f->s.bufwrite) { + f->s.stat = type2flash(f); + } + if (f->s.bufdir != FDCDIR_NONE) { + f->s.bufdir = FDCDIR_NONE; + dmac_sendready(FALSE); + } + + f->s.cmd = value; + cmd = (REG8)(value >> 4); + f->s.ctype = fdctype[cmd]; + /* TRACEOUT(("fdc cmd: %.2x", value)); */ + /* リストアコマンドにおいて + *  マリオは コマンド発行後にbusyを見張る + *  逆にソーサリアンとかは busyだとエラーになる… + * 条件は何? + */ + setbusy(f, 20); + switch(cmd) { + case 0x00: /* リストア */ + f->s.motor = 0x80; /* モーターOn? */ + f->s.c = 0; + f->s.step = 1; + f->s.r = 0; /* デゼニワールド */ + seekcmd(f); + f->s.rreg = 0; + break; + + case 0x01: /* シーク */ + f->s.motor = 0x80; /* モーターOn */ + f->s.step = (SINT8)((f->s.c<=f->s.data)?1:-1); + f->s.c = f->s.data; + seekcmd(f); + break; + + case 0x02: /* ステップ */ + case 0x03: + case 0x04: /* ステップイン */ + case 0x05: + case 0x06: /* ステップアウト */ + case 0x07: + f->s.stat = FDDSTAT_HEADENG; + if (f->s.motor) { + if (cmd & 0x04) { + f->s.step = (cmd & 0x02)?-1:1; + } + f->s.c += f->s.step; + if (cmd & 1) { + seekcmd(f); + } } break; + + case 0x08: /* リードデータ */ + case 0x09: + case 0x0a: /* ライトデータ */ + case 0x0b: + f->s.stat = type2cmd(f, f->s.r); + break; + + case 0xc: /* リードアドレス */ + setbusy(f, 200); + f->s.stat = crccmd(f); + break; + + case 0x0d: /* フォースインタラプト */ + setbusy(f, 0); /* 必要ない? */ + /* f->s.skip = 0; */ /* 000330 */ + f->s.stat = 0; + dmac_sendready(FALSE); + break; + + case 0x0e: /* リードトラック */ +#if !defined(CONST_DISKIMAGE) + setbusy(f, 200); + ZeroMemory(f->s.buffer, 0x1a00); + f->s.bufpos = 0; + f->s.bufsize = 0x1a00; + f->s.bufdir = FDCDIR_IN; + f->s.stat = 0; +#else + f->s.stat = FDDSTAT_SEEKERR; +#endif + break; + + case 0x0f: /* ライトトラック */ +#if !defined(CONST_DISKIMAGE) + setbusy(f, 200); + f->s.stat = wrtrkstart(f); +#else + f->s.stat = FDDSTAT_LOSTDATA; +#endif + break; + } +} + +static void IOOUTCALL fdc_o0ff9(FDC *f, REG8 value) { + + /* トラック */ + f->s.creg = value; +} + +static void IOOUTCALL fdc_o0ffa(FDC *f, REG8 value) { + + /* セクタ */ + fddmtr_waitsec(value); + f->s.r = value; + f->s.rreg = value; +} + +static void IOOUTCALL fdc_o0ffb(FDC *f, REG8 value) { + + /* データ */ + f->s.data = value; +#if !defined(CONST_DISKIMAGE) + if (f->s.motor) { + if (f->s.bufdir == FDCDIR_OUT) { + f->s.bufwrite = TRUE; + f->s.curtime = 0; + f->s.buffer[f->s.bufpos] = value; + if (!f->s.busy) { + f->s.bufpos++; + if (f->s.bufpos >= f->s.bufsize) { + fdcenddata(f); + } + } + } + else if (f->s.bufdir == FDCDIR_TAO) { + wrtrkdata(f, value); + } + } +#endif +} + +static void IOOUTCALL fdc_o0ffc(FDC *f, REG8 value) { + + /* ドライブ・サイド */ + f->s.ctbl[f->s.drv] = f->s.c; + f->s.c = f->s.ctbl[value & 0x03]; + f->s.motor = (UINT8)(value & 0x80); + f->s.drv = (UINT8)(value & 0x03); + f->s.h = (UINT8)((value >> 4) & 1); + f->s.cmd = 0; /* T&E SORCERIAN */ + f->s.ctype = 0; + f->s.stat = 0; + + fddmtr_drvset(); + if (!f->s.motor) { + f->s.r = 0; /* SACOM TELENET */ + f->s.rreg = 0; } +#if defined(SUPPORT_MOTORRISEUP) + setmotor(f, value); +#endif +} + +static void IOOUTCALL fdc_o0(FDC *f, REG8 value) { } -REG8 IOINPCALL fdc_i(UINT port) { - -// static BYTE timeoutwait; -// static BYTE last_r; -// static short last_off; +static REG8 IOINPCALL fdc_i0ff8(FDC *f) { + REG8 ret; - if ((port & (~7)) != 0x0ff8) { - return(0xff); + /* ステータス */ + ret = f->s.busy; + if (ret) { + return(ret); + } +#if 1 + if (f->s.bufdir >= FDCDIR_IN) { /* YsII */ + f->s.curtime++; + if (f->s.curtime >= 8) { + f->s.curtime = 0; + f->s.stat |= FDDSTAT_LOSTDATA; + f->s.bufpos++; + if (f->s.bufpos >= f->s.bufsize) { + fdcenddata(f); + } + } } -#if 0 - if ((port &= 0xf) != 8) { - last_r = -1; - last_off = -1; - timeoutwait = 4; - } -#endif - switch(port & 7) { - case 0: // ステータス - ret = fdc.s.busy; - if (ret) { - return(ret); - } -#if 0 - if (fdc.s.type == 2) { - if (last_r == _fdc.r && last_off == fdc.off && - !(--timeoutwait)) { - inc_off(); - timeoutwait = 4; - } - last_r = _fdc.r; - last_off = fdc.off; - } // Read Write時のみの変化でいい筈 -#endif - ret = getstat(); - if (!(ret & 0x02)) { - dmac_sendready(FALSE); - } - return(ret); - - case 1: // トラック - return(fdc.s.creg); - - case 2: // セクタ - return(fdc.s.rreg); - - case 3: // データ - if (fdc.s.motor) { - if (fdc.s.bufdir == FDCDIR_IN) { - fdc.s.data = fdc.s.buffer[fdc.s.bufpos]; -TRACEOUT(("read %.2x %.2x [%.4x]", fdc.s.data, fdc.s.bufpos, Z80_PC)); - bufposinc(); +#endif + ret = getstat(f); +#if 1 + if (!(ret & 0x02)) { + dmac_sendready(FALSE); + } +#endif + /* TRACEOUT(("ret->%.2x", ret)); */ + return(ret); +} + +static REG8 IOINPCALL fdc_i0ff9(FDC *f) { + + /* トラック */ + TRACEOUT(("fdc inp %.4x,%.2x", 0x0ff9, f->s.creg)); + return(f->s.creg); +} + +static REG8 IOINPCALL fdc_i0ffa(FDC *f) { + + /* セクタ */ + TRACEOUT(("fdc inp %.4x,%.2x", 0x0ffa, f->s.rreg)); + return(f->s.rreg); +} + +static REG8 IOINPCALL fdc_i0ffb(FDC *f) { + + /* データ */ + if (f->s.motor) { + if (f->s.bufdir == FDCDIR_IN) { + f->s.curtime = 0; +#if !defined(CONST_DISKIMAGE) + f->s.data = f->s.buffer[f->s.bufpos]; +#else + f->s.data = f->e.buffer[f->s.bufpos]; +#endif + if (!f->s.busy) { + f->s.bufpos++; + if (f->s.bufpos >= f->s.bufsize) { + fdcenddata(f); } } - return(fdc.s.data); + /* TRACEOUT(("read %.2x - %.2x [%.4x]", f->s.bufpos, f->s.data, Z80_PC)); */ + } + } + return(f->s.data); +} - case 4: // FM - case 5: // MFM - return(0x00); +static REG8 IOINPCALL fdc_i0ffc(FDC *f) { - case 6: // 1.6M - fdc.s.media = DISKTYPE_2HD; - break; + /* FM */ + return(0x00); +} - case 7: // 500K/1M - fdc.s.media = DISKTYPE_2D; - break; - } +static REG8 IOINPCALL fdc_i0ffd(FDC *f) { + + /* MFM */ + return(0x00); +} + +static REG8 IOINPCALL fdc_i0ffe(FDC *f) { + + /* 1.6M */ + f->s.media = DISKTYPE_2HD; + return(0xff); +} + +static REG8 IOINPCALL fdc_i0fff(FDC *f) { + + /* 500K/1M */ + f->s.media = DISKTYPE_2D; return(0xff); } -// ---- +/* IO */ + +typedef void (IOINPCALL * FNFDCOUT)(FDC *f, REG8 value); +static const FNFDCOUT s_fnOut[] = +{ + fdc_o0ff8, fdc_o0ff9, fdc_o0ffa, fdc_o0ffb, + fdc_o0ffc, fdc_o0, fdc_o0, fdc_o0, +}; + +typedef REG8 (IOINPCALL * FNFDCINP)(FDC *f); +static const FNFDCINP s_fnInp[] = +{ + fdc_i0ff8, fdc_i0ff9, fdc_i0ffa, fdc_i0ffb, + fdc_i0ffc, fdc_i0ffd, fdc_i0ffe, fdc_i0fff, +}; + +void IOINPCALL fdc_o(UINT port, REG8 value) +{ + if ((port & (~7)) != 0x0ff8) + { + return; + } + + /* TRACEOUT(("fdc out %.4x,%.2x", port, value)); */ + (s_fnOut[port & 7])(&fdc, value); +} + +REG8 IOINPCALL fdc_i(UINT uPort) +{ + if ((uPort & (~7)) != 0x0ff8) + { + return 0xff; + } + + /* TRACEOUT(("fdc inp %.4x", port)); */ + return (s_fnInp[uPort & 7])(&fdc); +} + + +/* reset */ void fdc_reset(void) { - FDDMTR_INIT; + fddmtr_initialize(); ZeroMemory(&fdc, sizeof(fdc)); fdc.s.step = 1; + fdc.s.equip = xmilcfg.fddequip; +#if defined(FIX_Z80A) + fdc.s.loopclock = 2000000 * 2 / 5; +#else + fdc.s.loopclock = pccore.realclock / 5; +#endif }