Commit | Line | Data |
---|---|---|
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 | |
96 | extern uint32 PC;\r | |
97 | extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2], dev_srq[2];\r | |
98 | \r | |
99 | int32 mtc_fnc = 0; /* function */\r | |
100 | int32 mtc_sta = 0; /* status register */\r | |
101 | int32 mtc_dtf = 0; /* data xfer flop */\r | |
102 | int32 mtc_1st = 0; /* first svc flop */\r | |
103 | int32 mtc_ctime = 40; /* command wait */\r | |
104 | int32 mtc_gtime = 1000; /* gap stop time */\r | |
105 | int32 mtc_xtime = 15; /* data xfer time */\r | |
106 | int32 mtc_stopioe = 1; /* stop on error */\r | |
107 | uint8 mtxb[DBSIZE] = { 0 }; /* data buffer */\r | |
108 | t_mtrlnt mt_ptr = 0, mt_max = 0; /* buffer ptrs */\r | |
109 | static 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 | |
112 | DEVICE mtd_dev, mtc_dev;\r | |
113 | int32 mtdio (int32 inst, int32 IR, int32 dat);\r | |
114 | int32 mtcio (int32 inst, int32 IR, int32 dat);\r | |
115 | t_stat mtc_svc (UNIT *uptr);\r | |
116 | t_stat mtd_reset (DEVICE *dptr);\r | |
117 | t_stat mtc_reset (DEVICE *dptr);\r | |
118 | t_stat mtc_attach (UNIT *uptr, char *cptr);\r | |
119 | t_stat mtc_detach (UNIT *uptr);\r | |
120 | t_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 | |
129 | DIB 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 | |
137 | UNIT mtd_unit = { UDATA (NULL, 0, 0) };\r | |
138 | \r | |
139 | REG 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 | |
152 | MTAB 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 | |
162 | DEVICE 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 | |
178 | UNIT mtc_unit = { UDATA (&mtc_svc, UNIT_ATTABLE + UNIT_ROABLE, 0) };\r | |
179 | \r | |
180 | REG 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 | |
200 | MTAB 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 | |
206 | DEVICE 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 | |
216 | int32 mtdio (int32 inst, int32 IR, int32 dat)\r | |
217 | {\r | |
218 | int32 devd;\r | |
219 | \r | |
220 | devd = IR & I_DEVMASK; /* get device no */\r | |
221 | switch (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 | |
256 | if (IR & I_HC) { clrFSR (devd); } /* H/C option */\r | |
257 | return dat;\r | |
258 | }\r | |
259 | \r | |
260 | int32 mtcio (int32 inst, int32 IR, int32 dat)\r | |
261 | {\r | |
262 | uint32 i;\r | |
263 | int32 devc, devd, valid;\r | |
264 | t_stat st;\r | |
265 | \r | |
266 | devc = IR & I_DEVMASK; /* get device no */\r | |
267 | devd = devc - 1;\r | |
268 | switch (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 | |
341 | if (IR & I_HC) { clrFSR (devc); } /* H/C option */\r | |
342 | return 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 | |
353 | t_stat mtc_svc (UNIT *uptr)\r | |
354 | {\r | |
355 | int32 devc, devd;\r | |
356 | t_mtrlnt tbc;\r | |
357 | t_stat st, r = SCPE_OK;\r | |
358 | \r | |
359 | devc = mtc_dib.devno; /* get device nos */\r | |
360 | devd = mtd_dib.devno;\r | |
361 | if ((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 | |
367 | switch (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 | |
455 | setFSR (devc); /* set cch flg */\r | |
456 | mtc_sta = mtc_sta & ~STA_BUSY; /* not busy */\r | |
457 | return r;\r | |
458 | }\r | |
459 | \r | |
460 | /* Map tape error status */\r | |
461 | \r | |
462 | t_stat mt_map_err (UNIT *uptr, t_stat st)\r | |
463 | {\r | |
464 | switch (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 | |
499 | return SCPE_OK;\r | |
500 | }\r | |
501 | \r | |
502 | /* Reset routine */\r | |
503 | \r | |
504 | t_stat mtd_reset (DEVICE *dptr)\r | |
505 | {\r | |
506 | hp_enbdis_pair (&mtd_dev, &mtc_dev); /* make pair cons */\r | |
507 | return mtc_reset (dptr); /* do common reset */\r | |
508 | }\r | |
509 | \r | |
510 | t_stat mtc_reset (DEVICE *dptr)\r | |
511 | {\r | |
512 | hp_enbdis_pair (&mtc_dev, &mtd_dev); /* make pair cons */\r | |
513 | mtc_fnc = 0;\r | |
514 | mtc_1st = mtc_dtf = 0;\r | |
515 | mtc_dib.cmd = mtd_dib.cmd = 0; /* clear cmd */\r | |
516 | mtc_dib.ctl = mtd_dib.ctl = 0; /* clear ctl */\r | |
517 | mtc_dib.flg = mtd_dib.flg = 0; /* clear flg */\r | |
518 | mtc_dib.fbf = mtd_dib.fbf = 0; /* clear fbf */\r | |
519 | mtc_dib.srq = mtd_dib.srq = 0; /* srq follows flg */\r | |
520 | sim_cancel (&mtc_unit); /* cancel activity */\r | |
521 | sim_tape_reset (&mtc_unit);\r | |
522 | if (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 | |
525 | else mtc_sta = STA_LOCAL | STA_BUSY;\r | |
526 | return SCPE_OK;\r | |
527 | }\r | |
528 | \r | |
529 | /* Attach routine */\r | |
530 | \r | |
531 | t_stat mtc_attach (UNIT *uptr, char *cptr)\r | |
532 | {\r | |
533 | t_stat r;\r | |
534 | \r | |
535 | r = sim_tape_attach (uptr, cptr); /* attach unit */\r | |
536 | if (r != SCPE_OK) return r; /* update status */\r | |
537 | mtc_sta = STA_BOT;\r | |
538 | return r;\r | |
539 | }\r | |
540 | \r | |
541 | /* Detach routine */\r | |
542 | \r | |
543 | t_stat mtc_detach (UNIT* uptr)\r | |
544 | {\r | |
545 | mtc_sta = 0; /* update status */\r | |
546 | return sim_tape_detach (uptr); /* detach unit */\r | |
547 | }\r |