|
|
| version 1.17, 2004/08/15 11:14:42 | version 1.24, 2009/03/23 15:02:25 |
|---|---|
| Line 1 | Line 1 |
| #include "compiler.h" | #include "compiler.h" |
| #include "dosio.h" | |
| #include "z80core.h" | #include "z80core.h" |
| #include "pccore.h" | #include "pccore.h" |
| #include "iocore.h" | #include "iocore.h" |
| #include "nevent.h" | #include "nevent.h" |
| #include "fddfile.h" | #include "fddfile.h" |
| #include "fdd_2d.h" | |
| #include "fdd_d88.h" | |
| #include "fdd_mtr.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) { | |
| 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) { | void neitem_fdcbusy(UINT id) { |
| fdc.s.busy = FALSE; | fdc.s.busy = 0; |
| if (fdc.s.bufdir) { | if (fdc.s.bufdir) { |
| // TRACEOUT(("dma ready!")); | /* TRACEOUT(("dma ready!")); */ |
| dmac_sendready(TRUE); | dmac_sendready(TRUE); |
| } | } |
| (void)id; | (void)id; |
| } | } |
| static void setbusy(SINT32 clock) { | static void setbusy(FDC *f, SINT32 clock) { |
| if (clock > 0) { | if (clock > 0) { |
| fdc.s.busy = TRUE; | f->s.busy = FDDSTAT_BUSY; |
| nevent_set(NEVENT_FDC, clock, neitem_fdcbusy, NEVENT_ABSOLUTE); | nevent_set(NEVENT_FDC, clock, neitem_fdcbusy, NEVENT_ABSOLUTE); |
| } | } |
| else { | else { |
| fdc.s.busy = FALSE; | f->s.busy = 0; |
| nevent_reset(NEVENT_FDC); | nevent_reset(NEVENT_FDC); |
| } | } |
| } | } |
| #if defined(SUPPORT_MOTORRISEUP) | #if defined(SUPPORT_MOTORRISEUP) |
| static void setmotor(REG8 drvcmd) { | static void setmotor(FDC *f, REG8 drvcmd) { |
| UINT drv; | UINT drv; |
| SINT32 clock; | SINT32 clock; |
| Line 44 static void setmotor(REG8 drvcmd) { | Line 250 static void setmotor(REG8 drvcmd) { |
| drv = drvcmd & 3; | drv = drvcmd & 3; |
| clock = CPU_CLOCK + CPU_BASECLOCK - CPU_REMCLOCK; | clock = CPU_CLOCK + CPU_BASECLOCK - CPU_REMCLOCK; |
| if (drvcmd & 0x80) { | if (drvcmd & 0x80) { |
| if (fdc.s.motorevent[drv] == FDCMOTOR_STOP) { | if (f->s.motorevent[drv] == FDCMOTOR_STOP) { |
| fdc.s.motorevent[drv] = FDCMOTOR_STARTING; | f->s.motorevent[drv] = FDCMOTOR_STARTING; |
| fdc.s.motorclock[drv] = clock; | f->s.motorclock[drv] = clock; |
| } | } |
| else if (fdc.s.motorevent[drv] == FDCMOTOR_STOPING) { | else if (f->s.motorevent[drv] == FDCMOTOR_STOPING) { |
| fdc.s.motorevent[drv] = FDCMOTOR_READY; | f->s.motorevent[drv] = FDCMOTOR_READY; |
| } | } |
| } | } |
| else { | else { |
| if ((fdc.s.motorevent[drv] == FDCMOTOR_STARTING) || | if ((f->s.motorevent[drv] == FDCMOTOR_STARTING) || |
| (fdc.s.motorevent[drv] == FDCMOTOR_READY)) { | (f->s.motorevent[drv] == FDCMOTOR_READY)) { |
| fdc.s.motorevent[drv] = FDCMOTOR_STOPING; | f->s.motorevent[drv] = FDCMOTOR_STOPING; |
| fdc.s.motorclock[drv] = clock; | f->s.motorclock[drv] = clock; |
| } | } |
| } | } |
| } | } |
| Line 81 void fdc_callback(void) { | Line 287 void fdc_callback(void) { |
| } | } |
| } | } |
| static SINT32 motorwait(REG8 drv) { | static SINT32 motorwait(const FDC *f) { |
| SINT32 curclock; | SINT32 curclock; |
| SINT32 nextclock; | SINT32 nextclock; |
| if (fdc.s.motorevent[drv] == FDCMOTOR_STARTING) { | if (f->s.motorevent[f->s.drv] == FDCMOTOR_STARTING) { |
| curclock = CPU_CLOCK + CPU_BASECLOCK - CPU_REMCLOCK; | curclock = CPU_CLOCK + CPU_BASECLOCK - CPU_REMCLOCK; |
| curclock -= fdc.s.motorclock[drv]; | curclock -= f->s.motorclock[f->s.drv]; |
| if (curclock < (SINT32)pccore.realclock) { | if (curclock < (SINT32)pccore.realclock) { |
| nextclock = pccore.realclock - curclock; | nextclock = pccore.realclock - curclock; |
| // TRACEOUT(("motor starting busy %d", nextclock)); | /* TRACEOUT(("motor starting busy %d", nextclock)); */ |
| return(nextclock); | return(nextclock); |
| } | } |
| } | } |
| Line 100 static SINT32 motorwait(REG8 drv) { | Line 306 static SINT32 motorwait(REG8 drv) { |
| #endif | #endif |
| static REG8 getstat(void) { | static REG8 getstat(FDC *f) { |
| FDDFILE fdd; | FDDFILE fdd; |
| REG8 cmd; | REG8 ctype; |
| REG8 type; | |
| REG8 ret; | REG8 ret; |
| fdd = fddfile + fdc.s.drv; | fdd = fddfile + f->s.drv; |
| cmd = (REG8)(fdc.s.cmd >> 4); | ctype = f->s.ctype; |
| type = fdc.s.type; | |
| if (fdd->type == DISKTYPE_NOTREADY) { | if (fdd->type == DISKTYPE_NOTREADY) { |
| ret = FDDSTAT_NOTREADY; | ret = FDDSTAT_NOTREADY; |
| } | } |
| else if (type != 0) { | |
| ret = fdc.s.stat; | |
| } | |
| else { | 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; | ret |= FDDSTAT_TRACK00; |
| } | } |
| if ((type == 0) || (type == 1) || (type == 4) || | if (!(ctype & FDCCTYPE_RO)) { |
| (cmd == 0x0a) || (cmd == 0x0b) || (cmd == 0x0f)) { | |
| if (fdd->protect) { | if (fdd->protect) { |
| ret |= FDDSTAT_WRITEP; | ret |= FDDSTAT_WRITEP; |
| } | } |
| } | } |
| if ((type == 1) || (type == 4)) { | if (ctype & (FDCCTYPE_CMD1 | FDCCTYPE_CMD4)) { |
| fdc.s.hole++; | f->s.hole++; |
| if (fdc.s.hole < 8) { | if (f->s.hole < 8) { |
| ret |= FDDSTAT_INDEX; | ret |= FDDSTAT_INDEX; |
| } | } |
| } | } |
| else if (!(ret & 0xf0)) { | else if (!(ret & 0xf0)) { |
| if (FDDMTR_BUSY) { | if (fddmtr_isbusy()) { |
| ret |= FDDSTAT_BUSY; | ret |= FDDSTAT_BUSY; |
| } | } |
| if (fdc.s.bufdir) { | if (f->s.bufdir) { |
| ret |= FDDSTAT_DRQ | FDDSTAT_BUSY; | ret |= FDDSTAT_DRQ | FDDSTAT_BUSY; |
| } | } |
| else if (cmd == 0x0f) { | |
| ret |= FDDSTAT_LOSTDATA; | |
| } | |
| } | } |
| return(ret); | return(ret); |
| } | } |
| static void seekcmd(void) { | static void seekcmd(FDC *f) { |
| FDDFILE fdd; | FDDFILE fdd; |
| UINT track; | UINT track; |
| fdc.s.crcnum = 0; | f->s.crcnum = 0; |
| fdc.s.creg = fdc.s.c; | f->s.creg = f->s.c; |
| fdd = fddfile + fdc.s.drv; | fdd = fddfile + f->s.drv; |
| track = (fdc.s.c << 1) + fdc.s.h; | track = (f->s.c << 1) + f->s.h; |
| fdc.s.stat = fdd->seek(fdd, fdc.s.media, track) | FDDSTAT_HEADENG; | f->s.stat = fdd->seek(fdd, f->s.media, track) | FDDSTAT_HEADENG; |
| FDDMTR_MOVE; | fddmtr_motormove(); |
| } | } |
| static REG8 type2cmd(REG8 sc) { | static REG8 type2cmd(FDC *f, REG8 sc) { |
| REG8 dir; | REG8 dir; |
| UINT track; | UINT track; |
| Line 176 static REG8 type2cmd(REG8 sc) { | Line 373 static REG8 type2cmd(REG8 sc) { |
| UINT32 secinfo; | UINT32 secinfo; |
| #endif | #endif |
| track = (fdc.s.c << 1) + fdc.s.h; | track = (f->s.c << 1) + f->s.h; |
| if (!(fdc.s.cmd & 0x20)) { | fdd = fddfile + f->s.drv; |
| p = fdc.s.buffer; | #if !defined(CONST_DISKIMAGE) |
| if (!(f->s.cmd & 0x20)) { | |
| p = f->s.buffer; | |
| dir = FDCDIR_IN; | dir = FDCDIR_IN; |
| } | } |
| else { | else { |
| p = NULL; | p = NULL; |
| dir = FDCDIR_OUT; | dir = FDCDIR_OUT; |
| } | } |
| size = sizeof(fdc.s.buffer); | size = sizeof(f->s.buffer); |
| fdd = fddfile + fdc.s.drv; | stat = fdd->read(fdd, f->s.media, track, sc, p, &size); |
| // 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) { | if (stat & FDDSTAT_RECNFND) { |
| size = 0; | size = 0; |
| dir = FDCDIR_NONE; | dir = FDCDIR_NONE; |
| } | } |
| else if (dir == FDCDIR_OUT) { | else if (dir == FDCDIR_OUT) { |
| if (size) { | if (size) { |
| ZeroMemory(fdc.s.buffer, size); | ZeroMemory(f->s.buffer, size); |
| } | } |
| stat = stat & (~FDDSTAT_RECTYPE); | stat = stat & (~FDDSTAT_RECTYPE); |
| } | } |
| fdc.s.bufmedia = fdc.s.media; | #else |
| fdc.s.bufunit = fdc.s.drv; | size = 0; |
| fdc.s.buftrack = track; | dir = FDCDIR_NONE; |
| fdc.s.bufsc = sc; | if (!(f->s.cmd & 0x20)) { |
| fdc.s.bufwrite = FALSE; | stat = fdd->readp(fdd, f->s.media, track, sc, (void **)&p, &size); |
| fdc.s.bufdir = dir; | if (!(stat & FDDSTAT_RECNFND)) { |
| fdc.s.bufmark = fdc.s.cmd & 1; | f->e.buffer = p; |
| fdc.s.bufpos = 0; | dir = FDCDIR_IN; |
| fdc.s.bufsize = size; | } |
| fdc.s.curtime = 0; | } |
| 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; | clock = 0; |
| #if defined(SUPPORT_MOTORRISEUP) | #if defined(SUPPORT_MOTORRISEUP) |
| clock += motorwait(fdc.s.drv); | clock += motorwait(f); |
| #endif | #endif |
| #if defined(SUPPORT_DISKEXT) | #if defined(SUPPORT_DISKEXT) |
| secinfo = fdd->sec(fdd, fdc.s.media, track, sc); | secinfo = fdd->sec(fdd, f->s.media, track, sc); |
| if (secinfo) { | if (secinfo) { |
| nextclock = LOW16(secinfo); | nextclock = LOW16(secinfo); |
| nextclock *= fdc.s.loopclock; | nextclock *= f->s.loopclock; |
| nextclock /= LOW16(secinfo >> 16); | nextclock /= LOW16(secinfo >> 16); |
| curclock = nevent_getwork(NEVENT_RTC); | curclock = nevent_getwork(NEVENT_RTC); |
| nextclock -= curclock; | nextclock -= curclock; |
| if (nextclock < 0) { | if (nextclock < 0) { |
| nextclock += fdc.s.loopclock; | nextclock += f->s.loopclock; |
| } | } |
| // TRACEOUT(("wait clock -> %d [%d/%d]", nextclock, | /* TRACEOUT(("wait clock -> %d [%d/%d]", nextclock, |
| // LOW16(secinfo), LOW16(secinfo >> 16))); | LOW16(secinfo), LOW16(secinfo >> 16))); */ |
| clock += nextclock; | clock += nextclock; |
| } | } |
| #endif | #endif |
| setbusy(max(clock, 500)); | setbusy(f, max(clock, 500)); |
| return(stat); | return(stat); |
| } | } |
| static REG8 type2flash(void) { | static REG8 type2flash(FDC *f) { |
| #if !defined(CONST_DISKIMAGE) | |
| FDDFILE fdd; | FDDFILE fdd; |
| fdc.s.bufwrite = FALSE; | f->s.bufwrite = FALSE; |
| fdd = fddfile + fdc.s.bufunit; | fdd = fddfile + f->s.bufunit; |
| if (fdd->protect) { | if (fdd->protect) { |
| return(FDDSTAT_WRITEFAULT); | return(FDDSTAT_WRITEFAULT); |
| } | } |
| return(fdd->write(fdd, fdc.s.bufmedia, fdc.s.buftrack, | return(fdd->write(fdd, f->s.bufmedia, f->s.buftrack, |
| fdc.s.bufsc, fdc.s.buffer, fdc.s.bufpos)); | 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; | UINT track; |
| FDDFILE fdd; | FDDFILE fdd; |
| REG8 stat; | REG8 stat; |
| track = (fdc.s.c << 1) + fdc.s.h; | #if !defined(CONST_DISKIMAGE) |
| fdd = fddfile + fdc.s.drv; | crcbuf = f->s.buffer; |
| // TRACEOUT(("fdd->crc %d %d %d", fdc.s.drv, track, fdc.s.crcnum)); | #else |
| stat = fdd->crc(fdd, fdc.s.media, track, fdc.s.crcnum, fdc.s.buffer); | 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) { | if (stat & FDDSTAT_RECNFND) { |
| fdc.s.crcnum = 0; | f->s.crcnum = 0; |
| stat = fdd->crc(fdd, fdc.s.media, track, 0, fdc.s.buffer); | stat = fdd->crc(fdd, f->s.media, track, 0, crcbuf); |
| } | } |
| if (!(stat & FDDSTAT_RECNFND)) { | if (!(stat & FDDSTAT_RECNFND)) { |
| fdc.s.bufdir = FDCDIR_IN; | f->s.bufdir = FDCDIR_IN; |
| fdc.s.bufsize = 6; | f->s.bufsize = 6; |
| fdc.s.rreg = fdc.s.buffer[0]; | f->s.rreg = crcbuf[0]; |
| fdc.s.crcnum++; | f->s.crcnum++; |
| } | } |
| else { | else { |
| fdc.s.bufdir = FDCDIR_NONE; | f->s.bufdir = FDCDIR_NONE; |
| fdc.s.bufsize = 0; | f->s.bufsize = 0; |
| } | } |
| fdc.s.bufwrite = FALSE; | f->s.bufwrite = FALSE; |
| fdc.s.curtime = 0; | f->s.curtime = 0; |
| return(stat); | return(stat); |
| } | } |
| static void bufposinc(void) { | static void fdcenddata(FDC *f) { |
| BRESULT r; | BRESULT r; |
| REG8 stat; | REG8 stat; |
| if (fdc.s.busy) { | r = FALSE; |
| return; | if (f->s.ctype & FDCCTYPE_CMD2) { |
| } | stat = 0; |
| fdc.s.bufpos++; | if (f->s.cmd & 0x10) { |
| fdc.s.curtime = 0; | r = TRUE; |
| 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; | |
| } | |
| } | } |
| fdc.s.bufdir = FDCDIR_NONE; | if ((f->s.cmd & 0x20) && (f->s.bufwrite)) { |
| dmac_sendready(FALSE); | stat = type2flash(f); |
| if (r) { | if (stat & (FDDSTAT_RECNFND | FDDSTAT_WRITEFAULT)) { |
| fdc.s.rreg = fdc.s.r + 1; | r = FALSE; |
| stat = type2cmd(fdc.s.rreg); | |
| if (!(stat & FDDSTAT_RECNFND)) { | |
| fdc.s.r = fdc.s.r + 1; | |
| fdc.s.stat = stat; | |
| } | } |
| 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; | |
| } | } |
| } | } |
| } | } |
| void IOOUTCALL fdc_o(UINT port, REG8 value) { | |
| /* IO-Sub */ | |
| static void IOOUTCALL fdc_o0ff8(FDC *f, REG8 value) { | |
| REG8 cmd; | REG8 cmd; |
| if ((port & (~7)) != 0x0ff8) { | /* コマンド */ |
| return; | if (f->s.bufwrite) { |
| f->s.stat = type2flash(f); | |
| } | } |
| // TRACEOUT(("fdc %.4x,%.2x [%.4x]", port, value, Z80_PC)); | if (f->s.bufdir != FDCDIR_NONE) { |
| switch(port & 7) { | f->s.bufdir = FDCDIR_NONE; |
| case 0: // コマンド | dmac_sendready(FALSE); |
| fdc.s.cmd = value; | } |
| cmd = (REG8)(value >> 4); | |
| fdc.s.type = fdctype[cmd]; | f->s.cmd = value; |
| // TRACEOUT(("fdc cmd: %.2x", value)); | cmd = (REG8)(value >> 4); |
| if (fdc.s.bufwrite) { | f->s.ctype = fdctype[cmd]; |
| fdc.s.stat = type2flash(); | /* TRACEOUT(("fdc cmd: %.2x", value)); */ |
| } | /* リストアコマンドにおいて |
| fdc.s.bufdir = FDCDIR_NONE; | * マリオは コマンド発行後にbusyを見張る |
| // リストアコマンドにおいて | * 逆にソーサリアンとかは busyだとエラーになる… |
| // マリオは コマンド発行後にbusyを見張る | * 条件は何? |
| // 逆にソーサリアンとかは busyだとエラーになる… | */ |
| // 条件は何? | setbusy(f, 20); |
| setbusy(20); | switch(cmd) { |
| switch(cmd) { | case 0x00: /* リストア */ |
| case 0x00: // リストア | f->s.motor = 0x80; /* モーターOn? */ |
| fdc.s.motor = 0x80; // モーターOn? | f->s.c = 0; |
| fdc.s.c = 0; | f->s.step = 1; |
| fdc.s.step = 1; | f->s.r = 0; /* デゼニワールド */ |
| fdc.s.r = 0; // デゼニワールド | seekcmd(f); |
| seekcmd(); | f->s.rreg = 0; |
| fdc.s.rreg = 0; | break; |
| break; | |
| case 0x01: /* シーク */ | |
| case 0x01: // シーク | f->s.motor = 0x80; /* モーターOn */ |
| fdc.s.motor = 0x80; // モーターOn | f->s.step = (SINT8)((f->s.c<=f->s.data)?1:-1); |
| fdc.s.step = (SINT8)((fdc.s.c<=fdc.s.data)?1:-1); | f->s.c = f->s.data; |
| fdc.s.c = fdc.s.data; | seekcmd(f); |
| seekcmd(); | break; |
| break; | |
| case 0x02: /* ステップ */ | |
| case 0x02: // ステップ | case 0x03: |
| case 0x03: | case 0x04: /* ステップイン */ |
| if (fdc.s.motor) { | case 0x05: |
| fdc.s.c += fdc.s.step; | case 0x06: /* ステップアウト */ |
| if (cmd & 1) { | case 0x07: |
| seekcmd(); | f->s.stat = FDDSTAT_HEADENG; |
| } | if (f->s.motor) { |
| } | if (cmd & 0x04) { |
| break; | f->s.step = (cmd & 0x02)?-1:1; |
| } | |
| case 0x04: // ステップイン | f->s.c += f->s.step; |
| case 0x05: | if (cmd & 1) { |
| if (fdc.s.motor) { | seekcmd(f); |
| 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: | |
| 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 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) | break; |
| setmotor(value); | |
| 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 | #endif |
| break; | break; |
| } | } |
| } | } |
| REG8 IOINPCALL fdc_i(UINT port) { | static void IOOUTCALL fdc_o0ff9(FDC *f, REG8 value) { |
| REG8 ret; | /* トラック */ |
| f->s.creg = value; | |
| } | |
| // TRACEOUT(("fdc inp %.4x", port)); | static void IOOUTCALL fdc_o0ffa(FDC *f, REG8 value) { |
| if ((port & (~7)) != 0x0ff8) { | /* セクタ */ |
| return(0xff); | fddmtr_waitsec(value); |
| } | f->s.r = value; |
| switch(port & 7) { | f->s.rreg = value; |
| case 0: // ステータス | } |
| ret = fdc.s.busy; | |
| if (ret) { | static void IOOUTCALL fdc_o0ffb(FDC *f, REG8 value) { |
| return(ret); | |
| /* データ */ | |
| 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) { | |
| } | |
| static REG8 IOINPCALL fdc_i0ff8(FDC *f) { | |
| REG8 ret; | |
| /* ステータス */ | |
| ret = f->s.busy; | |
| if (ret) { | |
| return(ret); | |
| } | |
| #if 1 | #if 1 |
| if (fdc.s.bufdir) { // YsII | if (f->s.bufdir >= FDCDIR_IN) { /* YsII */ |
| fdc.s.curtime++; | f->s.curtime++; |
| if (fdc.s.curtime >= 8) { | if (f->s.curtime >= 8) { |
| fdc.s.stat |= 0x04; | f->s.curtime = 0; |
| bufposinc(); | 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 | |
| /* 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 | #endif |
| ret = getstat(); | if (!f->s.busy) { |
| if (!(ret & 0x02)) { | f->s.bufpos++; |
| dmac_sendready(FALSE); | if (f->s.bufpos >= f->s.bufsize) { |
| } | fdcenddata(f); |
| // TRACEOUT(("ret->%.2x", ret)); | |
| 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.bufpos, fdc.s.data, Z80_PC)); | |
| bufposinc(); | |
| } | } |
| } | } |
| return(fdc.s.data); | /* TRACEOUT(("read %.2x - %.2x [%.4x]", f->s.bufpos, f->s.data, Z80_PC)); */ |
| } | |
| } | |
| return(f->s.data); | |
| } | |
| case 4: // FM | static REG8 IOINPCALL fdc_i0ffc(FDC *f) { |
| case 5: // MFM | |
| return(0x00); | |
| case 6: // 1.6M | /* FM */ |
| fdc.s.media = DISKTYPE_2HD; | return(0x00); |
| break; | } |
| case 7: // 500K/1M | static REG8 IOINPCALL fdc_i0ffd(FDC *f) { |
| fdc.s.media = DISKTYPE_2D; | |
| break; | /* 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); | 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) { | void fdc_reset(void) { |
| FDDMTR_INIT; | fddmtr_initialize(); |
| ZeroMemory(&fdc, sizeof(fdc)); | ZeroMemory(&fdc, sizeof(fdc)); |
| fdc.s.step = 1; | fdc.s.step = 1; |
| fdc.s.equip = xmilcfg.fddequip; | fdc.s.equip = xmilcfg.fddequip; |
| #if defined(FIX_Z80A) | |
| fdc.s.loopclock = 2000000 * 2 / 5; | |
| #else | |
| fdc.s.loopclock = pccore.realclock / 5; | fdc.s.loopclock = pccore.realclock / 5; |
| #endif | |
| } | } |