t_stat sim_tape_wrdata (UNIT *uptr, uint32 dat) { MT_CLR_PNU (uptr); if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ return MTSE_UNATT; if (sim_tape_wrp (uptr)) /* write prot? */ return MTSE_WRP; sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set pos */ sim_fwrite (&dat, sizeof (t_mtrlnt), 1, uptr->fileref); if (ferror (uptr->fileref)) { /* error? */ MT_SET_PNU (uptr); return sim_tape_ioerr (uptr); } uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* move tape */ return MTSE_OK; }
uint32 mt_tdv_status (uint32 un) { uint32 st; UNIT *uptr = &mt_unit[un]; if (uptr->flags & UNIT_ATT) { /* attached? */ st = uptr->UST; /* unit stat */ if (sim_tape_eot (uptr)) /* at EOT? */ st |= MTDV_EOT; if (!sim_tape_wrp (uptr)) /* not wlock? */ st |= MTDV_WRE; } else st = (CC2 << DVT_V_CC); if (sim_is_active (uptr + MT_REW)) /* unit rewinding? */ st |= (MTDV_REW | (CC2 << DVT_V_CC)); return st; }
t_stat sim_tape_wrrecf (UNIT *uptr, uint8 *buf, t_mtrlnt bc) { uint32 f = MT_GET_FMT (uptr); t_mtrlnt sbc; MT_CLR_PNU (uptr); sbc = MTR_L (bc); if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ return MTSE_UNATT; if (sim_tape_wrp (uptr)) /* write prot? */ return MTSE_WRP; if (sbc == 0) /* nothing to do? */ return MTSE_OK; sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set pos */ switch (f) { /* case on format */ case MTUF_F_STD: /* standard */ sbc = MTR_L ((bc + 1) & ~1); /* pad odd length */ case MTUF_F_E11: /* E11 */ sim_fwrite (&bc, sizeof (t_mtrlnt), 1, uptr->fileref); sim_fwrite (buf, sizeof (uint8), sbc, uptr->fileref); sim_fwrite (&bc, sizeof (t_mtrlnt), 1, uptr->fileref); if (ferror (uptr->fileref)) { /* error? */ MT_SET_PNU (uptr); return sim_tape_ioerr (uptr); } uptr->pos = uptr->pos + sbc + (2 * sizeof (t_mtrlnt)); /* move tape */ break; case MTUF_F_P7B: /* Pierce 7B */ buf[0] = buf[0] | P7B_SOR; /* mark start of rec */ sim_fwrite (buf, sizeof (uint8), sbc, uptr->fileref); sim_fwrite (buf, sizeof (uint8), 1, uptr->fileref); /* delimit rec */ if (ferror (uptr->fileref)) { /* error? */ MT_SET_PNU (uptr); return sim_tape_ioerr (uptr); } uptr->pos = uptr->pos + sbc; /* move tape */ break; } return MTSE_OK; }
t_stat mt_wrend (uint32 dev) { UNIT *uptr = mt_dev.units + (dev & MT_UNIT); t_mtrlnt tbc; t_stat st; sim_cancel (uptr); /* no more xfr's */ if (mt_bptr == 0) /* buf empty? */ return SCPE_OK; if (!(uptr->flags & UNIT_ATT)) { /* attached? */ mt_set_err (uptr); /* no, err, disc */ return SCPE_UNATT; } if (sim_tape_wrp (uptr)) { /* write lock? */ mt_set_err (uptr); /* yes, err, disc */ return SCPE_OK; } if (dev & DEV_MTS) { /* erase? */ if (mt_inst & CHC_REV) /* reverse? */ sim_tape_sprecr (uptr, &tbc); /* backspace */ st = sim_tape_wreom (uptr); /* write eom */ } else { t_bool passed_eot = sim_tape_eot (uptr); /* passed EOT? */ if ((mt_bptr == 1) && (mtxb[0] == 017) && /* wr eof? */ ((mt_inst & 01670) == 00050)) st = sim_tape_wrtmk (uptr); /* write tape mark */ else st = sim_tape_wrrecf (uptr, mtxb, mt_bptr); /* write record */ if (!passed_eot && sim_tape_eot (uptr)) /* just passed EOT? */ uptr->eotf = 1; } mt_bptr = 0; if (st != MTSE_OK) /* error? */ mt_set_err (uptr); if (st == MTSE_IOERR) return SCPE_IOERR; return SCPE_OK; }
t_stat mt_reset (DEVICE *dptr) { hp_enbdis_pair (dptr, /* make pair cons */ (dptr == &mtd_dev) ? &mtc_dev : &mtd_dev); if (dptr == &mtc_dev) /* command channel reset? */ mtcio (mtc_dib.devno, ioPOPIO, 0); /* send POPIO signal to command channel */ else /* data channel reset */ mtdio (mtd_dib.devno, ioPOPIO, 0); /* send POPIO signal to data channel */ mtc_fnc = 0; mtc_1st = mtc_dtf = 0; sim_cancel (&mtc_unit); /* cancel activity */ sim_tape_reset (&mtc_unit); if (mtc_unit.flags & UNIT_ATT) mtc_sta = (sim_tape_bot (&mtc_unit)? STA_BOT: 0) | (sim_tape_wrp (&mtc_unit)? STA_WLK: 0); else mtc_sta = STA_LOCAL | STA_BUSY; return SCPE_OK; }
t_stat ts_svc (UNIT *uptr) { int32 i, t, bc, fnc, mod, st0, st1; static const int32 fnc_mod[CMD_N_FNC] = { /* max mod+1 0 ill */ 0, 4, 0, 0, 1, 2, 1, 0, /* 00 - 07 */ 5, 3, 5, 1, 0, 0, 0, 1, /* 10 - 17 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 27 */ 0, 0, 0, 0, 0, 0, 0, 0 /* 30 - 37 */ }; static const int32 fnc_flg[CMD_N_FNC] = { 0, FLG_MO+FLG_AD, 0, 0, 0, FLG_MO+FLG_WR+FLG_AD, FLG_AD, 0, FLG_MO, FLG_MO+FLG_WR, FLG_MO, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 27 */ 0, 0, 0, 0, 0, 0, 0, 0 /* 30 - 37 */ }; static const char *fnc_name[CMD_N_FNC] = { "0", "READ", "2", "3", "WCHR", "WRITE", "WSSM", "7", "POS", "FMT", "CTL", "INIT", "14", "15", "16", "GSTA", "20", "21", "22", "23", "24", "25", "26", "27", "30", "31", "32", "33", "34", "35", "36", "37" }; if (ts_bcmd) { /* boot? */ ts_bcmd = 0; /* clear flag */ sim_tape_rewind (uptr); /* rewind */ if (uptr->flags & UNIT_ATT) { /* attached? */ cmdlnt = cmdadh = cmdadl = 0; /* defang rd */ ts_spacef (uptr, 1, FALSE); /* space fwd */ ts_readf (uptr, 512); /* read blk */ tssr = ts_updtssr (tssr | TSSR_SSR); } else tssr = ts_updtssr (tssr | TSSR_SSR | TC3); if (cmdhdr & CMD_IE) SET_INT (TS); return SCPE_OK; } if (!(cmdhdr & CMD_ACK)) { /* no acknowledge? */ tssr = ts_updtssr (tssr | TSSR_SSR); /* set rdy, int */ if (cmdhdr & CMD_IE) SET_INT (TS); ts_ownc = ts_ownm = 0; /* CPU owns all */ return SCPE_OK; } fnc = GET_FNC (cmdhdr); /* get fnc+mode */ mod = GET_MOD (cmdhdr); if (DEBUG_PRS (ts_dev)) { fprintf (sim_deb, ">>TS: cmd=%s, mod=%o, buf=%o, lnt=%d, pos=", fnc_name[fnc], mod, cmdadl, cmdlnt); fprint_val (sim_deb, ts_unit.pos, 10, T_ADDR_W, PV_LEFT); fprintf (sim_deb, "\n"); } if ((fnc != FNC_WCHR) && (tssr & TSSR_NBA)) { /* ~wr chr & nba? */ ts_endcmd (TC3, 0, 0); /* error */ return SCPE_OK; } if (ts_qatn && (wchopt & WCH_EAI)) { /* attn pending? */ ts_endcmd (TC1, 0, MSG_MATN | MSG_CATN); /* send attn msg */ SET_INT (TS); /* set interrupt */ ts_qatn = 0; /* not pending */ return SCPE_OK; } if (cmdhdr & CMD_CVC) /* cvc? clr vck */ msgxs0 = msgxs0 & ~XS0_VCK; if ((cmdhdr & CMD_MBZ) || (mod >= fnc_mod[fnc])) { /* test mbz */ ts_endcmd (TC3, XS0_ILC, MSG_ACK | MSG_MILL | MSG_CFAIL); return SCPE_OK; } if ((fnc_flg[fnc] & FLG_MO) && /* mot+(vck|!att)? */ ((msgxs0 & XS0_VCK) || !(uptr->flags & UNIT_ATT))) { ts_endcmd (TC3, XS0_NEF, MSG_ACK | MSG_MNEF | MSG_CFAIL); return SCPE_OK; } if ((fnc_flg[fnc] & FLG_WR) && /* write? */ sim_tape_wrp (uptr)) { /* write lck? */ ts_endcmd (TC3, XS0_WLE | XS0_NEF, MSG_ACK | MSG_MNEF | MSG_CFAIL); return SCPE_OK; } if ((((fnc == FNC_READ) && (mod == 1)) || /* read rev */ ((fnc == FNC_POS) && (mod & 1))) && /* space rev */ sim_tape_bot (uptr)) { /* BOT? */ ts_endcmd (TC3, XS0_NEF, MSG_ACK | MSG_MNEF | MSG_CFAIL); return SCPE_OK; } if ((fnc_flg[fnc] & FLG_AD) && (cmdadh & ADDRTEST)) { /* buf addr > 22b? */ ts_endcmd (TC3, XS0_ILA, MSG_ACK | MSG_MILL | MSG_CFAIL); return SCPE_OK; } st0 = st1 = 0; switch (fnc) { /* case on func */ case FNC_INIT: /* init */ if (!sim_tape_bot (uptr)) /* set if tape moves */ msgxs0 = msgxs0 | XS0_MOT; sim_tape_rewind (uptr); /* rewind */ case FNC_WSSM: /* write mem */ case FNC_GSTA: /* get status */ ts_endcmd (TC0, 0, MSG_ACK | MSG_CEND); /* send end packet */ return SCPE_OK; case FNC_WCHR: /* write char */ if ((cmdadh & ADDRTEST) || (cmdadl & 1) || (cmdlnt < 6)) { ts_endcmd (TSSR_NBA | TC3, XS0_ILA, 0); break; } tsba = (cmdadh << 16) | cmdadl; bc = ((WCH_PLNT << 1) > cmdlnt)? cmdlnt: WCH_PLNT << 1; t = Map_ReadW (tsba, bc, cpy_buf); /* fetch packet */ tsba = tsba + (bc - t); /* inc tsba */ if (t) { /* nxm? */ ts_endcmd (TSSR_NBA | TSSR_NXM | TC5, 0, 0); return SCPE_OK; } for (i = 0; i < (bc / 2); i++) /* copy packet */ tswchp[i] = cpy_buf[i]; if ((wchlnt < ((MSG_PLNT - 1) * 2)) || (wchadh & 0177700) || (wchadl & 1)) ts_endcmd (TSSR_NBA | TC3, 0, 0); else { msgxs2 = msgxs2 | XS2_XTF | 1; tssr = ts_updtssr (tssr & ~TSSR_NBA); ts_endcmd (TC0, 0, MSG_ACK | MSG_CEND); } return SCPE_OK; case FNC_CTL: /* control */ switch (mod) { /* case mode */ case 00: /* msg buf rls */ tssr = ts_updtssr (tssr | TSSR_SSR); /* set SSR */ if (wchopt & WCH_ERI) SET_INT (TS); ts_ownc = 0; ts_ownm = 1; /* keep msg */ break; case 01: /* rewind and unload */ if (!sim_tape_bot (uptr)) /* if tape moves */ msgxs0 = msgxs0 | XS0_MOT; sim_tape_detach (uptr); /* unload */ ts_endcmd (TC0, 0, MSG_ACK | MSG_CEND); break; case 02: /* clean */ ts_endcmd (TC0, 0, MSG_ACK | MSG_CEND); /* nop */ break; case 03: /* undefined */ ts_endcmd (TC3, XS0_ILC, MSG_ACK | MSG_MILL | MSG_CFAIL); return SCPE_OK; case 04: /* rewind */ if (!sim_tape_bot (uptr)) /* if tape moves */ msgxs0 = msgxs0 | XS0_MOT; sim_tape_rewind (uptr); ts_endcmd (TC0, XS0_BOT, MSG_ACK | MSG_CEND); break; } break; case FNC_READ: /* read */ switch (mod) { /* case mode */ case 00: /* fwd */ st0 = ts_readf (uptr, cmdlnt); /* read */ break; case 01: /* back */ st0 = ts_readr (uptr, cmdlnt); /* read */ break; case 02: /* reread fwd */ if (cmdhdr & CMD_OPP) { /* opposite? */ st0 = ts_readr (uptr, cmdlnt); st1 = ts_spacef (uptr, 1, FALSE); } else { st0 = ts_spacer (uptr, 1, FALSE); st1 = ts_readf (uptr, cmdlnt); } break; case 03: /* reread back */ if (cmdhdr & CMD_OPP) { /* opposite */ st0 = ts_readf (uptr, cmdlnt); st1 = ts_spacer (uptr, 1, FALSE); } else { st0 = ts_spacef (uptr, 1, FALSE); st1 = ts_readr (uptr, cmdlnt); } break; } ts_cmpendcmd (st0, st1); break; case FNC_WRIT: /* write */ switch (mod) { /* case mode */ case 00: /* write */ st0 = ts_write (uptr, cmdlnt); break; case 01: /* rewrite */ st0 = ts_spacer (uptr, 1, FALSE); st1 = ts_write (uptr, cmdlnt); break; } ts_cmpendcmd (st0, st1); break; case FNC_FMT: /* format */ switch (mod) { /* case mode */ case 00: /* write tmk */ st0 = ts_wtmk (uptr); break; case 01: /* erase */ break; case 02: /* retry tmk */ st0 = ts_spacer (uptr, 1, FALSE); st1 = ts_wtmk (uptr); break; } ts_cmpendcmd (st0, st1); break; case FNC_POS: /* position */ switch (mod) { /* case mode */ case 00: /* space fwd */ st0 = ts_spacef (uptr, cmdadl, TRUE); break; case 01: /* space rev */ st0 = ts_spacer (uptr, cmdadl, TRUE); break; case 02: /* space ffwd */ st0 = ts_skipf (uptr, cmdadl); break; case 03: /* space frev */ st0 = ts_skipr (uptr, cmdadl); break; case 04: /* rewind */ if (!sim_tape_bot (uptr)) /* if tape moves */ msgxs0 = msgxs0 | XS0_MOT; sim_tape_rewind (uptr); break; } ts_cmpendcmd (st0, 0); break; } return SCPE_OK; }
t_stat mtu_svc (UNIT *uptr) { uint32 cmd = uptr->UCMD; uint32 un = uptr - mt_unit; uint32 c; uint32 st; int32 t; t_mtrlnt tbc; t_stat r; if (cmd == MCM_INIT) { /* init state */ if ((t = sim_activate_time (uptr + MT_REW)) != 0) { /* rewinding? */ sim_activate (uptr, t); /* retry later */ return SCPE_OK; } st = chan_get_cmd (mt_dib.dva, &cmd); /* get command */ if (CHS_IFERR (st)) /* channel error? */ return mt_chan_err (st); if ((cmd & 0x80) || /* invalid cmd? */ (mt_op[cmd] == 0)) { uptr->UCMD = MCM_END; /* end state */ sim_activate (uptr, chan_ctl_time); /* resched ctlr */ return SCPE_OK; } else { /* valid cmd */ if ((mt_op[cmd] & O_REV) && /* reverse op */ (mt_unit[un].UST & MTDV_BOT)) { /* at load point? */ chan_uen (mt_dib.dva); /* channel end */ return SCPE_OK; } uptr->UCMD = cmd; /* unit state */ if (!(mt_op[cmd] & O_NMT)) /* motion? */ uptr->UST = 0; /* clear status */ } mt_blim = 0; /* no buffer yet */ sim_activate (uptr, chan_ctl_time); /* continue thread */ return SCPE_OK; /* done */ } if (cmd == MCM_END) { /* end state */ st = chan_end (mt_dib.dva); /* set channel end */ if (CHS_IFERR (st)) /* channel error? */ return mt_chan_err (st); if (st == CHS_CCH) { /* command chain? */ uptr->UCMD = MCM_INIT; /* restart thread */ sim_activate (uptr, chan_ctl_time); } else uptr->UCMD = 0; /* ctlr idle */ return SCPE_OK; /* done */ } if ((mt_op[cmd] & O_ATT) && /* op req att and */ ((uptr->flags & UNIT_ATT) == 0)) { /* not attached? */ sim_activate (uptr, mt_ctime); /* retry */ return mt_stopioe? SCPE_UNATT: SCPE_OK; } if ((mt_op[cmd] & O_WRE) && /* write op and */ sim_tape_wrp (uptr)) { /* write protected? */ uptr->UST |= MTDV_WLE; /* set status */ chan_uen (mt_dib.dva); /* unusual end */ return SCPE_OK; } r = SCPE_OK; switch (cmd) { /* case on command */ case MCM_SFWR: /* space forward */ if (r = sim_tape_sprecf (uptr, &tbc)) /* spc rec fwd, err? */ r = mt_map_err (uptr, r); /* map error */ break; case MCM_SBKR: /* space reverse */ if (r = sim_tape_sprecr (uptr, &tbc)) /* spc rec rev, err? */ r = mt_map_err (uptr, r); /* map error */ break; case MCM_SFWF: /* space fwd file */ while ((r = sim_tape_sprecf (uptr, &tbc)) == MTSE_OK) ; if (r != MTSE_TMK) /* stopped by tmk? */ r = mt_map_err (uptr, r); /* no, map error */ else r = SCPE_OK; break; case MCM_SBKF: /* space rev file */ while ((r = sim_tape_sprecr (uptr, &tbc)) == MTSE_OK) ; if (r != MTSE_TMK) /* stopped by tmk? */ r = mt_map_err (uptr, r); /* no, map error */ else r = SCPE_OK; break; case MCM_WTM: /* write eof */ if (r = sim_tape_wrtmk (uptr)) /* write tmk, err? */ r = mt_map_err (uptr, r); /* map error */ uptr->UST |= MTDV_EOF; /* set eof */ break; case MCM_RWU: /* rewind unload */ r = detach_unit (uptr); break; case MCM_REW: /* rewind */ case MCM_RWI: /* rewind and int */ if (r = sim_tape_rewind (uptr)) /* rewind */ r = mt_map_err (uptr, r); /* map error */ mt_unit[un + MT_REW].UCMD = uptr->UCMD; /* copy command */ sim_activate (uptr + MT_REW, mt_rwtime); /* sched compl */ break; case MCM_READ: /* read */ if (mt_blim == 0) { /* first read? */ r = sim_tape_rdrecf (uptr, mt_xb, &mt_blim, MT_MAXFR); if (r != MTSE_OK) { /* tape error? */ r = mt_map_err (uptr, r); /* map error */ break; } mt_bptr = 0; /* init rec ptr */ } c = mt_xb[mt_bptr++]; /* get char */ st = chan_WrMemB (mt_dib.dva, c); /* write to memory */ if (CHS_IFERR (st)) /* channel error? */ return mt_chan_err (st); if ((st != CHS_ZBC) && (mt_bptr != mt_blim)) { /* not done? */ sim_activate (uptr, mt_time); /* continue thread */ return SCPE_OK; } if (((st == CHS_ZBC) ^ (mt_bptr == mt_blim)) && /* length err? */ chan_set_chf (mt_dib.dva, CHF_LNTE)) /* uend taken? */ return SCPE_OK; /* finished */ break; /* normal end */ case MCM_RDBK: /* read reverse */ if (mt_blim == 0) { /* first read? */ r = sim_tape_rdrecr (uptr, mt_xb, &mt_blim, MT_MAXFR); if (r != MTSE_OK) { /* tape error? */ r = mt_map_err (uptr, r); /* map error */ break; } mt_bptr = mt_blim; /* init rec ptr */ } c = mt_xb[--mt_bptr]; /* get char */ st = chan_WrMemBR (mt_dib.dva, c); /* write mem rev */ if (CHS_IFERR (st)) /* channel error? */ return mt_chan_err (st); if ((st != CHS_ZBC) && (mt_bptr != 0)) { /* not done? */ sim_activate (uptr, mt_time); /* continue thread */ return SCPE_OK; } if (((st == CHS_ZBC) ^ (mt_bptr == 0)) && /* length err? */ chan_set_chf (mt_dib.dva, CHF_LNTE)) /* uend taken? */ return SCPE_OK; /* finished */ break; /* normal end */ case MCM_WRITE: /* write */ st = chan_RdMemB (mt_dib.dva, &c); /* read char */ if (CHS_IFERR (st)) { /* channel error? */ mt_flush_buf (uptr); /* flush buffer */ return mt_chan_err (st); } mt_xb[mt_blim++] = c; /* store in buffer */ if (st != CHS_ZBC) { /* end record? */ sim_activate (uptr, mt_time); /* continue thread */ return SCPE_OK; } r = mt_flush_buf (uptr); /* flush buffer */ break; } if (r != SCPE_OK) /* error? abort */ return CHS_IFERR(r)? SCPE_OK: r; uptr->UCMD = MCM_END; /* end state */ sim_activate (uptr, mt_ctime); /* sched ctlr */ return SCPE_OK; }
uint32 mtcio (uint32 select_code, IOSIG signal, uint32 data) { const IOSIG base_signal = IOBASE (signal); /* derive base signal */ uint32 i; int32 valid; switch (base_signal) { /* dispatch base I/O signal */ case ioCLF: /* clear flag flip-flop */ mtc_flag = mtc_flagbuf = CLEAR; break; case ioSTF: /* set flag flip-flop */ case ioENF: /* enable flag */ mtc_flag = mtc_flagbuf = SET; break; case ioSFC: /* skip if flag is clear */ setstdSKF (mtc); break; case ioSFS: /* skip if flag is set */ setstdSKF (mtc); break; case ioIOI: /* I/O data input */ data = mtc_sta & ~(STA_LOCAL | STA_WLK | STA_BUSY); if (mtc_unit.flags & UNIT_ATT) { /* construct status */ if (sim_is_active (&mtc_unit)) data = data | STA_BUSY; if (sim_tape_wrp (&mtc_unit)) data = data | STA_WLK; } else data = data | STA_BUSY | STA_LOCAL; break; case ioIOO: /* I/O data output */ data = data & 0377; mtc_sta = mtc_sta & ~STA_REJ; /* clear reject */ if (data == FNC_CLR) { /* clear? */ mt_clear (); /* send CLR to controller */ mtd_flag = mtd_flagbuf = CLEAR; /* clear data flag and flag buffer */ mtc_flag = mtc_flagbuf = SET; /* set command flag and flag buffer */ break; /* command completes immediately */ } for (i = valid = 0; i < sizeof (mtc_cmd); i++) /* is fnc valid? */ if (data == mtc_cmd[i]) valid = 1; if (!valid || sim_is_active (&mtc_unit) || /* is cmd valid? */ ((mtc_sta & STA_BOT) && (data == FNC_BSR)) || (sim_tape_wrp (&mtc_unit) && ((data == FNC_WC) || (data == FNC_GAP) || (data == FNC_WFM)))) mtc_sta = mtc_sta | STA_REJ; else { sim_activate (&mtc_unit, mtc_ctime); /* start tape */ mtc_fnc = data; /* save function */ mtc_sta = STA_BUSY; /* unit busy */ mt_ptr = 0; /* init buffer ptr */ mtcio (select_code, ioCLF, 0); /* clear flags */ mtcio (mtd_dib.devno, ioCLF, 0); mtc_1st = 1; /* set 1st flop */ mtc_dtf = 1; /* set xfer flop */ } break; case ioPOPIO: /* power-on preset to I/O */ mtc_flag = mtc_flagbuf = CLEAR; /* clear flag and flag buffer */ /* fall into CRS handler */ case ioCRS: /* control reset */ /* fall into CLC handler */ case ioCLC: /* clear control flip-flop */ mtc_control = CLEAR; break; case ioSTC: /* set control flip-flop */ mtc_control = SET; break; case ioSIR: /* set interrupt request */ setstdPRL (select_code, mtc); /* set standard PRL signal */ setstdIRQ (select_code, mtc); /* set standard IRQ signal */ setstdSRQ (select_code, mtc); /* set standard SRQ signal */ break; case ioIAK: /* interrupt acknowledge */ mtc_flagbuf = CLEAR; break; default: /* all other signals */ break; /* are ignored */ } if (signal > ioCLF) /* multiple signals? */ mtcio (select_code, ioCLF, 0); /* issue CLF */ else if (signal > ioSIR) /* signal affected interrupt status? */ mtcio (select_code, ioSIR, 0); /* set interrupt request */ return data; }
/* Handle processing of tape requests. */ t_stat mt_srv(UNIT * uptr) { int chan = uptr->u5 & MT_CHAN; int unit = uptr - mt_unit; int cmd = uptr->u5 & MT_CMD; DEVICE *dptr = find_dev_from_unit(uptr); t_mtrlnt reclen; t_stat r = SCPE_ARG; /* Force error if not set */ uint8 ch; int mode; t_mtrlnt loc; /* Simulate tape load delay */ if (uptr->u5 & MT_LOADED) { uptr->u5 &= ~MT_LOADED; uptr->u5 |= MT_BSY|MT_RDY; sim_debug(DEBUG_DETAIL, dptr, "Unit=%d Loaded\n", unit); sim_activate(uptr, 50000); return SCPE_OK; } if (uptr->u5 & MT_BSY) { uptr->u5 &= ~MT_BSY; sim_debug(DEBUG_DETAIL, dptr, "Unit=%d Online\n", unit); iostatus |= 1 << (uptr - mt_unit); if (uptr->u5 & MT_IDLE) sim_activate(uptr, 50000); return SCPE_OK; } if (uptr->u5 & MT_IDLE) { uptr->u5 &= ~MT_IDLE; if (uptr->u5 & MT_RDY) { sim_debug(DEBUG_DETAIL, dptr, "Unit=%d idling\n", unit); return SCPE_OK; } sim_debug(DEBUG_DETAIL, dptr, "Unit=%d start %02o\n", unit, cmd); } switch (cmd) { /* Handle interrogate */ case MT_INT: if (sim_tape_wrp(uptr)) chan_set_wrp(chan); uptr->u5 &= ~(MT_CMD|MT_BIN); uptr->u5 |= MT_RDY; chan_set_end(chan); sim_debug(DEBUG_DETAIL, dptr, "Status\n"); return SCPE_OK; case MT_RD: /* Read */ /* If at end of record, fill buffer */ if (BUF_EMPTY(uptr)) { sim_debug(DEBUG_DETAIL, dptr, "Read unit=%d %s ", unit, (uptr->u5 & MT_BIN)? "bin": "bcd"); if (sim_tape_eot(uptr)) { sim_activate(uptr, 4000); return mt_error(uptr, chan, MTSE_EOM, dptr); } r = sim_tape_rdrecf(uptr, &mt_buffer[chan][0], &reclen, BUFFSIZE); if (r != MTSE_OK) { if (r == MTSE_TMK) { sim_debug(DEBUG_DETAIL, dptr, "TM\n"); ch = 017; (void)chan_write_char(chan, &ch, 1); sim_activate(uptr, 4000); } else { sim_debug(DEBUG_DETAIL, dptr, "r=%d\n", r); sim_activate(uptr, 5000); } return mt_error(uptr, chan, r, dptr); } else { uptr->u5 &= ~(MT_BOT|MT_EOT); uptr->hwmark = reclen; } sim_debug(DEBUG_DETAIL, dptr, "%d chars\n", uptr->hwmark); uptr->u6 = 0; if ((uptr->u5 & MT_BIN) == 0) mode = 0100; else mode = 0; for (loc = 0; loc < reclen; loc++) { ch = mt_buffer[chan][loc] & 0177; if (((parity_table[ch & 077]) ^ (ch & 0100) ^ mode) == 0) { chan_set_error(chan); break; } } } ch = mt_buffer[chan][uptr->u6++] & 0177; /* 00 characters are not transfered in BCD mode */ if (ch == 0) { if (((uint32)uptr->u6) >= uptr->hwmark) { sim_activate(uptr, 4000); return mt_error(uptr, chan, MTSE_OK, dptr); } else { sim_activate(uptr, HT); return SCPE_OK; } } if (chan_write_char(chan, &ch, (((uint32)uptr->u6) >= uptr->hwmark) ? 1 : 0)) { sim_debug(DEBUG_DATA, dptr, "Read unit=%d %d EOR\n", unit, uptr->hwmark-uptr->u6); sim_activate(uptr, 4000); return mt_error(uptr, chan, MTSE_OK, dptr); } else { sim_debug(DEBUG_DATA, dptr, "Read data unit=%d %d %03o\n", unit, uptr->u6, ch); sim_activate(uptr, HT); } return SCPE_OK; case MT_RDBK: /* Read Backword */ /* If at end of record, fill buffer */ if (BUF_EMPTY(uptr)) { sim_debug(DEBUG_DETAIL, dptr, "Read back unit=%d %s ", unit, (uptr->u5 & MT_BIN)? "bin": "bcd"); if (sim_tape_bot(uptr)) { sim_activate(uptr, 4000); return mt_error(uptr, chan, MTSE_BOT, dptr); } r = sim_tape_rdrecr(uptr, &mt_buffer[chan][0], &reclen, BUFFSIZE); if (r != MTSE_OK) { if (r == MTSE_TMK) { sim_debug(DEBUG_DETAIL, dptr, "TM\n"); ch = 017; (void)chan_write_char(chan, &ch, 1); sim_activate(uptr, 4000); } else { uptr->u5 |= MT_BSY; sim_debug(DEBUG_DETAIL, dptr, "r=%d\n", r); sim_activate(uptr, 100); } return mt_error(uptr, chan, r, dptr); } else { uptr->u5 &= ~(MT_BOT|MT_EOT); uptr->hwmark = reclen; } sim_debug(DEBUG_DETAIL, dptr, "%d chars\n", uptr->hwmark); uptr->u6 = uptr->hwmark; if ((uptr->u5 & MT_BIN) == 0) mode = 0100; else mode = 0; for (loc = 0; loc < reclen; loc++) { ch = mt_buffer[chan][loc] & 0177; if (((parity_table[ch & 077]) ^ (ch & 0100) ^ mode) == 0) { chan_set_error(chan); break; } } } ch = mt_buffer[chan][--uptr->u6] & 0177; /* 00 characters are not transfered in BCD mode */ if (ch == 0) { if (uptr->u6 <= 0) { sim_activate(uptr, 4000); return mt_error(uptr, chan, MTSE_OK, dptr); } else { sim_activate(uptr, HT); return SCPE_OK; } } if (chan_write_char(chan, &ch, (uptr->u6 > 0) ? 0 : 1)) { sim_debug(DEBUG_DATA, dptr, "Read back unit=%d %d EOR\n", unit, uptr->hwmark-uptr->u6); sim_activate(uptr, 100); return mt_error(uptr, chan, MTSE_OK, dptr); } else { sim_debug(DEBUG_DATA, dptr, "Read back data unit=%d %d %03o\n", unit, uptr->u6, ch); sim_activate(uptr, HT); } return SCPE_OK; case MT_WR: /* Write */ /* Check if write protected */ if (uptr->u6 == 0 && sim_tape_wrp(uptr)) { sim_activate(uptr, 100); return mt_error(uptr, chan, MTSE_WRP, dptr); } if (chan_read_char(chan, &ch, (uptr->u6 > BUFFSIZE) ? 1 : 0)) { reclen = uptr->u6; /* If no transfer, then either erase */ if (reclen == 0) { sim_debug(DEBUG_DETAIL, dptr, "Erase\n"); r = MTSE_OK; } else if ((reclen == 1) && (cmd & MT_BIN) == 0 && (mt_buffer[chan][0] == 017)) { /* Check if write rtape mark */ sim_debug(DEBUG_DETAIL, dptr, "Write Mark unit=%d\n", unit); r = sim_tape_wrtmk(uptr); } else { sim_debug(DEBUG_DETAIL, dptr, "Write unit=%d Block %d %s chars\n", unit, reclen, (uptr->u5 & MT_BIN)? "bin": "bcd"); r = sim_tape_wrrecf(uptr, &mt_buffer[chan][0], reclen); } uptr->u5 &= ~(MT_BOT|MT_EOT); sim_activate(uptr, 4000); return mt_error(uptr, chan, r, dptr); /* Record errors */ } else { /* Copy data to buffer */ ch &= 077; ch |= parity_table[ch]; if ((uptr->u5 & MT_BIN)) ch ^= 0100; /* Don't write out even parity zeros */ if (ch != 0) mt_buffer[chan][uptr->u6++] = ch; sim_debug(DEBUG_DATA, dptr, "Write data unit=%d %d %03o\n", unit, uptr->u6, ch); uptr->hwmark = uptr->u6; } sim_activate(uptr, HT); return SCPE_OK; case MT_FSR: /* Space forward one record */ if (BUF_EMPTY(uptr)) { /* If at end of record, fill buffer */ sim_debug(DEBUG_DETAIL, dptr, "Space unit=%d ", unit); if (sim_tape_eot(uptr)) { uptr->u5 &= ~MT_BOT; sim_debug(DEBUG_DETAIL, dptr, "EOT\n"); sim_activate(uptr, 4000); return mt_error(uptr, chan, MTSE_EOM, dptr); } r = sim_tape_rdrecf(uptr, &mt_buffer[chan][0], &reclen, BUFFSIZE); if (r != MTSE_OK) { if (r == MTSE_TMK) { sim_debug(DEBUG_DETAIL, dptr, "TM "); reclen = 1; chan_set_eof(chan); } else { sim_debug(DEBUG_DETAIL, dptr, "r=%d ", r); reclen = 10; } } uptr->u5 &= ~(MT_BOT|MT_EOT); uptr->hwmark = reclen; sim_debug(DEBUG_DETAIL, dptr, "%d chars\n", uptr->hwmark); sim_activate(uptr, uptr->hwmark * HT); return SCPE_OK; } sim_activate(uptr, 4000); return mt_error(uptr, chan, MTSE_OK, dptr); case MT_BSR: /* Backspace record */ if (BUF_EMPTY(uptr)) { /* If at end of record, fill buffer */ sim_debug(DEBUG_DETAIL, dptr, "backspace unit=%d ", unit); if (sim_tape_bot(uptr)) { sim_debug(DEBUG_DETAIL, dptr, "BOT\n"); sim_activate(uptr, 100); return mt_error(uptr, chan, MTSE_BOT, dptr); } r = sim_tape_rdrecr(uptr, &mt_buffer[chan][0], &reclen, BUFFSIZE); if (r != MTSE_OK) { if (r == MTSE_TMK) { sim_debug(DEBUG_DETAIL, dptr, "TM "); reclen = 1; chan_set_eof(chan); } else { reclen = 10; sim_debug(DEBUG_DETAIL, dptr, "r=%d ", r); } } uptr->u5 &= ~(MT_BOT|MT_EOT); uptr->hwmark = reclen; sim_debug(DEBUG_DETAIL, dptr, "%d chars\n", uptr->hwmark); sim_activate(uptr, uptr->hwmark * HT); return SCPE_OK; } sim_activate(uptr, 4000); return mt_error(uptr, chan, MTSE_OK, dptr); case MT_REW: /* Rewind */ sim_debug(DEBUG_DETAIL, dptr, "Rewind unit=%d pos=%d\n", unit, uptr->pos); uptr->u5 &= ~(MT_CMD | MT_BIN | MT_IDLE | MT_RDY); uptr->u5 |= MT_BSY|MT_RDY; iostatus &= ~(1 << (uptr - mt_unit)); sim_activate(uptr, (uptr->pos/100) + 100); r = sim_tape_rewind(uptr); uptr->u5 &= ~MT_EOT; uptr->u5 |= MT_BOT; chan_set_end(chan); return r; } return mt_error(uptr, chan, r, dptr); }
t_stat mt (uint32 fnc, uint32 inst, uint32 *dat) { int32 u = inst & MT_UNIT; /* get unit */ UNIT *uptr = mt_dev.units + u; /* get unit ptr */ int32 t, new_ch; uint8 chr; t_stat r; switch (fnc) { /* case function */ case IO_CONN: /* connect */ new_ch = I_GETEOCH (inst); /* get new chan */ if (new_ch != mt_dib.chan) /* wrong chan? */ return SCPE_IERR; if (mt_gap) { /* in gap? */ mt_gap = 0; /* clr gap flg */ sim_cancel (uptr); /* cancel timer */ } else if (sim_is_active (uptr)) /* busy? */ CRETIOP; uptr->eotf = 0; /* clr eot flag */ mt_eof = 0; /* clr eof flag */ mt_skip = 0; /* clr skp flag */ mt_bptr = mt_blnt = 0; /* init buffer */ if ((inst & DEV_MTS)? (CHC_GETCPW (inst) < 2): /* scn & cpw<3? */ (inst & CHC_REV)) /* rw & rev? */ return STOP_INVIOP; mt_inst = inst; /* save inst */ if ((inst & DEV_MTS) && !(inst & DEV_OUT)) /* scanning? */ chan_set_flag (mt_dib.chan, CHF_SCAN); /* set chan flg */ xfr_req = xfr_req & ~XFR_MT0; /* clr xfr flag */ sim_activate (uptr, mt_gtime); /* start timer */ break; case IO_EOM1: /* EOM mode 1 */ new_ch = I_GETEOCH (inst); /* get new chan */ if (new_ch != mt_dib.chan) /* wrong chan? */ CRETIOP; t = inst & 07670; /* get command */ if ((t == 04010) && !sim_is_active (uptr)) { /* rewind? */ sim_tape_rewind (uptr); /* rewind unit */ uptr->eotf = 0; /* clr eot */ uptr->botf = 1; /* set bot */ } else if ((t == 03610) && sim_is_active (uptr) &&/* skip rec? */ ((mt_inst & DEV_OUT) == 0)) mt_skip = 1; /* set flag */ else CRETINS; break; case IO_DISC: /* disconnect */ sim_cancel (uptr); /* no more xfr's */ if (inst & DEV_OUT) { /* write? */ if (r = mt_wrend (inst)) /* end record */ return r; } break; case IO_WREOR: /* write eor */ chan_set_flag (mt_dib.chan, CHF_EOR); /* set eor flg */ if (r = mt_wrend (inst)) /* end record */ return r; mt_gap = 1; /* in gap */ sim_activate (uptr, mt_gtime); /* start timer */ break; case IO_SKS: /* SKS */ new_ch = I_GETSKCH (inst); /* get chan # */ if (new_ch != mt_dib.chan) /* wrong chan? */ return SCPE_IERR; if ((inst & (DEV_OUT | DEV_MTS)) == 0) { /* not sks 1n? */ t = I_GETSKCND (inst); /* get skip cond */ switch (t) { /* case sks cond */ case 001: /* sks 1021n */ *dat = 1; /* not magpak */ break; case 002: /* sks 1041n */ if (!(uptr->flags & UNIT_ATT) || /* not ready */ sim_is_active (uptr)) *dat = 1; break; case 004: /* sks 1101n */ if (!uptr->eotf) *dat = 1; /* not EOT */ break; case 010: /* sks 1201n */ if (!uptr->botf) *dat = 1; /* not BOT */ break; case 013: /* sks 12610 */ if (!mt_gap) *dat = 1; /* not in gap */ break; case 017: /* sks 13610 */ if (!mt_eof) *dat = 1; /* not EOF */ break; case 020: /* sks 1401n */ if (!sim_tape_wrp (uptr)) *dat = 1; /* not wrp */ break; case 031: /* sks 1621n */ case 033: /* sks 1661n */ *dat = 1; /* not 556bpi */ case 035: /* sks 1721n */ break; /* not 800bpi */ } } /* end if */ break; case IO_READ: /* read */ xfr_req = xfr_req & ~XFR_MT0; /* clr xfr flag */ if (mt_blnt == 0) { /* first read? */ r = mt_readrec (uptr); /* get data */ if ((r != SCPE_OK) || (mt_blnt == 0)) /* err, inv reclnt? */ return r; } uptr->botf = 0; /* off BOT */ if (mt_inst & CHC_REV) /* get next rev */ chr = mtxb[--mt_bptr] & 077; else chr = mtxb[mt_bptr++] & 077; /* get next fwd */ if (!(mt_inst & CHC_BIN)) /* bcd? */ chr = bcd_to_sds[chr]; *dat = chr & 077; /* give to chan */ if ((mt_inst & CHC_REV)? (mt_bptr <= 0): /* rev or fwd, */ (mt_bptr >= mt_blnt)) /* recd done? */ mt_readend (uptr); break; case IO_WRITE: /* write */ uptr->botf = 0; /* off BOT */ chr = (*dat) & 077; xfr_req = xfr_req & ~XFR_MT0; /* clr xfr flag */ if (!(mt_inst & CHC_BIN)) /* bcd? */ chr = sds_to_bcd[chr]; if (mt_bptr < MT_MAXFR) mtxb[mt_bptr++] = chr; /* insert in buf */ break; default: CRETINS; } return SCPE_OK; }
uint32 mt (uint32 dev, uint32 op, uint32 dat) { uint32 i, f, t; uint32 u = (dev - mt_dib.dno) / o_MT0; UNIT *uptr = mt_dev.units + u; switch (op) { /* case IO op */ case IO_ADR: /* select */ sch_adr (mt_dib.sch, dev); /* inform sel ch */ return BY; /* byte only */ case IO_RD: /* read data */ if (mt_xfr) /* xfr? set busy */ mt_sta = mt_sta | STA_BSY; return mt_db; /* return data */ case IO_WD: /* write data */ if (mt_xfr) { /* transfer? */ mt_sta = mt_sta | STA_BSY; /* set busy */ if ((uptr->UCMD & (MTC_STOP1 | MTC_STOP2)) && ((uptr->UCMD & MTC_MASK) == MTC_WR)) /* while stopping? */ mt_sta = mt_sta | STA_ERR; /* write overrun */ } mt_db = dat & DMASK8; /* store data */ break; case IO_SS: /* status */ mt_sta = mt_sta & STA_MASK; /* ctrl status */ if (uptr->flags & UNIT_ATT) /* attached? */ t = mt_sta | (uptr->UST & STA_UFLGS); /* yes, unit status */ else t = mt_sta | STA_DU; /* no, dev unavail */ if (t & SET_EX) /* test for ex */ t = t | STA_EX; return t; case IO_OC: /* command */ mt_arm[u] = int_chg (v_MT + u, dat, mt_arm[u]); f = dat & MTC_MASK; /* get cmd */ if (f == MTC_CLR) { /* clear? */ mt_reset (&mt_dev); /* reset world */ break; } if (((uptr->flags & UNIT_ATT) == 0) || /* ignore if unatt */ bad_cmd[f] || /* or bad cmd */ (((f == MTC_WR) || (f == MTC_WEOF)) && /* or write */ sim_tape_wrp (uptr))) /* and protected */ break; for (i = 0; i < MT_NUMDR; i++) { /* check other drvs */ if (sim_is_active (&mt_unit[i]) && /* active? */ (mt_unit[i].UCMD != MTC_REW)) { /* not rewind? */ sim_cancel (&mt_unit[i]); /* stop */ mt_unit[i].UCMD = 0; } } if (sim_is_active (uptr) && /* unit active? */ !(uptr->UCMD & (MTC_STOP1 | MTC_STOP2))) /* not stopping? */ break; /* ignore */ if ((f == MTC_WR) || (f == MTC_REW)) /* write, rew: bsy=0 */ mt_sta = 0; else mt_sta = STA_BSY; /* bsy=1,nmtn,eom,err=0 */ mt_bptr = mt_blnt = 0; /* not yet started */ if ((f == MTC_RD) || (f == MTC_WR)) /* data xfr? */ mt_xfr = 1; /* set xfr flag */ else mt_xfr = 0; uptr->UCMD = f; /* save cmd */ uptr->UST = 0; /* clr tape stat */ sim_activate (uptr, mt_rtime); /* start op */ break; } return 0; }
t_stat mt_io (int32 unit, int32 flag, int32 mod) { int32 t, wm_seen; t_mtrlnt i, tbc; t_stat st; t_bool passed_eot; UNIT *uptr; ind[IN_TAP] = 0; /* clear error */ if ((uptr = mt_sel_unit (unit)) == NULL) /* sel unit, save */ return STOP_INVMTU; /* (not valid) */ if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ return SCPE_UNATT; switch (mod) { case BCD_R: /* read */ if (DEBUG_PRS (mt_dev)) fprintf (sim_deb, ">>MT%d: read from %d", unit, BS); wm_seen = 0; /* no word mk seen */ st = sim_tape_rdrecf (uptr, dbuf, &tbc, MT_MAXFR); /* read rec */ if (st != MTSE_TMK) { /* not tmk? */ if (st == MTSE_RECE) /* rec in error? */ ind[IN_TAP] = 1; else if (st != MTSE_OK) { /* stop on error */ if (DEBUG_PRS (mt_dev)) fprintf (sim_deb, ", stopped by status = %d\n", st); break; } if (!(flag & MD_BIN) && /* BCD tape and */ ((dbuf[0] & CHAR) == BCD_TAPMRK)) /* first char TMK? */ uptr->IND = 1; /* set indicator */ } for (i = 0; i < tbc; i++) { /* loop thru buf */ if (!(flag & MD_BOOT) && /* not boot? check */ (M[BS] == (BCD_GRPMRK + WM))) { /* GWM in memory? */ if (DEBUG_PRS (mt_dev)) fprintf (sim_deb, " to %d, stopped by GMWM\n", BS); BS++; /* incr BS */ if (ADDR_ERR (BS)) { /* test for wrap */ BS = BA | (BS % MAXMEMSIZE); return STOP_WRAP; } return SCPE_OK; /* done */ } t = dbuf[i] & CHAR; /* get char, strip parity */ if (!(flag & MD_BIN) && (t == BCD_ALT)) /* BCD mode alt blank? */ t = BCD_BLANK; /* real blank */ if (flag & MD_WM) { /* word mk mode? */ if ((t == BCD_WM) && (wm_seen == 0)) /* WM char, none prev? */ wm_seen = WM; /* set flag */ else { M[BS] = wm_seen | (t & CHAR); /* char + wm seen */ wm_seen = 0; /* clear flag */ } } else M[BS] = (M[BS] & WM) | (t & CHAR); /* preserve mem WM */ if (!wm_seen) BS++; if (ADDR_ERR (BS)) { /* check next BS */ BS = BA | (BS % MAXMEMSIZE); return STOP_WRAP; } } if (M[BS] != (BCD_GRPMRK + WM)) { /* not GM+WM at end? */ if (flag & MD_WM) /* LCA: clear WM */ M[BS] = BCD_GRPMRK; else M[BS] = (M[BS] & WM) | BCD_GRPMRK; /* MCW: save WM */ } if (DEBUG_PRS (mt_dev)) fprintf (sim_deb, " to %d, stopped by EOR\n", BS); BS++; /* adv BS */ if (ADDR_ERR (BS)) { /* check final BS */ BS = BA | (BS % MAXMEMSIZE); return STOP_WRAP; } break; case BCD_W: if (sim_tape_wrp (uptr)) /* locked? */ return STOP_MTL; if (M[BS] == (BCD_GRPMRK + WM)) /* eor? */ return STOP_MTZ; if (DEBUG_PRS (mt_dev)) fprintf (sim_deb, ">>MT%d: write from %d", unit, BS); for (tbc = 0; (t = M[BS++]) != (BCD_GRPMRK + WM); ) { if ((t & WM) && (flag & MD_WM)) /* WM in wm mode? */ dbuf[tbc++] = BCD_WM; if (((t & CHAR) == BCD_BLANK) && !(flag & MD_BIN)) dbuf[tbc++] = BCD_ALT; else dbuf[tbc++] = t & CHAR; if (ADDR_ERR (BS)) { /* check next BS */ BS = BA | (BS % MAXMEMSIZE); return STOP_WRAP; } } if (DEBUG_PRS (mt_dev)) fprintf (sim_deb, " to %d\n", BS - 1); passed_eot = sim_tape_eot (uptr); /* passed EOT? */ st = sim_tape_wrrecf (uptr, dbuf, tbc); /* write record */ if (!passed_eot && sim_tape_eot (uptr)) /* just passed EOT? */ ind[IN_END] = 1; if (ADDR_ERR (BS)) { /* check final BS */ BS = BA | (BS % MAXMEMSIZE); return STOP_WRAP; } break; default: return STOP_INVM; } return mt_map_status (st); }
t_stat mt_func (int32 unit, int32 flag, int32 mod) { t_mtrlnt tbc; UNIT *uptr; t_stat st; ind[IN_TAP] = 0; /* clear error */ if ((uptr = mt_sel_unit (unit)) == NULL) /* sel unit, save */ return STOP_INVMTU; /* (not valid) */ if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ return SCPE_UNATT; switch (mod) { /* case on modifier */ case BCD_A: /* diagnostic read */ if (DEBUG_PRS (mt_dev)) fprintf (sim_deb, ">>MT%d: diagnostic read\n", unit); st = sim_tape_rdrecf (uptr, dbuf, &tbc, MT_MAXFR); /* read rec */ if (st != MTSE_TMK) { /* not tmk? */ if (st == MTSE_RECE) /* rec in error? */ ind[IN_TAP] = 1; else if (st != MTSE_OK) { /* stop on error */ if (DEBUG_PRS (mt_dev)) fprintf (sim_deb, ", stopped by status = %d\n", st); break; } if (!(flag & MD_BIN) && /* BCD tape and */ ((dbuf[0] & CHAR) == BCD_TAPMRK)) /* first char TMK? */ uptr->IND = 1; /* set indicator */ } break; case BCD_B: /* backspace */ if (DEBUG_PRS (mt_dev)) fprintf (sim_deb, ">>MT%d: backspace\n", unit); st = sim_tape_sprecr (uptr, &tbc); /* space rev */ break; /* end case */ case BCD_E: /* erase = nop */ if (DEBUG_PRS (mt_dev)) fprintf (sim_deb, ">>MT%d: erase\n", unit); if (sim_tape_wrp (uptr)) /* write protected? */ return STOP_MTL; return SCPE_OK; case BCD_M: /* write tapemark */ if (DEBUG_PRS (mt_dev)) fprintf (sim_deb, ">>MT%d: write tape mark\n", unit); st = sim_tape_wrtmk (uptr); /* write tmk */ break; case BCD_R: /* rewind */ if (DEBUG_PRS (mt_dev)) fprintf (sim_deb, ">>MT%d: rewind\n", unit); sim_tape_rewind (uptr); /* update position */ return SCPE_OK; case BCD_U: /* unload */ if (DEBUG_PRS (mt_dev)) fprintf (sim_deb, ">>MT%d: rewind and unload\n", unit); sim_tape_rewind (uptr); /* update position */ st = mt_detach (uptr); /* detach */ break; default: return STOP_INVM; } return mt_map_status (st); }
t_stat sim_tape_wrgap (UNIT *uptr, uint32 gaplen, uint32 bpi) { t_stat st; t_mtrlnt meta, sbc, new_len, rec_size; t_addr gap_pos = uptr->pos; uint32 file_size, marker_count; uint32 format = MT_GET_FMT (uptr); uint32 gap_alloc = 0; /* gap allocated from tape */ int32 gap_needed = (gaplen * bpi) / 10; /* gap remainder still needed */ const uint32 meta_size = sizeof (t_mtrlnt); /* bytes per metadatum */ const uint32 min_rec_size = 2 + sizeof (t_mtrlnt) * 2; /* smallest data record size */ MT_CLR_PNU (uptr); if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ return MTSE_UNATT; if (format != MTUF_F_STD) /* not SIMH fmt? */ return MTSE_FMT; if (sim_tape_wrp (uptr)) /* write protected? */ return MTSE_WRP; file_size = sim_fsize (uptr->fileref); /* get file size */ sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* position tape */ /* Read tape records and allocate to gap until amount required is consumed. Read next metadatum from tape: - EOF or EOM: allocate remainder of bytes needed. - TMK or GAP: allocate sizeof(metadatum) bytes. - Reverse GAP: allocate sizeof(metadatum) / 2 bytes. - Data record: see below. Loop until bytes needed = 0. */ do { sim_fread (&meta, meta_size, 1, uptr->fileref); /* read metadatum */ if (ferror (uptr->fileref)) { /* read error? */ uptr->pos = gap_pos; /* restore original position */ MT_SET_PNU (uptr); /* position not updated */ return sim_tape_ioerr (uptr); /* translate error */ } else uptr->pos = uptr->pos + meta_size; /* move tape over datum */ if (feof (uptr->fileref) || (meta == MTR_EOM)) { /* at eof or eom? */ gap_alloc = gap_alloc + gap_needed; /* allocate remainder */ gap_needed = 0; } else if ((meta == MTR_GAP) || (meta == MTR_TMK)) { /* gap or tape mark? */ gap_alloc = gap_alloc + meta_size; /* allocate marker space */ gap_needed = gap_needed - meta_size; /* reduce requirement */ } else if (meta == MTR_FHGAP) { /* half gap? */ uptr->pos = uptr->pos - meta_size / 2; /* backup to resync */ sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* position tape */ gap_alloc = gap_alloc + meta_size / 2; /* allocate marker space */ gap_needed = gap_needed - meta_size / 2; /* reduce requirement */ } else if (uptr->pos + MTR_L (meta) + meta_size > file_size) { /* rec len out of range? */ gap_alloc = gap_alloc + gap_needed; /* presume overwritten tape */ gap_needed = 0; /* allocate remainder */ } /* Allocate a data record: - Determine record size in bytes (including metadata) - If record size - bytes needed < smallest allowed record size, allocate entire record to gap, else allocate needed amount and truncate data record to reflect remainder. */ else { /* data record */ sbc = MTR_L (meta); /* get record data length */ rec_size = ((sbc + 1) & ~1) + meta_size * 2; /* overall size in bytes */ if (rec_size < gap_needed + min_rec_size) { /* rec too small? */ uptr->pos = uptr->pos - meta_size + rec_size; /* position past record */ sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* move tape */ gap_alloc = gap_alloc + rec_size; /* allocate record */ gap_needed = gap_needed - rec_size; /* reduce requirement */ } else { /* record size OK */ uptr->pos = uptr->pos - meta_size + gap_needed; /* position to end of gap */ new_len = MTR_F (meta) | (sbc - gap_needed); /* truncate to new len */ st = sim_tape_wrdata (uptr, new_len); /* write new rec len */ if (st != MTSE_OK) { /* write OK? */ uptr->pos = gap_pos; /* restore orig pos */ return st; /* PNU was set by wrdata */ } uptr->pos = uptr->pos + sbc - gap_needed; /* position to end of data */ st = sim_tape_wrdata (uptr, new_len); /* write new rec len */ if (st != MTSE_OK) { /* write OK? */ uptr->pos = gap_pos; /* restore orig pos */ return st; /* PNU was set by wrdata */ } gap_alloc = gap_alloc + gap_needed; /* allocate remainder */ gap_needed = 0; } } } while (gap_needed > 0); uptr->pos = gap_pos; /* reposition to gap start */ if (gap_alloc & (meta_size - 1)) { /* gap size "odd?" */ st = sim_tape_wrdata (uptr, MTR_FHGAP); /* write half gap marker */ if (st != MTSE_OK) { /* write OK? */ uptr->pos = gap_pos; /* restore orig pos */ return st; /* PNU was set by wrdata */ } uptr->pos = uptr->pos - meta_size / 2; /* realign position */ gap_alloc = gap_alloc - 2; /* decrease gap to write */ } marker_count = gap_alloc / meta_size; /* count of gap markers */ do { st = sim_tape_wrdata (uptr, MTR_GAP); /* write gap markers */ if (st != MTSE_OK) { /* write OK? */ uptr->pos = gap_pos; /* restore orig pos */ return st; /* PNU was set by wrdata */ } } while (--marker_count > 0); return MTSE_OK; }