--- xmil/io/fdc.c 2004/08/02 13:38:46 1.1 +++ xmil/io/fdc.c 2009/03/23 15:02:25 1.24 @@ -1,424 +1,851 @@ #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 +}; - BYTE FDC_c[4]; - BYTE driveset = 0; - BYTE fdcdummyread = 0; - WORD readdiag = 0; -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) { + FDDFILE fdd; -static BYTE fdd_stat(void) { + 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)); - FDDFILE fdd; + 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; - fdd = fddfile + fdc.drv; - switch(fdd->type) { - case DISKTYPE_NOTREADY: - return(0); + 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 DISKTYPE_BETA: - return(fdd_stat_2d()); + 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 DISKTYPE_D88: - default: - return(fdd_stat_d88()); + 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(0); + 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 -/*********************************************************************** - FDC (X1から見るI/Oに相当する関数) -***********************************************************************/ +/* ---- */ -static int inc_off(void) { +void neitem_fdcbusy(UINT id) { - BYTE ret; - FDDFILE fdd; + fdc.s.busy = 0; + if (fdc.s.bufdir) { + /* TRACEOUT(("dma ready!")); */ + dmac_sendready(TRUE); + } + (void)id; +} - if (!fdc.motor) { - return(0); +static void setbusy(FDC *f, SINT32 clock) { + + if (clock > 0) { + f->s.busy = FDDSTAT_BUSY; + nevent_set(NEVENT_FDC, clock, neitem_fdcbusy, NEVENT_ABSOLUTE); } - if (fdcdummyread) { - fdcdummyread--; - return(0); + 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 { - fdd = fddfile + fdc.drv; - switch(fdd->type) { - case DISKTYPE_NOTREADY: - return(0); + if ((f->s.motorevent[drv] == FDCMOTOR_STARTING) || + (f->s.motorevent[drv] == FDCMOTOR_READY)) { + f->s.motorevent[drv] = FDCMOTOR_STOPING; + f->s.motorclock[drv] = clock; + } + } +} - case DISKTYPE_BETA: - ret = fdd_incoff_2d(); - break; +void fdc_callback(void) { - case DISKTYPE_D88: - default: - ret = fdd_incoff_d88(); - break; + 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; + } } - if (ret) { - dma.DMA_REDY = 8; // <- DMA ノ レディシンゴウ ヲ クリア + else if (fdc.s.motorevent[i] == FDCMOTOR_STOPING) { + if ((clock - fdc.s.motorclock[i]) >= (SINT32)pccore.realclock) { + fdc.s.motorevent[i] = FDCMOTOR_STOP; + } } } - return(ret); } -void IOOUTCALL fdc_o(UINT port, REG8 value) { +static SINT32 motorwait(const FDC *f) { - REG8 cmd; + SINT32 curclock; + SINT32 nextclock; - port &= 0xf; - if (port == 8) { // コマンド - driveset = 0; - fdc.cmd = value; - cmd = (REG8)(value >> 4); - fdc.type = fdctype[cmd]; - fdc.skip = 2; - switch(cmd) { - case 0x00: // リストア - if (value & 8) { // LAYDOCK - fdc.skip = 0; - fdc.busyclock = 20; // ver0.25 (now testing) - fdc.busystart = h_cntbase + h_cnt; - } - fdc.motor = 0x80; // モーターOn? - fdc.c = 0; - fdc.treg = 0; - FDDMTR_MOVE; - fdc.step = 1; -#if 1 // ver0.25 - fdc.r = 0; // デゼニワールド - fdc.rreg = 0; + 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 - break; - case 0x01: // シーク - fdc.motor = 0x80; // モーターOn - fdc.step = (char)((fdc.c<=fdc.data)?1:-1); -#if 0 // スタクル // ver0.50 - fdc.rreg = fdc.r = 0; -#endif - fdc.c = fdc.data; - fdc.treg = fdc.data; - FDDMTR_MOVE; - break; - case 0x02: // ステップ - case 0x03: - if (fdc.motor) { - fdc.c += fdc.step; - if (cmd & 1) { - FDDMTR_MOVE; - fdc.treg = fdc.c; - } - } - break; +static REG8 getstat(FDC *f) { - case 0x04: // ステップイン - case 0x05: - if (fdc.motor) { - fdc.step = 1; - fdc.c++; - if (cmd & 1) { - FDDMTR_MOVE; - fdc.treg = fdc.c; - } - } - break; + FDDFILE fdd; + REG8 ctype; + REG8 ret; + + fdd = fddfile + f->s.drv; + ctype = f->s.ctype; + if (fdd->type == DISKTYPE_NOTREADY) { + ret = FDDSTAT_NOTREADY; + } + else { + ret = f->s.stat; + } + if ((ctype & FDCCTYPE_CMD1) && (f->s.c == 0)) { + ret |= FDDSTAT_TRACK00; + } + if (!(ctype & FDCCTYPE_RO)) { + if (fdd->protect) { + ret |= FDDSTAT_WRITEP; + } + } + if (ctype & (FDCCTYPE_CMD1 | FDCCTYPE_CMD4)) { + f->s.hole++; + if (f->s.hole < 8) { + ret |= FDDSTAT_INDEX; + } + } + else if (!(ret & 0xf0)) { + if (fddmtr_isbusy()) { + ret |= FDDSTAT_BUSY; + } + if (f->s.bufdir) { + ret |= FDDSTAT_DRQ | FDDSTAT_BUSY; + } + } + return(ret); +} - case 0x06: // ステップアウト - case 0x07: - if (fdc.motor) { - fdc.step = -1; - fdc.c--; - if (cmd & 1) { - FDDMTR_MOVE; - fdc.treg = fdc.c; - } - } - break; +static void seekcmd(FDC *f) { - case 0x08: // リードデータ - case 0x09: - case 0x0a: // ライトデータ - case 0x0b: - fdc.off = 0; - fdcdummyread = 2; - if (fdc.motor) { - if (dma.DMA_ENBL) { - dma.DMA_REDY = 0; -// fdc.skip = 0; // DMAで割り込みを監視する事! - } - } - break; + FDDFILE fdd; + UINT track; - case 0xc: // リードアドレス - fdc.crc_off = 0; - fdcdummyread = 2; - if (fdc.motor) { // ver0.25 - if (dma.DMA_ENBL) { - dma.DMA_REDY = 0; - } - } - { - FDDFILE fdd = fddfile + fdc.drv; - switch(fdd->type) { - case DISKTYPE_NOTREADY: - break; - - case DISKTYPE_BETA: - fdd_crc_2d(); - break; - - case DISKTYPE_D88: - default: - fdd_crc_d88(); - break; - } - } - break; + 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(); +} - case 0x0d: // フォースインタラプト - fdcdummyread = 0; // 必要ない? - fdc.skip = 0; // 000330 - dma.DMA_REDY = 8; // ver0.25 - break; +static REG8 type2cmd(FDC *f, REG8 sc) { - case 0x0e: // リードトラック - readdiag = 0; - break; + REG8 dir; + UINT track; + UINT8 *p; + FDDFILE fdd; + UINT size; + REG8 stat; + SINT32 clock; +#if defined(SUPPORT_DISKEXT) + SINT32 curclock; + SINT32 nextclock; + UINT32 secinfo; +#endif - case 0x0f: // ライトトラック - { - FDDFILE fdd = fddfile + fdc.drv; - switch(fdd->type) { - case DISKTYPE_NOTREADY: - case DISKTYPE_BETA: - break; - - case DISKTYPE_D88: - default: - if (fdc.motor) { // ver0.25 - init_tao_d88(); - if (dma.DMA_ENBL) { - dma.DMA_REDY = 0; - } - } - break; - } - } - break; + 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(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(f->s.buffer, size); + } + stat = stat & (~FDDSTAT_RECTYPE); + } +#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 { - cmd = (REG8)(fdc.cmd >> 4); - switch(port) { - case 0x09: // トラック - fdc.treg = value; - break; + 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); +} - case 0x0a: // セクタ - FDDMTR_WAITSEC(value); - fdc.r = value; - fdc.rreg = value; - break; +static REG8 type2flash(FDC *f) { - case 0x0b: // データ - fdc.data = value; - if ((cmd == 0x0a) || (cmd == 0x0b)) { - FDDFILE fdd = fddfile + fdc.drv; - switch(fdd->type) { - case DISKTYPE_NOTREADY: - break; - - case DISKTYPE_BETA: - fdd_write_2d(); - break; - - case DISKTYPE_D88: - default: - fdd_write_d88(); - break; - } - inc_off(); - } - else if (cmd == 0x0f) { // TRACK WRITE - FDDFILE fdd = fddfile + fdc.drv; - switch(fdd->type) { - case DISKTYPE_NOTREADY: - case DISKTYPE_BETA: - break; - - case DISKTYPE_D88: - default: - fdd_wtao_d88(value); - break; - } - } - break; +#if !defined(CONST_DISKIMAGE) + FDDFILE fdd; - case 0x0c: // ドライブ・サイド - driveset = 1; - FDC_c[fdc.drv] = fdc.c; - fdc.c = FDC_c[value & 0x03]; // XTAL !!! - fdc.motor = (UINT8)(value & 0x80); - fdc.drv = (UINT8)(value & 0x03); - fdc.h = (UINT8)((value >> 4) & 1); - - fdc.cmd = 0; // T&E SORCERIAN -// fdc.data = 0; // 影の伝説 - fdc.type = 0; - - FDDMTR_DRVSET; - if (!fdc.motor) { - fdc.r = 0; // SACOM TELENET - fdc.rreg = 0; -#if 0 // XTAL - fdc.c = 0; - fdc.step = 1; + f->s.bufwrite = FALSE; + fdd = fddfile + f->s.bufunit; + if (fdd->protect) { + return(FDDSTAT_WRITEFAULT); + } + 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 - } - break; +} + +static REG8 crccmd(FDC *f) { + + UINT8 *crcbuf; + UINT track; + FDDFILE fdd; + REG8 stat; + +#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) { + f->s.crcnum = 0; + stat = fdd->crc(fdd, f->s.media, track, 0, crcbuf); + } + if (!(stat & FDDSTAT_RECNFND)) { + f->s.bufdir = FDCDIR_IN; + f->s.bufsize = 6; + f->s.rreg = crcbuf[0]; + f->s.crcnum++; + } + else { + f->s.bufdir = FDCDIR_NONE; + f->s.bufsize = 0; + } + f->s.bufwrite = FALSE; + f->s.curtime = 0; + return(stat); +} + +static void fdcenddata(FDC *f) { + + BRESULT r; + REG8 stat; + + 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; + } + } + 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; } } } -REG8 IOINPCALL fdc_i(UINT port) { -static BYTE timeoutwait; -static BYTE last_r; -static short last_off; - BYTE ans; - REG8 cmd; - - cmd = (REG8)(fdc.cmd >> 4); - - if ((port &= 0xf) != 8) { - last_r = -1; - last_off = -1; - timeoutwait = 4; - } - switch(port) { - case 0x8: // ステータス - ans = 0; - fdcdummyread = 0; - if (fdc.skip) { - fdc.skip--; - return(0x01); - } - if (fdc.busyclock) { // ver0.25 - if (((h_cntbase + h_cnt) - fdc.busystart) < fdc.busyclock) { - return(0x01); + +/* IO-Sub */ + +static void IOOUTCALL fdc_o0ff8(FDC *f, REG8 value) { + + REG8 cmd; + + /* コマンド */ + 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); } - fdc.busyclock = 0; } - { - FDDFILE fdd = fddfile + fdc.drv; - if (fdd->type == DISKTYPE_NOTREADY) { - if (fdc.type == 1 && fdc.c == 0) { // ドライブチェック !!! - return(0x84); // ←接続されてる時だけ + 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); } - return(0x80); } } - if (fdc.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時のみの変化でいい筈 - if (!((ans = fdd_stat()) & 2)) { - dma.DMA_REDY = 8; // <- DMA ノ レディシンゴウ ヲ クリア - } + 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) { +} + +static REG8 IOINPCALL fdc_i0ff8(FDC *f) { + + REG8 ret; + + /* ステータス */ + ret = f->s.busy; + if (ret) { + return(ret); + } #if 1 - if (driveset) { // 0xffcを叩いた直後だったら - ans &= 0xc4; + 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); } + } + } +#endif + ret = getstat(f); +#if 1 + if (!(ret & 0x02)) { + dmac_sendready(FALSE); + } #endif - return(ans); + /* TRACEOUT(("ret->%.2x", ret)); */ + return(ret); +} - case 0x9: // トラック - return(fdc.treg); +static REG8 IOINPCALL fdc_i0ff9(FDC *f) { - case 0xa: // セクタ - return(fdc.rreg); // ver0.25 - - case 0xb: // データ - if (fdc.motor) { - if ((cmd == 0x08) || (cmd == 0x09)) { // リード・データ - FDDFILE fdd; - fdd = fddfile + fdc.drv; - switch(fdd->type) { - case DISKTYPE_NOTREADY: - break; - - case DISKTYPE_BETA: - fdd_read_2d(); - break; - - case DISKTYPE_D88: - default: - fdd_read_d88(); // WOODY POCO !!! - break; - } - inc_off(); - } - else if (cmd == 0x0c) { // リード・アドレス - if (fdc.crc_off < 6) { // ver0.25 - fdc.data = fdc.crc_dat[fdc.crc_off]; - if (fdcdummyread) { // ver0.25 - fdcdummyread--; - } - else { - fdc.crc_off++; - } - } - } - else if (cmd == 0x0e) { // ver0.25 - fdc.data = 0; - readdiag++; + /* トラック */ + 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.data); // WOODY POCO !!! + /* TRACEOUT(("read %.2x - %.2x [%.4x]", f->s.bufpos, f->s.data, Z80_PC)); */ + } + } + return(f->s.data); +} + +static REG8 IOINPCALL fdc_i0ffc(FDC *f) { + + /* FM */ + return(0x00); +} + +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); +} -// case 0xc: // FM -// case 0xd: // MFM -// break; - - case 0xe: // 1.6M - fdc.media = 1; - return(0xff); - - case 0xf: // 500K/1M - fdc.media = 0; - 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; } - return(0); + + /* 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.step = 1; - ZeroMemory(FDC_c, 4); + 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 }