--- xmil/io/fdc.c 2004/08/10 08:28:49 1.4 +++ xmil/io/fdc.c 2004/08/15 17:51:53 1.18 @@ -3,6 +3,7 @@ #include "z80core.h" #include "pccore.h" #include "iocore.h" +#include "nevent.h" #include "fddfile.h" #include "fdd_2d.h" #include "fdd_d88.h" @@ -12,32 +13,93 @@ static const UINT8 fdctype[] = {1,1,1,1,1,1,1,1,2,2,2,2,3,4,3,3}; -static void setbusy(UINT clock) { +void neitem_fdcbusy(UINT id) { - fdc.s.busystart = h_cntbase + h_cnt; - fdc.s.busyclock = clock; + fdc.s.busy = FALSE; + if (fdc.s.bufdir) { +// TRACEOUT(("dma ready!")); + dmac_sendready(TRUE); + } + (void)id; +} + +static void setbusy(SINT32 clock) { + + if (clock > 0) { + fdc.s.busy = TRUE; + nevent_set(NEVENT_FDC, clock, neitem_fdcbusy, NEVENT_ABSOLUTE); + } + else { + fdc.s.busy = FALSE; + nevent_reset(NEVENT_FDC); + } +} + +#if defined(SUPPORT_MOTORRISEUP) +static void setmotor(REG8 drvcmd) { + + UINT drv; + SINT32 clock; + + drv = drvcmd & 3; + clock = CPU_CLOCK + CPU_BASECLOCK - CPU_REMCLOCK; + if (drvcmd & 0x80) { + if (fdc.s.motorevent[drv] == FDCMOTOR_STOP) { + fdc.s.motorevent[drv] = FDCMOTOR_STARTING; + fdc.s.motorclock[drv] = clock; + } + else if (fdc.s.motorevent[drv] == FDCMOTOR_STOPING) { + fdc.s.motorevent[drv] = FDCMOTOR_READY; + } + } + else { + if ((fdc.s.motorevent[drv] == FDCMOTOR_STARTING) || + (fdc.s.motorevent[drv] == FDCMOTOR_READY)) { + fdc.s.motorevent[drv] = FDCMOTOR_STOPING; + fdc.s.motorclock[drv] = clock; + } + } } -REG8 fdcisbusy(void) { +void fdc_callback(void) { - UINT clock; + SINT32 clock; + UINT i; - if (fdc.s.busyclock) { - clock = h_cntbase + h_cnt; - if ((clock - fdc.s.busystart) < fdc.s.busyclock) { - return(0x01); + 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; + } } - fdc.s.busyclock = 0; - if ((fdc.s.type == 2) || (fdc.s.cmd == 0x0c) || (fdc.s.cmd == 0x0e)) { - if (fdc.s.bufpos < fdc.s.bufsize) { - TRACEOUT(("dma ready!")); - dma.DMA_REDY = 0; + else if (fdc.s.motorevent[i] == FDCMOTOR_STOPING) { + if ((clock - fdc.s.motorclock[i]) >= (SINT32)pccore.realclock) { + fdc.s.motorevent[i] = FDCMOTOR_STOP; } } } - return(0x00); } +static SINT32 motorwait(REG8 drv) { + + SINT32 curclock; + SINT32 nextclock; + + if (fdc.s.motorevent[drv] == FDCMOTOR_STARTING) { + curclock = CPU_CLOCK + CPU_BASECLOCK - CPU_REMCLOCK; + curclock -= fdc.s.motorclock[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) { FDDFILE fdd; @@ -107,6 +169,12 @@ 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)) { @@ -119,6 +187,7 @@ static REG8 type2cmd(REG8 sc) { } 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); if (stat & FDDSTAT_RECNFND) { size = 0; @@ -139,6 +208,29 @@ static REG8 type2cmd(REG8 sc) { fdc.s.bufmark = fdc.s.cmd & 1; fdc.s.bufpos = 0; fdc.s.bufsize = size; + fdc.s.curtime = 0; + + clock = 0; +#if defined(SUPPORT_MOTORRISEUP) + clock += motorwait(fdc.s.drv); +#endif +#if defined(SUPPORT_DISKEXT) + secinfo = fdd->sec(fdd, fdc.s.media, track, sc); + if (secinfo) { + nextclock = LOW16(secinfo); + nextclock *= fdc.s.loopclock; + nextclock /= LOW16(secinfo >> 16); + curclock = nevent_getwork(NEVENT_RTC); + nextclock -= curclock; + if (nextclock < 0) { + nextclock += fdc.s.loopclock; + } +// TRACEOUT(("wait clock -> %d [%d/%d]", nextclock, +// LOW16(secinfo), LOW16(secinfo >> 16))); + clock += nextclock; + } +#endif + setbusy(max(clock, 500)); return(stat); } @@ -163,6 +255,7 @@ static REG8 crccmd(void) { track = (fdc.s.c << 1) + fdc.s.h; fdd = fddfile + fdc.s.drv; +// TRACEOUT(("fdd->crc %d %d %d", fdc.s.drv, track, fdc.s.crcnum)); stat = fdd->crc(fdd, fdc.s.media, track, fdc.s.crcnum, fdc.s.buffer); if (stat & FDDSTAT_RECNFND) { fdc.s.crcnum = 0; @@ -172,12 +265,14 @@ static REG8 crccmd(void) { fdc.s.bufdir = FDCDIR_IN; fdc.s.bufsize = 6; fdc.s.rreg = fdc.s.buffer[0]; + fdc.s.crcnum++; } else { fdc.s.bufdir = FDCDIR_NONE; fdc.s.bufsize = 0; } fdc.s.bufwrite = FALSE; + fdc.s.curtime = 0; return(stat); } @@ -186,10 +281,11 @@ static void bufposinc(void) { BRESULT r; REG8 stat; - if (fdcisbusy()) { + if (fdc.s.busy) { return; } fdc.s.bufpos++; + fdc.s.curtime = 0; if (fdc.s.bufpos >= fdc.s.bufsize) { r = FALSE; if (fdc.s.type == 2) { @@ -204,21 +300,16 @@ static void bufposinc(void) { } 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; - } - } } - if (!r) { - dma.DMA_REDY = 8; - fdc.s.bufdir = FDCDIR_NONE; + fdc.s.bufdir = FDCDIR_NONE; + dmac_sendready(FALSE); + 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; + } } } } @@ -231,244 +322,202 @@ void IOOUTCALL fdc_o(UINT port, REG8 val return; } TRACEOUT(("fdc %.4x,%.2x [%.4x]", port, value, Z80_PC)); - port &= 0xf; - if (port == 8) { // コマンド - 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(); - } - 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; + 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; + // リストアコマンドにおいて + //  マリオは コマンド発行後にbusyを見張る + //  逆にソーサリアンとかは busyだとエラーになる… + // 条件は何? + setbusy(20); + switch(cmd) { + case 0x00: // リストア + 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(); + 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; + break; - case 0x04: // ステップイン - case 0x05: - if (fdc.s.motor) { - fdc.s.step = 1; - fdc.s.c++; - if (cmd & 1) { - seekcmd(); + case 0x04: // ステップイン + case 0x05: + if (fdc.s.motor) { + fdc.s.step = 1; + fdc.s.c++; + if (cmd & 1) { + seekcmd(); + } } - } - break; + break; - case 0x06: // ステップアウト - case 0x07: - if (fdc.s.motor) { - fdc.s.step = -1; - fdc.s.c--; - if (cmd & 1) { - seekcmd(); + case 0x06: // ステップアウト + case 0x07: + if (fdc.s.motor) { + fdc.s.step = -1; + fdc.s.c--; + if (cmd & 1) { + seekcmd(); + } } - } - break; + break; - case 0x08: // リードデータ - case 0x09: - case 0x0a: // ライトデータ - case 0x0b: - setbusy(200); - 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 - dma.DMA_REDY = 8; // ver0.25 - 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: // ライトトラック -#if 0 - { - FDDFILE fdd = fddfile + fdc.s.drv; - switch(fdd->type) { - case DISKTYPE_NOTREADY: - case DISKTYPE_BETA: - break; - - case DISKTYPE_D88: - default: - if (fdc.s.motor) { // ver0.25 - init_tao_d88(); - if (dma.DMA_ENBL) { - dma.DMA_REDY = 0; - } - } - break; - } - } -#endif - break; - } - } - else { - cmd = (REG8)(fdc.s.cmd >> 4); - switch(port) { - case 0x09: // トラック - fdc.s.c = value; - break; - - case 0x0a: // セクタ - FDDMTR_WAITSEC(value); - fdc.s.r = value; - fdc.s.rreg = value; - break; - - case 0x0b: // データ - 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(); - } -#if 0 - else if (cmd == 0x0f) { // TRACK WRITE - FDDFILE fdd = fddfile + fdc.s.drv; - switch(fdd->type) { - case DISKTYPE_NOTREADY: - case DISKTYPE_BETA: - break; - - case DISKTYPE_D88: - default: - fdd_wtao_d88(value); - break; - } - } -#endif - break; + case 0x08: // リードデータ + case 0x09: + case 0x0a: // ライトデータ + case 0x0b: + 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 + fdc.s.stat = 0; + 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 0x0c: // ドライブ・サイド - 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; - } - 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 defined(SUPPORT_MOTORRISEUP) + setmotor(value); +#endif + break; } } REG8 IOINPCALL fdc_i(UINT port) { -static BYTE timeoutwait; -static BYTE last_r; -static short last_off; - REG8 cmd; REG8 ret; +// TRACEOUT(("fdc inp %.4x", port)); + if ((port & (~7)) != 0x0ff8) { return(0xff); } - cmd = (REG8)(fdc.s.cmd >> 4); - if ((port &= 0xf) != 8) { - last_r = -1; - last_off = -1; - timeoutwait = 4; - } - switch(port) { - case 0x8: // ステータス - ret = fdcisbusy(); + 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; +#if 1 + if (fdc.s.bufdir) { // YsII + fdc.s.curtime++; + if (fdc.s.curtime >= 8) { + fdc.s.stat |= 0x04; + bufposinc(); } - last_r = _fdc.r; - last_off = fdc.off; - } // Read Write時のみの変化でいい筈 + } #endif ret = getstat(); if (!(ret & 0x02)) { - dma.DMA_REDY = 8; + dmac_sendready(FALSE); } +// TRACEOUT(("ret->%.2x", ret)); return(ret); - case 0x9: // トラック + case 1: // トラック return(fdc.s.creg); - case 0xa: // セクタ + case 2: // セクタ return(fdc.s.rreg); - case 0xb: // データ + case 3: // データ if (fdc.s.motor) { if (fdc.s.bufdir == FDCDIR_IN) { fdc.s.data = fdc.s.buffer[fdc.s.bufpos]; -// TRACEOUT(("sector read %.2x [%.2x]", fdc.s.data, fdc.s.bufpos)); +// TRACEOUT(("read %.2x - %.2x [%.4x]", fdc.s.bufpos, fdc.s.data, Z80_PC)); bufposinc(); } } - return(fdc.s.data); // WOODY POCO !!! + return(fdc.s.data); -// case 0xc: // FM -// case 0xd: // MFM -// break; + case 4: // FM + case 5: // MFM + return(0x00); - case 0xe: // 1.6M + case 6: // 1.6M fdc.s.media = DISKTYPE_2HD; - return(0xff); + break; - case 0xf: // 500K/1M + case 7: // 500K/1M fdc.s.media = DISKTYPE_2D; - return(0xff); + break; } - return(0); + return(0xff); } @@ -479,5 +528,7 @@ void fdc_reset(void) { FDDMTR_INIT; ZeroMemory(&fdc, sizeof(fdc)); fdc.s.step = 1; + fdc.s.equip = xmilcfg.fddequip; + fdc.s.loopclock = pccore.realclock / 5; }