t_stat dp_io (int32 fnc, int32 flg, int32 mod) { int32 dcf, drv, sec, psec, cnt, qwc, qzr, diff; UNIT *uptr; t_stat r; dcf = BS; /* save DCF addr */ qwc = 0; /* not wcheck */ ind[IN_DPW] = ind[IN_LNG] = ind[IN_UNA] = 0; /* clr indicators */ ind[IN_DSK] = ind[IN_ACC] = ind[IN_DBY] = 0; if (sim_is_active (&dp_unit[0])) { /* ctlr busy? */ ind[IN_DBY] = ind[IN_DSK] = 1; /* set indicators */ return SCPE_OK; } /* done */ AS = dcf + 6; /* AS for most ops */ BS = dcf + DCF_CNT - 1; /* minimum DCF */ if (ADDR_ERR (BS)) return STOP_WRAP; /* DCF in memory? */ if (M[dcf] & BBIT) drv = M[dcf + DCF_SEC + 1] & 0xE; /* impl sel? cyl 8-4-2 */ else drv = M[dcf] & DIGIT; /* get drive sel */ if ((drv == 0) || (drv & 1) || (drv > BCD_ZERO)) /* bad drive #? */ return STOP_INVDSK; drv = bcd_to_bin[drv] >> 1; /* convert */ uptr = dp_dev.units + drv; /* get unit ptr */ if ((uptr->flags & UNIT_ATT) == 0) { /* attached? */ ind[IN_DSK] = ind[IN_ACC] = 1; /* no, error */ CRETIOE (iochk, SCPE_UNATT); } if ((fnc == FNC_SEEK) && /* seek and */ (M[dcf + DCF_DIR_FL] & DCF_DSEEK) == DCF_DSEEK) { /* direct flag? */ diff = dp_cvt_bcd (dcf + DCF_DIR, DCF_DIR_LEN); /* cvt diff */ if (diff < 0) return STOP_INVDSC; /* error? */ diff = diff >> 1; /* diff is *2 */ if ((M[dcf + DCF_DIR + DCF_DIR_LEN - 1] & ZONE) == BBIT) diff = -diff; /* get sign */ uptr->CYL = uptr->CYL + diff; /* bound seek */ if (uptr->CYL < 0) uptr->CYL = 0; else if (uptr->CYL >= DP_NUMCY) { /* too big? */ uptr->CYL = 0; /* system hangs */ return STOP_INVDCY; } sim_activate (&dp_unit[0], dp_time); /* set ctlr busy */ return SCPE_OK; } /* done! */
t_stat dp (uint32 op, uint32 pa, uint32 f0, uint32 f1) { int32 drv, sa, sec, psec, cnt, qwc, qnr, t; UNIT *uptr; t_stat r; if (pa & 1) /* dcf must be even */ return STOP_INVDCF; ind[IN_DACH] = ind[IN_DWLR] = 0; /* clr indicators */ ind[IN_DERR] = ind[IN_DCYO] = 0; sa = ADDR_A (pa, DCF_SEC); /* ptr to sector */ if (((dp_unit[0].flags & UNIT_DIS) == 0) && /* only drive 0? */ (dp_unit[1].flags & UNIT_DIS) && (dp_unit[2].flags & UNIT_DIS) && (dp_unit[3].flags & UNIT_DIS)) drv = 0; /* ignore drv select */ else drv = (((M[pa] & 1)? M[pa]: M[sa]) & 0xE) >> 1; /* drive # */ if (drv >= DP_NUMDR) /* invalid? */ return STOP_INVDRV; uptr = dp_dev.units + drv; /* get unit ptr */ if ((uptr->flags & UNIT_ATT) == 0) { /* attached? */ ind[IN_DERR] = 1; /* no, error */ CRETIOE (dp_stop, SCPE_UNATT); } sec = dp_cvt_bcd (sa, DCF_SEC_LEN); /* cvt sector */ if ((sec < 0) || (sec >= (DP_NUMDR * DP_TOTSC))) /* bad sector? */ return STOP_INVDSC; if (op == OP_K) { /* seek? */ if (f1 != FNC_SEEK) /* really? */ return STOP_INVFNC; uptr->CYL = (sec / (DP_NUMSF * DP_NUMSC)) % /* set cyl # */ DP_NUMCY; return SCPE_OK; /* done! */ } cnt = dp_cvt_bcd (ADDR_A (pa, DCF_CNT), DCF_CNT_LEN); /* get count */ t = dp_cvt_bcd (ADDR_A (pa, DCF_ADR), DCF_ADR_LEN); /* get address */ if ((t < 0) || (t & 1)) /* bad address? */ return STOP_INVDBA; dp_ba = t; /* save addr */ if (f1 >= FNC_WRI) /* invalid func? */ return STOP_INVFNC; if (op == OP_RN) /* read? set wch */ qwc = f1 & FNC_WCH; else if (op == OP_WN) { /* write? */ if (op & FNC_WCH) /* cant check */ return STOP_INVFNC; f1 = f1 + FNC_WRI; /* offset fnc */ } else return STOP_INVFNC; /* not R or W */ qnr = f1 & FNC_NRL; /* no rec check? */ switch (f1 & ~(FNC_WCH | FNC_NRL)) { /* case on function */ case FNC_SEC: /* read sectors */ if (cnt <= 0) /* bad count? */ return STOP_INVDCN; psec = dp_fndsec (uptr, sec, TRUE); /* find sector */ if (psec < 0) /* error? */ CRETIOE (dp_stop, STOP_DACERR); do { /* loop on count */ if ((r = dp_rdsec (uptr, psec, qnr, qwc))) /* read sector */ break; sec++; psec++; /* next sector */ } while ((--cnt > 0) && ((r = dp_nexsec (uptr, sec, psec, TRUE)) == SCPE_OK)); break; /* done, clean up */ case FNC_TRK: /* read track */ psec = dp_trkop (drv, sec); /* start of track */ for (cnt = 0; cnt < DP_NUMSC; cnt++) { /* full track */ if ((r = dp_rdadr (uptr, psec, qnr, qwc))) /* read addr */ break; /* error? */ if ((r = dp_rdsec (uptr, psec, qnr, qwc))) /* read data */ break; /* error? */ psec = dp_trkop (drv, sec) + ((psec + 1) % DP_NUMSC); } break; /* done, clean up */ case FNC_SEC + FNC_WRI: /* write */ if (cnt <= 0) /* bad count? */ return STOP_INVDCN; psec = dp_fndsec (uptr, sec, FALSE); /* find sector */ if (psec < 0) /* error? */ CRETIOE (dp_stop, STOP_DACERR); do { /* loop on count */ if ((r = dp_tstgm (M[dp_ba], qnr))) /* start with gm? */ break; if ((r = dp_wrsec (uptr, psec, qnr))) /* write data */ break; sec++; psec++; /* next sector */ } while ((--cnt > 0) && ((r = dp_nexsec (uptr, sec, psec, FALSE)) == SCPE_OK)); break; /* done, clean up */ case FNC_TRK + FNC_WRI: /* write track */ if ((uptr->flags & UNIT_WAE) == 0) /* enabled? */ return STOP_WRADIS; psec = dp_trkop (drv, sec); /* start of track */ for (cnt = 0; cnt < DP_NUMSC; cnt++) { /* full track */ if ((r = dp_tstgm (M[dp_ba], qnr))) /* start with gm? */ break; if ((r = dp_wradr (uptr, psec, qnr))) /* write addr */ break; if ((r = dp_wrsec (uptr, psec, qnr))) /* write data */ break; psec = dp_trkop (drv, sec) + ((psec + 1) % DP_NUMSC); } break; /* done, clean up */ default: /* unknown */ return STOP_INVFNC; } if ((r == SCPE_OK) && !qnr) { /* eor check? */ if ((M[dp_ba] & DIGIT) != GRP_MARK) { /* GM at end? */ ind[IN_DWLR] = ind[IN_DERR] = 1; /* no, error */ r = STOP_WRLERR; } } if ((r != SCPE_OK) && /* error? */ (dp_stop || !ind[IN_DERR])) /* iochk or stop? */ return r; return SCPE_OK; /* continue */ }
if ((fnc == FNC_SEEK) && /* seek and */ (M[dcf + DCF_DIR_FL] & DCF_DSEEK) == DCF_DSEEK) { /* direct flag? */ diff = dp_cvt_bcd (dcf + DCF_DIR, DCF_DIR_LEN); /* cvt diff */ if (diff < 0) return STOP_INVDSC; /* error? */ diff = diff >> 1; /* diff is *2 */ if ((M[dcf + DCF_DIR + DCF_DIR_LEN - 1] & ZONE) == BBIT) diff = -diff; /* get sign */ uptr->CYL = uptr->CYL + diff; /* bound seek */ if (uptr->CYL < 0) uptr->CYL = 0; else if (uptr->CYL >= DP_NUMCY) { /* too big? */ uptr->CYL = 0; /* system hangs */ return STOP_INVDCY; } sim_activate (&dp_unit[0], dp_time); /* set ctlr busy */ return SCPE_OK; } /* done! */ sec = dp_cvt_bcd (dcf + DCF_SEC, DCF_SEC_LEN); /* cvt sector */ if ((sec < 0) || (sec >= (DP_NUMDR * DP_TOTSC))) /* bad sector? */ return STOP_INVDSC; if (fnc == FNC_SEEK) { /* seek? */ uptr->CYL = (sec / (DP_NUMSF * DP_NUMSC)) % /* set cyl # */ DP_NUMCY; sim_activate (&dp_unit[0], dp_time); /* set ctlr busy */ return SCPE_OK; } /* done! */ BS = dcf + DCF_LEN; /* full DCF */ if (ADDR_ERR (BS)) return STOP_WRAP; /* DCF in memory? */ cnt = dp_get_cnt (dcf); /* get count */ if (cnt < 0) return STOP_INVDCN; /* bad count? */ if (fnc >= FNC_WOFF) return STOP_INVDFN; /* invalid func */ if (mod == BCD_W) { /* write? */