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 (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
mta(int32 pulse,int32 code,int32 AC)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) /* ignore if busy */
286 break;
287 if ((uptr->USTAT & STA_RDY) == 0) { /* drive not ready? */
288 mta_sta = mta_sta | STA_ILL; /* illegal op */
289 dev_busy = dev_busy & ~INT_MTA; /* clear busy */
290 dev_done = dev_done | INT_MTA; /* set done */
291 int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable);
292 }
293 else if ((c == CU_REWIND) || (c == CU_UNLOAD)) { /* rewind, unload? */
294 mta_upddsta (uptr, (uptr->USTAT & /* update status */
295 ~(STA_BOT | STA_EOF | STA_EOT | STA_RDY)) | STA_REW);
296 sim_activate (uptr, mta_rwait); /* start IO */
297 if (c == CU_UNLOAD)
298 detach_unit (uptr);
299 }
300 else {
301 mta_sta = 0; /* clear errors */
302 dev_busy = dev_busy | INT_MTA; /* set busy */
303 dev_done = dev_done & ~INT_MTA; /* clear done */
304 int_req = int_req & ~INT_MTA; /* clear int */
305 if (ctype[c])
306 sim_activate (uptr, mta_cwait);
307 else {
308 mta_upddsta (uptr, uptr->USTAT &
309 ~(STA_BOT | STA_EOF | STA_EOT | STA_RDY));
310 sim_activate (uptr, mta_rwait);
311 }
312 }
313 mta_updcsta (uptr); /* update status */
314 break;
315
316 case iopC: /* clear */
317 for (u = 0; u < MTA_NUMDR; u++) { /* loop thru units */
318 uptr = mta_dev.units + u; /* cancel IO */
319 if (sim_is_active (uptr) && !(uptr->USTAT & STA_REW)) {
320 mta_upddsta (uptr, uptr->USTAT | STA_RDY);
321 sim_cancel (uptr);
322 }
323 }
324 dev_busy = dev_busy & ~INT_MTA; /* clear busy */
325 dev_done = dev_done & ~INT_MTA; /* clear done */
326 int_req = int_req & ~INT_MTA; /* clear int */
327 mta_sta = mta_cu = 0; /* clear registers */
328 mta_updcsta (&mta_unit[0]); /* update status */
329 break;
330 } /* end case pulse */
331
332 return rval;
333 }
334
335 /* Unit service
336
337 If rewind done, reposition to start of tape, set status
338 else, do operation, clear busy, set done, interrupt
339 */
340
mta_svc(UNIT * uptr)341 t_stat mta_svc (UNIT *uptr)
342 {
343 int32 c, p, pa, u;
344 t_mtrlnt i, cbc, tbc, wc;
345 uint16 c1, c2;
346 t_stat st, r = SCPE_OK;
347
348 u = uptr - mta_dev.units; /* get unit number */
349 c = GET_CMD (mta_cu); /* command */
350 wc = WC_SIZE - (mta_wc & WC_MASK); /* io wc */
351
352 if (uptr->USTAT & STA_REW) { /* rewind? */
353 sim_tape_rewind (uptr); /* update tape */
354 mta_upddsta (uptr, (uptr->USTAT & ~STA_REW) | STA_BOT | STA_RDY);
355 if (u == GET_UNIT (mta_cu))
356 mta_updcsta (uptr);
357 return SCPE_OK;
358 }
359
360 if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */
361 mta_upddsta (uptr, 0); /* unit off line */
362 mta_sta = mta_sta | STA_ILL; /* illegal operation */
363 }
364 else switch (c) { /* case on command */
365
366 case CU_CMODE: /* controller mode */
367 mta_ep = mta_cu & CU_EP;
368 break;
369
370 case CU_DMODE: /* drive mode */
371 if (!sim_tape_bot (uptr)) /* must be BOT */
372 mta_sta = mta_sta | STA_ILL;
373 else mta_upddsta (uptr, (mta_cu & CU_PE)? /* update drv status */
374 uptr->USTAT | STA_PEM: uptr->USTAT & ~ STA_PEM);
375 break;
376
377 case CU_READ: /* read */
378 case CU_READNS: /* read non-stop */
379 st = sim_tape_rdrecf (uptr, mtxb, &tbc, MTA_MAXFR); /* read rec */
380 if (st == MTSE_RECE) /* rec in err? */
381 mta_sta = mta_sta | STA_DAE;
382 else if (st != MTSE_OK) { /* other error? */
383 r = mta_map_err (uptr, st); /* map error */
384 break;
385 }
386 cbc = wc * 2; /* expected bc */
387 if (tbc & 1) /* odd byte count? */
388 mta_sta = mta_sta | STA_ODD;
389 if (tbc > cbc) /* too big? */
390 mta_sta = mta_sta | STA_WCO;
391 else {
392 cbc = tbc; /* no, use it */
393 wc = (cbc + 1) / 2; /* adjust wc */
394 }
395 for (i = p = 0; i < wc; i++) { /* copy buf to mem */
396 c1 = mtxb[p++];
397 c2 = mtxb[p++];
398 pa = MapAddr (0, mta_ma); /* map address */
399 if (MEM_ADDR_OK (pa))
400 M[pa] = (c1 << 8) | c2;
401 mta_ma = (mta_ma + 1) & AMASK;
402 }
403 mta_wc = (mta_wc + wc) & DMASK;
404 mta_upddsta (uptr, uptr->USTAT | STA_RDY);
405 break;
406
407 case CU_WRITE: /* write */
408 tbc = wc * 2; /* io byte count */
409 for (i = p = 0; i < wc; i++) { /* copy to buffer */
410 pa = MapAddr (0, mta_ma); /* map address */
411 mtxb[p++] = (M[pa] >> 8) & 0377;
412 mtxb[p++] = M[pa] & 0377;
413 mta_ma = (mta_ma + 1) & AMASK;
414 }
415 if ((st = sim_tape_wrrecf (uptr, mtxb, tbc))) { /* write rec, err? */
416 r = mta_map_err (uptr, st); /* map error */
417 mta_ma = (mta_ma - wc) & AMASK; /* restore wc */
418 }
419 else mta_wc = 0; /* clear wc */
420 mta_upddsta (uptr, uptr->USTAT | STA_RDY);
421 break;
422
423 case CU_WREOF: /* write eof */
424 if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */
425 r = mta_map_err (uptr, st); /* map error */
426 else mta_upddsta (uptr, uptr->USTAT | STA_EOF | STA_RDY);
427 break;
428
429 case CU_ERASE: /* erase */
430 if (sim_tape_wrp (uptr)) /* write protected? */
431 r = mta_map_err (uptr, MTSE_WRP); /* map error */
432 else mta_upddsta (uptr, uptr->USTAT | STA_RDY);
433 break;
434
435 case CU_SPACEF: /* space forward */
436 do {
437 mta_wc = (mta_wc + 1) & DMASK; /* incr wc */
438 if ((st = sim_tape_sprecf (uptr, &tbc))) { /* space rec fwd, err? */
439 r = mta_map_err (uptr, st); /* map error */
440 break;
441 }
442 } while (mta_wc != 0);
443 mta_upddsta (uptr, uptr->USTAT | STA_RDY);
444 mta_ma = mta_wc; /* word count = # records */
445 break;
446
447 case CU_SPACER: /* space reverse */
448 do {
449 mta_wc = (mta_wc + 1) & DMASK; /* incr wc */
450 if ((st = sim_tape_sprecr (uptr, &tbc))) { /* space rec rev, err? */
451 r = mta_map_err (uptr, st); /* map error */
452 break;
453 }
454 } while (mta_wc != 0);
455 mta_upddsta (uptr, uptr->USTAT | STA_RDY);
456 mta_ma = mta_wc; /* word count = # records */
457 break;
458
459 default: /* reserved */
460 mta_sta = mta_sta | STA_ILL;
461 mta_upddsta (uptr, uptr->USTAT | STA_RDY);
462 break;
463 } /* end case */
464
465 mta_updcsta (uptr); /* update status */
466 dev_busy = dev_busy & ~INT_MTA; /* clear busy */
467 dev_done = dev_done | INT_MTA; /* set done */
468 int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable);
469 return r;
470 }
471
472 /* Update controller status */
473
mta_updcsta(UNIT * uptr)474 int32 mta_updcsta (UNIT *uptr) /* update ctrl */
475 {
476 mta_sta = (mta_sta & ~(STA_DYN | STA_CLR | STA_ERR1 | STA_ERR2)) |
477 (uptr->USTAT & STA_DYN) | STA_SET;
478 if (mta_sta & STA_EFLGS1)
479 mta_sta = mta_sta | STA_ERR1;
480 if (mta_sta & STA_EFLGS2)
481 mta_sta = mta_sta | STA_ERR2;
482 return mta_sta;
483 }
484
485 /* Update drive status */
486
mta_upddsta(UNIT * uptr,int32 newsta)487 void mta_upddsta (UNIT *uptr, int32 newsta) /* drive status */
488 {
489 int32 change;
490
491 if ((uptr->flags & UNIT_ATT) == 0) /* offline? */
492 newsta = 0;
493 change = (uptr->USTAT ^ newsta) & STA_MON; /* changes? */
494 uptr->USTAT = newsta & STA_DYN; /* update status */
495 if (change) {
496 /* if (mta_ep) { /* if polling */
497 /* u = uptr - mta_dev.units; /* unit num */
498 /* mta_sta = (mta_sta & ~STA_UNIT) | (u << STA_V_UNIT);
499 /* set polling interupt...
500 /* } */
501 mta_sta = mta_sta | STA_CHG; /* flag change */
502 }
503 return;
504 }
505
506 /* Map tape error status */
507
mta_map_err(UNIT * uptr,t_stat st)508 t_stat mta_map_err (UNIT *uptr, t_stat st)
509 {
510 switch (st) {
511
512 case MTSE_FMT: /* illegal fmt */
513 mta_upddsta (uptr, uptr->USTAT | STA_WLK | STA_RDY);
514 case MTSE_UNATT: /* unattached */
515 mta_sta = mta_sta | STA_ILL;
516 case MTSE_OK: /* no error */
517 return SCPE_IERR; /* never get here! */
518
519 case MTSE_TMK: /* end of file */
520 mta_upddsta (uptr, uptr->USTAT | STA_RDY | STA_EOF);
521 break;
522
523 case MTSE_IOERR: /* IO error */
524 mta_sta = mta_sta | STA_DAE; /* data error */
525 mta_upddsta (uptr, uptr->USTAT | STA_RDY); /* ready */
526 return SCPE_IOERR;
527
528 case MTSE_INVRL: /* invalid rec lnt */
529 mta_sta = mta_sta | STA_DAE; /* data error */
530 mta_upddsta (uptr, uptr->USTAT | STA_RDY); /* ready */
531 return SCPE_MTRLNT;
532
533 case MTSE_RECE: /* record in error */
534 mta_sta = mta_sta | STA_DAE; /* data error */
535 mta_upddsta (uptr, uptr->USTAT | STA_RDY); /* ready */
536 break;
537
538 case MTSE_EOM: /* end of medium */
539 mta_sta = mta_sta | STA_BAT; /* bad tape */
540 mta_upddsta (uptr, uptr->USTAT | STA_RDY); /* ready */
541 break;
542
543 case MTSE_BOT: /* reverse into BOT */
544 mta_upddsta (uptr, uptr->USTAT | STA_RDY | STA_BOT);
545 break;
546
547 case MTSE_WRP: /* write protect */
548 mta_upddsta (uptr, uptr->USTAT | STA_WLK | STA_RDY);
549 mta_sta = mta_sta | STA_ILL; /* illegal operation */
550 break;
551 }
552
553 return SCPE_OK;
554 }
555
556 /* Reset routine */
557
mta_reset(DEVICE * dptr)558 t_stat mta_reset (DEVICE *dptr)
559 {
560 int32 u;
561 UNIT *uptr;
562
563 dev_busy = dev_busy & ~INT_MTA; /* clear busy */
564 dev_done = dev_done & ~INT_MTA; /* clear done, int */
565 int_req = int_req & ~INT_MTA;
566 mta_cu = mta_wc = mta_ma = mta_sta = 0; /* clear registers */
567 mta_ep = 0;
568
569 /* AOS Installer does an IORST after a tape rewind command but before it can
570 be serviced, yet expects the tape to have been rewound */
571
572 for (u = 0; u < MTA_NUMDR; u++) { /* loop thru units */
573 uptr = mta_dev.units + u;
574 if (sim_is_active (uptr) && /* active and */
575 (uptr->flags & STA_REW)) /* rewinding? */
576 sim_tape_rewind (uptr); /* update tape */
577 sim_tape_reset (uptr); /* clear pos flag */
578 sim_cancel (uptr); /* cancel activity */
579 if (uptr->flags & UNIT_ATT) uptr->USTAT = STA_RDY |
580 (uptr->USTAT & STA_PEM) |
581 (sim_tape_wrp (uptr)? STA_WLK: 0) |
582 (sim_tape_bot (uptr)? STA_BOT: 0);
583 else uptr->USTAT = 0;
584 }
585 mta_updcsta (&mta_unit[0]); /* update status */
586 if (mtxb == NULL)
587 mtxb = (uint8 *) calloc (MTA_MAXFR, sizeof (uint8));
588 if (mtxb == NULL)
589 return SCPE_MEM;
590 return SCPE_OK;
591 }
592
593 /* Attach routine */
594
mta_attach(UNIT * uptr,char * cptr)595 t_stat mta_attach (UNIT *uptr, char *cptr)
596 {
597 t_stat r;
598
599 r = sim_tape_attach (uptr, cptr);
600 if (r != SCPE_OK)
601 return r;
602 if (!sim_is_active (uptr))
603 mta_upddsta (uptr, STA_RDY | STA_BOT | STA_PEM |
604 (sim_tape_wrp (uptr)? STA_WLK: 0));
605 return r;
606 }
607
608 /* Detach routine */
609
mta_detach(UNIT * uptr)610 t_stat mta_detach (UNIT* uptr)
611 {
612 if (!(uptr->flags & UNIT_ATT)) /* attached? */
613 return SCPE_OK;
614 if (!sim_is_active (uptr))
615 mta_upddsta (uptr, 0);
616 return sim_tape_detach (uptr);
617 }
618
619 /* Write lock/unlock validate routine */
620
mta_vlock(UNIT * uptr,int32 val,char * cptr,void * desc)621 t_stat mta_vlock (UNIT *uptr, int32 val, char *cptr, void *desc)
622 {
623 if ((uptr->flags & UNIT_ATT) && (val || sim_tape_wrp (uptr)))
624 mta_upddsta (uptr, uptr->USTAT | STA_WLK);
625 else mta_upddsta (uptr, uptr->USTAT & ~STA_WLK);
626 return SCPE_OK;
627 }
628
629 /* Boot routine */
630
mta_boot(int32 unitno,DEVICE * dptr)631 t_stat mta_boot (int32 unitno, DEVICE *dptr)
632 {
633 sim_tape_rewind( &mta_unit[unitno] ) ;
634 /*
635 use common rewind/reset code
636 device reset
637 rewind 'tape' file
638 device
639 unit
640 controller
641 */
642 cpu_boot( unitno, dptr ) ;
643 SR = 0100000 + DEV_MTA ;
644 return ( SCPE_OK );
645 } /* end of 'mta_boot' */
646