t_stat sim_tape_wrtmk (UNIT *uptr) { if (MT_GET_FMT (uptr) == MTUF_F_P7B) { /* P7B? */ uint8 buf = P7B_EOF; /* eof mark */ return sim_tape_wrrecf (uptr, &buf, 1); /* write char */ } return sim_tape_wrdata (uptr, MTR_TMK); }
t_stat mt_flush_buf (UNIT *uptr) { t_stat st; if (mt_blim == 0) /* any output? */ return SCPE_OK; if (st = sim_tape_wrrecf (uptr, mt_xb, mt_blim)) /* write, err? */ return mt_map_err (uptr, st); /* map error */ return SCPE_OK; }
t_stat mt_clear (void) { t_stat st; if (sim_is_active (&mtc_unit) && /* write in prog? */ (mtc_fnc == FNC_WC) && (mt_ptr > 0)) { /* yes, bad rec */ if (st = sim_tape_wrrecf (&mtc_unit, mtxb, mt_ptr | MTR_ERF)) mt_map_err (&mtc_unit, st); } if (((mtc_fnc == FNC_REW) || (mtc_fnc == FNC_RWS)) && sim_is_active (&mtc_unit)) sim_cancel (&mtc_unit); mtc_1st = mtc_dtf = 0; mtc_sta = mtc_sta & STA_BOT; return SCPE_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; }
int32 ts_write (UNIT *uptr, int32 fc) { int32 i, t; uint32 wa; t_stat st; msgrfc = fc; if (fc == 0) /* byte count */ fc = 0200000; tsba = (cmdadh << 16) | cmdadl; /* buf addr */ if (cmdhdr & CMD_SWP) { /* swapped? */ for (i = 0; i < fc; i++) { /* copy mem to buf */ wa = tsba ^ 1; /* apply OPP */ if (Map_ReadB (wa, 1, &tsxb[i])) { /* fetch byte, nxm? */ tssr = ts_updtssr (tssr | TSSR_NXM); return TC5; } tsba = tsba + 1; } } else { t = Map_ReadB (tsba, fc, tsxb); /* fetch record */ tsba = tsba + (fc - t); /* update tsba */ if (t) { /* nxm? */ tssr = ts_updtssr (tssr | TSSR_NXM); return TC5; } } if ((st = sim_tape_wrrecf (uptr, tsxb, fc))) /* write rec, err? */ return ts_map_status (st); /* return status */ msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ msgrfc = 0; if (sim_tape_eot (&ts_unit)) /* EOT on write? */ return XTC (XS0_EOT, TC2); return 0; }
t_stat mtc_svc (UNIT *uptr) { t_mtrlnt tbc; t_stat st, r = SCPE_OK; if ((mtc_unit.flags & UNIT_ATT) == 0) { /* offline? */ mtc_sta = STA_LOCAL | STA_REJ; /* rejected */ mtcio (mtc_dib.devno, ioENF, 0); /* set cch flg */ return IORETURN (mtc_stopioe, SCPE_UNATT); } switch (mtc_fnc) { /* case on function */ case FNC_REW: /* rewind */ sim_tape_rewind (uptr); /* BOT */ mtc_sta = STA_BOT; /* update status */ break; case FNC_RWS: /* rewind and offline */ sim_tape_rewind (uptr); /* clear position */ return sim_tape_detach (uptr); /* don't set cch flg */ case FNC_WFM: /* write file mark */ if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */ r = mt_map_err (uptr, st); /* map error */ mtc_sta = STA_EOF; /* set EOF status */ break; case FNC_GAP: /* erase gap */ break; case FNC_FSR: /* space forward */ if (st = sim_tape_sprecf (uptr, &tbc)) /* space rec fwd, err? */ r = mt_map_err (uptr, st); /* map error */ break; case FNC_BSR: /* space reverse */ if (st = sim_tape_sprecr (uptr, &tbc)) /* space rec rev, err? */ r = mt_map_err (uptr, st); /* map error */ break; case FNC_RC: /* read */ if (mtc_1st) { /* first svc? */ mtc_1st = mt_ptr = 0; /* clr 1st flop */ st = sim_tape_rdrecf (uptr, mtxb, &mt_max, DBSIZE); /* read rec */ if (st == MTSE_RECE) mtc_sta = mtc_sta | STA_PAR; /* rec in err? */ else if (st != MTSE_OK) { /* other error? */ r = mt_map_err (uptr, st); /* map error */ if (r == SCPE_OK) { /* recoverable? */ sim_activate (uptr, mtc_gtime); /* sched IRG */ mtc_fnc = 0; /* NOP func */ return SCPE_OK; } break; /* non-recov, done */ } if (mt_max < 12) { /* record too short? */ mtc_sta = mtc_sta | STA_PAR; /* set flag */ break; } } if (mtc_dtf && (mt_ptr < mt_max)) { /* more chars? */ if (mtd_flag) mtc_sta = mtc_sta | STA_TIM; mtc_unit.buf = mtxb[mt_ptr++]; /* fetch next */ mtdio (mtd_dib.devno, ioENF, 0); /* set dch flg */ sim_activate (uptr, mtc_xtime); /* re-activate */ return SCPE_OK; } sim_activate (uptr, mtc_gtime); /* schedule gap */ mtc_fnc = 0; /* nop */ return SCPE_OK; case FNC_WC: /* write */ if (mtc_1st) mtc_1st = 0; /* no xfr on first */ else { if (mt_ptr < DBSIZE) { /* room in buffer? */ mtxb[mt_ptr++] = mtc_unit.buf; mtc_sta = mtc_sta & ~STA_BOT; /* clear BOT */ } else mtc_sta = mtc_sta | STA_PAR; } if (mtc_dtf) { /* xfer flop set? */ mtdio (mtd_dib.devno, ioENF, 0); /* set dch flg */ sim_activate (uptr, mtc_xtime); /* re-activate */ return SCPE_OK; } if (mt_ptr) { /* write buffer */ if (st = sim_tape_wrrecf (uptr, mtxb, mt_ptr)) { /* write, err? */ r = mt_map_err (uptr, st); /* map error */ break; /* done */ } } sim_activate (uptr, mtc_gtime); /* schedule gap */ mtc_fnc = 0; /* nop */ return SCPE_OK; default: /* unknown */ break; } mtcio (mtc_dib.devno, ioENF, 0); /* set cch flg */ mtc_sta = mtc_sta & ~STA_BUSY; /* not busy */ return r; }
/* 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_svc (UNIT *uptr) { uint32 i; int32 u = uptr - mt_dev.units; uint32 dev = mt_dib.dno + (u * o_MT0); t_mtrlnt tbc; t_bool passed_eot; t_stat st, r = SCPE_OK; if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ uptr->UCMD = 0; /* clr cmd */ uptr->UST = 0; /* set status */ mt_xfr = 0; /* clr op flags */ mt_sta = STA_ERR | STA_EOM; /* set status */ if (mt_arm[u]) /* interrupt */ SET_INT (v_MT + u); return IORETURN (mt_stopioe, SCPE_UNATT); } if (uptr->UCMD & MTC_STOP2) { /* stop, gen NMTN? */ uptr->UCMD = 0; /* clr cmd */ uptr->UST = uptr->UST | STA_NMTN; /* set nmtn */ mt_xfr = 0; /* clr xfr */ if (mt_arm[u]) /* set intr */ SET_INT (v_MT + u); return SCPE_OK; } if (uptr->UCMD & MTC_STOP1) { /* stop, gen EOM? */ uptr->UCMD = uptr->UCMD | MTC_STOP2; /* clr cmd */ mt_sta = (mt_sta & ~STA_BSY) | STA_EOM; /* clr busy, set eom */ if (mt_arm[u]) /* set intr */ SET_INT (v_MT + u); sim_activate (uptr, mt_rtime); /* schedule */ return SCPE_OK; } passed_eot = sim_tape_eot (uptr); /* passed EOT? */ switch (uptr->UCMD) { /* case on function */ case MTC_REW: /* rewind */ sim_tape_rewind (uptr); /* reposition */ uptr->UCMD = 0; /* clr cmd */ uptr->UST = STA_NMTN | STA_EOT; /* update status */ mt_sta = mt_sta & ~STA_BSY; /* don't set EOM */ if (mt_arm[u]) /* interrupt */ SET_INT (v_MT + u); return SCPE_OK; /* For read, busy = 1 => buffer empty For write, busy = 1 => buffer full For read, data transfers continue for the full length of the record, or the maximum size of the transfer buffer For write, data transfers continue until a write is attempted and the buffer is empty */ case MTC_RD: /* read */ if (mt_blnt == 0) { /* first time? */ st = sim_tape_rdrecf (uptr, mtxb, &tbc, MT_MAXFR); /* read rec */ if (st == MTSE_RECE) /* rec in err? */ mt_sta = mt_sta | STA_ERR; else if (st != SCPE_OK) { /* other error? */ r = mt_map_err (uptr, st); /* map error */ if (sch_actv (mt_dib.sch, dev)) /* if sch, stop */ sch_stop (mt_dib.sch); break; } mt_blnt = tbc; /* set buf lnt */ } if (sch_actv (mt_dib.sch, dev)) { /* sch active? */ i = sch_wrmem (mt_dib.sch, mtxb, mt_blnt); /* store rec in mem */ if (sch_actv (mt_dib.sch, dev)) /* sch still active? */ sch_stop (mt_dib.sch); /* stop chan, long rd */ else if (i < mt_blnt) /* process entire rec? */ mt_sta = mt_sta | STA_ERR; /* no, overrun error */ } else if (mt_bptr < mt_blnt) { /* no, if !eor */ if (!(mt_sta & STA_BSY)) /* busy still clr? */ mt_sta = mt_sta | STA_ERR; /* read overrun */ mt_db = mtxb[mt_bptr++]; /* get next byte */ mt_sta = mt_sta & ~STA_BSY; /* !busy = buf full */ if (mt_arm[u]) /* set intr */ SET_INT (v_MT + u); sim_activate (uptr, mt_wtime); /* reschedule */ return SCPE_OK; } break; /* record done */ case MTC_WR: /* write */ if (sch_actv (mt_dib.sch, dev)) { /* sch active? */ mt_bptr = sch_rdmem (mt_dib.sch, mtxb, MT_MAXFR); /* get rec */ if (sch_actv (mt_dib.sch, dev)) /* not done? */ sch_stop (mt_dib.sch); /* stop chan */ } else if (mt_sta & STA_BSY) { /* no, if !eor */ if (mt_bptr < MT_MAXFR) /* if room */ mtxb[mt_bptr++] = mt_db; /* store in buf */ mt_sta = mt_sta & ~STA_BSY; /* !busy = buf emp */ if (mt_arm[u]) /* set intr */ SET_INT (v_MT + u); sim_activate (uptr, mt_wtime); /* reschedule */ return SCPE_OK; } if (mt_bptr) { /* any chars? */ if ((st = sim_tape_wrrecf (uptr, mtxb, mt_bptr)))/* write, err? */ r = mt_map_err (uptr, st); /* map error */ } break; /* record done */ case MTC_WEOF: /* write eof */ if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */ r = mt_map_err (uptr, st); /* map error */ mt_sta = mt_sta | STA_EOF; /* set eof */ if (mt_arm[u]) /* set intr */ SET_INT (v_MT + u); break; case MTC_SKFF: /* skip file fwd */ while ((st = sim_tape_sprecf (uptr, &tbc)) == MTSE_OK) ; if (st == MTSE_TMK) { /* stopped by tmk? */ mt_sta = mt_sta | STA_EOF; /* set eof */ if (mt_arm[u]) /* set intr */ SET_INT (v_MT + u); } else r = mt_map_err (uptr, st); /* map error */ break; case MTC_SKFR: /* skip file rev */ while ((st = sim_tape_sprecr (uptr, &tbc)) == MTSE_OK) ; if (st == MTSE_TMK) { /* stopped by tmk? */ mt_sta = mt_sta | STA_EOF; /* set eof */ if (mt_arm[u]) /* set intr */ SET_INT (v_MT + u); } else r = mt_map_err (uptr, st); /* map error */ break; case MTC_SPCR: /* backspace */ if ((st = sim_tape_sprecr (uptr, &tbc))) /* skip rec rev, err? */ r = mt_map_err (uptr, st); /* map error */ break; } /* end case */ if (!passed_eot && sim_tape_eot (uptr)) /* just passed EOT? */ uptr->UST = uptr->UST | STA_EOT; uptr->UCMD = uptr->UCMD | MTC_STOP1; /* set stop stage 1 */ sim_activate (uptr, mt_rtime); /* schedule */ return r; }
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); }