First Commit of my working state
[simh.git] / HP2100 / hp2100_mt.c
CommitLineData
196ba1fc
PH
1/* hp2100_mt.c: HP 2100 12559A 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 12559A 3030 nine track magnetic tape\r
27\r
28 28-Dec-06 JDB Added ioCRS state to I/O decoders (action unverified)\r
29 07-Oct-04 JDB Allow enable/disable from either device\r
30 14-Aug-04 RMS Modified handling of end of medium (suggested by Dave Bryan)\r
31 06-Jul-04 RMS Fixed spurious timing error after CLC (found by Dave Bryan)\r
32 26-Apr-04 RMS Fixed SFS x,C and SFC x,C\r
33 Implemented DMA SRQ (follows FLG)\r
34 21-Dec-03 RMS Adjusted msc_ctime for TSB (from Mike Gemeny)\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-Sep-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 20-Jan-02 RMS Fixed bug on last character write\r
43 03-Dec-01 RMS Added read only unit, extended SET/SHOW support\r
44 07-Sep-01 RMS Moved function prototypes\r
45 30-Nov-00 RMS Made variable names unique\r
46 04-Oct-98 RMS V2.4 magtape format\r
47\r
48 Magnetic tapes are represented as a series of variable records\r
49 of the form:\r
50\r
51 32b byte count\r
52 byte 0\r
53 byte 1\r
54 :\r
55 byte n-2\r
56 byte n-1\r
57 32b byte count\r
58\r
59 If the byte count is odd, the record is padded with an extra byte\r
60 of junk. File marks are represented by a byte count of 0.\r
61\r
62 Unusually among HP peripherals, the 12559 does not have a command flop,\r
63 and its flag and flag buffer power up as clear rather than set.\r
64*/\r
65\r
66#include "hp2100_defs.h"\r
67#include "sim_tape.h"\r
68\r
69#define DB_V_SIZE 16 /* max data buf */\r
70#define DBSIZE (1 << DB_V_SIZE) /* max data cmd */\r
71\r
72/* Command - mtc_fnc */\r
73\r
74#define FNC_CLR 0300 /* clear */\r
75#define FNC_WC 0031 /* write */\r
76#define FNC_RC 0023 /* read */\r
77#define FNC_GAP 0011 /* write gap */\r
78#define FNC_FSR 0003 /* forward space */\r
79#define FNC_BSR 0041 /* backward space */\r
80#define FNC_REW 0201 /* rewind */\r
81#define FNC_RWS 0101 /* rewind and offline */\r
82#define FNC_WFM 0035 /* write file mark */\r
83\r
84/* Status - stored in mtc_sta, (d) = dynamic */\r
85\r
86#define STA_LOCAL 0400 /* local (d) */\r
87#define STA_EOF 0200 /* end of file */\r
88#define STA_BOT 0100 /* beginning of tape */\r
89#define STA_EOT 0040 /* end of tape */\r
90#define STA_TIM 0020 /* timing error */\r
91#define STA_REJ 0010 /* programming error */\r
92#define STA_WLK 0004 /* write locked (d) */\r
93#define STA_PAR 0002 /* parity error */\r
94#define STA_BUSY 0001 /* busy (d) */\r
95\r
96extern uint32 PC;\r
97extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2], dev_srq[2];\r
98\r
99int32 mtc_fnc = 0; /* function */\r
100int32 mtc_sta = 0; /* status register */\r
101int32 mtc_dtf = 0; /* data xfer flop */\r
102int32 mtc_1st = 0; /* first svc flop */\r
103int32 mtc_ctime = 40; /* command wait */\r
104int32 mtc_gtime = 1000; /* gap stop time */\r
105int32 mtc_xtime = 15; /* data xfer time */\r
106int32 mtc_stopioe = 1; /* stop on error */\r
107uint8 mtxb[DBSIZE] = { 0 }; /* data buffer */\r
108t_mtrlnt mt_ptr = 0, mt_max = 0; /* buffer ptrs */\r
109static const int32 mtc_cmd[] = {\r
110 FNC_WC, FNC_RC, FNC_GAP, FNC_FSR, FNC_BSR, FNC_REW, FNC_RWS, FNC_WFM };\r
111\r
112DEVICE mtd_dev, mtc_dev;\r
113int32 mtdio (int32 inst, int32 IR, int32 dat);\r
114int32 mtcio (int32 inst, int32 IR, int32 dat);\r
115t_stat mtc_svc (UNIT *uptr);\r
116t_stat mtd_reset (DEVICE *dptr);\r
117t_stat mtc_reset (DEVICE *dptr);\r
118t_stat mtc_attach (UNIT *uptr, char *cptr);\r
119t_stat mtc_detach (UNIT *uptr);\r
120t_stat mt_map_err (UNIT *uptr, t_stat st);\r
121\r
122/* MTD data structures\r
123\r
124 mtd_dev MTD device descriptor\r
125 mtd_unit MTD unit list\r
126 mtd_reg MTD register list\r
127*/\r
128\r
129DIB mt_dib[] = {\r
130 { MTD, 0, 0, 0, 0, 0, &mtdio },\r
131 { MTC, 0, 0, 0, 0, 0, &mtcio }\r
132 };\r
133\r
134#define mtd_dib mt_dib[0]\r
135#define mtc_dib mt_dib[1]\r
136\r
137UNIT mtd_unit = { UDATA (NULL, 0, 0) };\r
138\r
139REG mtd_reg[] = {\r
140 { FLDATA (CMD, mtd_dib.cmd, 0), REG_HRO },\r
141 { FLDATA (CTL, mtd_dib.ctl, 0), REG_HRO },\r
142 { FLDATA (FLG, mtd_dib.flg, 0) },\r
143 { FLDATA (FBF, mtd_dib.fbf, 0) },\r
144 { FLDATA (SRQ, mtd_dib.srq, 0) },\r
145 { BRDATA (DBUF, mtxb, 8, 8, DBSIZE) },\r
146 { DRDATA (BPTR, mt_ptr, DB_V_SIZE + 1) },\r
147 { DRDATA (BMAX, mt_max, DB_V_SIZE + 1) },\r
148 { ORDATA (DEVNO, mtd_dib.devno, 6), REG_HRO },\r
149 { NULL }\r
150 };\r
151\r
152MTAB mtd_mod[] = {\r
153 { MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL },\r
154 { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL },\r
155 { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT",\r
156 &sim_tape_set_fmt, &sim_tape_show_fmt, NULL },\r
157 { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO",\r
158 &hp_setdev, &hp_showdev, &mtd_dev },\r
159 { 0 }\r
160 };\r
161\r
162DEVICE mtd_dev = {\r
163 "MTD", &mtd_unit, mtd_reg, mtd_mod,\r
164 1, 10, 16, 1, 8, 8,\r
165 NULL, NULL, &mtd_reset,\r
166 NULL, NULL, NULL,\r
167 &mtd_dib, DEV_DISABLE | DEV_DIS\r
168 };\r
169\r
170/* MTC data structures\r
171\r
172 mtc_dev MTC device descriptor\r
173 mtc_unit MTC unit list\r
174 mtc_reg MTC register list\r
175 mtc_mod MTC modifier list\r
176*/\r
177\r
178UNIT mtc_unit = { UDATA (&mtc_svc, UNIT_ATTABLE + UNIT_ROABLE, 0) };\r
179\r
180REG mtc_reg[] = {\r
181 { ORDATA (FNC, mtc_fnc, 8) },\r
182 { ORDATA (STA, mtc_sta, 9) },\r
183 { ORDATA (BUF, mtc_unit.buf, 8) },\r
184 { FLDATA (CMD, mtc_dib.cmd, 0), REG_HRO },\r
185 { FLDATA (CTL, mtc_dib.ctl, 0) },\r
186 { FLDATA (FLG, mtc_dib.flg, 0) },\r
187 { FLDATA (FBF, mtc_dib.fbf, 0) },\r
188 { FLDATA (SRQ, mtc_dib.srq, 0) },\r
189 { FLDATA (DTF, mtc_dtf, 0) },\r
190 { FLDATA (FSVC, mtc_1st, 0) },\r
191 { DRDATA (POS, mtc_unit.pos, T_ADDR_W), PV_LEFT },\r
192 { DRDATA (CTIME, mtc_ctime, 24), REG_NZ + PV_LEFT },\r
193 { DRDATA (GTIME, mtc_gtime, 24), REG_NZ + PV_LEFT },\r
194 { DRDATA (XTIME, mtc_xtime, 24), REG_NZ + PV_LEFT },\r
195 { FLDATA (STOP_IOE, mtc_stopioe, 0) },\r
196 { ORDATA (DEVNO, mtc_dib.devno, 6), REG_HRO },\r
197 { NULL }\r
198 };\r
199\r
200MTAB mtc_mod[] = {\r
201 { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO",\r
202 &hp_setdev, &hp_showdev, &mtd_dev },\r
203 { 0 }\r
204 };\r
205\r
206DEVICE mtc_dev = {\r
207 "MTC", &mtc_unit, mtc_reg, mtc_mod,\r
208 1, 10, 31, 1, 8, 8,\r
209 NULL, NULL, &mtc_reset,\r
210 NULL, &mtc_attach, &mtc_detach,\r
211 &mtc_dib, DEV_DISABLE | DEV_DIS\r
212 };\r
213\r
214/* IO instructions */\r
215\r
216int32 mtdio (int32 inst, int32 IR, int32 dat)\r
217{\r
218int32 devd;\r
219\r
220devd = IR & I_DEVMASK; /* get device no */\r
221switch (inst) { /* case on opcode */\r
222\r
223 case ioFLG: /* flag clear/set */\r
224 if ((IR & I_HC) == 0) { setFSR (devd); } /* STF */\r
225 break;\r
226\r
227 case ioSFC: /* skip flag clear */\r
228 if (FLG (devd) == 0) PC = (PC + 1) & VAMASK;\r
229 break;\r
230\r
231 case ioSFS: /* skip flag set */\r
232 if (FLG (devd) != 0) PC = (PC + 1) & VAMASK;\r
233 break;\r
234\r
235 case ioOTX: /* output */\r
236 mtc_unit.buf = dat & 0377; /* store data */\r
237 break;\r
238\r
239 case ioMIX: /* merge */\r
240 dat = dat | mtc_unit.buf;\r
241 break;\r
242\r
243 case ioLIX: /* load */\r
244 dat = mtc_unit.buf;\r
245 break;\r
246\r
247 case ioCRS: /* control reset (action unverif) */\r
248 case ioCTL: /* control clear/set */\r
249 if (IR & I_CTL) mtc_dtf = 0; /* CLC: clr xfer flop */\r
250 break;\r
251\r
252 default:\r
253 break;\r
254 }\r
255\r
256if (IR & I_HC) { clrFSR (devd); } /* H/C option */\r
257return dat;\r
258}\r
259\r
260int32 mtcio (int32 inst, int32 IR, int32 dat)\r
261{\r
262uint32 i;\r
263int32 devc, devd, valid;\r
264t_stat st;\r
265\r
266devc = IR & I_DEVMASK; /* get device no */\r
267devd = devc - 1;\r
268switch (inst) { /* case on opcode */\r
269\r
270 case ioFLG: /* flag clear/set */\r
271 if ((IR & I_HC) == 0) { setFSR (devc); } /* STF */\r
272 break;\r
273\r
274 case ioSFC: /* skip flag clear */\r
275 if (FLG (devc) == 0) PC = (PC + 1) & VAMASK;\r
276 break;\r
277\r
278 case ioSFS: /* skip flag set */\r
279 if (FLG (devc) != 0) PC = (PC + 1) & VAMASK;\r
280 break;\r
281\r
282 case ioOTX: /* output */\r
283 dat = dat & 0377;\r
284 mtc_sta = mtc_sta & ~STA_REJ; /* clear reject */\r
285 if (dat == FNC_CLR) { /* clear? */\r
286 if (sim_is_active (&mtc_unit) && /* write in prog? */\r
287 (mtc_fnc == FNC_WC) && (mt_ptr > 0)) { /* yes, bad rec */\r
288 if (st = sim_tape_wrrecf (&mtc_unit, mtxb, mt_ptr | MTR_ERF))\r
289 mt_map_err (&mtc_unit, st);\r
290 }\r
291 if (((mtc_fnc == FNC_REW) || (mtc_fnc == FNC_RWS)) &&\r
292 sim_is_active (&mtc_unit)) sim_cancel (&mtc_unit);\r
293 mtc_1st = mtc_dtf = 0;\r
294 mtc_sta = mtc_sta & STA_BOT;\r
295 clrCTL (devc); /* init device */\r
296 clrFSR (devc);\r
297 clrCTL (devd);\r
298 clrFSR (devd);\r
299 return SCPE_OK;\r
300 }\r
301 for (i = valid = 0; i < sizeof (mtc_cmd); i++) /* is fnc valid? */\r
302 if (dat == mtc_cmd[i]) valid = 1;\r
303 if (!valid || sim_is_active (&mtc_unit) || /* is cmd valid? */\r
304 ((mtc_sta & STA_BOT) && (dat == FNC_BSR)) ||\r
305 (sim_tape_wrp (&mtc_unit) &&\r
306 ((dat == FNC_WC) || (dat == FNC_GAP) || (dat == FNC_WFM))))\r
307 mtc_sta = mtc_sta | STA_REJ;\r
308 else {\r
309 sim_activate (&mtc_unit, mtc_ctime); /* start tape */\r
310 mtc_fnc = dat; /* save function */\r
311 mtc_sta = STA_BUSY; /* unit busy */\r
312 mt_ptr = 0; /* init buffer ptr */\r
313 clrFSR (devc); /* clear flags */\r
314 clrFSR (devd);\r
315 mtc_1st = 1; /* set 1st flop */\r
316 mtc_dtf = 1; /* set xfer flop */\r
317 }\r
318 break;\r
319\r
320 case ioLIX: /* load */\r
321 dat = 0;\r
322 case ioMIX: /* merge */\r
323 dat = dat | (mtc_sta & ~(STA_LOCAL | STA_WLK | STA_BUSY));\r
324 if (mtc_unit.flags & UNIT_ATT) { /* construct status */\r
325 if (sim_is_active (&mtc_unit)) dat = dat | STA_BUSY;\r
326 if (sim_tape_wrp (&mtc_unit)) dat = dat | STA_WLK;\r
327 }\r
328 else dat = dat | STA_BUSY | STA_LOCAL;\r
329 break;\r
330\r
331 case ioCRS: /* control reset (action unverif) */\r
332 case ioCTL: /* control clear/set */\r
333 if (IR & I_CTL) { clrCTL (devc); } /* CLC */\r
334 else { setCTL (devc); } /* STC */\r
335 break;\r
336\r
337 default:\r
338 break;\r
339 }\r
340\r
341if (IR & I_HC) { clrFSR (devc); } /* H/C option */\r
342return dat;\r
343}\r
344\r
345/* Unit service\r
346\r
347 If rewind done, reposition to start of tape, set status\r
348 else, do operation, set done, interrupt\r
349\r
350 Can't be write locked, can only write lock detached unit\r
351*/\r
352\r
353t_stat mtc_svc (UNIT *uptr)\r
354{\r
355int32 devc, devd;\r
356t_mtrlnt tbc;\r
357t_stat st, r = SCPE_OK;\r
358\r
359devc = mtc_dib.devno; /* get device nos */\r
360devd = mtd_dib.devno;\r
361if ((mtc_unit.flags & UNIT_ATT) == 0) { /* offline? */\r
362 mtc_sta = STA_LOCAL | STA_REJ; /* rejected */\r
363 setFSR (devc); /* set cch flg */\r
364 return IORETURN (mtc_stopioe, SCPE_UNATT);\r
365 }\r
366\r
367switch (mtc_fnc) { /* case on function */\r
368\r
369 case FNC_REW: /* rewind */\r
370 sim_tape_rewind (uptr); /* BOT */\r
371 mtc_sta = STA_BOT; /* update status */\r
372 break;\r
373\r
374 case FNC_RWS: /* rewind and offline */\r
375 sim_tape_rewind (uptr); /* clear position */\r
376 return sim_tape_detach (uptr); /* don't set cch flg */\r
377\r
378 case FNC_WFM: /* write file mark */\r
379 if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */\r
380 r = mt_map_err (uptr, st); /* map error */\r
381 mtc_sta = STA_EOF; /* set EOF status */\r
382 break;\r
383\r
384 case FNC_GAP: /* erase gap */\r
385 break;\r
386\r
387 case FNC_FSR: /* space forward */\r
388 if (st = sim_tape_sprecf (uptr, &tbc)) /* space rec fwd, err? */\r
389 r = mt_map_err (uptr, st); /* map error */\r
390 break;\r
391\r
392 case FNC_BSR: /* space reverse */\r
393 if (st = sim_tape_sprecr (uptr, &tbc)) /* space rec rev, err? */\r
394 r = mt_map_err (uptr, st); /* map error */\r
395 break;\r
396\r
397 case FNC_RC: /* read */\r
398 if (mtc_1st) { /* first svc? */\r
399 mtc_1st = mt_ptr = 0; /* clr 1st flop */\r
400 st = sim_tape_rdrecf (uptr, mtxb, &mt_max, DBSIZE); /* read rec */\r
401 if (st == MTSE_RECE) mtc_sta = mtc_sta | STA_PAR; /* rec in err? */\r
402 else if (st != MTSE_OK) { /* other error? */\r
403 r = mt_map_err (uptr, st); /* map error */\r
404 if (r == SCPE_OK) { /* recoverable? */\r
405 sim_activate (uptr, mtc_gtime); /* sched IRG */\r
406 mtc_fnc = 0; /* NOP func */\r
407 return SCPE_OK;\r
408 }\r
409 break; /* non-recov, done */\r
410 }\r
411 if (mt_max < 12) { /* record too short? */\r
412 mtc_sta = mtc_sta | STA_PAR; /* set flag */\r
413 break;\r
414 }\r
415 }\r
416 if (mtc_dtf && (mt_ptr < mt_max)) { /* more chars? */\r
417 if (FLG (devd)) mtc_sta = mtc_sta | STA_TIM;\r
418 mtc_unit.buf = mtxb[mt_ptr++]; /* fetch next */\r
419 setFSR (devd); /* set dch flg */\r
420 sim_activate (uptr, mtc_xtime); /* re-activate */\r
421 return SCPE_OK;\r
422 }\r
423 sim_activate (uptr, mtc_gtime); /* schedule gap */\r
424 mtc_fnc = 0; /* nop */\r
425 return SCPE_OK;\r
426\r
427 case FNC_WC: /* write */\r
428 if (mtc_1st) mtc_1st = 0; /* no xfr on first */\r
429 else {\r
430 if (mt_ptr < DBSIZE) { /* room in buffer? */\r
431 mtxb[mt_ptr++] = mtc_unit.buf;\r
432 mtc_sta = mtc_sta & ~STA_BOT; /* clear BOT */\r
433 }\r
434 else mtc_sta = mtc_sta | STA_PAR;\r
435 }\r
436 if (mtc_dtf) { /* xfer flop set? */\r
437 setFSR (devd); /* set dch flag */\r
438 sim_activate (uptr, mtc_xtime); /* re-activate */\r
439 return SCPE_OK;\r
440 }\r
441 if (mt_ptr) { /* write buffer */\r
442 if (st = sim_tape_wrrecf (uptr, mtxb, mt_ptr)) { /* write, err? */\r
443 r = mt_map_err (uptr, st); /* map error */\r
444 break; /* done */\r
445 }\r
446 }\r
447 sim_activate (uptr, mtc_gtime); /* schedule gap */\r
448 mtc_fnc = 0; /* nop */\r
449 return SCPE_OK;\r
450\r
451 default: /* unknown */\r
452 break;\r
453 }\r
454\r
455setFSR (devc); /* set cch flg */\r
456mtc_sta = mtc_sta & ~STA_BUSY; /* not busy */\r
457return r;\r
458}\r
459\r
460/* Map tape error status */\r
461\r
462t_stat mt_map_err (UNIT *uptr, t_stat st)\r
463{\r
464switch (st) {\r
465\r
466 case MTSE_FMT: /* illegal fmt */\r
467 case MTSE_UNATT: /* unattached */\r
468 mtc_sta = mtc_sta | STA_REJ; /* reject */\r
469 case MTSE_OK: /* no error */\r
470 return SCPE_IERR; /* never get here! */\r
471\r
472 case MTSE_EOM: /* end of medium */\r
473 case MTSE_TMK: /* end of file */\r
474 mtc_sta = mtc_sta | STA_EOF; /* eof */\r
475 break;\r
476\r
477 case MTSE_IOERR: /* IO error */\r
478 mtc_sta = mtc_sta | STA_PAR; /* error */\r
479 if (mtc_stopioe) return SCPE_IOERR;\r
480 break;\r
481\r
482 case MTSE_INVRL: /* invalid rec lnt */\r
483 mtc_sta = mtc_sta | STA_PAR;\r
484 return SCPE_MTRLNT;\r
485\r
486 case MTSE_RECE: /* record in error */\r
487 mtc_sta = mtc_sta | STA_PAR; /* error */\r
488 break;\r
489\r
490 case MTSE_BOT: /* reverse into BOT */\r
491 mtc_sta = mtc_sta | STA_BOT; /* set status */\r
492 break;\r
493\r
494 case MTSE_WRP: /* write protect */\r
495 mtc_sta = mtc_sta | STA_REJ; /* reject */\r
496 break;\r
497 }\r
498\r
499return SCPE_OK;\r
500}\r
501\r
502/* Reset routine */\r
503\r
504t_stat mtd_reset (DEVICE *dptr)\r
505{\r
506hp_enbdis_pair (&mtd_dev, &mtc_dev); /* make pair cons */\r
507return mtc_reset (dptr); /* do common reset */\r
508}\r
509\r
510t_stat mtc_reset (DEVICE *dptr)\r
511{\r
512hp_enbdis_pair (&mtc_dev, &mtd_dev); /* make pair cons */\r
513mtc_fnc = 0;\r
514mtc_1st = mtc_dtf = 0;\r
515mtc_dib.cmd = mtd_dib.cmd = 0; /* clear cmd */\r
516mtc_dib.ctl = mtd_dib.ctl = 0; /* clear ctl */\r
517mtc_dib.flg = mtd_dib.flg = 0; /* clear flg */\r
518mtc_dib.fbf = mtd_dib.fbf = 0; /* clear fbf */\r
519mtc_dib.srq = mtd_dib.srq = 0; /* srq follows flg */\r
520sim_cancel (&mtc_unit); /* cancel activity */\r
521sim_tape_reset (&mtc_unit);\r
522if (mtc_unit.flags & UNIT_ATT) mtc_sta =\r
523 (sim_tape_bot (&mtc_unit)? STA_BOT: 0) |\r
524 (sim_tape_wrp (&mtc_unit)? STA_WLK: 0);\r
525else mtc_sta = STA_LOCAL | STA_BUSY;\r
526return SCPE_OK;\r
527}\r
528\r
529/* Attach routine */\r
530\r
531t_stat mtc_attach (UNIT *uptr, char *cptr)\r
532{\r
533t_stat r;\r
534\r
535r = sim_tape_attach (uptr, cptr); /* attach unit */\r
536if (r != SCPE_OK) return r; /* update status */\r
537mtc_sta = STA_BOT;\r
538return r;\r
539}\r
540\r
541/* Detach routine */\r
542\r
543t_stat mtc_detach (UNIT* uptr)\r
544{\r
545mtc_sta = 0; /* update status */\r
546return sim_tape_detach (uptr); /* detach unit */\r
547}\r