1 /* pdp11_tu.c - PDP-11 TM02/TU16 TM03/TU45/TU77 Massbus magnetic tape controller
3 Copyright (c) 1993-2007, Robert M Supnik
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following conditions:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 Except as contained in this notice, the name of Robert M Supnik shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from Robert M Supnik.
28 17-May-07 RMS CS1 DVA resides in device, not MBA
29 29-Apr-07 RMS Fixed bug in setting FCE on TMK (found by Naoki Hamada)
30 16-Feb-06 RMS Added tape capacity checking
31 12-Nov-05 RMS Changed default formatter to TM03 (for VMS)
32 31-Oct-05 RMS Fixed address width for large files
33 16-Aug-05 RMS Fixed C++ declaration and cast problems
34 31-Mar-05 RMS Fixed inaccuracies in error reporting
35 18-Mar-05 RMS Added attached test to detach routine
36 10-Sep-04 RMS Cloned from pdp10_tu.c
38 Magnetic tapes are represented as a series of variable 8b records
41 32b record length in bytes - exact number, sign = error
47 32b record length in bytes - exact number, sign = error
49 If the byte count is odd, the record is padded with an extra byte
50 of junk. File marks are represented by a single record length of 0.
51 End of tape is two consecutive end of file marks.
54 #if defined (VM_PDP10)
55 #error "PDP-10 uses pdp10_tu.c!"
57 #elif defined (VM_PDP11)
58 #include "pdp11_defs.h"
59 #define DEV_DIS_INIT DEV_DIS
61 #elif defined (VM_VAX)
63 #define DEV_DIS_INIT 0
65 #error "Qbus not supported!"
71 #define TU_NUMFM 1 /* #formatters */
72 #define TU_NUMDR 8 /* #drives */
73 #define USTAT u3 /* unit status */
74 #define UDENS u4 /* unit density */
75 #define UD_UNK 0 /* unknown */
76 #define MT_MAXFR (1 << 16) /* max data buf */
77 #define DEV_V_TM03 (DEV_V_FFUF + 0) /* TM02/TM03 */
78 #define DEV_TM03 (1 << DEV_V_TM03)
79 #define UNIT_V_TYPE (MTUF_V_UF + 0)
80 #define UNIT_M_TYPE 03
81 #define UNIT_TYPE (UNIT_M_TYPE << UNIT_V_TYPE)
82 #define UNIT_TE16 (0 << UNIT_V_TYPE)
83 #define UNIT_TU45 (1 << UNIT_V_TYPE)
84 #define UNIT_TU77 (2 << UNIT_V_TYPE)
85 #define GET_TYPE(x) (((x) >> UNIT_V_TYPE) & UNIT_M_TYPE)
90 #define CS1_GO CSR_GO /* go */
91 #define CS1_V_FNC 1 /* function pos */
92 #define CS1_M_FNC 037 /* function mask */
93 #define CS1_N_FNC (CS1_M_FNC + 1)
94 #define FNC_NOP 000 /* no operation */
95 #define FNC_UNLOAD 001 /* unload */
96 #define FNC_REWIND 003 /* rewind */
97 #define FNC_FCLR 004 /* formatter clear */
98 #define FNC_RIP 010 /* read in preset */
99 #define FNC_ERASE 012 /* erase tape */
100 #define FNC_WREOF 013 /* write tape mark */
101 #define FNC_SPACEF 014 /* space forward */
102 #define FNC_SPACER 015 /* space reverse */
103 #define FNC_XFER 024 /* >=? data xfr */
104 #define FNC_WCHKF 024 /* write check */
105 #define FNC_WCHKR 027 /* write check rev */
106 #define FNC_WRITE 030 /* write */
107 #define FNC_READF 034 /* read forward */
108 #define FNC_READR 037 /* read reverse */
110 #define CS1_DVA 04000 /* drive avail */
111 #define GET_FNC(x) (((x) >> CS1_V_FNC) & CS1_M_FNC)
113 /* TUFS - formatter status - offset 1
114 + indicates kept in drive status
115 ^ indicates calculated on the fly
119 #define FS_SAT 0000001 /* slave attention */
120 #define FS_BOT 0000002 /* ^beginning of tape */
121 #define FS_TMK 0000004 /* end of file */
122 #define FS_ID 0000010 /* ID burst detected */
123 #define FS_SLOW 0000020 /* slowing down NI */
124 #define FS_PE 0000040 /* ^PE status */
125 #define FS_SSC 0000100 /* slave stat change */
126 #define FS_RDY 0000200 /* ^formatter ready */
127 #define FS_FPR 0000400 /* formatter present */
128 #define FS_EOT 0002000 /* +end of tape */
129 #define FS_WRL 0004000 /* ^write locked */
130 #define FS_MOL 0010000 /* ^medium online */
131 #define FS_PIP 0020000 /* +pos in progress */
132 #define FS_ERR 0040000 /* ^error */
133 #define FS_ATA 0100000 /* attention active */
134 #define FS_REW 0200000 /* +rewinding */
136 #define FS_DYN (FS_ERR | FS_PIP | FS_MOL | FS_WRL | FS_EOT | \
137 FS_RDY | FS_PE | FS_BOT)
139 /* TUER - error register - offset 2 */
142 #define ER_ILF 0000001 /* illegal func */
143 #define ER_ILR 0000002 /* illegal register */
144 #define ER_RMR 0000004 /* reg mod refused */
145 #define ER_MCP 0000010 /* Mbus cpar err NI */
146 #define ER_FER 0000020 /* format sel err */
147 #define ER_MDP 0000040 /* Mbus dpar err NI */
148 #define ER_VPE 0000100 /* vert parity err */
149 #define ER_CRC 0000200 /* CRC err NI */
150 #define ER_NSG 0000400 /* non std gap err NI */
151 #define ER_FCE 0001000 /* frame count err */
152 #define ER_ITM 0002000 /* inv tape mark NI */
153 #define ER_NXF 0004000 /* wlock or fnc err */
154 #define ER_DTE 0010000 /* time err NI */
155 #define ER_OPI 0020000 /* op incomplete */
156 #define ER_UNS 0040000 /* drive unsafe */
157 #define ER_DCK 0100000 /* data check NI */
159 /* TUMR - maintenance register - offset 03 */
162 #define MR_RW 0177637 /* read/write */
164 /* TUAS - attention summary - offset 4 */
167 #define AS_U0 0000001 /* unit 0 flag */
169 /* TUFC - offset 5 */
173 /* TUDT - drive type - offset 6 */
176 #define DT_NSA 0100000 /* not sect addr */
177 #define DT_TAPE 0040000 /* tape */
178 #define DT_PRES 0002000 /* slave present */
179 #define DT_TM03 0000040 /* TM03 formatter */
180 #define DT_OFF 0000010 /* drive off */
181 #define DT_TU16 0000011 /* TE16 */
182 #define DT_TU45 0000012 /* TU45 */
183 #define DT_TU77 0000014 /* TU77 */
185 /* TUCC - check character, read only - offset 7 */
188 #define CC_MBZ 0177000 /* must be zero */
190 /* TUSN - serial number - offset 8 */
194 /* TUTC - tape control register - offset 9 */
197 #define TC_V_UNIT 0 /* unit select */
199 #define TC_V_EVN 0000010 /* even parity */
200 #define TC_V_FMT 4 /* format select */
202 #define TC_STD 014 /* standard */
203 #define TC_CDUMP 015 /* core dump */
204 #define TC_V_DEN 8 /* density select */
206 #define TC_800 3 /* 800 bpi */
207 #define TC_1600 4 /* 1600 bpi */
208 #define TC_AER 0010000 /* abort on error */
209 #define TC_SAC 0020000 /* slave addr change */
210 #define TC_FCS 0040000 /* frame count status */
211 #define TC_ACC 0100000 /* accelerating NI */
212 #define TC_RW 0013777
213 #define TC_MBZ 0004000
214 #define TC_RIP ((TC_800 << TC_V_DEN) | (TC_STD << TC_V_FMT))
215 #define GET_DEN(x) (((x) >> TC_V_DEN) & TC_M_DEN)
216 #define GET_FMT(x) (((x) >> TC_V_FMT) & TC_M_FMT)
217 #define GET_DRV(x) (((x) >> TC_V_UNIT) & TC_M_UNIT)
219 int32 tucs1
= 0; /* control/status 1 */
220 int32 tufc
= 0; /* frame count */
221 int32 tufs
= 0; /* formatter status */
222 int32 tuer
= 0; /* error status */
223 int32 tucc
= 0; /* check character */
224 int32 tumr
= 0; /* maint register */
225 int32 tutc
= 0; /* tape control */
226 int32 tu_time
= 10; /* record latency */
227 int32 tu_stopioe
= 1; /* stop on error */
228 static uint8
*xbuf
= NULL
; /* xfer buffer */
229 static uint16
*wbuf
= NULL
;
230 static int32 fmt_test
[16] = { /* fmt valid */
231 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0
233 static int32 dt_map
[3] = { DT_TU16
, DT_TU45
, DT_TU77
};
234 static char *tu_fname
[CS1_N_FNC
] = {
235 "NOP", "UNLD", "2", "REW", "FCLR", "5", "6", "7",
236 "RIP", "11", "ERASE", "WREOF", "SPCF", "SPCR", "16", "17",
237 "20", "21", "22", "23", "WRCHKF", "25", "26", "WRCHKR",
238 "WRITE", "31", "32", "33", "READF", "35", "36" "READR"
241 extern int32 sim_switches
;
242 extern FILE *sim_deb
;
244 t_stat
tu_mbrd (int32
*data
, int32 PA
, int32 fmtr
);
245 t_stat
tu_mbwr (int32 data
, int32 PA
, int32 fmtr
);
246 t_stat
tu_svc (UNIT
*uptr
);
247 t_stat
tu_reset (DEVICE
*dptr
);
248 t_stat
tu_attach (UNIT
*uptr
, char *cptr
);
249 t_stat
tu_detach (UNIT
*uptr
);
250 t_stat
tu_boot (int32 unitno
, DEVICE
*dptr
);
251 t_stat
tu_set_fmtr (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
);
252 t_stat
tu_show_fmtr (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
);
253 t_stat
tu_go (int32 drv
);
254 int32
tu_abort (void);
255 void tu_set_er (int32 flg
);
256 void tu_clr_as (int32 mask
);
257 void tu_update_fs (int32 flg
, int32 drv
);
258 t_stat
tu_map_err (int32 drv
, t_stat st
, t_bool qdt
);
260 /* TU data structures
262 tu_dev TU device descriptor
264 tu_reg TU register list
265 tu_mod TU modifier list
268 DIB tu_dib
= { MBA_TU
, 0, &tu_mbrd
, &tu_mbwr
,0, 0, 0, { &tu_abort
} };
271 { UDATA (&tu_svc
, UNIT_ATTABLE
+UNIT_DISABLE
+UNIT_ROABLE
, 0) },
272 { UDATA (&tu_svc
, UNIT_ATTABLE
+UNIT_DISABLE
+UNIT_ROABLE
, 0) },
273 { UDATA (&tu_svc
, UNIT_ATTABLE
+UNIT_DISABLE
+UNIT_ROABLE
, 0) },
274 { UDATA (&tu_svc
, UNIT_ATTABLE
+UNIT_DISABLE
+UNIT_ROABLE
, 0) },
275 { UDATA (&tu_svc
, UNIT_ATTABLE
+UNIT_DISABLE
+UNIT_ROABLE
, 0) },
276 { UDATA (&tu_svc
, UNIT_ATTABLE
+UNIT_DISABLE
+UNIT_ROABLE
, 0) },
277 { UDATA (&tu_svc
, UNIT_ATTABLE
+UNIT_DISABLE
+UNIT_ROABLE
, 0) },
278 { UDATA (&tu_svc
, UNIT_ATTABLE
+UNIT_DISABLE
+UNIT_ROABLE
, 0) }
282 { GRDATA (CS1
, tucs1
, DEV_RDX
, 6, 0) },
283 { GRDATA (FC
, tufc
, DEV_RDX
, 16, 0) },
284 { GRDATA (FS
, tufs
, DEV_RDX
, 16, 0) },
285 { GRDATA (ER
, tuer
, DEV_RDX
, 16, 0) },
286 { GRDATA (CC
, tucc
, DEV_RDX
, 16, 0) },
287 { GRDATA (MR
, tumr
, DEV_RDX
, 16, 0) },
288 { GRDATA (TC
, tutc
, DEV_RDX
, 16, 0) },
289 { FLDATA (STOP_IOE
, tu_stopioe
, 0) },
290 { DRDATA (TIME
, tu_time
, 24), PV_LEFT
},
291 { URDATA (UST
, tu_unit
[0].USTAT
, DEV_RDX
, 17, 0, TU_NUMDR
, 0) },
292 { URDATA (POS
, tu_unit
[0].pos
, 10, T_ADDR_W
, 0,
293 TU_NUMDR
, PV_LEFT
| REG_RO
) },
298 { MTAB_XTD
|MTAB_VDV
, 0, "MASSBUS", "MASSBUS", NULL
, &mba_show_num
},
299 #if defined (VM_PDP11)
300 { MTAB_XTD
|MTAB_VDV
, 0, "FORMATTER", "TM02",
301 &tu_set_fmtr
, &tu_show_fmtr
},
302 { MTAB_XTD
|MTAB_VDV
, 1, NULL
, "TM03",
303 &tu_set_fmtr
, NULL
},
305 { MTAB_XTD
|MTAB_VDV
, 0, "FORMATTER", NULL
,
306 NULL
, &tu_show_fmtr
},
308 { MTUF_WLK
, 0, "write enabled", "WRITEENABLED", NULL
},
309 { MTUF_WLK
, MTUF_WLK
, "write locked", "LOCKED", NULL
},
310 { UNIT_TYPE
, UNIT_TE16
, "TE16", "TE16", NULL
},
311 { UNIT_TYPE
, UNIT_TU45
, "TU45", "TU45", NULL
},
312 { UNIT_TYPE
, UNIT_TU77
, "TU77", "TU77", NULL
},
313 { MTAB_XTD
|MTAB_VUN
, 0, "FORMAT", "FORMAT",
314 &sim_tape_set_fmt
, &sim_tape_show_fmt
, NULL
},
315 { MTAB_XTD
|MTAB_VUN
, 0, "CAPACITY", "CAPACITY",
316 &sim_tape_set_capac
, &sim_tape_show_capac
, NULL
},
321 "TU", tu_unit
, tu_reg
, tu_mod
,
322 TU_NUMDR
, 10, T_ADDR_W
, 1, DEV_RDX
, 8,
323 NULL
, NULL
, &tu_reset
,
324 &tu_boot
, &tu_attach
, &tu_detach
,
325 &tu_dib
, DEV_MBUS
|DEV_UBUS
|DEV_QBUS
|DEV_DEBUG
|DEV_DISABLE
|DEV_DIS_INIT
|DEV_TM03
328 /* Massbus register read */
330 t_stat
tu_mbrd (int32
*data
, int32 ofs
, int32 fmtr
)
334 if (fmtr
!= 0) { /* only one fmtr */
338 drv
= GET_DRV (tutc
); /* get current unit */
339 tu_update_fs (0, drv
); /* update status */
341 switch (ofs
) { /* decode offset */
343 case CS1_OF
: /* MTCS1 */
344 *data
= (tucs1
& CS1_RW
) | CS1_DVA
; /* DVA always set */
347 case FC_OF
: /* MTFC */
351 case FS_OF
: /* MTFS */
352 *data
= tufs
& 0177777; /* mask off rewind */
355 case ER_OF
: /* MTER */
359 case AS_OF
: /* MTAS */
360 *data
= (tufs
& FS_ATA
)? AS_U0
: 0;
363 case CC_OF
: /* MTCC */
364 *data
= tucc
= tucc
& ~CC_MBZ
;
367 case MR_OF
: /* MTMR */
371 case DT_OF
: /* MTDT */
372 *data
= DT_NSA
| DT_TAPE
| /* fmtr flags */
373 ((tu_dev
.flags
& DEV_TM03
)? DT_TM03
: 0);
374 if (tu_unit
[drv
].flags
& UNIT_DIS
) *data
|= DT_OFF
;
375 else *data
|= DT_PRES
| dt_map
[GET_TYPE (tu_unit
[drv
].flags
)];
378 case SN_OF
: /* MTSN */
379 *data
= (tu_unit
[drv
].flags
& UNIT_DIS
)? 0: 040 | (drv
+ 1);
382 case TC_OF
: /* MTTC */
383 *data
= tutc
= tutc
& ~TC_MBZ
;
386 default: /* all others */
393 /* Massbus register write */
395 t_stat
tu_mbwr (int32 data
, int32 ofs
, int32 fmtr
)
399 if (fmtr
!= 0) return MBE_NXD
; /* only one fmtr */
400 drv
= GET_DRV (tutc
); /* get current unit */
402 switch (ofs
) { /* decode PA<4:1> */
404 case CS1_OF
: /* MTCS1 */
405 if (tucs1
& CS1_GO
) tu_set_er (ER_RMR
);
407 tucs1
= data
& CS1_RW
;
408 if (tucs1
& CS1_GO
) return tu_go (drv
);
412 case FC_OF
: /* MTFC */
413 if (tucs1
& CS1_GO
) tu_set_er (ER_RMR
);
416 tutc
= tutc
| TC_FCS
; /* set fc flag */
420 case AS_OF
: /* MTAS */
424 case MR_OF
: /* MTMR */
425 tumr
= (tumr
& ~MR_RW
) | (data
& MR_RW
);
428 case TC_OF
: /* MTTC */
429 if (tucs1
& CS1_GO
) tu_set_er (ER_RMR
);
431 tutc
= (tutc
& ~TC_RW
) | (data
& TC_RW
) | TC_SAC
;
432 drv
= GET_DRV (tutc
);
436 case FS_OF
: /* MTFS */
437 case ER_OF
: /* MTER */
438 case CC_OF
: /* MTCC */
439 case DT_OF
: /* MTDT */
440 case SN_OF
: /* MTSN */
441 if (tucs1
& CS1_GO
) tu_set_er (ER_RMR
);
442 break; /* read only */
444 default: /* all others */
448 tu_update_fs (0, drv
);
452 /* New magtape command */
454 t_stat
tu_go (int32 drv
)
459 fnc
= GET_FNC (tucs1
); /* get function */
460 den
= GET_DEN (tutc
); /* get density */
461 uptr
= tu_dev
.units
+ drv
; /* get unit */
462 if (DEBUG_PRS (tu_dev
)) fprintf (sim_deb
,
463 ">>TU%d STRT: fnc=%s, fc=%06o, fs=%06o, er=%06o, pos=%d\n",
464 drv
, tu_fname
[fnc
], tufc
, tufs
, tuer
, uptr
->pos
);
466 if ((fnc
!= FNC_FCLR
) && /* not clear & err */
467 ((tufs
& FS_ERR
) || sim_is_active (uptr
))) { /* or in motion? */
468 tu_set_er (ER_ILF
); /* set err */
469 tucs1
= tucs1
& ~CS1_GO
; /* clear go */
470 tu_update_fs (FS_ATA
, drv
); /* set attn */
473 tu_clr_as (AS_U0
); /* clear ATA */
474 tutc
= tutc
& ~TC_SAC
; /* clear addr change */
476 switch (fnc
) { /* case on function */
478 case FNC_FCLR
: /* drive clear */
479 tuer
= 0; /* clear errors */
480 tutc
= tutc
& ~TC_FCS
; /* clear fc status */
481 tufs
= tufs
& ~(FS_SAT
| FS_SSC
| FS_ID
| FS_ERR
);
482 sim_cancel (uptr
); /* reset drive */
485 tucs1
= tucs1
& ~CS1_GO
; /* no operation */
488 case FNC_RIP
: /* read-in preset */
489 tutc
= TC_RIP
; /* set tutc */
490 sim_tape_rewind (&tu_unit
[0]); /* rewind unit 0 */
491 tu_unit
[0].USTAT
= 0;
492 tucs1
= tucs1
& ~CS1_GO
;
493 tufs
= tufs
& ~FS_TMK
;
496 case FNC_UNLOAD
: /* unload */
497 if ((uptr
->flags
& UNIT_ATT
) == 0) { /* unattached? */
502 uptr
->USTAT
= FS_REW
;
503 sim_activate (uptr
, tu_time
);
504 tucs1
= tucs1
& ~CS1_GO
;
505 tufs
= tufs
& ~FS_TMK
;
509 if ((uptr
->flags
& UNIT_ATT
) == 0) { /* unattached? */
513 uptr
->USTAT
= FS_PIP
| FS_REW
;
514 sim_activate (uptr
, tu_time
);
515 tucs1
= tucs1
& ~CS1_GO
;
516 tufs
= tufs
& ~FS_TMK
;
520 if ((uptr
->flags
& UNIT_ATT
) == 0) { /* unattached? */
524 if (sim_tape_eot (uptr
) || ((tutc
& TC_FCS
) == 0)) {
528 uptr
->USTAT
= FS_PIP
;
532 if ((uptr
->flags
& UNIT_ATT
) == 0) { /* unattached? */
536 if (sim_tape_bot (uptr
) || ((tutc
& TC_FCS
) == 0)) {
540 uptr
->USTAT
= FS_PIP
;
543 case FNC_WCHKR
: /* wchk = read */
544 case FNC_READR
: /* read rev */
545 if (tufs
& FS_BOT
) { /* beginning of tape? */
551 case FNC_WRITE
: /* write */
552 if (((tutc
& TC_FCS
) == 0) || /* frame cnt = 0? */
553 ((den
== TC_800
) && (tufc
> 0777765))) { /* NRZI, fc < 13? */
557 case FNC_WREOF
: /* write tape mark */
558 case FNC_ERASE
: /* erase */
559 if (sim_tape_wrp (uptr
)) { /* write locked? */
563 case FNC_WCHKF
: /* wchk = read */
564 case FNC_READF
: /* read */
566 if ((uptr
->flags
& UNIT_ATT
) == 0) { /* unattached? */
570 if (fmt_test
[GET_FMT (tutc
)] == 0) { /* invalid format? */
574 if (uptr
->UDENS
== UD_UNK
) uptr
->UDENS
= den
; /* set dens */
577 tufs
= tufs
& ~(FS_TMK
| FS_ID
); /* clear eof, id */
578 sim_activate (uptr
, tu_time
);
581 default: /* all others */
582 tu_set_er (ER_ILF
); /* not supported */
584 } /* end case function */
586 tucs1
= tucs1
& ~CS1_GO
; /* clear go */
587 tu_update_fs (FS_ATA
, drv
); /* set attn */
593 t_stat
tu_abort (void)
595 return tu_reset (&tu_dev
);
600 Complete movement or data transfer command
601 Unit must exist - can't remove an active unit
602 Unit must be attached - detach cancels in progress operations
605 t_stat
tu_svc (UNIT
*uptr
)
607 int32 fnc
, fmt
, j
, xbc
;
610 t_stat st
, r
= SCPE_OK
;
612 drv
= (int32
) (uptr
- tu_dev
.units
); /* get drive # */
613 if (uptr
->USTAT
& FS_REW
) { /* rewind or unload? */
614 sim_tape_rewind (uptr
); /* rewind tape */
615 uptr
->USTAT
= 0; /* clear status */
616 tu_update_fs (FS_ATA
| FS_SSC
, drv
);
620 fnc
= GET_FNC (tucs1
); /* get command */
621 fmt
= GET_FMT (tutc
); /* get format */
622 fc
= 0200000 - tufc
; /* get frame count */
623 uptr
->USTAT
= 0; /* clear status */
625 if ((uptr
->flags
& UNIT_ATT
) == 0) {
626 tu_set_er (ER_UNS
); /* set formatter error */
627 if (fnc
>= FNC_XFER
) mba_set_don (tu_dib
.ba
);
628 tu_update_fs (FS_ATA
, drv
);
629 return (tu_stopioe
? SCPE_UNATT
: SCPE_OK
);
631 switch (fnc
) { /* case on function */
633 /* Non-data transfer commands - set ATA when done */
635 case FNC_SPACEF
: /* space forward */
637 tufc
= (tufc
+ 1) & 0177777; /* incr fc */
638 if (st
= sim_tape_sprecf (uptr
, &tbc
)) { /* space rec fwd, err? */
639 r
= tu_map_err (drv
, st
, 0); /* map error */
642 } while ((tufc
!= 0) && !sim_tape_eot (uptr
));
643 if (tufc
) tu_set_er (ER_FCE
);
644 else tutc
= tutc
& ~TC_FCS
;
647 case FNC_SPACER
: /* space reverse */
649 tufc
= (tufc
+ 1) & 0177777; /* incr wc */
650 if (st
= sim_tape_sprecr (uptr
, &tbc
)) { /* space rec rev, err? */
651 r
= tu_map_err (drv
, st
, 0); /* map error */
655 if (tufc
) tu_set_er (ER_FCE
);
656 else tutc
= tutc
& ~TC_FCS
;
659 case FNC_WREOF
: /* write end of file */
660 if (st
= sim_tape_wrtmk (uptr
)) /* write tmk, err? */
661 r
= tu_map_err (drv
, st
, 0); /* map error */
665 if (sim_tape_wrp (uptr
)) /* write protected? */
666 r
= tu_map_err (drv
, MTSE_WRP
, 0); /* map error */
669 /* Unit service - data transfer commands */
671 case FNC_READF
: /* read */
672 case FNC_WCHKF
: /* wcheck = read */
673 tufc
= 0; /* clear frame count */
674 if ((uptr
->UDENS
== TC_1600
) && sim_tape_bot (uptr
))
675 tufs
= tufs
| FS_ID
; /* PE BOT? ID burst */
676 if (st
= sim_tape_rdrecf (uptr
, xbuf
, &tbc
, MT_MAXFR
)) { /* read fwd */
677 if (st
== MTSE_TMK
) tu_set_er (ER_FCE
); /* tmk also sets FCE */
678 r
= tu_map_err (drv
, st
, 1); /* map error */
681 for (i
= tbc
; i
< tbc
+ 4; i
++) xbuf
[i
] = 0; /* pad with 0's */
682 if (fmt
== TC_CDUMP
) { /* core dump? */
683 for (i
= j
= 0; i
< tbc
; i
= i
+ 4) {
684 wbuf
[j
++] = ((uint16
) xbuf
[i
] & 0xF) |
685 (((uint16
) (xbuf
[i
+ 1] & 0xF)) << 4) |
686 (((uint16
) (xbuf
[i
+ 2] & 0xF)) << 8) |
687 (((uint16
) (xbuf
[i
+ 3] & 0xf)) << 12);
689 xbc
= (tbc
+ 1) >> 1;
691 else { /* standard */
692 for (i
= j
= 0; i
< tbc
; i
= i
+ 2) {
693 wbuf
[j
++] = ((uint16
) xbuf
[i
]) |
694 (((uint16
) xbuf
[i
+ 1]) << 8);
698 if (mba_get_bc (tu_dib
.ba
) > xbc
) /* record short? */
699 tu_set_er (ER_FCE
); /* set FCE, ATN */
700 if (fnc
== FNC_WCHKF
) mba_chbufW (tu_dib
.ba
, xbc
, wbuf
);
701 else mba_wrbufW (tu_dib
.ba
, xbc
, wbuf
);
702 tufc
= tbc
& 0177777;
705 case FNC_WRITE
: /* write */
706 xbc
= mba_rdbufW (tu_dib
.ba
, fc
, wbuf
); /* read buffer */
707 if (xbc
== 0) break; /* anything?? */
708 if (fmt
== TC_CDUMP
) { /* core dump? */
709 for (i
= j
= 0; j
< xbc
; j
= j
+ 1) {
710 xbuf
[i
++] = wbuf
[j
] & 0xF;
711 xbuf
[i
++] = (wbuf
[j
] >> 4) & 0xF;
712 xbuf
[i
++] = (wbuf
[j
] >> 8) & 0xF;
713 xbuf
[i
++] = (wbuf
[j
] >> 12) & 0xF;
715 tbc
= (xbc
+ 1) >> 1;
717 else { /* standard */
718 for (i
= j
= 0; j
< xbc
; j
= j
+ 1) {
719 xbuf
[i
++] = wbuf
[j
] & 0377;
720 xbuf
[i
++] = (wbuf
[j
] >> 8) & 0377;
724 if (st
= sim_tape_wrrecf (uptr
, xbuf
, tbc
)) /* write rec, err? */
725 r
= tu_map_err (drv
, st
, 1); /* map error */
727 tufc
= (tufc
+ tbc
) & 0177777;
728 if (tufc
== 0) tutc
= tutc
& ~TC_FCS
;
732 case FNC_READR
: /* read reverse */
733 case FNC_WCHKR
: /* wcheck = read */
734 tufc
= 0; /* clear frame count */
735 if (st
= sim_tape_rdrecr (uptr
, xbuf
+ 4, &tbc
, MT_MAXFR
)) { /* read rev */
736 if (st
== MTSE_TMK
) tu_set_er (ER_FCE
); /* tmk also sets FCE */
737 r
= tu_map_err (drv
, st
, 1); /* map error */
740 for (i
= 0; i
< 4; i
++) xbuf
[i
] = 0; /* pad with 0's */
741 if (fmt
== TC_CDUMP
) { /* core dump? */
742 for (i
= tbc
+ 3, j
= 0; i
> 3; i
= i
- 4) {
743 wbuf
[j
++] = ((uint16
) xbuf
[i
] & 0xF) |
744 (((uint16
) (xbuf
[i
- 1] & 0xF)) << 4) |
745 (((uint16
) (xbuf
[i
- 2] & 0xF)) << 8) |
746 (((uint16
) (xbuf
[i
- 3] & 0xf)) << 12);
748 xbc
= (tbc
+ 1) >> 1;
750 else { /* standard */
751 for (i
= tbc
+ 3, j
= 0; i
> 3; i
= i
- 2) {
752 wbuf
[j
++] = ((uint16
) xbuf
[i
]) |
753 (((uint16
) xbuf
[i
- 1]) << 8);
757 if (mba_get_bc (tu_dib
.ba
) > xbc
) /* record short? */
758 tu_set_er (ER_FCE
); /* set FCE, ATN */
759 if (fnc
== FNC_WCHKR
) mba_chbufW (tu_dib
.ba
, xbc
, wbuf
);
760 else mba_wrbufW (tu_dib
.ba
, xbc
, wbuf
);
761 tufc
= tbc
& 0177777;
765 tucs1
= tucs1
& ~CS1_GO
; /* clear go */
766 if (fnc
>= FNC_XFER
) { /* data xfer? */
767 mba_set_don (tu_dib
.ba
); /* set done */
768 tu_update_fs (0, drv
); /* update fs */
770 else tu_update_fs (FS_ATA
, drv
); /* no, set attn */
771 if (DEBUG_PRS (tu_dev
)) fprintf (sim_deb
,
772 ">>TU%d DONE: fnc=%s, fc=%06o, fs=%06o, er=%06o, pos=%d\n",
773 drv
, tu_fname
[fnc
], tufc
, tufs
, tuer
, uptr
->pos
);
777 /* Set formatter error */
779 void tu_set_er (int32 flg
)
782 tufs
= tufs
| FS_ATA
;
783 mba_upd_ata (tu_dib
.ba
, 1);
787 /* Clear attention */
789 void tu_clr_as (int32 mask
)
791 if (mask
& AS_U0
) tufs
= tufs
& ~FS_ATA
;
792 mba_upd_ata (tu_dib
.ba
, tufs
& FS_ATA
);
796 /* Formatter update status */
798 void tu_update_fs (int32 flg
, int32 drv
)
800 int32 act
= sim_is_active (&tu_unit
[drv
]);
802 tufs
= (tufs
& ~FS_DYN
) | FS_FPR
| flg
;
803 if (tu_unit
[drv
].flags
& UNIT_ATT
) {
804 tufs
= tufs
| FS_MOL
| tu_unit
[drv
].USTAT
;
805 if (tu_unit
[drv
].UDENS
== TC_1600
) tufs
= tufs
| FS_PE
;
806 if (sim_tape_wrp (&tu_unit
[drv
])) tufs
= tufs
| FS_WRL
;
808 if (sim_tape_bot (&tu_unit
[drv
]))
809 tufs
= tufs
| FS_BOT
;
810 if (sim_tape_eot (&tu_unit
[drv
]))
811 tufs
= tufs
| FS_EOT
;
814 if (tuer
) tufs
= tufs
| FS_ERR
;
815 if (tufs
&& !act
) tufs
= tufs
| FS_RDY
;
816 if (flg
& FS_ATA
) mba_upd_ata (tu_dib
.ba
, 1);
820 /* Map tape error status */
822 t_stat
tu_map_err (int32 drv
, t_stat st
, t_bool qdt
)
826 case MTSE_FMT
: /* illegal fmt */
827 case MTSE_UNATT
: /* not attached */
828 tu_set_er (ER_NXF
); /* can't execute */
829 if (qdt
) mba_set_exc (tu_dib
.ba
); /* set exception */
832 case MTSE_TMK
: /* end of file */
833 tufs
= tufs
| FS_TMK
;
836 case MTSE_IOERR
: /* IO error */
837 tu_set_er (ER_VPE
); /* flag error */
838 if (qdt
) mba_set_exc (tu_dib
.ba
); /* set exception */
839 return (tu_stopioe
? SCPE_IOERR
: SCPE_OK
);
841 case MTSE_INVRL
: /* invalid rec lnt */
842 tu_set_er (ER_VPE
); /* flag error */
843 if (qdt
) mba_set_exc (tu_dib
.ba
); /* set exception */
846 case MTSE_RECE
: /* record in error */
847 tu_set_er (ER_CRC
); /* set crc err */
848 if (qdt
) mba_set_exc (tu_dib
.ba
); /* set exception */
851 case MTSE_EOM
: /* end of medium */
852 tu_set_er (ER_OPI
); /* incomplete */
853 if (qdt
) mba_set_exc (tu_dib
.ba
); /* set exception */
856 case MTSE_BOT
: /* reverse into BOT */
859 case MTSE_WRP
: /* write protect */
860 tu_set_er (ER_NXF
); /* can't execute */
861 if (qdt
) mba_set_exc (tu_dib
.ba
); /* set exception */
864 default: /* unknown error */
873 t_stat
tu_reset (DEVICE
*dptr
)
878 mba_set_enbdis (MBA_TU
, tu_dev
.flags
& DEV_DIS
);
882 tufs
= FS_FPR
| FS_RDY
;
883 if (sim_switches
& SWMASK ('P')) tutc
= 0; /* powerup? clr TC */
884 else tutc
= tutc
& ~TC_FCS
; /* no, clr <fcs> */
885 for (u
= 0; u
< TU_NUMDR
; u
++) { /* loop thru units */
886 uptr
= tu_dev
.units
+ u
;
887 sim_tape_reset (uptr
); /* clear pos flag */
888 sim_cancel (uptr
); /* cancel activity */
891 if (xbuf
== NULL
) xbuf
= (uint8
*) calloc (MT_MAXFR
+ 4, sizeof (uint8
));
892 if (xbuf
== NULL
) return SCPE_MEM
;
893 if (wbuf
== NULL
) wbuf
= (uint16
*) calloc ((MT_MAXFR
+ 4) >> 1, sizeof (uint16
));
894 if (wbuf
== NULL
) return SCPE_MEM
;
900 t_stat
tu_attach (UNIT
*uptr
, char *cptr
)
902 int32 drv
= uptr
- tu_dev
.units
, flg
;
905 r
= sim_tape_attach (uptr
, cptr
);
906 if (r
!= SCPE_OK
) return r
;
907 uptr
->USTAT
= 0; /* clear unit status */
908 uptr
->UDENS
= UD_UNK
; /* unknown density */
909 flg
= FS_ATA
| FS_SSC
; /* set attention */
910 if (GET_DRV (tutc
) == drv
) flg
= flg
| FS_SAT
; /* sel drv? set SAT */
911 tu_update_fs (flg
, drv
); /* update status */
917 t_stat
tu_detach (UNIT
* uptr
)
919 int32 drv
= uptr
- tu_dev
.units
;
921 if (!(uptr
->flags
& UNIT_ATT
)) return SCPE_OK
; /* attached? */
922 uptr
->USTAT
= 0; /* clear status flags */
923 tu_update_fs (FS_ATA
| FS_SSC
, drv
); /* update status */
924 return sim_tape_detach (uptr
);
927 /* Set/show formatter type */
929 t_stat
tu_set_fmtr (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
931 DEVICE
*dptr
= find_dev_from_unit (uptr
);
933 if (cptr
!= NULL
) return SCPE_ARG
;
934 if (dptr
== NULL
) return SCPE_IERR
;
935 if (val
) dptr
->flags
= dptr
->flags
| DEV_TM03
;
936 else dptr
->flags
= dptr
->flags
& ~DEV_TM03
;
940 t_stat
tu_show_fmtr (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
942 DEVICE
*dptr
= find_dev_from_unit (uptr
);
944 if (dptr
== NULL
) return SCPE_IERR
;
945 fprintf (st
, "TM0%d", (dptr
->flags
& DEV_TM03
? 3: 2));
949 /* Device bootstrap */
953 #elif defined (VM_PDP11)
955 #define BOOT_START 016000 /* start */
956 #define BOOT_ENTRY (BOOT_START + 002) /* entry */
957 #define BOOT_UNIT (BOOT_START + 010) /* unit number */
958 #define BOOT_CSR (BOOT_START + 014) /* CSR */
959 #define BOOT_LEN (sizeof (boot_rom) / sizeof (uint16))
961 static const uint16 boot_rom
[] = {
963 0012706, BOOT_START
, /* mov #boot_start, sp */
964 0012700, 0000000, /* mov #unit, r0 */
965 0012701, 0172440, /* mov #TUCS1, r1 */
966 0012761, 0000040, 0000010, /* mov #CS2_CLR, 10(r1) ; reset */
967 0012711, 0000021, /* mov #RIP+GO, (r1) ; rip */
968 0010004, /* mov r0, r4 */
969 0052704, 0002300, /* bis #2300, r4 ; set den */
970 0010461, 0000032, /* mov r4, 32(r1) ; set unit */
971 0012761, 0177777, 0000006, /* mov #-1, 6(r1) ; set fc */
972 0012711, 0000031, /* mov #SPCF+GO, (r1) ; skip rec */
973 0105761, 0000012, /* tstb 12 (r1) ; fmtr rdy? */
974 0100375, /* bpl .-4 */
975 0012761, 0177000, 0000002, /* mov #-1000, 2(r1) ; set wc */
976 0005061, 0000004, /* clr 4(r1) ; clr ba */
977 0005061, 0000006, /* clr 6(r1) ; clr fc */
978 0012711, 0000071, /* mov #READ+GO, (r1) ; read */
979 0105711, /* tstb (r1) ; wait */
980 0100376, /* bpl .-2 */
981 0005002, /* clr R2 */
982 0005003, /* clr R3 */
983 0012704, BOOT_START
+020, /* mov #start+020, r4 */
984 0005005, /* clr R5 */
985 0105011, /* clrb (r1) */
989 t_stat
tu_boot (int32 unitno
, DEVICE
*dptr
)
992 extern int32 saved_PC
;
995 for (i
= 0; i
< BOOT_LEN
; i
++) M
[(BOOT_START
>> 1) + i
] = boot_rom
[i
];
996 M
[BOOT_UNIT
>> 1] = unitno
& (TU_NUMDR
- 1);
997 M
[BOOT_CSR
>> 1] = mba_get_csr (tu_dib
.ba
) & DMASK
;
998 saved_PC
= BOOT_ENTRY
;
1004 t_stat
tu_boot (int32 unitno
, DEVICE
*dptr
)