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