| version 1.8, 2004/08/11 13:53:53 | 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) { | 
 |  |  | 
| 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) { | if (fdc.s.bufdir) { | 
| TRACEOUT(("dma ready!")); | /* TRACEOUT(("dma ready!")); */ | 
| dma.DMA_REDY = 0; | dmac_sendready(TRUE); | 
 | } | } | 
 |  | (void)id; | 
 | } | } | 
 |  |  | 
| static void setbusy(UINT clock) { | static void setbusy(FDC *f, SINT32 clock) { | 
 |  |  | 
| fdc.s.busy = TRUE; | if (clock > 0) { | 
| nevent_set(NEVENT_FDC, clock, nvitem_fdcbusy, NEVENT_ABSOLUTE); | 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 REG8 getstat(void) { | 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(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 97  static REG8 type2cmd(REG8 sc) { | Line 366  static REG8 type2cmd(REG8 sc) { | 
 | FDDFILE fdd; | FDDFILE fdd; | 
 | UINT    size; | UINT    size; | 
 | REG8    stat; | REG8    stat; | 
 |  | SINT32  clock; | 
 |  | #if defined(SUPPORT_DISKEXT) | 
 |  | SINT32  curclock; | 
 |  | SINT32  nextclock; | 
 |  | UINT32  secinfo; | 
 |  | #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; | } | 
|  | } | 
|  | 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); | 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; | 
| stat = fdd->crc(fdd, fdc.s.media, track, fdc.s.crcnum, fdc.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) { | 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]; | 
|  | 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; | 
|  | 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) { | 
| if (fdc.s.bufpos >= fdc.s.bufsize) { | r = TRUE; | 
| r = FALSE; | } | 
| if (fdc.s.type == 2) { | if ((f->s.cmd & 0x20) && (f->s.bufwrite)) { | 
| stat = 0; | stat = type2flash(f); | 
| if (fdc.s.cmd & 0x10) { | if (stat & (FDDSTAT_RECNFND | FDDSTAT_WRITEFAULT)) { | 
| r = TRUE; | r = FALSE; | 
| } |  | 
| 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; |  | 
| } |  | 
 | } | } | 
 |  | f->s.stat = stat; | 
 | } | } | 
| if (!r) { | } | 
| dma.DMA_REDY = 8; | f->s.bufdir = FDCDIR_NONE; | 
| fdc.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)); | } | 
| switch(port & 7) { | if (f->s.bufdir != FDCDIR_NONE) { | 
| case 0:                                                                 // コマンド | f->s.bufdir = FDCDIR_NONE; | 
| fdc.s.cmd = value; | dmac_sendready(FALSE); | 
| cmd = (REG8)(value >> 4); | } | 
| fdc.s.type = fdctype[cmd]; |  | 
| TRACEOUT(("fdc cmd: %.2x", value)); | f->s.cmd = value; | 
| if (fdc.s.bufwrite) { | cmd = (REG8)(value >> 4); | 
| fdc.s.stat = type2flash(); | f->s.ctype = fdctype[cmd]; | 
| } | /* TRACEOUT(("fdc cmd: %.2x", value)); */ | 
| fdc.s.bufdir = FDCDIR_NONE; | /* リストアコマンドにおいて | 
| setbusy(20); | *  マリオは コマンド発行後にbusyを見張る | 
| switch(cmd) { | *  逆にソーサリアンとかは busyだとエラーになる… | 
| case 0x00:                                                              // リストア | * 条件は何? | 
| if (value & 8) {                                        // LAYDOCK | */ | 
| setbusy(0); | setbusy(f, 20); | 
| } | switch(cmd) { | 
| fdc.s.motor = 0x80;                                     // モーターOn? | case 0x00:                                                              /* リストア */ | 
| fdc.s.c = 0; | f->s.motor = 0x80;                                      /* モーターOn? */ | 
| fdc.s.step = 1; | f->s.c = 0; | 
| fdc.s.r = 0;                                            // デゼニワールド | f->s.step = 1; | 
| seekcmd(); | f->s.r = 0;                                                     /* デゼニワールド */ | 
| fdc.s.rreg = 0; | seekcmd(f); | 
| break; | f->s.rreg = 0; | 
|  | break; | 
| case 0x01:                                                              // シーク |  | 
| fdc.s.motor = 0x80;                                     // モーターOn | case 0x01:                                                              /* シーク */ | 
| fdc.s.step = (SINT8)((fdc.s.c<=fdc.s.data)?1:-1); | f->s.motor = 0x80;                                      /* モーターOn */ | 
| fdc.s.c = fdc.s.data; | f->s.step = (SINT8)((f->s.c<=f->s.data)?1:-1); | 
| seekcmd(); | f->s.c = f->s.data; | 
| break; | seekcmd(f); | 
|  | break; | 
| case 0x02:                                                              // ステップ |  | 
| case 0x03: | case 0x02:                                                              /* ステップ */ | 
| if (fdc.s.motor) { | case 0x03: | 
| fdc.s.c += fdc.s.step; | case 0x04:                                                              /* ステップイン */ | 
| if (cmd & 1) { | case 0x05: | 
| seekcmd(); | case 0x06:                                                              /* ステップアウト */ | 
| } | case 0x07: | 
| } | f->s.stat = FDDSTAT_HEADENG; | 
| break; | if (f->s.motor) { | 
|  | if (cmd & 0x04) { | 
| case 0x04:                                                              // ステップイン | f->s.step = (cmd & 0x02)?-1:1; | 
| case 0x05: | } | 
| if (fdc.s.motor) { | f->s.c += f->s.step; | 
| fdc.s.step = 1; | if (cmd & 1) { | 
| fdc.s.c++; | seekcmd(f); | 
| 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 |  | 
| 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:                                                              // ライトトラック |  | 
| 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; |  | 
 | } | } | 
 | break; | 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 | 
 | } | } | 
 |  |  | 
