First Commit of my working state
[simh.git] / PDP11 / pdp11_tu.c
CommitLineData
196ba1fc
PH
1/* pdp11_tu.c - PDP-11 TM02/TU16 TM03/TU45/TU77 Massbus magnetic tape controller\r
2\r
3 Copyright (c) 1993-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 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 tu TM02/TM03 magtape\r
27\r
28 17-May-07 RMS CS1 DVA resides in device, not MBA\r
29 29-Apr-07 RMS Fixed bug in setting FCE on TMK (found by Naoki Hamada)\r
30 16-Feb-06 RMS Added tape capacity checking\r
31 12-Nov-05 RMS Changed default formatter to TM03 (for VMS)\r
32 31-Oct-05 RMS Fixed address width for large files\r
33 16-Aug-05 RMS Fixed C++ declaration and cast problems\r
34 31-Mar-05 RMS Fixed inaccuracies in error reporting\r
35 18-Mar-05 RMS Added attached test to detach routine\r
36 10-Sep-04 RMS Cloned from pdp10_tu.c\r
37\r
38 Magnetic tapes are represented as a series of variable 8b records\r
39 of the form:\r
40\r
41 32b record length in bytes - exact number, sign = error\r
42 byte 0\r
43 byte 1\r
44 :\r
45 byte n-2\r
46 byte n-1\r
47 32b record length in bytes - exact number, sign = error\r
48\r
49 If the byte count is odd, the record is padded with an extra byte\r
50 of junk. File marks are represented by a single record length of 0.\r
51 End of tape is two consecutive end of file marks.\r
52*/\r
53\r
54#if defined (VM_PDP10)\r
55#error "PDP-10 uses pdp10_tu.c!"\r
56\r
57#elif defined (VM_PDP11)\r
58#include "pdp11_defs.h"\r
59#define DEV_DIS_INIT DEV_DIS\r
60\r
61#elif defined (VM_VAX)\r
62#include "vax_defs.h"\r
63#define DEV_DIS_INIT 0\r
64#if (!UNIBUS)\r
65#error "Qbus not supported!"\r
66#endif\r
67\r
68#endif\r
69#include "sim_tape.h"\r
70\r
71#define TU_NUMFM 1 /* #formatters */\r
72#define TU_NUMDR 8 /* #drives */\r
73#define USTAT u3 /* unit status */\r
74#define UDENS u4 /* unit density */\r
75#define UD_UNK 0 /* unknown */\r
76#define MT_MAXFR (1 << 16) /* max data buf */\r
77#define DEV_V_TM03 (DEV_V_FFUF + 0) /* TM02/TM03 */\r
78#define DEV_TM03 (1 << DEV_V_TM03)\r
79#define UNIT_V_TYPE (MTUF_V_UF + 0)\r
80#define UNIT_M_TYPE 03\r
81#define UNIT_TYPE (UNIT_M_TYPE << UNIT_V_TYPE)\r
82#define UNIT_TE16 (0 << UNIT_V_TYPE)\r
83#define UNIT_TU45 (1 << UNIT_V_TYPE)\r
84#define UNIT_TU77 (2 << UNIT_V_TYPE)\r
85#define GET_TYPE(x) (((x) >> UNIT_V_TYPE) & UNIT_M_TYPE)\r
86\r
87/* CS1 - offset 0 */\r
88\r
89#define CS1_OF 0\r
90#define CS1_GO CSR_GO /* go */\r
91#define CS1_V_FNC 1 /* function pos */\r
92#define CS1_M_FNC 037 /* function mask */\r
93#define CS1_N_FNC (CS1_M_FNC + 1)\r
94#define FNC_NOP 000 /* no operation */\r
95#define FNC_UNLOAD 001 /* unload */\r
96#define FNC_REWIND 003 /* rewind */\r
97#define FNC_FCLR 004 /* formatter clear */\r
98#define FNC_RIP 010 /* read in preset */\r
99#define FNC_ERASE 012 /* erase tape */\r
100#define FNC_WREOF 013 /* write tape mark */\r
101#define FNC_SPACEF 014 /* space forward */\r
102#define FNC_SPACER 015 /* space reverse */\r
103#define FNC_XFER 024 /* >=? data xfr */\r
104#define FNC_WCHKF 024 /* write check */\r
105#define FNC_WCHKR 027 /* write check rev */\r
106#define FNC_WRITE 030 /* write */\r
107#define FNC_READF 034 /* read forward */\r
108#define FNC_READR 037 /* read reverse */\r
109#define CS1_RW 077\r
110#define CS1_DVA 04000 /* drive avail */\r
111#define GET_FNC(x) (((x) >> CS1_V_FNC) & CS1_M_FNC)\r
112\r
113/* TUFS - formatter status - offset 1\r
114 + indicates kept in drive status\r
115 ^ indicates calculated on the fly\r
116*/\r
117\r
118#define FS_OF 1\r
119#define FS_SAT 0000001 /* slave attention */\r
120#define FS_BOT 0000002 /* ^beginning of tape */\r
121#define FS_TMK 0000004 /* end of file */\r
122#define FS_ID 0000010 /* ID burst detected */\r
123#define FS_SLOW 0000020 /* slowing down NI */\r
124#define FS_PE 0000040 /* ^PE status */\r
125#define FS_SSC 0000100 /* slave stat change */\r
126#define FS_RDY 0000200 /* ^formatter ready */\r
127#define FS_FPR 0000400 /* formatter present */\r
128#define FS_EOT 0002000 /* +end of tape */\r
129#define FS_WRL 0004000 /* ^write locked */\r
130#define FS_MOL 0010000 /* ^medium online */\r
131#define FS_PIP 0020000 /* +pos in progress */\r
132#define FS_ERR 0040000 /* ^error */\r
133#define FS_ATA 0100000 /* attention active */\r
134#define FS_REW 0200000 /* +rewinding */\r
135\r
136#define FS_DYN (FS_ERR | FS_PIP | FS_MOL | FS_WRL | FS_EOT | \\r
137 FS_RDY | FS_PE | FS_BOT)\r
138\r
139/* TUER - error register - offset 2 */\r
140\r
141#define ER_OF 2\r
142#define ER_ILF 0000001 /* illegal func */\r
143#define ER_ILR 0000002 /* illegal register */\r
144#define ER_RMR 0000004 /* reg mod refused */\r
145#define ER_MCP 0000010 /* Mbus cpar err NI */\r
146#define ER_FER 0000020 /* format sel err */\r
147#define ER_MDP 0000040 /* Mbus dpar err NI */\r
148#define ER_VPE 0000100 /* vert parity err */\r
149#define ER_CRC 0000200 /* CRC err NI */\r
150#define ER_NSG 0000400 /* non std gap err NI */\r
151#define ER_FCE 0001000 /* frame count err */\r
152#define ER_ITM 0002000 /* inv tape mark NI */\r
153#define ER_NXF 0004000 /* wlock or fnc err */\r
154#define ER_DTE 0010000 /* time err NI */\r
155#define ER_OPI 0020000 /* op incomplete */\r
156#define ER_UNS 0040000 /* drive unsafe */\r
157#define ER_DCK 0100000 /* data check NI */\r
158\r
159/* TUMR - maintenance register - offset 03 */\r
160\r
161#define MR_OF 3\r
162#define MR_RW 0177637 /* read/write */\r
163\r
164/* TUAS - attention summary - offset 4 */\r
165\r
166#define AS_OF 4\r
167#define AS_U0 0000001 /* unit 0 flag */\r
168\r
169/* TUFC - offset 5 */\r
170\r
171#define FC_OF 5\r
172\r
173/* TUDT - drive type - offset 6 */\r
174\r
175#define DT_OF 6\r
176#define DT_NSA 0100000 /* not sect addr */\r
177#define DT_TAPE 0040000 /* tape */\r
178#define DT_PRES 0002000 /* slave present */\r
179#define DT_TM03 0000040 /* TM03 formatter */\r
180#define DT_OFF 0000010 /* drive off */\r
181#define DT_TU16 0000011 /* TE16 */\r
182#define DT_TU45 0000012 /* TU45 */\r
183#define DT_TU77 0000014 /* TU77 */\r
184\r
185/* TUCC - check character, read only - offset 7 */\r
186\r
187#define CC_OF 7\r
188#define CC_MBZ 0177000 /* must be zero */\r
189\r
190/* TUSN - serial number - offset 8 */\r
191\r
192#define SN_OF 8\r
193\r
194/* TUTC - tape control register - offset 9 */\r
195\r
196#define TC_OF 9\r
197#define TC_V_UNIT 0 /* unit select */\r
198#define TC_M_UNIT 07\r
199#define TC_V_EVN 0000010 /* even parity */\r
200#define TC_V_FMT 4 /* format select */\r
201#define TC_M_FMT 017\r
202#define TC_STD 014 /* standard */\r
203#define TC_CDUMP 015 /* core dump */\r
204#define TC_V_DEN 8 /* density select */\r
205#define TC_M_DEN 07\r
206#define TC_800 3 /* 800 bpi */\r
207#define TC_1600 4 /* 1600 bpi */\r
208#define TC_AER 0010000 /* abort on error */\r
209#define TC_SAC 0020000 /* slave addr change */\r
210#define TC_FCS 0040000 /* frame count status */\r
211#define TC_ACC 0100000 /* accelerating NI */\r
212#define TC_RW 0013777\r
213#define TC_MBZ 0004000\r
214#define TC_RIP ((TC_800 << TC_V_DEN) | (TC_STD << TC_V_FMT))\r
215#define GET_DEN(x) (((x) >> TC_V_DEN) & TC_M_DEN)\r
216#define GET_FMT(x) (((x) >> TC_V_FMT) & TC_M_FMT)\r
217#define GET_DRV(x) (((x) >> TC_V_UNIT) & TC_M_UNIT)\r
218\r
219int32 tucs1 = 0; /* control/status 1 */\r
220int32 tufc = 0; /* frame count */\r
221int32 tufs = 0; /* formatter status */\r
222int32 tuer = 0; /* error status */\r
223int32 tucc = 0; /* check character */\r
224int32 tumr = 0; /* maint register */\r
225int32 tutc = 0; /* tape control */\r
226int32 tu_time = 10; /* record latency */\r
227int32 tu_stopioe = 1; /* stop on error */\r
228static uint8 *xbuf = NULL; /* xfer buffer */\r
229static uint16 *wbuf = NULL;\r
230static int32 fmt_test[16] = { /* fmt valid */\r
231 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0\r
232 };\r
233static int32 dt_map[3] = { DT_TU16, DT_TU45, DT_TU77 };\r
234static char *tu_fname[CS1_N_FNC] = {\r
235 "NOP", "UNLD", "2", "REW", "FCLR", "5", "6", "7",\r
236 "RIP", "11", "ERASE", "WREOF", "SPCF", "SPCR", "16", "17",\r
237 "20", "21", "22", "23", "WRCHKF", "25", "26", "WRCHKR",\r
238 "WRITE", "31", "32", "33", "READF", "35", "36" "READR"\r
239 };\r
240\r
241extern int32 sim_switches;\r
242extern FILE *sim_deb;\r
243\r
244t_stat tu_mbrd (int32 *data, int32 PA, int32 fmtr);\r
245t_stat tu_mbwr (int32 data, int32 PA, int32 fmtr);\r
246t_stat tu_svc (UNIT *uptr);\r
247t_stat tu_reset (DEVICE *dptr);\r
248t_stat tu_attach (UNIT *uptr, char *cptr);\r
249t_stat tu_detach (UNIT *uptr);\r
250t_stat tu_boot (int32 unitno, DEVICE *dptr);\r
251t_stat tu_set_fmtr (UNIT *uptr, int32 val, char *cptr, void *desc);\r
252t_stat tu_show_fmtr (FILE *st, UNIT *uptr, int32 val, void *desc);\r
253t_stat tu_go (int32 drv);\r
254int32 tu_abort (void);\r
255void tu_set_er (int32 flg);\r
256void tu_clr_as (int32 mask);\r
257void tu_update_fs (int32 flg, int32 drv);\r
258t_stat tu_map_err (int32 drv, t_stat st, t_bool qdt);\r
259\r
260/* TU data structures\r
261\r
262 tu_dev TU device descriptor\r
263 tu_unit TU unit list\r
264 tu_reg TU register list\r
265 tu_mod TU modifier list\r
266*/\r
267\r
268DIB tu_dib = { MBA_TU, 0, &tu_mbrd, &tu_mbwr,0, 0, 0, { &tu_abort } };\r
269\r
270UNIT tu_unit[] = {\r
271 { UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },\r
272 { UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },\r
273 { UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },\r
274 { UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },\r
275 { UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },\r
276 { UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },\r
277 { UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },\r
278 { UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }\r
279 };\r
280\r
281REG tu_reg[] = {\r
282 { GRDATA (CS1, tucs1, DEV_RDX, 6, 0) },\r
283 { GRDATA (FC, tufc, DEV_RDX, 16, 0) },\r
284 { GRDATA (FS, tufs, DEV_RDX, 16, 0) },\r
285 { GRDATA (ER, tuer, DEV_RDX, 16, 0) },\r
286 { GRDATA (CC, tucc, DEV_RDX, 16, 0) },\r
287 { GRDATA (MR, tumr, DEV_RDX, 16, 0) },\r
288 { GRDATA (TC, tutc, DEV_RDX, 16, 0) },\r
289 { FLDATA (STOP_IOE, tu_stopioe, 0) },\r
290 { DRDATA (TIME, tu_time, 24), PV_LEFT },\r
291 { URDATA (UST, tu_unit[0].USTAT, DEV_RDX, 17, 0, TU_NUMDR, 0) },\r
292 { URDATA (POS, tu_unit[0].pos, 10, T_ADDR_W, 0,\r
293 TU_NUMDR, PV_LEFT | REG_RO) },\r
294 { NULL }\r
295 };\r
296\r
297MTAB tu_mod[] = {\r
298 { MTAB_XTD|MTAB_VDV, 0, "MASSBUS", "MASSBUS", NULL, &mba_show_num },\r
299#if defined (VM_PDP11)\r
300 { MTAB_XTD|MTAB_VDV, 0, "FORMATTER", "TM02",\r
301 &tu_set_fmtr, &tu_show_fmtr },\r
302 { MTAB_XTD|MTAB_VDV, 1, NULL, "TM03",\r
303 &tu_set_fmtr, NULL },\r
304#else\r
305 { MTAB_XTD|MTAB_VDV, 0, "FORMATTER", NULL,\r
306 NULL, &tu_show_fmtr },\r
307#endif\r
308 { MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL },\r
309 { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL },\r
310 { UNIT_TYPE, UNIT_TE16, "TE16", "TE16", NULL },\r
311 { UNIT_TYPE, UNIT_TU45, "TU45", "TU45", NULL },\r
312 { UNIT_TYPE, UNIT_TU77, "TU77", "TU77", NULL },\r
313 { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT",\r
314 &sim_tape_set_fmt, &sim_tape_show_fmt, NULL },\r
315 { MTAB_XTD|MTAB_VUN, 0, "CAPACITY", "CAPACITY",\r
316 &sim_tape_set_capac, &sim_tape_show_capac, NULL },\r
317 { 0 }\r
318 };\r
319\r
320DEVICE tu_dev = {\r
321 "TU", tu_unit, tu_reg, tu_mod,\r
322 TU_NUMDR, 10, T_ADDR_W, 1, DEV_RDX, 8,\r
323 NULL, NULL, &tu_reset,\r
324 &tu_boot, &tu_attach, &tu_detach,\r
325 &tu_dib, DEV_MBUS|DEV_UBUS|DEV_QBUS|DEV_DEBUG|DEV_DISABLE|DEV_DIS_INIT|DEV_TM03\r
326 };\r
327\r
328/* Massbus register read */\r
329\r
330t_stat tu_mbrd (int32 *data, int32 ofs, int32 fmtr)\r
331{\r
332int32 drv;\r
333\r
334if (fmtr != 0) { /* only one fmtr */\r
335 *data = 0;\r
336 return MBE_NXD;\r
337 }\r
338drv = GET_DRV (tutc); /* get current unit */\r
339tu_update_fs (0, drv); /* update status */\r
340\r
341switch (ofs) { /* decode offset */\r
342\r
343 case CS1_OF: /* MTCS1 */\r
344 *data = (tucs1 & CS1_RW) | CS1_DVA; /* DVA always set */\r
345 break;\r
346\r
347 case FC_OF: /* MTFC */\r
348 *data = tufc;\r
349 break;\r
350\r
351 case FS_OF: /* MTFS */\r
352 *data = tufs & 0177777; /* mask off rewind */\r
353 break;\r
354\r
355 case ER_OF: /* MTER */\r
356 *data = tuer;\r
357 break;\r
358\r
359 case AS_OF: /* MTAS */\r
360 *data = (tufs & FS_ATA)? AS_U0: 0;\r
361 break;\r
362\r
363 case CC_OF: /* MTCC */\r
364 *data = tucc = tucc & ~CC_MBZ;\r
365 break;\r
366\r
367 case MR_OF: /* MTMR */\r
368 *data = tumr;\r
369 break;\r
370\r
371 case DT_OF: /* MTDT */\r
372 *data = DT_NSA | DT_TAPE | /* fmtr flags */\r
373 ((tu_dev.flags & DEV_TM03)? DT_TM03: 0);\r
374 if (tu_unit[drv].flags & UNIT_DIS) *data |= DT_OFF;\r
375 else *data |= DT_PRES | dt_map[GET_TYPE (tu_unit[drv].flags)];\r
376 break;\r
377\r
378 case SN_OF: /* MTSN */\r
379 *data = (tu_unit[drv].flags & UNIT_DIS)? 0: 040 | (drv + 1);\r
380 break;\r
381\r
382 case TC_OF: /* MTTC */\r
383 *data = tutc = tutc & ~TC_MBZ;\r
384 break;\r
385\r
386 default: /* all others */\r
387 return MBE_NXR;\r
388 }\r
389\r
390return SCPE_OK;\r
391}\r
392\r
393/* Massbus register write */\r
394\r
395t_stat tu_mbwr (int32 data, int32 ofs, int32 fmtr)\r
396{\r
397int32 drv;\r
398\r
399if (fmtr != 0) return MBE_NXD; /* only one fmtr */\r
400drv = GET_DRV (tutc); /* get current unit */\r
401\r
402switch (ofs) { /* decode PA<4:1> */\r
403\r
404 case CS1_OF: /* MTCS1 */\r
405 if (tucs1 & CS1_GO) tu_set_er (ER_RMR);\r
406 else {\r
407 tucs1 = data & CS1_RW;\r
408 if (tucs1 & CS1_GO) return tu_go (drv);\r
409 }\r
410 break; \r
411\r
412 case FC_OF: /* MTFC */\r
413 if (tucs1 & CS1_GO) tu_set_er (ER_RMR);\r
414 else {\r
415 tufc = data;\r
416 tutc = tutc | TC_FCS; /* set fc flag */\r
417 }\r
418 break;\r
419\r
420 case AS_OF: /* MTAS */\r
421 tu_clr_as (data);\r
422 break;\r
423\r
424 case MR_OF: /* MTMR */\r
425 tumr = (tumr & ~MR_RW) | (data & MR_RW);\r
426 break;\r
427\r
428 case TC_OF: /* MTTC */\r
429 if (tucs1 & CS1_GO) tu_set_er (ER_RMR);\r
430 else {\r
431 tutc = (tutc & ~TC_RW) | (data & TC_RW) | TC_SAC;\r
432 drv = GET_DRV (tutc);\r
433 }\r
434 break;\r
435\r
436 case FS_OF: /* MTFS */\r
437 case ER_OF: /* MTER */\r
438 case CC_OF: /* MTCC */\r
439 case DT_OF: /* MTDT */\r
440 case SN_OF: /* MTSN */\r
441 if (tucs1 & CS1_GO) tu_set_er (ER_RMR);\r
442 break; /* read only */\r
443\r
444 default: /* all others */\r
445 return MBE_NXR;\r
446 } /* end switch */\r
447\r
448tu_update_fs (0, drv);\r
449return SCPE_OK;\r
450}\r
451\r
452/* New magtape command */\r
453\r
454t_stat tu_go (int32 drv)\r
455{\r
456int32 fnc, den;\r
457UNIT *uptr;\r
458\r
459fnc = GET_FNC (tucs1); /* get function */\r
460den = GET_DEN (tutc); /* get density */\r
461uptr = tu_dev.units + drv; /* get unit */\r
462if (DEBUG_PRS (tu_dev)) fprintf (sim_deb,\r
463 ">>TU%d STRT: fnc=%s, fc=%06o, fs=%06o, er=%06o, pos=%d\n",\r
464 drv, tu_fname[fnc], tufc, tufs, tuer, uptr->pos);\r
465\r
466if ((fnc != FNC_FCLR) && /* not clear & err */\r
467 ((tufs & FS_ERR) || sim_is_active (uptr))) { /* or in motion? */\r
468 tu_set_er (ER_ILF); /* set err */\r
469 tucs1 = tucs1 & ~CS1_GO; /* clear go */\r
470 tu_update_fs (FS_ATA, drv); /* set attn */\r
471 return MBE_GOE;\r
472 }\r
473tu_clr_as (AS_U0); /* clear ATA */\r
474tutc = tutc & ~TC_SAC; /* clear addr change */\r
475\r
476switch (fnc) { /* case on function */\r
477\r
478 case FNC_FCLR: /* drive clear */\r
479 tuer = 0; /* clear errors */\r
480 tutc = tutc & ~TC_FCS; /* clear fc status */\r
481 tufs = tufs & ~(FS_SAT | FS_SSC | FS_ID | FS_ERR);\r
482 sim_cancel (uptr); /* reset drive */\r
483 uptr->USTAT = 0;\r
484 case FNC_NOP:\r
485 tucs1 = tucs1 & ~CS1_GO; /* no operation */\r
486 return SCPE_OK;\r
487\r
488 case FNC_RIP: /* read-in preset */\r
489 tutc = TC_RIP; /* set tutc */\r
490 sim_tape_rewind (&tu_unit[0]); /* rewind unit 0 */\r
491 tu_unit[0].USTAT = 0;\r
492 tucs1 = tucs1 & ~CS1_GO;\r
493 tufs = tufs & ~FS_TMK;\r
494 return SCPE_OK;\r
495\r
496 case FNC_UNLOAD: /* unload */\r
497 if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */\r
498 tu_set_er (ER_UNS);\r
499 break;\r
500 }\r
501 detach_unit (uptr);\r
502 uptr->USTAT = FS_REW;\r
503 sim_activate (uptr, tu_time);\r
504 tucs1 = tucs1 & ~CS1_GO;\r
505 tufs = tufs & ~FS_TMK;\r
506 return SCPE_OK; \r
507\r
508 case FNC_REWIND:\r
509 if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */\r
510 tu_set_er (ER_UNS);\r
511 break;\r
512 }\r
513 uptr->USTAT = FS_PIP | FS_REW;\r
514 sim_activate (uptr, tu_time);\r
515 tucs1 = tucs1 & ~CS1_GO;\r
516 tufs = tufs & ~FS_TMK;\r
517 return SCPE_OK;\r
518\r
519 case FNC_SPACEF:\r
520 if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */\r
521 tu_set_er (ER_UNS);\r
522 break;\r
523 }\r
524 if (sim_tape_eot (uptr) || ((tutc & TC_FCS) == 0)) {\r
525 tu_set_er (ER_NXF);\r
526 break;\r
527 }\r
528 uptr->USTAT = FS_PIP;\r
529 goto GO_XFER;\r
530\r
531 case FNC_SPACER:\r
532 if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */\r
533 tu_set_er (ER_UNS);\r
534 break;\r
535 }\r
536 if (sim_tape_bot (uptr) || ((tutc & TC_FCS) == 0)) {\r
537 tu_set_er (ER_NXF);\r
538 break;\r
539 }\r
540 uptr->USTAT = FS_PIP;\r
541 goto GO_XFER;\r
542\r
543 case FNC_WCHKR: /* wchk = read */\r
544 case FNC_READR: /* read rev */\r
545 if (tufs & FS_BOT) { /* beginning of tape? */\r
546 tu_set_er (ER_NXF);\r
547 break;\r
548 }\r
549 goto DATA_XFER;\r
550\r
551 case FNC_WRITE: /* write */\r
552 if (((tutc & TC_FCS) == 0) || /* frame cnt = 0? */\r
553 ((den == TC_800) && (tufc > 0777765))) { /* NRZI, fc < 13? */\r
554 tu_set_er (ER_NXF);\r
555 break;\r
556 }\r
557 case FNC_WREOF: /* write tape mark */\r
558 case FNC_ERASE: /* erase */\r
559 if (sim_tape_wrp (uptr)) { /* write locked? */\r
560 tu_set_er (ER_NXF);\r
561 break;\r
562 }\r
563 case FNC_WCHKF: /* wchk = read */\r
564 case FNC_READF: /* read */\r
565 DATA_XFER:\r
566 if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */\r
567 tu_set_er (ER_UNS);\r
568 break;\r
569 }\r
570 if (fmt_test[GET_FMT (tutc)] == 0) { /* invalid format? */\r
571 tu_set_er (ER_FER);\r
572 break;\r
573 }\r
574 if (uptr->UDENS == UD_UNK) uptr->UDENS = den; /* set dens */\r
575 uptr->USTAT = 0;\r
576 GO_XFER:\r
577 tufs = tufs & ~(FS_TMK | FS_ID); /* clear eof, id */\r
578 sim_activate (uptr, tu_time);\r
579 return SCPE_OK;\r
580\r
581 default: /* all others */\r
582 tu_set_er (ER_ILF); /* not supported */\r
583 break;\r
584 } /* end case function */\r
585\r
586tucs1 = tucs1 & ~CS1_GO; /* clear go */\r
587tu_update_fs (FS_ATA, drv); /* set attn */\r
588return MBE_GOE;\r
589}\r
590\r
591/* Abort transfer */\r
592\r
593t_stat tu_abort (void)\r
594{\r
595return tu_reset (&tu_dev);\r
596}\r
597\r
598/* Unit service\r
599\r
600 Complete movement or data transfer command\r
601 Unit must exist - can't remove an active unit\r
602 Unit must be attached - detach cancels in progress operations\r
603*/\r
604\r
605t_stat tu_svc (UNIT *uptr)\r
606{\r
607int32 fnc, fmt, j, xbc;\r
608int32 fc, drv;\r
609t_mtrlnt i, tbc;\r
610t_stat st, r = SCPE_OK;\r
611\r
612drv = (int32) (uptr - tu_dev.units); /* get drive # */\r
613if (uptr->USTAT & FS_REW) { /* rewind or unload? */\r
614 sim_tape_rewind (uptr); /* rewind tape */\r
615 uptr->USTAT = 0; /* clear status */\r
616 tu_update_fs (FS_ATA | FS_SSC, drv);\r
617 return SCPE_OK;\r
618 }\r
619\r
620fnc = GET_FNC (tucs1); /* get command */\r
621fmt = GET_FMT (tutc); /* get format */\r
622fc = 0200000 - tufc; /* get frame count */\r
623uptr->USTAT = 0; /* clear status */\r
624\r
625if ((uptr->flags & UNIT_ATT) == 0) {\r
626 tu_set_er (ER_UNS); /* set formatter error */\r
627 if (fnc >= FNC_XFER) mba_set_don (tu_dib.ba);\r
628 tu_update_fs (FS_ATA, drv);\r
629 return (tu_stopioe? SCPE_UNATT: SCPE_OK);\r
630 }\r
631switch (fnc) { /* case on function */\r
632\r
633/* Non-data transfer commands - set ATA when done */\r
634\r
635 case FNC_SPACEF: /* space forward */\r
636 do {\r
637 tufc = (tufc + 1) & 0177777; /* incr fc */\r
638 if (st = sim_tape_sprecf (uptr, &tbc)) { /* space rec fwd, err? */\r
639 r = tu_map_err (drv, st, 0); /* map error */\r
640 break;\r
641 }\r
642 } while ((tufc != 0) && !sim_tape_eot (uptr));\r
643 if (tufc) tu_set_er (ER_FCE);\r
644 else tutc = tutc & ~TC_FCS;\r
645 break;\r
646\r
647 case FNC_SPACER: /* space reverse */\r
648 do {\r
649 tufc = (tufc + 1) & 0177777; /* incr wc */\r
650 if (st = sim_tape_sprecr (uptr, &tbc)) { /* space rec rev, err? */\r
651 r = tu_map_err (drv, st, 0); /* map error */\r
652 break;\r
653 }\r
654 } while (tufc != 0);\r
655 if (tufc) tu_set_er (ER_FCE);\r
656 else tutc = tutc & ~TC_FCS;\r
657 break;\r
658\r
659 case FNC_WREOF: /* write end of file */\r
660 if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */\r
661 r = tu_map_err (drv, st, 0); /* map error */\r
662 break;\r
663\r
664 case FNC_ERASE:\r
665 if (sim_tape_wrp (uptr)) /* write protected? */\r
666 r = tu_map_err (drv, MTSE_WRP, 0); /* map error */\r
667 break;\r
668\r
669/* Unit service - data transfer commands */\r
670\r
671 case FNC_READF: /* read */\r
672 case FNC_WCHKF: /* wcheck = read */\r
673 tufc = 0; /* clear frame count */\r
674 if ((uptr->UDENS == TC_1600) && sim_tape_bot (uptr))\r
675 tufs = tufs | FS_ID; /* PE BOT? ID burst */\r
676 if (st = sim_tape_rdrecf (uptr, xbuf, &tbc, MT_MAXFR)) { /* read fwd */\r
677 if (st == MTSE_TMK) tu_set_er (ER_FCE); /* tmk also sets FCE */\r
678 r = tu_map_err (drv, st, 1); /* map error */\r
679 break; /* done */\r
680 }\r
681 for (i = tbc; i < tbc + 4; i++) xbuf[i] = 0; /* pad with 0's */\r
682 if (fmt == TC_CDUMP) { /* core dump? */\r
683 for (i = j = 0; i < tbc; i = i + 4) {\r
684 wbuf[j++] = ((uint16) xbuf[i] & 0xF) |\r
685 (((uint16) (xbuf[i + 1] & 0xF)) << 4) |\r
686 (((uint16) (xbuf[i + 2] & 0xF)) << 8) |\r
687 (((uint16) (xbuf[i + 3] & 0xf)) << 12);\r
688 }\r
689 xbc = (tbc + 1) >> 1;\r
690 }\r
691 else { /* standard */\r
692 for (i = j = 0; i < tbc; i = i + 2) {\r
693 wbuf[j++] = ((uint16) xbuf[i]) |\r
694 (((uint16) xbuf[i + 1]) << 8);\r
695 }\r
696 xbc = tbc;\r
697 }\r
698 if (mba_get_bc (tu_dib.ba) > xbc) /* record short? */\r
699 tu_set_er (ER_FCE); /* set FCE, ATN */\r
700 if (fnc == FNC_WCHKF) mba_chbufW (tu_dib.ba, xbc, wbuf);\r
701 else mba_wrbufW (tu_dib.ba, xbc, wbuf);\r
702 tufc = tbc & 0177777;\r
703 break;\r
704\r
705 case FNC_WRITE: /* write */\r
706 xbc = mba_rdbufW (tu_dib.ba, fc, wbuf); /* read buffer */\r
707 if (xbc == 0) break; /* anything?? */\r
708 if (fmt == TC_CDUMP) { /* core dump? */\r
709 for (i = j = 0; j < xbc; j = j + 1) {\r
710 xbuf[i++] = wbuf[j] & 0xF;\r
711 xbuf[i++] = (wbuf[j] >> 4) & 0xF;\r
712 xbuf[i++] = (wbuf[j] >> 8) & 0xF;\r
713 xbuf[i++] = (wbuf[j] >> 12) & 0xF;\r
714 }\r
715 tbc = (xbc + 1) >> 1;\r
716 }\r
717 else { /* standard */\r
718 for (i = j = 0; j < xbc; j = j + 1) {\r
719 xbuf[i++] = wbuf[j] & 0377;\r
720 xbuf[i++] = (wbuf[j] >> 8) & 0377;\r
721 }\r
722 tbc = xbc;\r
723 }\r
724 if (st = sim_tape_wrrecf (uptr, xbuf, tbc)) /* write rec, err? */\r
725 r = tu_map_err (drv, st, 1); /* map error */\r
726 else {\r
727 tufc = (tufc + tbc) & 0177777;\r
728 if (tufc == 0) tutc = tutc & ~TC_FCS;\r
729 }\r
730 break;\r
731\r
732 case FNC_READR: /* read reverse */\r
733 case FNC_WCHKR: /* wcheck = read */\r
734 tufc = 0; /* clear frame count */\r
735 if (st = sim_tape_rdrecr (uptr, xbuf + 4, &tbc, MT_MAXFR)) { /* read rev */\r
736 if (st == MTSE_TMK) tu_set_er (ER_FCE); /* tmk also sets FCE */\r
737 r = tu_map_err (drv, st, 1); /* map error */\r
738 break; /* done */\r
739 }\r
740 for (i = 0; i < 4; i++) xbuf[i] = 0; /* pad with 0's */\r
741 if (fmt == TC_CDUMP) { /* core dump? */\r
742 for (i = tbc + 3, j = 0; i > 3; i = i - 4) {\r
743 wbuf[j++] = ((uint16) xbuf[i] & 0xF) |\r
744 (((uint16) (xbuf[i - 1] & 0xF)) << 4) |\r
745 (((uint16) (xbuf[i - 2] & 0xF)) << 8) |\r
746 (((uint16) (xbuf[i - 3] & 0xf)) << 12);\r
747 }\r
748 xbc = (tbc + 1) >> 1;\r
749 }\r
750 else { /* standard */\r
751 for (i = tbc + 3, j = 0; i > 3; i = i - 2) {\r
752 wbuf[j++] = ((uint16) xbuf[i]) |\r
753 (((uint16) xbuf[i - 1]) << 8);\r
754 }\r
755 xbc = tbc;\r
756 }\r
757 if (mba_get_bc (tu_dib.ba) > xbc) /* record short? */\r
758 tu_set_er (ER_FCE); /* set FCE, ATN */\r
759 if (fnc == FNC_WCHKR) mba_chbufW (tu_dib.ba, xbc, wbuf);\r
760 else mba_wrbufW (tu_dib.ba, xbc, wbuf);\r
761 tufc = tbc & 0177777;\r
762 break;\r
763 } /* end case */\r
764\r
765tucs1 = tucs1 & ~CS1_GO; /* clear go */\r
766if (fnc >= FNC_XFER) { /* data xfer? */\r
767 mba_set_don (tu_dib.ba); /* set done */\r
768 tu_update_fs (0, drv); /* update fs */\r
769 }\r
770else tu_update_fs (FS_ATA, drv); /* no, set attn */\r
771if (DEBUG_PRS (tu_dev)) fprintf (sim_deb,\r
772 ">>TU%d DONE: fnc=%s, fc=%06o, fs=%06o, er=%06o, pos=%d\n",\r
773 drv, tu_fname[fnc], tufc, tufs, tuer, uptr->pos);\r
774return SCPE_OK;\r
775}\r
776\r
777/* Set formatter error */\r
778\r
779void tu_set_er (int32 flg)\r
780{\r
781tuer = tuer | flg;\r
782tufs = tufs | FS_ATA;\r
783mba_upd_ata (tu_dib.ba, 1);\r
784return;\r
785}\r
786\r
787/* Clear attention */\r
788\r
789void tu_clr_as (int32 mask)\r
790{\r
791if (mask & AS_U0) tufs = tufs & ~FS_ATA;\r
792mba_upd_ata (tu_dib.ba, tufs & FS_ATA);\r
793return;\r
794}\r
795\r
796/* Formatter update status */\r
797\r
798void tu_update_fs (int32 flg, int32 drv)\r
799{\r
800int32 act = sim_is_active (&tu_unit[drv]);\r
801\r
802tufs = (tufs & ~FS_DYN) | FS_FPR | flg;\r
803if (tu_unit[drv].flags & UNIT_ATT) {\r
804 tufs = tufs | FS_MOL | tu_unit[drv].USTAT;\r
805 if (tu_unit[drv].UDENS == TC_1600) tufs = tufs | FS_PE;\r
806 if (sim_tape_wrp (&tu_unit[drv])) tufs = tufs | FS_WRL;\r
807 if (!act) {\r
808 if (sim_tape_bot (&tu_unit[drv]))\r
809 tufs = tufs | FS_BOT;\r
810 if (sim_tape_eot (&tu_unit[drv]))\r
811 tufs = tufs | FS_EOT;\r
812 }\r
813 }\r
814if (tuer) tufs = tufs | FS_ERR;\r
815if (tufs && !act) tufs = tufs | FS_RDY;\r
816if (flg & FS_ATA) mba_upd_ata (tu_dib.ba, 1);\r
817return;\r
818}\r
819\r
820/* Map tape error status */\r
821\r
822t_stat tu_map_err (int32 drv, t_stat st, t_bool qdt)\r
823{\r
824switch (st) {\r
825\r
826 case MTSE_FMT: /* illegal fmt */\r
827 case MTSE_UNATT: /* not attached */\r
828 tu_set_er (ER_NXF); /* can't execute */\r
829 if (qdt) mba_set_exc (tu_dib.ba); /* set exception */\r
830 break;\r
831\r
832 case MTSE_TMK: /* end of file */\r
833 tufs = tufs | FS_TMK;\r
834 break;\r
835\r
836 case MTSE_IOERR: /* IO error */\r
837 tu_set_er (ER_VPE); /* flag error */\r
838 if (qdt) mba_set_exc (tu_dib.ba); /* set exception */\r
839 return (tu_stopioe? SCPE_IOERR: SCPE_OK);\r
840\r
841 case MTSE_INVRL: /* invalid rec lnt */\r
842 tu_set_er (ER_VPE); /* flag error */\r
843 if (qdt) mba_set_exc (tu_dib.ba); /* set exception */\r
844 return SCPE_MTRLNT;\r
845\r
846 case MTSE_RECE: /* record in error */\r
847 tu_set_er (ER_CRC); /* set crc err */\r
848 if (qdt) mba_set_exc (tu_dib.ba); /* set exception */\r
849 break;\r
850\r
851 case MTSE_EOM: /* end of medium */\r
852 tu_set_er (ER_OPI); /* incomplete */\r
853 if (qdt) mba_set_exc (tu_dib.ba); /* set exception */\r
854 break;\r
855\r
856 case MTSE_BOT: /* reverse into BOT */\r
857 return SCPE_OK;\r
858\r
859 case MTSE_WRP: /* write protect */\r
860 tu_set_er (ER_NXF); /* can't execute */\r
861 if (qdt) mba_set_exc (tu_dib.ba); /* set exception */\r
862 break;\r
863\r
864 default: /* unknown error */\r
865 return SCPE_IERR;\r
866 }\r
867\r
868return SCPE_OK;\r
869}\r
870\r
871/* Reset routine */\r
872\r
873t_stat tu_reset (DEVICE *dptr)\r
874{\r
875int32 u;\r
876UNIT *uptr;\r
877\r
878mba_set_enbdis (MBA_TU, tu_dev.flags & DEV_DIS);\r
879tucs1 = 0;\r
880tufc = 0;\r
881tuer = 0;\r
882tufs = FS_FPR | FS_RDY;\r
883if (sim_switches & SWMASK ('P')) tutc = 0; /* powerup? clr TC */\r
884else tutc = tutc & ~TC_FCS; /* no, clr <fcs> */\r
885for (u = 0; u < TU_NUMDR; u++) { /* loop thru units */\r
886 uptr = tu_dev.units + u;\r
887 sim_tape_reset (uptr); /* clear pos flag */\r
888 sim_cancel (uptr); /* cancel activity */\r
889 uptr->USTAT = 0;\r
890 }\r
891if (xbuf == NULL) xbuf = (uint8 *) calloc (MT_MAXFR + 4, sizeof (uint8));\r
892if (xbuf == NULL) return SCPE_MEM;\r
893if (wbuf == NULL) wbuf = (uint16 *) calloc ((MT_MAXFR + 4) >> 1, sizeof (uint16));\r
894if (wbuf == NULL) return SCPE_MEM;\r
895return SCPE_OK;\r
896}\r
897\r
898/* Attach routine */\r
899\r
900t_stat tu_attach (UNIT *uptr, char *cptr)\r
901{\r
902int32 drv = uptr - tu_dev.units, flg;\r
903t_stat r;\r
904\r
905r = sim_tape_attach (uptr, cptr);\r
906if (r != SCPE_OK) return r;\r
907uptr->USTAT = 0; /* clear unit status */\r
908uptr->UDENS = UD_UNK; /* unknown density */\r
909flg = FS_ATA | FS_SSC; /* set attention */\r
910if (GET_DRV (tutc) == drv) flg = flg | FS_SAT; /* sel drv? set SAT */\r
911tu_update_fs (flg, drv); /* update status */\r
912return r;\r
913}\r
914\r
915/* Detach routine */\r
916\r
917t_stat tu_detach (UNIT* uptr)\r
918{\r
919int32 drv = uptr - tu_dev.units;\r
920\r
921if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; /* attached? */\r
922uptr->USTAT = 0; /* clear status flags */\r
923tu_update_fs (FS_ATA | FS_SSC, drv); /* update status */\r
924return sim_tape_detach (uptr);\r
925}\r
926\r
927/* Set/show formatter type */\r
928\r
929t_stat tu_set_fmtr (UNIT *uptr, int32 val, char *cptr, void *desc)\r
930{\r
931DEVICE *dptr = find_dev_from_unit (uptr);\r
932\r
933if (cptr != NULL) return SCPE_ARG;\r
934if (dptr == NULL) return SCPE_IERR;\r
935if (val) dptr->flags = dptr->flags | DEV_TM03;\r
936else dptr->flags = dptr->flags & ~DEV_TM03;\r
937return SCPE_OK;\r
938}\r
939\r
940t_stat tu_show_fmtr (FILE *st, UNIT *uptr, int32 val, void *desc)\r
941{\r
942DEVICE *dptr = find_dev_from_unit (uptr);\r
943\r
944if (dptr == NULL) return SCPE_IERR;\r
945fprintf (st, "TM0%d", (dptr->flags & DEV_TM03? 3: 2));\r
946return SCPE_OK;\r
947}\r
948\r
949/* Device bootstrap */\r
950\r
951#if defined (PDP11)\r
952\r
953#elif defined (VM_PDP11)\r
954\r
955#define BOOT_START 016000 /* start */\r
956#define BOOT_ENTRY (BOOT_START + 002) /* entry */\r
957#define BOOT_UNIT (BOOT_START + 010) /* unit number */\r
958#define BOOT_CSR (BOOT_START + 014) /* CSR */\r
959#define BOOT_LEN (sizeof (boot_rom) / sizeof (uint16))\r
960\r
961static const uint16 boot_rom[] = {\r
962 0046515, /* "MM" */\r
963 0012706, BOOT_START, /* mov #boot_start, sp */\r
964 0012700, 0000000, /* mov #unit, r0 */\r
965 0012701, 0172440, /* mov #TUCS1, r1 */\r
966 0012761, 0000040, 0000010, /* mov #CS2_CLR, 10(r1) ; reset */\r
967 0012711, 0000021, /* mov #RIP+GO, (r1) ; rip */\r
968 0010004, /* mov r0, r4 */\r
969 0052704, 0002300, /* bis #2300, r4 ; set den */\r
970 0010461, 0000032, /* mov r4, 32(r1) ; set unit */\r
971 0012761, 0177777, 0000006, /* mov #-1, 6(r1) ; set fc */\r
972 0012711, 0000031, /* mov #SPCF+GO, (r1) ; skip rec */\r
973 0105761, 0000012, /* tstb 12 (r1) ; fmtr rdy? */\r
974 0100375, /* bpl .-4 */\r
975 0012761, 0177000, 0000002, /* mov #-1000, 2(r1) ; set wc */\r
976 0005061, 0000004, /* clr 4(r1) ; clr ba */\r
977 0005061, 0000006, /* clr 6(r1) ; clr fc */\r
978 0012711, 0000071, /* mov #READ+GO, (r1) ; read */\r
979 0105711, /* tstb (r1) ; wait */\r
980 0100376, /* bpl .-2 */\r
981 0005002, /* clr R2 */\r
982 0005003, /* clr R3 */\r
983 0012704, BOOT_START+020, /* mov #start+020, r4 */\r
984 0005005, /* clr R5 */\r
985 0105011, /* clrb (r1) */\r
986 0005007 /* clr PC */\r
987 };\r
988\r
989t_stat tu_boot (int32 unitno, DEVICE *dptr)\r
990{\r
991int32 i;\r
992extern int32 saved_PC;\r
993extern uint16 *M;\r
994\r
995for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i];\r
996M[BOOT_UNIT >> 1] = unitno & (TU_NUMDR - 1);\r
997M[BOOT_CSR >> 1] = mba_get_csr (tu_dib.ba) & DMASK;\r
998saved_PC = BOOT_ENTRY;\r
999return SCPE_OK;\r
1000}\r
1001\r
1002#else\r
1003\r
1004t_stat tu_boot (int32 unitno, DEVICE *dptr)\r
1005{\r
1006return SCPE_NOFNC;\r
1007}\r
1008\r
1009#endif\r