First Commit of my working state
[simh.git] / PDP8 / pdp8_mt.c
1 /* pdp8_mt.c: PDP-8 magnetic tape simulator
2
3 Copyright (c) 1993-2006, Robert M Supnik
4
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22 Except as contained in this notice, the name of Robert M Supnik shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from Robert M Supnik.
25
26 mt TM8E/TU10 magtape
27
28 16-Feb-06 RMS Added tape capacity checking
29 16-Aug-05 RMS Fixed C++ declaration and cast problems
30 18-Mar-05 RMS Added attached test to detach routine
31 25-Apr-03 RMS Revised for extended file support
32 29-Mar-03 RMS Added multiformat support
33 04-Mar-03 RMS Fixed bug in SKTR
34 01-Mar-03 RMS Fixed interrupt handling
35 Revised for magtape library
36 30-Oct-02 RMS Revised BOT handling, added error record handling
37 04-Oct-02 RMS Added DIBs, device number support
38 30-Aug-02 RMS Revamped error handling
39 28-Aug-02 RMS Added end of medium support
40 30-May-02 RMS Widened POS to 32b
41 22-Apr-02 RMS Added maximum record length test
42 06-Jan-02 RMS Changed enable/disable support
43 30-Nov-01 RMS Added read only unit, extended SET/SHOW support
44 24-Nov-01 RMS Changed UST, POS, FLG to arrays
45 25-Apr-01 RMS Added device enable/disable support
46 04-Oct-98 RMS V2.4 magtape format
47 22-Jan-97 RMS V2.3 magtape format
48 01-Jan-96 RMS Rewritten from TM8-E Maintenance Manual
49
50 Magnetic tapes are represented as a series of variable records
51 of the form:
52
53 32b byte count
54 byte 0
55 byte 1
56 :
57 byte n-2
58 byte n-1
59 32b byte count
60
61 If the byte count is odd, the record is padded with an extra byte
62 of junk. File marks are represented by a byte count of 0.
63 */
64
65 #include "pdp8_defs.h"
66 #include "sim_tape.h"
67
68 #define MT_NUMDR 8 /* #drives */
69 #define USTAT u3 /* unit status */
70 #define MT_MAXFR (1 << 16) /* max record lnt */
71 #define WC_SIZE (1 << 12) /* max word count */
72 #define WC_MASK (WC_SIZE - 1)
73
74 /* Command/unit - mt_cu */
75
76 #define CU_V_UNIT 9 /* unit */
77 #define CU_M_UNIT 07
78 #define CU_PARITY 00400 /* parity select */
79 #define CU_IEE 00200 /* error int enable */
80 #define CU_IED 00100 /* done int enable */
81 #define CU_V_EMA 3 /* ext mem address */
82 #define CU_M_EMA 07
83 #define CU_EMA (CU_M_EMA << CU_V_EMA)
84 #define CU_DTY 00002 /* drive type */
85 #define CU_UNPAK 00001 /* 6b vs 8b mode */
86 #define GET_UNIT(x) (((x) >> CU_V_UNIT) & CU_M_UNIT)
87 #define GET_EMA(x) (((x) & CU_EMA) << (12 - CU_V_EMA))
88
89 /* Function - mt_fn */
90
91 #define FN_V_FNC 9 /* function */
92 #define FN_M_FNC 07
93 #define FN_UNLOAD 00
94 #define FN_REWIND 01
95 #define FN_READ 02
96 #define FN_CMPARE 03
97 #define FN_WRITE 04
98 #define FN_WREOF 05
99 #define FN_SPACEF 06
100 #define FN_SPACER 07
101 #define FN_ERASE 00400 /* erase */
102 #define FN_CRC 00200 /* read CRC */
103 #define FN_GO 00100 /* go */
104 #define FN_INC 00040 /* incr mode */
105 #define FN_RMASK 07700 /* readable bits */
106 #define GET_FNC(x) (((x) >> FN_V_FNC) & FN_M_FNC)
107
108 /* Status - stored in mt_sta or (*) uptr->USTAT */
109
110 #define STA_ERR (04000 << 12) /* error */
111 #define STA_REW (02000 << 12) /* *rewinding */
112 #define STA_BOT (01000 << 12) /* *start of tape */
113 #define STA_REM (00400 << 12) /* *offline */
114 #define STA_PAR (00200 << 12) /* parity error */
115 #define STA_EOF (00100 << 12) /* *end of file */
116 #define STA_RLE (00040 << 12) /* rec lnt error */
117 #define STA_DLT (00020 << 12) /* data late */
118 #define STA_EOT (00010 << 12) /* *end of tape */
119 #define STA_WLK (00004 << 12) /* *write locked */
120 #define STA_CPE (00002 << 12) /* compare error */
121 #define STA_ILL (00001 << 12) /* illegal */
122 #define STA_9TK 00040 /* 9 track */
123 /* #define STA_BAD 00020 /* bad tape?? */
124 #define STA_INC 00010 /* increment error */
125 #define STA_LAT 00004 /* lateral par error */
126 #define STA_CRC 00002 /* CRC error */
127 #define STA_LON 00001 /* long par error */
128
129 #define STA_CLR (FN_RMASK | 00020) /* always clear */
130 #define STA_DYN (STA_REW | STA_BOT | STA_REM | STA_EOF | \
131 STA_EOT | STA_WLK) /* kept in USTAT */
132
133 extern uint16 M[];
134 extern int32 int_req, stop_inst;
135 extern UNIT cpu_unit;
136
137 int32 mt_cu = 0; /* command/unit */
138 int32 mt_fn = 0; /* function */
139 int32 mt_ca = 0; /* current address */
140 int32 mt_wc = 0; /* word count */
141 int32 mt_sta = 0; /* status register */
142 int32 mt_db = 0; /* data buffer */
143 int32 mt_done = 0; /* mag tape flag */
144 int32 mt_time = 10; /* record latency */
145 int32 mt_stopioe = 1; /* stop on error */
146 uint8 *mtxb = NULL; /* transfer buffer */
147
148 DEVICE mt_dev;
149 int32 mt70 (int32 IR, int32 AC);
150 int32 mt71 (int32 IR, int32 AC);
151 int32 mt72 (int32 IR, int32 AC);
152 t_stat mt_svc (UNIT *uptr);
153 t_stat mt_reset (DEVICE *dptr);
154 t_stat mt_attach (UNIT *uptr, char *cptr);
155 t_stat mt_detach (UNIT *uptr);
156 int32 mt_updcsta (UNIT *uptr);
157 int32 mt_ixma (int32 xma);
158 t_stat mt_map_err (UNIT *uptr, t_stat st);
159 t_stat mt_vlock (UNIT *uptr, int32 val, char *cptr, void *desc);
160 UNIT *mt_busy (void);
161 void mt_set_done (void);
162
163 /* MT data structures
164
165 mt_dev MT device descriptor
166 mt_unit MT unit list
167 mt_reg MT register list
168 mt_mod MT modifier list
169 */
170
171 DIB mt_dib = { DEV_MT, 3, { &mt70, &mt71, &mt72 } };
172
173 UNIT mt_unit[] = {
174 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
175 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
176 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
177 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
178 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
179 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
180 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
181 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }
182 };
183
184 REG mt_reg[] = {
185 { ORDATA (CMD, mt_cu, 12) },
186 { ORDATA (FNC, mt_fn, 12) },
187 { ORDATA (CA, mt_ca, 12) },
188 { ORDATA (WC, mt_wc, 12) },
189 { ORDATA (DB, mt_db, 12) },
190 { GRDATA (STA, mt_sta, 8, 12, 12) },
191 { ORDATA (STA2, mt_sta, 6) },
192 { FLDATA (DONE, mt_done, 0) },
193 { FLDATA (INT, int_req, INT_V_MT) },
194 { FLDATA (STOP_IOE, mt_stopioe, 0) },
195 { DRDATA (TIME, mt_time, 24), PV_LEFT },
196 { URDATA (UST, mt_unit[0].USTAT, 8, 16, 0, MT_NUMDR, 0) },
197 { URDATA (POS, mt_unit[0].pos, 10, T_ADDR_W, 0,
198 MT_NUMDR, PV_LEFT | REG_RO) },
199 { FLDATA (DEVNUM, mt_dib.dev, 6), REG_HRO },
200 { NULL }
201 };
202
203 MTAB mt_mod[] = {
204 { MTUF_WLK, 0, "write enabled", "WRITEENABLED", &mt_vlock },
205 { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", &mt_vlock },
206 { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT",
207 &sim_tape_set_fmt, &sim_tape_show_fmt, NULL },
208 { MTAB_XTD|MTAB_VUN, 0, "CAPACITY", "CAPACITY",
209 &sim_tape_set_capac, &sim_tape_show_capac, NULL },
210 { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
211 &set_dev, &show_dev, NULL },
212 { 0 }
213 };
214
215 DEVICE mt_dev = {
216 "MT", mt_unit, mt_reg, mt_mod,
217 MT_NUMDR, 10, 31, 1, 8, 8,
218 NULL, NULL, &mt_reset,
219 NULL, &mt_attach, &mt_detach,
220 &mt_dib, DEV_DISABLE
221 };
222
223 /* IOT routines */
224
225 int32 mt70 (int32 IR, int32 AC)
226 {
227 int32 f;
228 UNIT *uptr;
229
230 uptr = mt_dev.units + GET_UNIT (mt_cu); /* get unit */
231 switch (IR & 07) { /* decode IR<9:11> */
232
233 case 1: /* LWCR */
234 mt_wc = AC; /* load word count */
235 return 0;
236
237 case 2: /* CWCR */
238 mt_wc = 0; /* clear word count */
239 return AC;
240
241 case 3: /* LCAR */
242 mt_ca = AC; /* load mem address */
243 return 0;
244
245 case 4: /* CCAR */
246 mt_ca = 0; /* clear mem address */
247 return AC;
248
249 case 5: /* LCMR */
250 if (mt_busy ()) mt_sta = mt_sta | STA_ILL | STA_ERR; /* busy? illegal op */
251 mt_cu = AC; /* load command reg */
252 mt_updcsta (mt_dev.units + GET_UNIT (mt_cu));
253 return 0;
254
255 case 6: /* LFGR */
256 if (mt_busy ()) mt_sta = mt_sta | STA_ILL | STA_ERR; /* busy? illegal op */
257 mt_fn = AC; /* load function */
258 if ((mt_fn & FN_GO) == 0) { /* go set? */
259 mt_updcsta (uptr); /* update status */
260 return 0;
261 }
262 f = GET_FNC (mt_fn); /* get function */
263 if (((uptr->flags & UNIT_ATT) == 0) ||
264 sim_is_active (uptr) ||
265 (((f == FN_WRITE) || (f == FN_WREOF)) && sim_tape_wrp (uptr))
266 || (((f == FN_SPACER) || (f == FN_REWIND)) && sim_tape_bot (uptr))) {
267 mt_sta = mt_sta | STA_ILL | STA_ERR; /* illegal op error */
268 mt_set_done (); /* set done */
269 mt_updcsta (uptr); /* update status */
270 return 0;
271 }
272 uptr->USTAT = uptr->USTAT & STA_WLK; /* clear status */
273 if (f == FN_UNLOAD) { /* unload? */
274 detach_unit (uptr); /* set offline */
275 uptr->USTAT = STA_REW | STA_REM; /* rewinding, off */
276 mt_set_done (); /* set done */
277 }
278 else if (f == FN_REWIND) { /* rewind */
279 uptr->USTAT = uptr->USTAT | STA_REW; /* rewinding */
280 mt_set_done (); /* set done */
281 }
282 else mt_done = 0; /* clear done */
283 mt_updcsta (uptr); /* update status */
284 sim_activate (uptr, mt_time); /* start io */
285 return 0;
286
287 case 7: /* LDBR */
288 if (mt_busy ()) mt_sta = mt_sta | STA_ILL | STA_ERR; /* busy? illegal op */
289 mt_db = AC; /* load buffer */
290 mt_set_done (); /* set done */
291 mt_updcsta (uptr); /* update status */
292 return 0;
293 } /* end switch */
294
295 return (stop_inst << IOT_V_REASON) + AC; /* ill inst */
296 }
297
298 int32 mt71 (int32 IR, int32 AC)
299 {
300 UNIT *uptr;
301
302 uptr = mt_dev.units + GET_UNIT (mt_cu);
303 switch (IR & 07) { /* decode IR<9:11> */
304
305 case 1: /* RWCR */
306 return mt_wc; /* read word count */
307
308 case 2: /* CLT */
309 mt_reset (&mt_dev); /* reset everything */
310 return AC;
311
312 case 3: /* RCAR */
313 return mt_ca; /* read mem address */
314
315 case 4: /* RMSR */
316 return ((mt_updcsta (uptr) >> 12) & 07777); /* read status */
317
318 case 5: /* RCMR */
319 return mt_cu; /* read command */
320
321 case 6: /* RFSR */
322 return (((mt_fn & FN_RMASK) | (mt_updcsta (uptr) & ~FN_RMASK))
323 & 07777); /* read function */
324
325 case 7: /* RDBR */
326 return mt_db; /* read data buffer */
327 }
328
329 return (stop_inst << IOT_V_REASON) + AC; /* ill inst */
330 }
331
332 int32 mt72 (int32 IR, int32 AC)
333 {
334 UNIT *uptr;
335
336 uptr = mt_dev.units + GET_UNIT (mt_cu); /* get unit */
337 switch (IR & 07) { /* decode IR<9:11> */
338
339 case 1: /* SKEF */
340 return (mt_sta & STA_ERR)? IOT_SKP + AC: AC;
341
342 case 2: /* SKCB */
343 return (!mt_busy ())? IOT_SKP + AC: AC;
344
345 case 3: /* SKJD */
346 return mt_done? IOT_SKP + AC: AC;
347
348 case 4: /* SKTR */
349 return (!sim_is_active (uptr) &&
350 (uptr->flags & UNIT_ATT))? IOT_SKP + AC: AC;
351
352 case 5: /* CLF */
353 if (!sim_is_active (uptr)) mt_reset (&mt_dev); /* if TUR, zap */
354 else { /* just ctrl zap */
355 mt_sta = 0; /* clear status */
356 mt_done = 0; /* clear done */
357 mt_updcsta (uptr); /* update status */
358 }
359 return AC;
360 } /* end switch */
361
362 return (stop_inst << IOT_V_REASON) + AC; /* ill inst */
363 }
364
365 /* Unit service
366
367 If rewind done, reposition to start of tape, set status
368 else, do operation, set done, interrupt
369 */
370
371 t_stat mt_svc (UNIT *uptr)
372 {
373 int32 f, i, p, u, wc, xma;
374 t_mtrlnt tbc, cbc;
375 t_bool passed_eot;
376 uint16 c, c1, c2;
377 t_stat st, r = SCPE_OK;
378
379 u = (int32) (uptr - mt_dev.units); /* get unit number */
380 f = GET_FNC (mt_fn); /* get command */
381 xma = GET_EMA (mt_cu) + mt_ca; /* get mem addr */
382 wc = WC_SIZE - mt_wc; /* get wc */
383
384 if (uptr->USTAT & STA_REW) { /* rewind? */
385 sim_tape_rewind (uptr); /* update position */
386 if (uptr->flags & UNIT_ATT) /* still on line? */
387 uptr->USTAT = (uptr->USTAT & STA_WLK) | STA_BOT;
388 else uptr->USTAT = STA_REM;
389 if (u == GET_UNIT (mt_cu)) { /* selected? */
390 mt_set_done (); /* set done */
391 mt_updcsta (uptr); /* update status */
392 }
393 return SCPE_OK;
394 }
395
396 if ((uptr->flags & UNIT_ATT) == 0) { /* if not attached */
397 uptr->USTAT = STA_REM; /* unit off line */
398 mt_sta = mt_sta | STA_ILL | STA_ERR; /* illegal operation */
399 mt_set_done (); /* set done */
400 mt_updcsta (uptr); /* update status */
401 return IORETURN (mt_stopioe, SCPE_UNATT);
402 }
403
404 passed_eot = sim_tape_eot (uptr); /* passed eot? */
405 switch (f) { /* case on function */
406
407 case FN_READ: /* read */
408 case FN_CMPARE: /* read/compare */
409 st = sim_tape_rdrecf (uptr, mtxb, &tbc, MT_MAXFR); /* read rec */
410 if (st == MTSE_RECE) mt_sta = mt_sta | STA_PAR | STA_ERR; /* rec in err? */
411 else if (st != MTSE_OK) { /* other error? */
412 r = mt_map_err (uptr, st); /* map error */
413 mt_sta = mt_sta | STA_RLE | STA_ERR; /* err, eof/eom, tmk */
414 break;
415 }
416 cbc = (mt_cu & CU_UNPAK)? wc: wc * 2; /* expected bc */
417 if (tbc != cbc) mt_sta = mt_sta | STA_RLE | STA_ERR; /* wrong size? */
418 if (tbc < cbc) { /* record small? */
419 cbc = tbc; /* use smaller */
420 wc = (mt_cu & CU_UNPAK)? cbc: (cbc + 1) / 2;
421 }
422 for (i = p = 0; i < wc; i++) { /* copy buffer */
423 xma = mt_ixma (xma); /* increment xma */
424 mt_wc = (mt_wc + 1) & 07777; /* incr word cnt */
425 if (mt_cu & CU_UNPAK) c = mtxb[p++];
426 else {
427 c1 = mtxb[p++] & 077;
428 c2 = mtxb[p++] & 077;
429 c = (c1 << 6) | c2;
430 }
431 if ((f == FN_READ) && MEM_ADDR_OK (xma)) M[xma] = c;
432 else if ((f == FN_CMPARE) && (M[xma] != c)) {
433 mt_sta = mt_sta | STA_CPE | STA_ERR;
434 break;
435 }
436 }
437 break;
438
439 case FN_WRITE: /* write */
440 tbc = (mt_cu & CU_UNPAK)? wc: wc * 2;
441 for (i = p = 0; i < wc; i++) { /* copy buf to tape */
442 xma = mt_ixma (xma); /* incr mem addr */
443 if (mt_cu & CU_UNPAK) mtxb[p++] = M[xma] & 0377;
444 else {
445 mtxb[p++] = (M[xma] >> 6) & 077;
446 mtxb[p++] = M[xma] & 077;
447 }
448 }
449 if (st = sim_tape_wrrecf (uptr, mtxb, tbc)) { /* write rec, err? */
450 r = mt_map_err (uptr, st); /* map error */
451 xma = GET_EMA (mt_cu) + mt_ca; /* restore xma */
452 }
453 else mt_wc = 0; /* ok, clear wc */
454 break;
455
456 case FN_WREOF:
457 if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */
458 r = mt_map_err (uptr, st); /* map error */
459 break;
460
461 case FN_SPACEF: /* space forward */
462 do {
463 mt_wc = (mt_wc + 1) & 07777; /* incr wc */
464 if (st = sim_tape_sprecf (uptr, &tbc)) { /* space rec fwd, err? */
465 r = mt_map_err (uptr, st); /* map error */
466 break; /* stop */
467 }
468 } while ((mt_wc != 0) && (passed_eot || !sim_tape_eot (uptr)));
469 break;
470
471 case FN_SPACER: /* space reverse */
472 do {
473 mt_wc = (mt_wc + 1) & 07777; /* incr wc */
474 if (st = sim_tape_sprecr (uptr, &tbc)) { /* space rec rev, err? */
475 r = mt_map_err (uptr, st); /* map error */
476 break; /* stop */
477 }
478 } while (mt_wc != 0);
479 break;
480 } /* end case */
481
482 if (!passed_eot && sim_tape_eot (uptr)) /* just passed EOT? */
483 uptr->USTAT = uptr->USTAT | STA_EOT;
484 mt_cu = (mt_cu & ~CU_EMA) | ((xma >> (12 - CU_V_EMA)) & CU_EMA);
485 mt_ca = xma & 07777; /* update mem addr */
486 mt_set_done (); /* set done */
487 mt_updcsta (uptr); /* update status */
488 return r;
489 }
490
491 /* Update controller status */
492
493 int32 mt_updcsta (UNIT *uptr)
494 {
495 mt_sta = (mt_sta & ~(STA_DYN | STA_CLR)) | (uptr->USTAT & STA_DYN);
496 if (((mt_sta & STA_ERR) && (mt_cu & CU_IEE)) ||
497 (mt_done && (mt_cu & CU_IED))) int_req = int_req | INT_MT;
498 else int_req = int_req & ~INT_MT;
499 return mt_sta;
500 }
501
502 /* Test if controller busy */
503
504 UNIT *mt_busy (void)
505 {
506 int32 u;
507 UNIT *uptr;
508
509 for (u = 0; u < MT_NUMDR; u++) { /* loop thru units */
510 uptr = mt_dev.units + u;
511 if (sim_is_active (uptr) && ((uptr->USTAT & STA_REW) == 0))
512 return uptr;
513 }
514 return NULL;
515 }
516
517 /* Increment extended memory address */
518
519 int32 mt_ixma (int32 xma) /* incr extended ma */
520 {
521 int32 v;
522
523 v = ((xma + 1) & 07777) | (xma & 070000); /* wrapped incr */
524 if (mt_fn & FN_INC) { /* increment mode? */
525 if (xma == 077777) mt_sta = mt_sta | STA_INC | STA_ERR; /* at limit? error */
526 else v = xma + 1; /* else 15b incr */
527 }
528 return v;
529 }
530
531 /* Set done */
532
533 void mt_set_done (void)
534 {
535 mt_done = 1; /* set done */
536 mt_fn = mt_fn & ~(FN_CRC | FN_GO | FN_INC); /* clear func<4:6> */
537 return;
538 }
539
540 /* Map tape error status */
541
542 t_stat mt_map_err (UNIT *uptr, t_stat st)
543 {
544 switch (st) {
545
546 case MTSE_FMT: /* illegal fmt */
547 case MTSE_UNATT: /* unattached */
548 mt_sta = mt_sta | STA_ILL | STA_ERR;
549 case MTSE_OK: /* no error */
550 return SCPE_IERR; /* never get here! */
551
552 case MTSE_TMK: /* end of file */
553 uptr->USTAT = uptr->USTAT | STA_EOF; /* set EOF */
554 mt_sta = mt_sta | STA_ERR;
555 break;
556
557 case MTSE_IOERR: /* IO error */
558 mt_sta = mt_sta | STA_PAR | STA_ERR; /* set par err */
559 if (mt_stopioe) return SCPE_IOERR;
560 break;
561
562 case MTSE_INVRL: /* invalid rec lnt */
563 mt_sta = mt_sta | STA_PAR | STA_ERR; /* set par err */
564 return SCPE_MTRLNT;
565
566 case MTSE_RECE: /* record in error */
567 case MTSE_EOM: /* end of medium */
568 mt_sta = mt_sta | STA_PAR | STA_ERR; /* set par err */
569 break;
570
571 case MTSE_BOT: /* reverse into BOT */
572 uptr->USTAT = uptr->USTAT | STA_BOT; /* set status */
573 mt_sta = mt_sta | STA_ERR;
574 break;
575
576 case MTSE_WRP: /* write protect */
577 mt_sta = mt_sta | STA_ILL | STA_ERR; /* illegal operation */
578 break;
579 }
580
581 return SCPE_OK;
582 }
583
584 /* Reset routine */
585
586 t_stat mt_reset (DEVICE *dptr)
587 {
588 int32 u;
589 UNIT *uptr;
590
591 mt_cu = mt_fn = mt_wc = mt_ca = mt_db = mt_sta = mt_done = 0;
592 int_req = int_req & ~INT_MT; /* clear interrupt */
593 for (u = 0; u < MT_NUMDR; u++) { /* loop thru units */
594 uptr = mt_dev.units + u;
595 sim_cancel (uptr); /* cancel activity */
596 sim_tape_reset (uptr); /* reset tape */
597 if (uptr->flags & UNIT_ATT) uptr->USTAT =
598 (sim_tape_bot (uptr)? STA_BOT: 0) |
599 (sim_tape_wrp (uptr)? STA_WLK: 0);
600 else uptr->USTAT = STA_REM;
601 }
602 if (mtxb == NULL) mtxb = (uint8 *) calloc (MT_MAXFR, sizeof (uint8));
603 if (mtxb == NULL) return SCPE_MEM;
604 return SCPE_OK;
605 }
606
607 /* Attach routine */
608
609 t_stat mt_attach (UNIT *uptr, char *cptr)
610 {
611 t_stat r;
612 int32 u = uptr - mt_dev.units; /* get unit number */
613
614 r = sim_tape_attach (uptr, cptr);
615 if (r != SCPE_OK) return r;
616 uptr->USTAT = STA_BOT | (sim_tape_wrp (uptr)? STA_WLK: 0);
617 if (u == GET_UNIT (mt_cu)) mt_updcsta (uptr);
618 return r;
619 }
620
621 /* Detach routine */
622
623 t_stat mt_detach (UNIT* uptr)
624 {
625 int32 u = uptr - mt_dev.units; /* get unit number */
626
627 if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; /* check for attached */
628 if (!sim_is_active (uptr)) uptr->USTAT = STA_REM;
629 if (u == GET_UNIT (mt_cu)) mt_updcsta (uptr);
630 return sim_tape_detach (uptr);
631 }
632
633 /* Write lock/enable routine */
634
635 t_stat mt_vlock (UNIT *uptr, int32 val, char *cptr, void *desc)
636 {
637 int32 u = uptr - mt_dev.units; /* get unit number */
638
639 if ((uptr->flags & UNIT_ATT) && (val || sim_tape_wrp (uptr)))
640 uptr->USTAT = uptr->USTAT | STA_WLK;
641 else uptr->USTAT = uptr->USTAT & ~STA_WLK;
642 if (u == GET_UNIT (mt_cu)) mt_updcsta (uptr);
643 return SCPE_OK;
644 }