First Commit of my working state
[simh.git] / NOVA / nova_mta.c
1 /* nova_mta.c: NOVA magnetic tape simulator
2
3 Copyright (c) 1993-2008, 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 mta magnetic tape
27
28 04-Jul-07 BKR fixed boot code to properly boot self-boot tapes;
29 boot routine now uses standard DG APL boot code;
30 device name changed to DG's MTA from DEC's MT.
31 16-Aug-05 RMS Fixed C++ declaration and cast problems
32 18-Mar-05 RMS Added attached test to detach routine
33 22-Nov-03 CEO DIB returns # records skipped after space fwd
34 22-Nov-03 CEO Removed cancel of tape events in IORST
35 25-Apr-03 RMS Revised for extended file support
36 28-Mar-03 RMS Added multiformat support
37 28-Feb-03 RMS Revised for magtape library
38 30-Oct-02 RMS Fixed BOT handling, added error record handling
39 08-Oct-02 RMS Added DIB
40 30-Sep-02 RMS Revamped error handling
41 28-Aug-02 RMS Added end of medium support
42 30-May-02 RMS Widened POS to 32b
43 22-Apr-02 RMS Added maximum record length test
44 06-Jan-02 RMS Revised enable/disable support
45 30-Nov-01 RMS Added read only unit, extended SET/SHOW support
46 24-Nov-01 RMS Changed POS, USTAT, FLG to an array
47 26-Apr-01 RMS Added device enable/disable support
48 18-Apr-01 RMS Changed to rewind tape before boot
49 10-Dec-00 RMS Added Eclipse support from Charles Owen
50 15-Oct-00 RMS Editorial changes
51 11-Nov-98 CEO Removed clear of mta_ma on iopC
52 04-Oct-98 RMS V2.4 magtape format
53 18-Jan-97 RMS V2.3 magtape format
54 29-Jun-96 RMS Added unit enable/disable support
55
56 Magnetic tapes are represented as a series of variable records
57 of the form:
58
59 32b byte count byte count is little endian
60 byte 0
61 byte 1
62 :
63 byte n-2
64 byte n-1
65 32b byte count
66
67 If the byte count is odd, the record is padded with an extra byte
68 of junk. File marks are represented by a byte count of 0 and are
69 not duplicated; end of tape by end of file.
70 */
71
72 #include "nova_defs.h"
73 #include "sim_tape.h"
74
75 #define MTA_NUMDR 8 /* #drives */
76 #define USTAT u3 /* unit status */
77 #define MTA_MAXFR (1 << 16) /* max record lnt */
78 #define WC_SIZE (1 << 14) /* max word count */
79 #define WC_MASK (WC_SIZE - 1)
80
81 /* Command/unit */
82
83 #define CU_CI 0100000 /* clear interrupt */
84 #define CU_EP 0002000 /* poll enable */
85 #define CU_DE 0001000 /* disable erase */
86 #define CU_DA 0000400 /* disable autoretry */
87 #define CU_PE 0000400 /* PE mode */
88 #define CU_V_CMD 3 /* command */
89 #define CU_M_CMD 027
90 #define CU_READ 000
91 #define CU_REWIND 001
92 #define CU_CMODE 002
93 #define CU_SPACEF 003
94 #define CU_SPACER 004
95 #define CU_WRITE 005
96 #define CU_WREOF 006
97 #define CU_ERASE 007
98 #define CU_READNS 020
99 #define CU_UNLOAD 021
100 #define CU_DMODE 022
101 #define CU_V_UNIT 0 /* unit */
102 #define CU_M_UNIT 07
103 #define GET_CMD(x) (((x) >> CU_V_CMD) & CU_M_CMD)
104 #define GET_UNIT(x) (((x) >> CU_V_UNIT) & CU_M_UNIT)
105
106 /* Status 1 - stored in mta_sta<31:16> or (*) uptr->USTAT<31:16> */
107
108 #define STA_ERR1 (0100000u << 16) /* error */
109 #define STA_DLT (0040000 << 16) /* data late */
110 #define STA_REW (0020000 << 16) /* *rewinding */
111 #define STA_ILL (0010000 << 16) /* illegal */
112 #define STA_HDN (0004000 << 16) /* high density */
113 #define STA_DAE (0002000 << 16) /* data error */
114 #define STA_EOT (0001000 << 16) /* *end of tape */
115 #define STA_EOF (0000400 << 16) /* *end of file */
116 #define STA_BOT (0000200 << 16) /* *start of tape */
117 #define STA_9TK (0000100 << 16) /* nine track */
118 #define STA_BAT (0000040 << 16) /* bad tape */
119 #define STA_CHG (0000010 << 16) /* status change */
120 #define STA_WLK (0000004 << 16) /* *write lock */
121 #define STA_ODD (0000002 << 16) /* odd character */
122 #define STA_RDY (0000001 << 16) /* *drive ready */
123
124 /* Status 2 - stored in mta_sta<15:0> or (*) uptr->USTAT<15:0> */
125
126 #define STA_ERR2 0100000 /* error */
127 #define STA_RWY 0040000 /* runaway tape */
128 #define STA_FGP 0020000 /* false gap */
129 #define STA_CDL 0004000 /* corrected dlt */
130 #define STA_V_UNIT 8
131 #define STA_M_UNIT 07 /* unit */
132 #define STA_WCO 0000200 /* word count ovflo */
133 #define STA_BDS 0000100 /* bad signal */
134 #define STA_OVS 0000040 /* overskew */
135 #define STA_CRC 0000020 /* check error */
136 #define STA_STE 0000010 /* single trk error */
137 #define STA_FPR 0000004 /* false preamble */
138 #define STA_FMT 0000002 /* format error */
139 #define STA_PEM 0000001 /* *PE mode */
140
141 #define STA_EFLGS1 (STA_DLT | STA_ILL | STA_DAE | STA_EOT | \
142 STA_EOF | STA_BOT | STA_BAT | STA_ODD)
143 #define STA_EFLGS2 (STA_FGP | STA_CDL | STA_BDS | STA_OVS | \
144 STA_CRC | STA_FPR | STA_FPR) /* set error 2 */
145 #define STA_CLR ((020 << 16) | 0010000) /* always clear */
146 #define STA_SET (STA_HDN | STA_9TK) /* always set */
147 #define STA_DYN (STA_REW | STA_EOT | STA_EOF | STA_BOT | \
148 STA_WLK | STA_RDY | STA_PEM) /* kept in USTAT */
149 #define STA_MON (STA_REW | STA_BOT | STA_WLK | STA_RDY | \
150 STA_PEM) /* set status chg */
151
152 extern uint16 M[];
153 extern UNIT cpu_unit;
154 extern int32 int_req, dev_busy, dev_done, dev_disable;
155 extern int32 SR, AMASK;
156
157 extern t_stat cpu_boot(int32 unitno, DEVICE * dptr ) ;
158
159
160 int32 mta_ma = 0; /* memory address */
161 int32 mta_wc = 0; /* word count */
162 int32 mta_cu = 0; /* command/unit */
163 int32 mta_sta = 0; /* status register */
164 int32 mta_ep = 0; /* enable polling */
165 int32 mta_cwait = 100; /* command latency */
166 int32 mta_rwait = 100; /* record latency */
167 uint8 *mtxb = NULL; /* transfer buffer */
168
169 DEVICE mta_dev;
170 int32 mta (int32 pulse, int32 code, int32 AC);
171 t_stat mta_svc (UNIT *uptr);
172 t_stat mta_reset (DEVICE *dptr);
173 t_stat mta_boot (int32 unitno, DEVICE *dptr);
174 t_stat mta_attach (UNIT *uptr, char *cptr);
175 t_stat mta_detach (UNIT *uptr);
176 int32 mta_updcsta (UNIT *uptr);
177 void mta_upddsta (UNIT *uptr, int32 newsta);
178 t_stat mta_map_err (UNIT *uptr, t_stat st);
179 t_stat mta_vlock (UNIT *uptr, int32 val, char *cptr, void *desc);
180
181 static const int ctype[32] = { /* c vs r timing */
182 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
183 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1
184 };
185
186 /* MTA data structures
187
188 mta_dev MTA device descriptor
189 mta_unit MTA unit list
190 mta_reg MTA register list
191 mta_mod MTA modifier list
192 */
193
194 DIB mta_dib = { DEV_MTA, INT_MTA, PI_MTA, &mta };
195
196 UNIT mta_unit[] = {
197 { UDATA (&mta_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
198 { UDATA (&mta_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
199 { UDATA (&mta_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
200 { UDATA (&mta_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
201 { UDATA (&mta_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
202 { UDATA (&mta_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
203 { UDATA (&mta_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
204 { UDATA (&mta_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }
205 };
206
207 REG mta_reg[] = {
208 { ORDATA (CU, mta_cu, 16) },
209 { ORDATA (MA, mta_ma, 16) },
210 { ORDATA (WC, mta_wc, 16) },
211 { GRDATA (STA1, mta_sta, 8, 16, 16) },
212 { ORDATA (STA2, mta_sta, 16) },
213 { FLDATA (EP, mta_ep, 0) },
214 { FLDATA (BUSY, dev_busy, INT_V_MTA) },
215 { FLDATA (DONE, dev_done, INT_V_MTA) },
216 { FLDATA (DISABLE, dev_disable, INT_V_MTA) },
217 { FLDATA (INT, int_req, INT_V_MTA) },
218 { DRDATA (CTIME, mta_cwait, 24), PV_LEFT },
219 { DRDATA (RTIME, mta_rwait, 24), PV_LEFT },
220 { URDATA (UST, mta_unit[0].USTAT, 8, 32, 0, MTA_NUMDR, 0) },
221 { URDATA (POS, mta_unit[0].pos, 8, T_ADDR_W, 0,
222 MTA_NUMDR, REG_RO | PV_LEFT) },
223 { NULL }
224 };
225
226 MTAB mta_mod[] = {
227 { MTUF_WLK, 0, "write enabled", "WRITEENABLED", &mta_vlock },
228 { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", &mta_vlock },
229 { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT",
230 &sim_tape_set_fmt, &sim_tape_show_fmt, NULL },
231 { 0 }
232 };
233
234 DEVICE mta_dev = {
235 "MTA", mta_unit, mta_reg, mta_mod,
236 MTA_NUMDR, 10, 31, 1, 8, 8,
237 NULL, NULL, &mta_reset,
238 &mta_boot, &mta_attach, &mta_detach,
239 &mta_dib, DEV_DISABLE
240 };
241
242 /* IOT routine */
243
244 int32 mta (int32 pulse, int32 code, int32 AC)
245 {
246 UNIT *uptr;
247 int32 u, c, rval;
248
249 rval = 0;
250 uptr = mta_dev.units + GET_UNIT(mta_cu); /* get unit */
251 switch (code) { /* decode IR<5:7> */
252
253 case ioDIA: /* DIA */
254 rval = (mta_updcsta (uptr) >> 16) & DMASK; /* return status 1 */
255 break;
256
257 case ioDOA: /* DOA */
258 /* if (AC & CU_CI) ... clear ep int */
259 mta_cu = AC; /* save cmd/unit */
260 uptr = mta_dev.units + GET_UNIT(mta_cu); /* get unit */
261 mta_updcsta (uptr); /* update status */
262 break;
263
264 case ioDIB: /* DIB */
265 rval = mta_ma & AMASK; /* return ma */
266 break;
267
268 case ioDOB: /* DOB */
269 mta_ma = AC & AMASK; /* save ma */
270 break;
271
272 case ioDIC: /* DIC */
273 rval = mta_updcsta (uptr) & DMASK; /* return status 2 */
274 break;
275
276 case ioDOC: /* DOC */
277 mta_wc = ((AC & 040000) << 1) | (AC & 077777); /* save wc */
278 break;
279 } /* end switch code */
280
281 switch (pulse) { /* decode IR<8:9> */
282
283 case iopS: /* start */
284 c = GET_CMD (mta_cu); /* get command */
285 if (dev_busy & INT_MTA) break; /* ignore if busy */
286 if ((uptr->USTAT & STA_RDY) == 0) { /* drive not ready? */
287 mta_sta = mta_sta | STA_ILL; /* illegal op */
288 dev_busy = dev_busy & ~INT_MTA; /* clear busy */
289 dev_done = dev_done | INT_MTA; /* set done */
290 int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable);
291 }
292 else if ((c == CU_REWIND) || (c == CU_UNLOAD)) { /* rewind, unload? */
293 mta_upddsta (uptr, (uptr->USTAT & /* update status */
294 ~(STA_BOT | STA_EOF | STA_EOT | STA_RDY)) | STA_REW);
295 sim_activate (uptr, mta_rwait); /* start IO */
296 if (c == CU_UNLOAD) detach_unit (uptr);
297 }
298 else {
299 mta_sta = 0; /* clear errors */
300 dev_busy = dev_busy | INT_MTA; /* set busy */
301 dev_done = dev_done & ~INT_MTA; /* clear done */
302 int_req = int_req & ~INT_MTA; /* clear int */
303 if (ctype[c]) sim_activate (uptr, mta_cwait);
304 else {
305 mta_upddsta (uptr, uptr->USTAT &
306 ~(STA_BOT | STA_EOF | STA_EOT | STA_RDY));
307 sim_activate (uptr, mta_rwait);
308 }
309 }
310 mta_updcsta (uptr); /* update status */
311 break;
312
313 case iopC: /* clear */
314 for (u = 0; u < MTA_NUMDR; u++) { /* loop thru units */
315 uptr = mta_dev.units + u; /* cancel IO */
316 if (sim_is_active (uptr) && !(uptr->USTAT & STA_REW)) {
317 mta_upddsta (uptr, uptr->USTAT | STA_RDY);
318 sim_cancel (uptr);
319 }
320 }
321 dev_busy = dev_busy & ~INT_MTA; /* clear busy */
322 dev_done = dev_done & ~INT_MTA; /* clear done */
323 int_req = int_req & ~INT_MTA; /* clear int */
324 mta_sta = mta_cu = 0; /* clear registers */
325 mta_updcsta (&mta_unit[0]); /* update status */
326 break;
327 } /* end case pulse */
328
329 return rval;
330 }
331
332 /* Unit service
333
334 If rewind done, reposition to start of tape, set status
335 else, do operation, clear busy, set done, interrupt
336 */
337
338 t_stat mta_svc (UNIT *uptr)
339 {
340 int32 c, p, pa, u;
341 t_mtrlnt i, cbc, tbc, wc;
342 uint16 c1, c2;
343 t_stat st, r = SCPE_OK;
344
345 u = uptr - mta_dev.units; /* get unit number */
346 c = GET_CMD (mta_cu); /* command */
347 wc = WC_SIZE - (mta_wc & WC_MASK); /* io wc */
348
349 if (uptr->USTAT & STA_REW) { /* rewind? */
350 sim_tape_rewind (uptr); /* update tape */
351 mta_upddsta (uptr, (uptr->USTAT & ~STA_REW) | STA_BOT | STA_RDY);
352 if (u == GET_UNIT (mta_cu)) mta_updcsta (uptr);
353 return SCPE_OK;
354 }
355
356 if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */
357 mta_upddsta (uptr, 0); /* unit off line */
358 mta_sta = mta_sta | STA_ILL; /* illegal operation */
359 }
360 else switch (c) { /* case on command */
361
362 case CU_CMODE: /* controller mode */
363 mta_ep = mta_cu & CU_EP;
364 break;
365
366 case CU_DMODE: /* drive mode */
367 if (!sim_tape_bot (uptr)) mta_sta = mta_sta | STA_ILL; /* must be BOT */
368 else mta_upddsta (uptr, (mta_cu & CU_PE)? /* update drv status */
369 uptr->USTAT | STA_PEM: uptr->USTAT & ~ STA_PEM);
370 break;
371
372 case CU_READ: /* read */
373 case CU_READNS: /* read non-stop */
374 st = sim_tape_rdrecf (uptr, mtxb, &tbc, MTA_MAXFR); /* read rec */
375 if (st == MTSE_RECE) mta_sta = mta_sta | STA_DAE; /* rec in err? */
376 else if (st != MTSE_OK) { /* other error? */
377 r = mta_map_err (uptr, st); /* map error */
378 break;
379 }
380 cbc = wc * 2; /* expected bc */
381 if (tbc & 1) mta_sta = mta_sta | STA_ODD; /* odd byte count? */
382 if (tbc > cbc) mta_sta = mta_sta | STA_WCO; /* too big? */
383 else {
384 cbc = tbc; /* no, use it */
385 wc = (cbc + 1) / 2; /* adjust wc */
386 }
387 for (i = p = 0; i < wc; i++) { /* copy buf to mem */
388 c1 = mtxb[p++];
389 c2 = mtxb[p++];
390 pa = MapAddr (0, mta_ma); /* map address */
391 if (MEM_ADDR_OK (pa)) M[pa] = (c1 << 8) | c2;
392 mta_ma = (mta_ma + 1) & AMASK;
393 }
394 mta_wc = (mta_wc + wc) & DMASK;
395 mta_upddsta (uptr, uptr->USTAT | STA_RDY);
396 break;
397
398 case CU_WRITE: /* write */
399 tbc = wc * 2; /* io byte count */
400 for (i = p = 0; i < wc; i++) { /* copy to buffer */
401 pa = MapAddr (0, mta_ma); /* map address */
402 mtxb[p++] = (M[pa] >> 8) & 0377;
403 mtxb[p++] = M[pa] & 0377;
404 mta_ma = (mta_ma + 1) & AMASK;
405 }
406 if (st = sim_tape_wrrecf (uptr, mtxb, tbc)) { /* write rec, err? */
407 r = mta_map_err (uptr, st); /* map error */
408 mta_ma = (mta_ma - wc) & AMASK; /* restore wc */
409 }
410 else mta_wc = 0; /* clear wc */
411 mta_upddsta (uptr, uptr->USTAT | STA_RDY);
412 break;
413
414 case CU_WREOF: /* write eof */
415 if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */
416 r = mta_map_err (uptr, st); /* map error */
417 else mta_upddsta (uptr, uptr->USTAT | STA_EOF | STA_RDY);
418 break;
419
420 case CU_ERASE: /* erase */
421 if (sim_tape_wrp (uptr)) /* write protected? */
422 r = mta_map_err (uptr, MTSE_WRP); /* map error */
423 else mta_upddsta (uptr, uptr->USTAT | STA_RDY);
424 break;
425
426 case CU_SPACEF: /* space forward */
427 do {
428 mta_wc = (mta_wc + 1) & DMASK; /* incr wc */
429 if (st = sim_tape_sprecf (uptr, &tbc)) { /* space rec fwd, err? */
430 r = mta_map_err (uptr, st); /* map error */
431 break;
432 }
433 } while (mta_wc != 0);
434 mta_upddsta (uptr, uptr->USTAT | STA_RDY);
435 mta_ma = mta_wc; /* word count = # records */
436 break;
437
438 case CU_SPACER: /* space reverse */
439 do {
440 mta_wc = (mta_wc + 1) & DMASK; /* incr wc */
441 if (st = sim_tape_sprecr (uptr, &tbc)) { /* space rec rev, err? */
442 r = mta_map_err (uptr, st); /* map error */
443 break;
444 }
445 } while (mta_wc != 0);
446 mta_upddsta (uptr, uptr->USTAT | STA_RDY);
447 mta_ma = mta_wc; /* word count = # records */
448 break;
449
450 default: /* reserved */
451 mta_sta = mta_sta | STA_ILL;
452 mta_upddsta (uptr, uptr->USTAT | STA_RDY);
453 break;
454 } /* end case */
455
456 mta_updcsta (uptr); /* update status */
457 dev_busy = dev_busy & ~INT_MTA; /* clear busy */
458 dev_done = dev_done | INT_MTA; /* set done */
459 int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable);
460 return r;
461 }
462
463 /* Update controller status */
464
465 int32 mta_updcsta (UNIT *uptr) /* update ctrl */
466 {
467 mta_sta = (mta_sta & ~(STA_DYN | STA_CLR | STA_ERR1 | STA_ERR2)) |
468 (uptr->USTAT & STA_DYN) | STA_SET;
469 if (mta_sta & STA_EFLGS1) mta_sta = mta_sta | STA_ERR1;
470 if (mta_sta & STA_EFLGS2) mta_sta = mta_sta | STA_ERR2;
471 return mta_sta;
472 }
473
474 /* Update drive status */
475
476 void mta_upddsta (UNIT *uptr, int32 newsta) /* drive status */
477 {
478 int32 change;
479
480 if ((uptr->flags & UNIT_ATT) == 0) newsta = 0; /* offline? */
481 change = (uptr->USTAT ^ newsta) & STA_MON; /* changes? */
482 uptr->USTAT = newsta & STA_DYN; /* update status */
483 if (change) {
484 /* if (mta_ep) { /* if polling */
485 /* u = uptr - mta_dev.units; /* unit num */
486 /* mta_sta = (mta_sta & ~STA_UNIT) | (u << STA_V_UNIT);
487 /* set polling interupt...
488 /* } */
489 mta_sta = mta_sta | STA_CHG; /* flag change */
490 }
491 return;
492 }
493
494 /* Map tape error status */
495
496 t_stat mta_map_err (UNIT *uptr, t_stat st)
497 {
498 switch (st) {
499
500 case MTSE_FMT: /* illegal fmt */
501 mta_upddsta (uptr, uptr->USTAT | STA_WLK | STA_RDY);
502 case MTSE_UNATT: /* unattached */
503 mta_sta = mta_sta | STA_ILL;
504 case MTSE_OK: /* no error */
505 return SCPE_IERR; /* never get here! */
506
507 case MTSE_TMK: /* end of file */
508 mta_upddsta (uptr, uptr->USTAT | STA_RDY | STA_EOF);
509 break;
510
511 case MTSE_IOERR: /* IO error */
512 mta_sta = mta_sta | STA_DAE; /* data error */
513 mta_upddsta (uptr, uptr->USTAT | STA_RDY); /* ready */
514 return SCPE_IOERR;
515
516 case MTSE_INVRL: /* invalid rec lnt */
517 mta_sta = mta_sta | STA_DAE; /* data error */
518 mta_upddsta (uptr, uptr->USTAT | STA_RDY); /* ready */
519 return SCPE_MTRLNT;
520
521 case MTSE_RECE: /* record in error */
522 mta_sta = mta_sta | STA_DAE; /* data error */
523 mta_upddsta (uptr, uptr->USTAT | STA_RDY); /* ready */
524 break;
525
526 case MTSE_EOM: /* end of medium */
527 mta_sta = mta_sta | STA_BAT; /* bad tape */
528 mta_upddsta (uptr, uptr->USTAT | STA_RDY); /* ready */
529 break;
530
531 case MTSE_BOT: /* reverse into BOT */
532 mta_upddsta (uptr, uptr->USTAT | STA_RDY | STA_BOT);
533 break;
534
535 case MTSE_WRP: /* write protect */
536 mta_upddsta (uptr, uptr->USTAT | STA_WLK | STA_RDY);
537 mta_sta = mta_sta | STA_ILL; /* illegal operation */
538 break;
539 }
540
541 return SCPE_OK;
542 }
543
544 /* Reset routine */
545
546 t_stat mta_reset (DEVICE *dptr)
547 {
548 int32 u;
549 UNIT *uptr;
550
551 dev_busy = dev_busy & ~INT_MTA; /* clear busy */
552 dev_done = dev_done & ~INT_MTA; /* clear done, int */
553 int_req = int_req & ~INT_MTA;
554 mta_cu = mta_wc = mta_ma = mta_sta = 0; /* clear registers */
555 mta_ep = 0;
556
557 /* AOS Installer does an IORST after a tape rewind command but before it can
558 be serviced, yet expects the tape to have been rewound */
559
560 for (u = 0; u < MTA_NUMDR; u++) { /* loop thru units */
561 uptr = mta_dev.units + u;
562 if (sim_is_active (uptr) && /* active and */
563 (uptr->flags & STA_REW)) /* rewinding? */
564 sim_tape_rewind (uptr); /* update tape */
565 sim_tape_reset (uptr); /* clear pos flag */
566 sim_cancel (uptr); /* cancel activity */
567 if (uptr->flags & UNIT_ATT) uptr->USTAT = STA_RDY |
568 (uptr->USTAT & STA_PEM) |
569 (sim_tape_wrp (uptr)? STA_WLK: 0) |
570 (sim_tape_bot (uptr)? STA_BOT: 0);
571 else uptr->USTAT = 0;
572 }
573 mta_updcsta (&mta_unit[0]); /* update status */
574 if (mtxb == NULL) mtxb = (uint8 *) calloc (MTA_MAXFR, sizeof (uint8));
575 if (mtxb == NULL) return SCPE_MEM;
576 return SCPE_OK;
577 }
578
579 /* Attach routine */
580
581 t_stat mta_attach (UNIT *uptr, char *cptr)
582 {
583 t_stat r;
584
585 r = sim_tape_attach (uptr, cptr);
586 if (r != SCPE_OK) return r;
587 if (!sim_is_active (uptr)) mta_upddsta (uptr, STA_RDY | STA_BOT | STA_PEM |
588 (sim_tape_wrp (uptr)? STA_WLK: 0));
589 return r;
590 }
591
592 /* Detach routine */
593
594 t_stat mta_detach (UNIT* uptr)
595 {
596 if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; /* attached? */
597 if (!sim_is_active (uptr)) mta_upddsta (uptr, 0);
598 return sim_tape_detach (uptr);
599 }
600
601 /* Write lock/unlock validate routine */
602
603 t_stat mta_vlock (UNIT *uptr, int32 val, char *cptr, void *desc)
604 {
605 if ((uptr->flags & UNIT_ATT) && (val || sim_tape_wrp (uptr)))
606 mta_upddsta (uptr, uptr->USTAT | STA_WLK);
607 else mta_upddsta (uptr, uptr->USTAT & ~STA_WLK);
608 return SCPE_OK;
609 }
610
611
612 /* Boot routine */
613
614 t_stat mta_boot (int32 unitno, DEVICE *dptr)
615 {
616 sim_tape_rewind( &mta_unit[unitno] ) ;
617 /*
618 use common rewind/reset code
619 device reset
620 rewind 'tape' file
621 device
622 unit
623 controller
624 */
625 cpu_boot( unitno, dptr ) ;
626 SR = 0100000 + DEV_MTA ;
627 return ( SCPE_OK );
628 } /* end of 'mta_boot' */