| REG8 IOINPCALL fdc_i(UINT port) { | static void IOOUTCALL fdc_o0(FDC *f, REG8 value) { | 
|  | } | 
| // static       BYTE    timeoutwait; |  | 
| // static       BYTE    last_r; | static REG8 IOINPCALL fdc_i0ff8(FDC *f) { | 
| // static       short   last_off; |  | 
 | REG8    ret; | 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 | #endif | 
| if ((port &= 0xf) != 8) { | ret = getstat(f); | 
| last_r = -1; | #if 1 | 
| last_off = -1; | if (!(ret & 0x02)) { | 
| timeoutwait = 4; | dmac_sendready(FALSE); | 
| } | } | 
| #endif | #endif | 
| switch(port & 7) { | /* TRACEOUT(("ret->%.2x", ret)); */ | 
| case 0:                                                                 // ステータス | return(ret); | 
| ret = fdc.s.busy; | } | 
| if (ret) { |  | 
| return(ret); | static REG8 IOINPCALL fdc_i0ff9(FDC *f) { | 
| } |  | 
| #if 0 | /* トラック */ | 
| if (fdc.s.type == 2) { | TRACEOUT(("fdc inp %.4x,%.2x", 0x0ff9, f->s.creg)); | 
| if (last_r == _fdc.r && last_off == fdc.off && | return(f->s.creg); | 
| !(--timeoutwait)) { | } | 
| inc_off(); |  | 
| timeoutwait = 4; | static REG8 IOINPCALL fdc_i0ffa(FDC *f) { | 
| } |  | 
| last_r = _fdc.r; | /* セクタ */ | 
| last_off = fdc.off; | TRACEOUT(("fdc inp %.4x,%.2x", 0x0ffa, f->s.rreg)); | 
| }                                                       // Read Write時のみの変化でいい筈 | return(f->s.rreg); | 
| #endif | } | 
| ret = getstat(); |  | 
| if (!(ret & 0x02)) { | static REG8 IOINPCALL fdc_i0ffb(FDC *f) { | 
| dma.DMA_REDY = 8; |  | 
| } | /* データ */ | 
| return(ret); | if (f->s.motor) { | 
|  | if (f->s.bufdir == FDCDIR_IN) { | 
| case 1:                                                                 // トラック | f->s.curtime = 0; | 
| return(fdc.s.creg); | #if !defined(CONST_DISKIMAGE) | 
|  | f->s.data = f->s.buffer[f->s.bufpos]; | 
| case 2:                                                                 // セクタ | #else | 
| return(fdc.s.rreg); | f->s.data = f->e.buffer[f->s.bufpos]; | 
|  | #endif | 
| case 3:                                                                 // データ | if (!f->s.busy) { | 
| if (fdc.s.motor) { | f->s.bufpos++; | 
| if (fdc.s.bufdir == FDCDIR_IN) { | if (f->s.bufpos >= f->s.bufsize) { | 
| fdc.s.data = fdc.s.buffer[fdc.s.bufpos]; | fdcenddata(f); | 
| TRACEOUT(("read %.2x %.2x [%.4x]", fdc.s.data, fdc.s.bufpos, 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; | 
 |  | #if defined(FIX_Z80A) | 
 |  | fdc.s.loopclock = 2000000 * 2 / 5; | 
 |  | #else | 
 |  | fdc.s.loopclock = pccore.realclock / 5; | 
 |  | #endif | 
 | } | } | 
 |  |  |