home *** CD-ROM | disk | FTP | other *** search
- /* PDP-8 magnetic tape simulator
-
- Copyright (c) 1995, 1996, Robert M Supnik, Digital Equipment Corporation
- Commercial use prohibited
-
- 1-Jan-96 RMS Rewritten from TM8-E Maintenance Manual
-
- Magnetic tapes are represented as a series of variable 16b records
- of the form:
-
- byte count
- byte 0'byte 1
- :
- byte n-2'byte n-1
-
- If the byte count is odd, the record is padded with an extra byte
- of junk. File marks are represented by a byte count of 0.
- */
-
- #include "pdp8_defs.h"
-
- #define MT_NUMDR 8 /* #drives */
- #define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
- #define UNIT_WLK 1 << UNIT_V_WLK
- #define USTAT u3 /* unit status */
- #define UNUM u4 /* unit number */
- #define SBSIZE (1 << 12) /* max space cmd */
- #define SBMASK (SBSIZE - 1)
-
- /* Command/unit - mt_cu */
-
- #define CU_V_UNIT 9 /* unit */
- #define CU_M_UNIT 07
- #define CU_PARITY 00400 /* parity select */
- #define CU_IEE 00200 /* error int enable */
- #define CU_IED 00100 /* done int enable */
- #define CU_V_EMA 3 /* ext mem address */
- #define CU_M_EMA 07
- #define CU_EMA (CU_M_EMA << CU_V_EMA)
- #define CU_DTY 00002 /* drive type */
- #define CU_UNPAK 00001 /* 6b vs 8b mode */
- #define GET_UNIT(x) (((x) >> CU_V_UNIT) & CU_M_UNIT)
- #define GET_EMA(x) (((x) & CU_EMA) << (12 - CU_V_EMA))
-
- /* Function - mt_fn */
-
- #define FN_V_FNC 9 /* function */
- #define FN_M_FNC 07
- #define FN_UNLOAD 00
- #define FN_REWIND 01
- #define FN_READ 02
- #define FN_CMPARE 03
- #define FN_WRITE 04
- #define FN_WREOF 05
- #define FN_SPACEF 06
- #define FN_SPACER 07
- #define FN_ERASE 00400 /* erase */
- #define FN_CRC 00200 /* read CRC */
- #define FN_GO 00100 /* go */
- #define FN_INC 00040 /* incr mode */
- #define FN_RMASK 07740 /* readable bits */
- #define GET_FNC(x) (((x) >> FN_V_FNC) & FN_M_FNC)
-
- /* Status - stored in mt_sta or (*) uptr -> USTAT */
-
- #define STA_ERR (04000 << 12) /* error */
- #define STA_REW (02000 << 12) /* *rewinding */
- #define STA_BOT (01000 << 12) /* *start of tape */
- #define STA_REM (00400 << 12) /* *offline */
- #define STA_PAR (00200 << 12) /* parity error */
- #define STA_EOF (00100 << 12) /* *end of file */
- #define STA_RLE (00040 << 12) /* rec lnt error */
- #define STA_DLT (00020 << 12) /* data late */
- #define STA_EOT (00010 << 12) /* *end of tape */
- #define STA_WLK (00004 << 12) /* *write locked */
- #define STA_CPE (00002 << 12) /* compare error */
- #define STA_ILL (00001 << 12) /* illegal */
- #define STA_INC 00010 /* increment error */
- #define STA_LAT 00004 /* lateral par error */
- #define STA_CRC 00002 /* CRC error */
- #define STA_LON 00001 /* long par error */
-
- #define STA_CLR (FN_RMASK | 00020) /* always clear */
- #define STA_DYN (STA_REW | STA_BOT | STA_REM | STA_EOF | \
- STA_EOT | STA_WLK) /* kept in USTAT */
- #define STA_EFLGS (STA_BOT | STA_PAR | STA_RLE | STA_DLT | \
- STA_EOT | STA_CPE | STA_ILL | STA_EOF | STA_INC)
- /* set error */
- #define TUR(u) (!sim_is_active (u)) /* tape unit ready */
-
- extern unsigned short M[];
- extern int int_req, stop_inst;
- extern UNIT cpu_unit;
- int mt_cu = 0; /* command/unit */
- int mt_fn = 0; /* function */
- int mt_ca = 0; /* current address */
- int mt_wc = 0; /* word count */
- int mt_sta = 0; /* status register */
- int mt_db = 0; /* data buffer */
- int mt_done = 0; /* mag tape flag */
- int mt_time = 10; /* record latency */
- int mt_stopioe = 1; /* stop on error */
- int mt_svc (UNIT *uptr);
- int mt_reset (DEVICE *dptr);
- int mt_attach (UNIT *uptr, char *cptr);
- int mt_detach (UNIT *uptr);
- int mt_updcsta (UNIT *uptr);
- int mt_ixma (int xma);
- int mt_vlock (UNIT *uptr, int val);
- UNIT *mt_busy (void);
- void mt_set_done (void);
- extern int sim_activate (UNIT *uptr, int interval);
- extern int sim_cancel (UNIT *uptr);
- extern int sim_is_active (UNIT *uptr);
- extern int attach_unit (UNIT *uptr, char *cptr);
- extern int detach_unit (UNIT *uptr);
-
- /* MT data structures
-
- mt_dev MT device descriptor
- mt_unit MT unit list
- mt_reg MT register list
- mt_mod MT modifier list
- */
-
- UNIT mt_unit[] = {
- { UDATA (&mt_svc, UNIT_ATTABLE, 0) },
- { UDATA (&mt_svc, UNIT_ATTABLE, 0) },
- { UDATA (&mt_svc, UNIT_ATTABLE, 0) },
- { UDATA (&mt_svc, UNIT_ATTABLE, 0) },
- { UDATA (&mt_svc, UNIT_ATTABLE, 0) },
- { UDATA (&mt_svc, UNIT_ATTABLE, 0) },
- { UDATA (&mt_svc, UNIT_ATTABLE, 0) },
- { UDATA (&mt_svc, UNIT_ATTABLE, 0) } };
-
- REG mt_reg[] = {
- { ORDATA (CMD, mt_cu, 12) },
- { ORDATA (FNC, mt_fn, 12) },
- { ORDATA (CA, mt_ca, 12) },
- { ORDATA (WC, mt_wc, 12) },
- { ORDATA (DB, mt_db, 12) },
- { GRDATA (STA, mt_sta, 8, 12, 12) },
- { ORDATA (STA2, mt_sta, 6) },
- { FLDATA (DONE, mt_done, 0) },
- { FLDATA (INT, int_req, INT_V_MT) },
- { FLDATA (STOP_IOE, mt_stopioe, 0) },
- { DRDATA (TIME, mt_time, 24), PV_LEFT },
- { ORDATA (UST0, mt_unit[0].USTAT, 24) },
- { ORDATA (UST1, mt_unit[1].USTAT, 24) },
- { ORDATA (UST2, mt_unit[2].USTAT, 24) },
- { ORDATA (UST3, mt_unit[3].USTAT, 24) },
- { ORDATA (UST4, mt_unit[4].USTAT, 24) },
- { ORDATA (UST5, mt_unit[5].USTAT, 24) },
- { ORDATA (UST6, mt_unit[6].USTAT, 24) },
- { ORDATA (UST7, mt_unit[7].USTAT, 24) },
- { GRDATA (POS0, mt_unit[0].pos, 10, 31, 1), PV_LEFT + REG_RO },
- { GRDATA (POS1, mt_unit[1].pos, 10, 31, 1), PV_LEFT + REG_RO },
- { GRDATA (POS2, mt_unit[2].pos, 10, 31, 1), PV_LEFT + REG_RO },
- { GRDATA (POS3, mt_unit[3].pos, 10, 31, 1), PV_LEFT + REG_RO },
- { GRDATA (POS4, mt_unit[4].pos, 10, 31, 1), PV_LEFT + REG_RO },
- { GRDATA (POS5, mt_unit[5].pos, 10, 31, 1), PV_LEFT + REG_RO },
- { GRDATA (POS6, mt_unit[6].pos, 10, 31, 1), PV_LEFT + REG_RO },
- { GRDATA (POS7, mt_unit[7].pos, 10, 31, 1), PV_LEFT + REG_RO },
- { FLDATA (WLK0, mt_unit[0].flags, UNIT_V_WLK), REG_HRO },
- { FLDATA (WLK1, mt_unit[1].flags, UNIT_V_WLK), REG_HRO },
- { FLDATA (WLK2, mt_unit[2].flags, UNIT_V_WLK), REG_HRO },
- { FLDATA (WLK3, mt_unit[3].flags, UNIT_V_WLK), REG_HRO },
- { FLDATA (WLK4, mt_unit[4].flags, UNIT_V_WLK), REG_HRO },
- { FLDATA (WLK5, mt_unit[5].flags, UNIT_V_WLK), REG_HRO },
- { FLDATA (WLK6, mt_unit[6].flags, UNIT_V_WLK), REG_HRO },
- { FLDATA (WLK7, mt_unit[7].flags, UNIT_V_WLK), REG_HRO },
- { NULL } };
-
- MTAB mt_mod[] = {
- { UNIT_WLK, 0, "write enabled", "ENABLED", &mt_vlock },
- { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", &mt_vlock },
- { 0 } };
-
- DEVICE mt_dev = {
- "MT", mt_unit, mt_reg, mt_mod,
- MT_NUMDR, 10, 32, 1, 8, 16,
- NULL, NULL, &mt_reset,
- NULL, &mt_attach, &mt_detach };
-
- /* IOT routines */
-
- int mt70 (int pulse, int AC)
- {
- int f;
- UNIT *bu, *uptr;
-
- uptr = mt_dev.units + GET_UNIT (mt_cu); /* get unit */
- switch (pulse) { /* decode IR<9:11> */
- case 1: /* LWCR */
- mt_wc = AC; /* load word count */
- return 0;
- case 2: /* CWCR */
- mt_wc = 0; /* clear word count */
- return AC;
- case 3: /* LCAR */
- mt_ca = AC; /* load mem address */
- return 0;
- case 4: /* CCAR */
- mt_ca = 0; /* clear mem address */
- return AC;
- case 5: /* LCMR */
- if (mt_busy ()) mt_sta = mt_sta | STA_ILL; /* busy? illegal op */
- mt_cu = AC; /* load command reg */
- mt_updcsta (mt_dev.units + GET_UNIT (mt_cu));
- return 0;
-
- /* MT70, continued */
-
- case 6: /* LFGR */
- if (mt_busy ()) mt_sta = mt_sta | STA_ILL; /* busy? illegal op */
- mt_fn = AC; /* load function */
- if ((mt_fn & FN_GO) == 0) { /* go set? */
- mt_updcsta (uptr); /* update status */
- return 0; }
- f = GET_FNC (mt_fn); /* get function */
- if (((uptr -> flags & UNIT_ATT) == 0) || !TUR (uptr) ||
- (((f == FN_WRITE) || (f == FN_WREOF)) && (uptr -> flags & UNIT_WLK))
- || (((f == FN_SPACER) || (f == FN_REWIND)) && (uptr -> pos == 0))) {
- mt_sta = mt_sta | STA_ILL; /* illegal op error */
- mt_set_done (); /* set done */
- mt_updcsta (uptr); /* update status */
- return 0; }
- uptr -> USTAT = uptr -> USTAT & STA_WLK; /* clear status */
- if (f == FN_UNLOAD) { /* unload? */
- detach_unit (uptr); /* set offline */
- uptr -> USTAT = STA_REW | STA_REM; /* rewinding, off */
- mt_set_done (); } /* set done */
- else if (f == FN_REWIND) { /* rewind */
- uptr -> USTAT = uptr -> USTAT | STA_REW; /* rewinding */
- mt_set_done (); } /* set done */
- else mt_done = 0; /* clear done */
- mt_updcsta (uptr); /* update status */
- sim_activate (uptr, mt_time); /* start io */
- return 0;
- case 7: /* LDBR */
- if (mt_busy ()) mt_sta = mt_sta | STA_ILL; /* busy? illegal op */
- mt_db = AC; /* load buffer */
- mt_set_done (); /* set done */
- mt_updcsta (uptr); /* update status */
- return 0;
- default:
- return (stop_inst << IOT_V_REASON) + AC; } /* end switch */
- return AC;
- }
-
- /* IOTs, continued */
-
- int mt71 (int pulse, int AC)
- {
- UNIT *uptr;
-
- uptr = mt_dev.units + GET_UNIT (mt_cu);
- switch (pulse) { /* decode IR<9:11> */
- case 1: /* RWCR */
- return mt_wc; /* read word count */
- case 2: /* CLT */
- mt_reset (&mt_dev); /* reset everything */
- return AC;
- case 3: /* RCAR */
- return mt_ca; /* read mem address */
- case 4: /* RMSR */
- return ((mt_updcsta (uptr) >> 12) & 07777); /* read status */
- case 5: /* RCMR */
- return mt_cu; /* read command */
- case 6: /* RFSR */
- return (((mt_fn & FN_RMASK) | (mt_updcsta (uptr) & ~FN_RMASK))
- & 07777); /* read function */
- case 7: /* RDBR */
- return mt_db; /* read data buffer */
- default:
- return (stop_inst << IOT_V_REASON) + AC; } /* end switch */
- return AC;
- }
-
- int mt72 (int pulse, int AC)
- {
- UNIT *uptr;
-
- uptr = mt_dev.units + GET_UNIT (mt_cu); /* get unit */
- switch (pulse) { /* decode IR<9:11> */
- case 1: /* SKEF */
- return (mt_sta & STA_ERR)? IOT_SKP + AC: AC;
- case 2: /* SKCB */
- return (!mt_busy ())? IOT_SKP + AC: AC;
- case 3: /* SKJD */
- return mt_done? IOT_SKP + AC: AC;
- case 4: /* SKTR */
- return (TUR (uptr))? IOT_SKP + AC: AC;
- case 5: /* CLF */
- if (TUR (uptr)) mt_reset (&mt_dev); /* if TUR, zap */
- else { mt_sta = 0; /* clear status */
- mt_done = 0; /* clear done */
- mt_updcsta (uptr); } /* update status */
- return AC;
- default:
- return (stop_inst << IOT_V_REASON) + AC; } /* end switch */
- return AC;
- }
-
- /* Unit service
-
- If rewind done, reposition to start of tape, set status
- else, do operation, set done, interrupt
- */
-
- int mt_svc (UNIT *uptr)
- {
- int rval, c, f, i, p, u, err;
- int awc, wc, xma;
- unsigned short bc, sbuf[SBSIZE + 1];
- static const unsigned short bceof = 0;
-
- u = uptr -> UNUM; /* get unit number */
- if (uptr -> USTAT & STA_REW) { /* rewind? */
- uptr -> pos = 0; /* update position */
- if (uptr -> flags & UNIT_ATT) /* still on line? */
- uptr -> USTAT = (uptr -> USTAT & STA_WLK) | STA_BOT;
- else uptr -> USTAT = STA_REM;
- if (u == GET_UNIT (mt_cu)) { /* selected? */
- mt_set_done (); /* set done */
- mt_updcsta (uptr); } /* update status */
- return SCPE_OK; }
-
- if ((uptr -> flags & UNIT_ATT) == 0) { /* if not attached */
- uptr -> USTAT = STA_REM; /* unit off line */
- mt_sta = mt_sta | STA_ILL; /* illegal operation */
- mt_set_done (); /* set done */
- mt_updcsta (uptr); /* update status */
- return IORETURN (mt_stopioe, SCPE_UNATT); }
-
- f = GET_FNC (mt_fn); /* get command */
- if (((f == FN_WRITE) || (f == FN_WREOF)) && (uptr -> flags & UNIT_WLK)) {
- mt_sta = mt_sta | STA_ILL; /* illegal operation */
- mt_set_done (); /* set done */
- mt_updcsta (uptr); /* update status */
- return SCPE_OK; }
-
- err = 0;
- rval = SCPE_OK;
- xma = GET_EMA (mt_cu) + mt_ca; /* get mem addr */
- wc = 010000 - mt_wc; /* get wc */
- switch (f) { /* case on function */
-
- /* Unit service, continued */
-
- case FN_READ: /* read */
- case FN_CMPARE: /* read/compare */
- fseek (uptr -> fileref, uptr -> pos, SEEK_SET);
- fread (&bc, sizeof (short), 1, uptr -> fileref); /* read byte count */
- if ((err = ferror (uptr -> fileref)) || /* error or eof? */
- (feof (uptr -> fileref))) {
- uptr -> USTAT = uptr -> USTAT | STA_EOT | STA_RLE;
- break; }
- if (bc == 0) { /* tape mark? */
- uptr -> USTAT = uptr -> USTAT | STA_EOF | STA_RLE;
- uptr -> pos = uptr -> pos + sizeof (short);
- break; }
- awc = (mt_cu & CU_UNPAK)? ((int) bc): ((int) bc + 1) >> 1;
- if (awc != wc) mt_sta = mt_sta | STA_RLE; /* wrong size? */
- if (awc < wc) wc = awc; /* use smaller */
- i = fread (sbuf, sizeof (short), wc, uptr -> fileref);
- for ( ; i < wc; i++) sbuf[i] = 0; /* fill with 0's */
- err = ferror (uptr -> fileref);
- for (i = p = 0; i < wc; i++) { /* copy buffer */
- xma = mt_ixma (xma); /* increment xma */
- if (mt_cu & CU_UNPAK) { /* unpacked? */
- if (i & 1) c = sbuf[p++] & 0377;
- else c = (sbuf[p] >> 8) & 0377; }
- else { c = ((sbuf[p] >> 2) & 07700) | (sbuf[p] & 077);
- p++; }
- if ((f == FN_READ) && MEM_ADDR_OK (xma)) M[xma] = c;
- else if ((f == FN_CMPARE) && (M[xma] != c)) {
- mt_sta = mt_sta | STA_CPE;
- break; } }
- mt_wc = (mt_wc + wc) & 07777; /* update wc */
- uptr -> pos = uptr -> pos + (((int) bc + 1) & ~1) + sizeof (short);
- break;
- case FN_WRITE: /* write */
- fseek (uptr -> fileref, uptr -> pos, SEEK_SET);
- sbuf[0] = bc = (mt_cu & CU_UNPAK)? wc: wc << 1;
- for (i = p = 0; i < wc; i++) { /* copy buf to tape */
- xma = mt_ixma (xma); /* incr mem addr */
- if (mt_cu & CU_UNPAK) { /* unpacked? */
- if (i & 1) sbuf[p] = sbuf[p] | (M[xma] & 0377);
- else sbuf[++p] = (M[xma] & 0377) << 8; }
- else sbuf[++p] = ((M[xma] & 07700) << 2) | (M[xma] & 077); }
- fwrite (sbuf, sizeof (short), p + 1, uptr -> fileref);
- err = ferror (uptr -> fileref);
- mt_wc = 0;
- uptr -> pos = uptr -> pos + (((int) bc + 1) & ~1) + sizeof (short);
- break;
- case FN_WREOF:
- fseek (uptr -> fileref, uptr -> pos, SEEK_SET);
- fwrite (&bceof, sizeof (short), 1, uptr -> fileref); /* write eof */
- err = ferror (uptr -> fileref);
- uptr -> pos = uptr -> pos + sizeof (short); /* update position */
- break;
-
- /* Unit service, continued */
-
- case FN_SPACEF: /* space forward */
- do { mt_wc = (mt_wc + 1) & 07777; /* incr wc */
- fseek (uptr -> fileref, uptr -> pos, SEEK_SET);
- fread (&bc, sizeof (short), 1, uptr -> fileref); /* read bc */
- if ((err = ferror (uptr -> fileref)) || /* error or eof? */
- feof (uptr -> fileref)) {
- uptr -> USTAT = uptr -> USTAT | STA_EOT;
- break; }
- uptr -> pos = uptr -> pos + sizeof (short);
- if (bc == 0) { /* zero bc? */
- uptr -> USTAT = uptr -> USTAT | STA_EOF;
- break; }
- uptr -> pos = uptr -> pos + (((int) bc + 1) & ~1); }
- while (mt_wc != 0);
- break;
- case FN_SPACER: /* space reverse */
- for (i = 0; i < SBSIZE; i++) sbuf[i] = 0; /* clear table */
- for (i = 0, p = 0; p < uptr -> pos; ) { /* build table */
- fseek (uptr -> fileref, p, SEEK_SET);
- fread (&sbuf[i], sizeof (short), 1, uptr -> fileref);
- if ((err = ferror (uptr -> fileref)) ||
- (feof (uptr -> fileref))) {
- uptr -> pos = p;
- break; }
- p = p + sizeof (short) + (((int) sbuf[i] + 1) & ~1);
- i = (i + 1) & SBMASK; }
- if (uptr -> pos == 0) { /* at BOT? */
- uptr -> USTAT = uptr -> USTAT | STA_BOT;
- break; }
- do { mt_wc = (mt_wc + 1) & 07777; /* incr wc */
- i = (i - 1) & SBMASK;
- uptr -> pos = uptr -> pos - sizeof (short) -
- (((int) sbuf[i] + 1) & ~1);
- if (uptr -> pos == 0) /* start of tape? */
- uptr -> USTAT = uptr -> USTAT | STA_BOT;
- if (sbuf[i] == 0) /* start of prv file? */
- uptr -> USTAT = uptr -> USTAT | STA_EOF;
- if (uptr -> USTAT & (STA_BOT | STA_EOF)) break; }
- while (mt_wc != 0);
- break; } /* end case */
-
- /* Unit service, continued */
-
- if (err != 0) { /* I/O error */
- mt_sta = mt_sta | STA_PAR | STA_CRC; /* flag error */
- perror ("MT I/O error");
- rval = SCPE_IOERR;
- clearerr (uptr -> fileref); }
- mt_cu = (mt_cu & ~CU_EMA) | ((xma >> (12 - CU_V_EMA)) & CU_EMA);
- mt_ca = xma & 07777; /* update mem addr */
- mt_set_done (); /* set done */
- mt_updcsta (uptr); /* update status */
- return IORETURN (mt_stopioe, rval);
- }
-
- /* Update controller status */
-
- int mt_updcsta (UNIT *uptr)
- {
- mt_sta = (mt_sta & ~(STA_DYN | STA_ERR | STA_CLR)) | (uptr -> USTAT & STA_DYN);
- if (mt_sta & STA_EFLGS) mt_sta = mt_sta | STA_ERR;
- if (((mt_sta & STA_ERR) && (mt_cu & CU_IEE)) ||
- (mt_done && (mt_cu & CU_IED))) int_req = int_req | INT_MT;
- else int_req = int_req & ~INT_MT;
- return mt_sta;
- }
-
- /* Test if controller busy */
-
- UNIT *mt_busy (void)
- {
- int u;
- UNIT *uptr;
-
- for (u = 0; u < MT_NUMDR; u++) { /* loop thru units */
- uptr = mt_dev.units + u;
- if (sim_is_active (uptr) && ((uptr -> USTAT & STA_REW) == 0))
- return uptr; }
- return NULL;
- }
-
- /* Increment extended memory address */
-
- int mt_ixma (int xma) /* incr extended ma */
- {
- int v;
-
- v = ((xma + 1) & 07777) | (xma & 070000); /* wrapped incr */
- if (mt_fn & FN_INC) { /* increment mode? */
- if (xma == 077777) mt_sta = mt_sta | STA_INC; /* at limit? error */
- else v = xma + 1; } /* else 15b incr */
- return v;
- }
-
- /* Set done */
-
- void mt_set_done (void)
- {
- mt_done = 1; /* set done */
- mt_fn = mt_fn & ~(FN_CRC | FN_GO | FN_INC); /* clear func<4:6> */
- return;
- }
-
- /* Reset routine */
-
- int mt_reset (DEVICE *dptr)
- {
- int i, u;
- UNIT *uptr;
-
- mt_cu = mt_fn = mt_wc = mt_ca = mt_db = mt_sta = mt_done = 0;
- int_req = int_req & ~INT_MT; /* clear interrupt */
- for (u = 0; u < MT_NUMDR; u++) { /* loop thru units */
- uptr = mt_dev.units + u;
- uptr -> UNUM = u; /* init drive number */
- sim_cancel (uptr); /* cancel activity */
- if (uptr -> flags & UNIT_ATT) uptr -> USTAT =
- ((uptr -> pos)? 0: STA_BOT) |
- ((uptr -> flags & UNIT_WLK)? STA_WLK: 0);
- else uptr -> USTAT = STA_REM; }
- return SCPE_OK;
- }
-
- /* Attach routine */
-
- int mt_attach (UNIT *uptr, char *cptr)
- {
- int r;
-
- r = attach_unit (uptr, cptr);
- if (r != SCPE_OK) return r;
- uptr -> USTAT = STA_BOT | ((uptr -> flags & UNIT_WLK)? STA_WLK: 0);
- if (uptr -> UNUM == GET_UNIT (mt_cu)) mt_updcsta (uptr);
- return r;
- }
-
- /* Detach routine */
-
- int mt_detach (UNIT* uptr)
- {
- if (!sim_is_active (uptr)) uptr -> USTAT = STA_REM;
- if (uptr -> UNUM == GET_UNIT (mt_cu)) mt_updcsta (uptr);
- return detach_unit (uptr);
- }
-
- /* Write lock/enable routine */
-
- int mt_vlock (UNIT *uptr, int val)
- {
- if ((uptr -> flags & UNIT_ATT) && val) uptr -> USTAT = uptr -> USTAT | STA_WLK;
- else uptr -> USTAT = uptr -> USTAT & ~STA_WLK;
- if (uptr -> UNUM == GET_UNIT (mt_cu)) mt_updcsta (uptr);
- return SCPE_OK;
- }
-