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