First Commit of my working state
[simh.git] / PDP11 / pdp11_ta.c
CommitLineData
196ba1fc
PH
1/* pdp11_ta.c: PDP-11 cassette tape simulator\r
2\r
3 Copyright (c) 2007, 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 ATAION OF CONTRATA, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20 CONNETAION 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 ta TA11/TU60 cassette tape\r
27\r
28 06-Aug-07 RMS Foward op at BOT skips initial file gap\r
29\r
30 Magnetic tapes are represented as a series of variable records\r
31 of the form:\r
32\r
33 32b byte count\r
34 byte 0\r
35 byte 1\r
36 :\r
37 byte n-2\r
38 byte n-1\r
39 32b byte count\r
40\r
41 If the byte count is odd, the record is padded with an extra byte\r
42 of junk. File marks are represented by a byte count of 0.\r
43\r
44 Cassette format differs in one very significant way: it has file gaps\r
45 rather than file marks. If the controller spaces or reads into a file\r
46 gap and then reverses direction, the file gap is not seen again. This\r
47 is in contrast to magnetic tapes, where the file mark is a character\r
48 sequence and is seen again if direction is reversed. In addition,\r
49 cassettes have an initial file gap which is automatically skipped on\r
50 forward operations from beginning of tape.\r
51*/\r
52\r
53#include "pdp11_defs.h"\r
54#include "sim_tape.h"\r
55\r
56#define TA_NUMDR 2 /* #drives */\r
57#define FNC u3 /* unit function */\r
58#define UST u4 /* unit status */\r
59#define TA_SIZE 93000 /* chars/tape */\r
60#define TA_MAXFR (TA_SIZE) /* max record lnt */\r
61\r
62/* Control/status - TACS */\r
63\r
64#define TACS_ERR (1 << CSR_V_ERR) /* error */\r
65#define TACS_CRC 0040000 /* CRC */\r
66#define TACS_BEOT 0020000 /* BOT/EOT */\r
67#define TACS_WLK 0010000 /* write lock */\r
68#define TACS_EOF 0004000 /* end file */\r
69#define TACS_TIM 0002000 /* timing */\r
70#define TACS_EMP 0001000 /* empty */\r
71#define TACS_V_UNIT 8 /* unit */\r
72#define TACS_M_UNIT (TA_NUMDR - 1)\r
73#define TACS_UNIT (TACS_M_UNIT << TACS_V_UNIT)\r
74#define TACS_TR (1 << CSR_V_DONE) /* transfer req */\r
75#define TACS_IE (1 << CSR_V_IE) /* interrupt enable */\r
76#define TACS_RDY 0000040 /* ready */\r
77#define TACS_ILBS 0000020 /* start CRC */\r
78#define TACS_V_FNC 1 /* function */\r
79#define TACS_M_FNC 07\r
80#define TACS_WFG 00\r
81#define TACS_WRITE 01\r
82#define TACS_READ 02\r
83#define TACS_SRF 03\r
84#define TACS_SRB 04\r
85#define TACS_SFF 05\r
86#define TACS_SFB 06\r
87#define TACS_REW 07\r
88#define TACS_2ND 010\r
89#define TACS_3RD 030\r
90#define TACS_FNC (TACS_M_FNC << TACS_V_FNC)\r
91#define TACS_GO (1 << CSR_V_GO) /* go */\r
92#define TACS_W (TACS_UNIT|TACS_IE|TACS_ILBS|TACS_FNC)\r
93#define TACS_XFRERR (TACS_ERR|TACS_CRC|TACS_WLK|TACS_EOF|TACS_TIM)\r
94#define GET_UNIT(x) (((x) >> TACS_V_UNIT) & TACS_M_UNIT)\r
95#define GET_FNC(x) (((x) >> TACS_V_FNC) & TACS_M_FNC)\r
96\r
97/* Function code flags */\r
98\r
99#define OP_WRI 01 /* op is a write */\r
100#define OP_REV 02 /* op is rev motion */\r
101#define OP_FWD 04 /* op is fwd motion */\r
102\r
103/* Unit status flags */\r
104\r
105#define UST_REV (OP_REV) /* last op was rev */\r
106#define UST_GAP 01 /* last op hit gap */\r
107\r
108extern int32 int_req[IPL_HLVL];\r
109extern FILE *sim_deb;\r
110\r
111uint32 ta_cs = 0; /* control/status */\r
112uint32 ta_idb = 0; /* input data buf */\r
113uint32 ta_odb = 0; /* output data buf */\r
114uint32 ta_write = 0; /* TU60 write flag */\r
115uint32 ta_bptr = 0; /* buf ptr */\r
116uint32 ta_blnt = 0; /* buf length */\r
117int32 ta_stime = 1000; /* start time */\r
118int32 ta_ctime = 100; /* char latency */\r
119uint32 ta_stopioe = 1; /* stop on error */\r
120uint8 *ta_xb = NULL; /* transfer buffer */\r
121static uint8 ta_fnc_tab[TACS_M_FNC + 1] = {\r
122 OP_WRI|OP_FWD, OP_WRI|OP_FWD, OP_FWD, OP_REV,\r
123 OP_REV , OP_FWD, OP_FWD, 0\r
124 };\r
125\r
126DEVICE ta_dev;\r
127t_stat ta_rd (int32 *data, int32 PA, int32 access);\r
128t_stat ta_wr (int32 data, int32 PA, int32 access);\r
129t_stat ta_svc (UNIT *uptr);\r
130t_stat ta_reset (DEVICE *dptr);\r
131t_stat ta_attach (UNIT *uptr, char *cptr);\r
132t_stat ta_detach (UNIT *uptr);\r
133void ta_go (void);\r
134t_stat ta_map_err (UNIT *uptr, t_stat st);\r
135UNIT *ta_busy (void);\r
136void ta_set_tr (void);\r
137uint32 ta_updsta (UNIT *uptr);\r
138uint32 ta_crc (uint8 *buf, uint32 cnt);\r
139\r
140/* TA data structures\r
141\r
142 ta_dev TA device descriptor\r
143 ta_unit TA unit list\r
144 ta_reg TA register list\r
145 ta_mod TA modifier list\r
146*/\r
147\r
148DIB ta_dib = {\r
149 IOBA_TA, IOLN_TA, &ta_rd, &ta_wr,\r
150 1, IVCL (TA), VEC_TA, { NULL }\r
151 };\r
152\r
153UNIT ta_unit[] = {\r
154 { UDATA (&ta_svc, UNIT_ATTABLE+UNIT_ROABLE, TA_SIZE) },\r
155 { UDATA (&ta_svc, UNIT_ATTABLE+UNIT_ROABLE, TA_SIZE) },\r
156 };\r
157\r
158REG ta_reg[] = {\r
159 { ORDATA (TACS, ta_cs, 16) },\r
160 { ORDATA (TAIDB, ta_idb, 8) },\r
161 { ORDATA (TAODB, ta_odb, 8) },\r
162 { FLDATA (WRITE, ta_write, 0) },\r
163 { FLDATA (INT, IREQ (TA), INT_V_TA) },\r
164 { FLDATA (ERR, ta_cs, CSR_V_ERR) },\r
165 { FLDATA (TR, ta_cs, CSR_V_DONE) },\r
166 { FLDATA (IE, ta_cs, CSR_V_IE) },\r
167 { DRDATA (BPTR, ta_bptr, 17) },\r
168 { DRDATA (BLNT, ta_blnt, 17) },\r
169 { DRDATA (STIME, ta_stime, 24), PV_LEFT + REG_NZ },\r
170 { DRDATA (CTIME, ta_ctime, 24), PV_LEFT + REG_NZ },\r
171 { FLDATA (STOP_IOE, ta_stopioe, 0) },\r
172 { URDATA (UFNC, ta_unit[0].FNC, 8, 5, 0, TA_NUMDR, 0), REG_HRO },\r
173 { URDATA (UST, ta_unit[0].UST, 8, 2, 0, TA_NUMDR, 0), REG_HRO },\r
174 { URDATA (POS, ta_unit[0].pos, 10, T_ADDR_W, 0,\r
175 TA_NUMDR, PV_LEFT | REG_RO) },\r
176 { ORDATA (DEVADDR, ta_dib.ba, 32), REG_HRO },\r
177 { ORDATA (DEVVEC, ta_dib.vec, 16), REG_HRO },\r
178 { NULL }\r
179 };\r
180\r
181MTAB ta_mod[] = {\r
182 { MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL },\r
183 { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL }, \r
184// { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT",\r
185// &sim_tape_set_fmt, &sim_tape_show_fmt, NULL },\r
186 { MTAB_XTD|MTAB_VUN, 0, "CAPACITY", NULL,\r
187 NULL, &sim_tape_show_capac, NULL },\r
188 { MTAB_XTD|MTAB_VDV, IOLN_TA, "ADDRESS", "ADDRESS",\r
189 &set_addr, &show_addr, NULL },\r
190 { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR",\r
191 &set_vec, &show_vec, NULL },\r
192 { 0 }\r
193 };\r
194\r
195DEVICE ta_dev = {\r
196 "TA", ta_unit, ta_reg, ta_mod,\r
197 TA_NUMDR, 10, 31, 1, 8, 8,\r
198 NULL, NULL, &ta_reset,\r
199 NULL, &ta_attach, &ta_detach,\r
200 &ta_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG\r
201 };\r
202\r
203/* I/O dispatch routines, I/O addresses 17777500 - 17777503\r
204\r
205 17777500 TACS read/write\r
206 17777502 TADB read/write\r
207*/\r
208\r
209t_stat ta_rd (int32 *data, int32 PA, int32 access)\r
210{\r
211switch ((PA >> 1) & 01) { /* decode PA<1> */\r
212\r
213 case 0: /* TACSR */\r
214 *data = ta_updsta (NULL); /* update status */\r
215 break;\r
216\r
217 case 1: /* TADB */\r
218 *data = ta_idb; /* return byte */\r
219 ta_cs &= ~TACS_TR; /* clear tra req */\r
220 ta_updsta (NULL);\r
221 break;\r
222 }\r
223\r
224return SCPE_OK;\r
225}\r
226\r
227t_stat ta_wr (int32 data, int32 PA, int32 access)\r
228{\r
229switch ((PA >> 1) & 01) { /* decode PA<1> */\r
230\r
231 case 0: /* TACS */\r
232 if (access == WRITEB) data = (PA & 1)? /* byte write? */\r
233 (ta_cs & 0377) | (data << 8): /* merge old */\r
234 (ta_cs & ~0377) | data;\r
235 ta_cs = (ta_cs & ~TACS_W) | (data & TACS_W); /* merge new */\r
236 if ((data & CSR_GO) && !ta_busy ()) /* go, not busy? */\r
237 ta_go (); /* start operation */\r
238 if (ta_cs & TACS_ILBS) ta_cs &= ~TACS_TR; /* ILBS inhibits TR */\r
239 break;\r
240\r
241 case 1: /* TADB */\r
242 if (PA & 1) break; /* ignore odd byte */\r
243 ta_odb = data; /* return byte */\r
244 ta_cs &= ~TACS_TR; /* clear tra req */\r
245 break;\r
246 } /* end switch */\r
247\r
248ta_updsta (NULL); /* update status */\r
249return SCPE_OK;\r
250}\r
251\r
252/* Start a new operation - cassette is not busy */\r
253\r
254void ta_go (void)\r
255{\r
256UNIT *uptr = ta_dev.units + GET_UNIT (ta_cs);\r
257uint32 fnc = GET_FNC (ta_cs);\r
258uint32 flg = ta_fnc_tab[fnc];\r
259uint32 old_ust = uptr->UST;\r
260\r
261if (DEBUG_PRS (ta_dev)) fprintf (sim_deb,\r
262 ">>TA start: op=%o, old_sta = %o, pos=%d\n",\r
263 fnc, uptr->UST, uptr->pos);\r
264ta_cs &= ~(TACS_XFRERR|TACS_EMP|TACS_TR|TACS_RDY); /* clr err, tr, rdy */\r
265ta_bptr = 0; /* init buffer */\r
266ta_blnt = 0;\r
267if ((uptr->flags & UNIT_ATT) == 0) {\r
268 ta_cs |= TACS_ERR|TACS_EMP|TACS_RDY;\r
269 return;\r
270 }\r
271if (flg & OP_WRI) { /* write op? */\r
272 if (sim_tape_wrp (uptr)) { /* locked? */\r
273 ta_cs |= TACS_ERR|TACS_WLK|TACS_RDY; /* don't start */\r
274 return;\r
275 }\r
276 ta_odb = 0;\r
277 ta_write = 1;\r
278 }\r
279else {\r
280 ta_idb = 0;\r
281 ta_write = 0;\r
282 }\r
283ta_cs &= ~TACS_BEOT; /* tape in motion */\r
284uptr->FNC = fnc; /* save function */\r
285if ((fnc != TACS_REW) && !(flg & OP_WRI)) { /* spc/read cmd? */\r
286 t_mtrlnt t;\r
287 t_stat st;\r
288 uptr->UST = flg & UST_REV; /* save direction */\r
289 if (sim_tape_bot (uptr) && (flg & OP_FWD)) { /* spc/read fwd bot? */\r
290 st = sim_tape_rdrecf (uptr, ta_xb, &t, TA_MAXFR); /* skip file gap */\r
291 if (st != MTSE_TMK) /* not there? */\r
292 sim_tape_rewind (uptr); /* restore tap pos */\r
293 else old_ust = 0; /* defang next */\r
294 }\r
295 if ((old_ust ^ uptr->UST) == (UST_REV|UST_GAP)) { /* reverse in gap? */\r
296 if (uptr->UST) /* skip file gap */\r
297 sim_tape_rdrecr (uptr, ta_xb, &t, TA_MAXFR);\r
298 else sim_tape_rdrecf (uptr, ta_xb, &t, TA_MAXFR);\r
299 if (DEBUG_PRS (ta_dev)) fprintf (sim_deb,\r
300 ">>TA skip gap: op=%o, old_sta = %o, pos=%d\n",\r
301 fnc, uptr->UST, uptr->pos);\r
302 }\r
303 }\r
304else uptr->UST = 0;\r
305sim_activate (uptr, ta_stime); /* schedule op */\r
306return;\r
307}\r
308\r
309/* Unit service */\r
310\r
311t_stat ta_svc (UNIT *uptr)\r
312{\r
313uint32 i, crc;\r
314uint32 flg = ta_fnc_tab[uptr->FNC & TACS_M_FNC];\r
315t_mtrlnt tbc;\r
316t_stat st, r;\r
317\r
318if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */\r
319 ta_cs |= TACS_ERR|TACS_EMP|TACS_RDY;\r
320 ta_updsta (uptr); /* update status */\r
321 return (ta_stopioe? SCPE_UNATT: SCPE_OK);\r
322 }\r
323if (((flg & OP_FWD) && sim_tape_eot (uptr)) || /* illegal motion? */\r
324 ((flg & OP_REV) && sim_tape_bot (uptr))) {\r
325 ta_cs |= TACS_ERR|TACS_BEOT|TACS_RDY; /* error */\r
326 ta_updsta (uptr);\r
327 return SCPE_OK;\r
328 }\r
329\r
330r = SCPE_OK;\r
331switch (uptr->FNC) { /* case on function */\r
332\r
333 case TACS_READ: /* read start */\r
334 st = sim_tape_rdrecf (uptr, ta_xb, &ta_blnt, TA_MAXFR); /* get rec */\r
335 if (st == MTSE_RECE) ta_cs |= TACS_ERR|TACS_CRC; /* rec in err? */\r
336 else if (st != MTSE_OK) { /* other error? */\r
337 r = ta_map_err (uptr, st); /* map error */\r
338 break;\r
339 }\r
340 crc = ta_crc (ta_xb, ta_blnt); /* calculate CRC */\r
341 ta_xb[ta_blnt++] = (crc >> 8) & 0377; /* append to buffer */\r
342 ta_xb[ta_blnt++] = crc & 0377;\r
343 uptr->FNC |= TACS_2ND; /* next state */\r
344 sim_activate (uptr, ta_ctime); /* sched next char */\r
345 return SCPE_OK;\r
346\r
347 case TACS_READ|TACS_2ND: /* read char */\r
348 if (ta_bptr < ta_blnt) /* more chars? */\r
349 ta_idb = ta_xb[ta_bptr++];\r
350 else { /* no */\r
351 ta_idb = 0;\r
352 ta_cs |= TACS_ERR|TACS_CRC; /* overrun */\r
353 break; /* tape stops */\r
354 }\r
355 if (ta_cs & TACS_ILBS) { /* CRC seq? */\r
356 uptr->FNC |= TACS_3RD; /* next state */\r
357 sim_activate (uptr, ta_stime); /* sched CRC chk */\r
358 }\r
359 else {\r
360 ta_set_tr (); /* set tra req */\r
361 sim_activate (uptr, ta_ctime); /* sched next char */\r
362 }\r
363 return SCPE_OK;\r
364\r
365 case TACS_READ|TACS_3RD: /* second read CRC */\r
366 if (ta_bptr != ta_blnt) { /* partial read? */\r
367 crc = ta_crc (ta_xb, ta_bptr + 2); /* actual CRC */\r
368 if (crc != 0) ta_cs |= TACS_ERR|TACS_CRC; /* must be zero */\r
369 }\r
370 break; /* read done */\r
371\r
372 case TACS_WRITE: /* write start */\r
373 for (i = 0; i < TA_MAXFR; i++) ta_xb[i] = 0; /* clear buffer */\r
374 ta_set_tr (); /* set tra req */\r
375 uptr->FNC |= TACS_2ND; /* next state */\r
376 sim_activate (uptr, ta_ctime); /* sched next char */\r
377 return SCPE_OK;\r
378\r
379 case TACS_WRITE|TACS_2ND: /* write char */\r
380 if (ta_cs & TACS_ILBS) { /* CRC seq? */\r
381 uptr->FNC |= TACS_3RD; /* next state */\r
382 sim_activate (uptr, ta_stime); /* sched wri done */\r
383 }\r
384 else {\r
385 if ((ta_bptr < TA_MAXFR) && /* room in buf? */\r
386 ((uptr->pos + ta_bptr) < uptr->capac)) /* room on tape? */\r
387 ta_xb[ta_bptr++] = ta_odb; /* store char */\r
388 ta_set_tr (); /* set tra req */\r
389 sim_activate (uptr, ta_ctime); /* sched next char */\r
390 }\r
391 return SCPE_OK;\r
392\r
393 case TACS_WRITE|TACS_3RD: /* write CRC */\r
394 if (ta_bptr) { /* anything to write? */\r
395 if (st = sim_tape_wrrecf (uptr, ta_xb, ta_bptr)) /* write, err? */\r
396 r = ta_map_err (uptr, st); /* map error */\r
397 }\r
398 break; /* op done */\r
399\r
400 case TACS_WFG: /* write file gap */\r
401 if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */\r
402 r = ta_map_err (uptr, st); /* map error */\r
403 break;\r
404\r
405 case TACS_REW: /* rewind */\r
406 sim_tape_rewind (uptr);\r
407 ta_cs |= TACS_BEOT; /* bot, no error */\r
408 break;\r
409\r
410 case TACS_SRB: /* space rev blk */\r
411 if (st = sim_tape_sprecr (uptr, &tbc)) /* space rev, err? */\r
412 r = ta_map_err (uptr, st); /* map error */\r
413 break;\r
414\r
415 case TACS_SRF: /* space rev file */\r
416 while ((st = sim_tape_sprecr (uptr, &tbc)) == MTSE_OK) ;\r
417 if (st == MTSE_TMK) /* if tape mark, */\r
418 ta_cs |= TACS_EOF; /* set EOF, no err */\r
419 else r = ta_map_err (uptr, st); /* else map error */\r
420 break;\r
421\r
422 case TACS_SFB: /* space fwd blk */\r
423 if (st = sim_tape_sprecf (uptr, &tbc)) /* space rev, err? */\r
424 r = ta_map_err (uptr, st); /* map error */\r
425 ta_cs |= TACS_CRC; /* CRC sets, no err */\r
426 break;\r
427\r
428 case TACS_SFF: /* space fwd file */\r
429 while ((st = sim_tape_sprecf (uptr, &tbc)) == MTSE_OK) ;\r
430 if (st == MTSE_TMK) /* if tape mark, */\r
431 ta_cs |= TACS_EOF; /* set EOF, no err */\r
432 else r = ta_map_err (uptr, st); /* else map error */\r
433 break;\r
434\r
435 default: /* never get here! */\r
436 return SCPE_IERR; \r
437 } /* end case */\r
438\r
439ta_cs |= TACS_RDY; /* set ready */\r
440ta_updsta (uptr); /* update status */\r
441if (DEBUG_PRS (ta_dev)) fprintf (sim_deb,\r
442 ">>TA done: op=%o, status = %o, pos=%d\n",\r
443 uptr->FNC, ta_cs, uptr->pos);\r
444return r;\r
445}\r
446\r
447/* Update controller status */\r
448\r
449uint32 ta_updsta (UNIT *uptr)\r
450{\r
451if (uptr == NULL) { /* unit specified? */\r
452 if ((uptr = ta_busy ()) == NULL) /* use busy */\r
453 uptr = ta_dev.units + GET_UNIT (ta_cs); /* use sel unit */\r
454 }\r
455else if (ta_cs & TACS_EOF) uptr->UST |= UST_GAP; /* save EOF */\r
456if (uptr->flags & UNIT_ATT) ta_cs &= ~TACS_EMP; /* attached? */\r
457else ta_cs |= TACS_EMP|TACS_RDY; /* no, empty, ready */\r
458if ((ta_cs & TACS_IE) && /* int enabled? */\r
459 (ta_cs & (TACS_TR|TACS_RDY))) /* req or ready? */\r
460 SET_INT (TA); /* set int req */\r
461else CLR_INT (TA); /* no, clr int req */\r
462return ta_cs;\r
463}\r
464\r
465/* Set transfer request */\r
466\r
467void ta_set_tr (void)\r
468{\r
469if (ta_cs & TACS_TR) ta_cs |= (TACS_ERR|TACS_TIM); /* flag still set? */\r
470else ta_cs |= TACS_TR; /* set xfr req */\r
471if (ta_cs & TACS_IE) SET_INT (TA); /* if ie, int req */\r
472return;\r
473}\r
474\r
475/* Test if controller busy */\r
476\r
477UNIT *ta_busy (void)\r
478{\r
479uint32 u;\r
480UNIT *uptr;\r
481\r
482for (u = 0; u < TA_NUMDR; u++) { /* loop thru units */\r
483 uptr = ta_dev.units + u;\r
484 if (sim_is_active (uptr)) return uptr;\r
485 }\r
486return NULL;\r
487}\r
488\r
489/* Calculate CRC on buffer */\r
490\r
491uint32 ta_crc (uint8 *buf, uint32 cnt)\r
492{\r
493uint32 crc, i, j;\r
494\r
495crc = 0;\r
496for (i = 0; i < cnt; i++) {\r
497 crc = crc ^ (((uint32) buf[i]) << 8);\r
498 for (j = 0; j < 8; j++) {\r
499 if (crc & 1) crc = (crc >> 1) ^ 0xA001;\r
500 else crc = crc >> 1;\r
501 }\r
502 }\r
503return crc;\r
504}\r
505\r
506/* Map error status */\r
507\r
508t_stat ta_map_err (UNIT *uptr, t_stat st)\r
509{\r
510switch (st) {\r
511\r
512 case MTSE_FMT: /* illegal fmt */\r
513 case MTSE_UNATT: /* unattached */\r
514 ta_cs |= TACS_ERR|TACS_CRC;\r
515 case MTSE_OK: /* no error */\r
516 return SCPE_IERR; /* never get here! */\r
517\r
518 case MTSE_TMK: /* end of file */\r
519 ta_cs |= TACS_ERR|TACS_EOF;\r
520 break;\r
521\r
522 case MTSE_IOERR: /* IO error */\r
523 ta_cs |= TACS_ERR|TACS_CRC; /* set crc err */\r
524 if (ta_stopioe) return SCPE_IOERR;\r
525 break;\r
526\r
527 case MTSE_INVRL: /* invalid rec lnt */\r
528 ta_cs |= TACS_ERR|TACS_CRC; /* set crc err */\r
529 return SCPE_MTRLNT;\r
530\r
531 case MTSE_RECE: /* record in error */\r
532 case MTSE_EOM: /* end of medium */\r
533 ta_cs |= TACS_ERR|TACS_CRC; /* set crc err */\r
534 break;\r
535\r
536 case MTSE_BOT: /* reverse into BOT */\r
537 ta_cs |= TACS_ERR|TACS_BEOT; /* set bot */\r
538 break;\r
539\r
540 case MTSE_WRP: /* write protect */\r
541 ta_cs |= TACS_ERR|TACS_WLK; /* set wlk err */\r
542 break;\r
543 }\r
544\r
545return SCPE_OK;\r
546}\r
547\r
548/* Reset routine */\r
549\r
550t_stat ta_reset (DEVICE *dptr)\r
551{\r
552uint32 u;\r
553UNIT *uptr;\r
554\r
555ta_cs = 0;\r
556ta_idb = 0;\r
557ta_odb = 0;\r
558ta_write = 0;\r
559ta_bptr = 0;\r
560ta_blnt = 0;\r
561CLR_INT (TA); /* clear interrupt */\r
562for (u = 0; u < TA_NUMDR; u++) { /* loop thru units */\r
563 uptr = ta_dev.units + u;\r
564 sim_cancel (uptr); /* cancel activity */\r
565 sim_tape_reset (uptr); /* reset tape */\r
566 }\r
567if (ta_xb == NULL) ta_xb = (uint8 *) calloc (TA_MAXFR + 2, sizeof (uint8));\r
568if (ta_xb == NULL) return SCPE_MEM;\r
569return SCPE_OK;\r
570}\r
571\r
572/* Attach routine */\r
573\r
574t_stat ta_attach (UNIT *uptr, char *cptr)\r
575{\r
576t_stat r;\r
577\r
578r = sim_tape_attach (uptr, cptr);\r
579if (r != SCPE_OK) return r;\r
580ta_updsta (NULL);\r
581uptr->UST = 0;\r
582return r;\r
583}\r
584\r
585/* Detach routine */\r
586\r
587t_stat ta_detach (UNIT* uptr)\r
588{\r
589t_stat r;\r
590\r
591if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; /* check attached */\r
592r = sim_tape_detach (uptr);\r
593ta_updsta (NULL);\r
594uptr->UST = 0;\r
595return r;\r
596}\r