1 /* pdp11_tq.c: TMSCP tape controller simulator
3 Copyright (c) 2002-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.
26 tq TQK50 tape controller
28 18-Jun-07 RMS Added UNIT_IDLE flag to timer thread
29 16-Feb-06 RMS Revised for new magtape capacity checking
30 31-Oct-05 RMS Fixed address width for large files
31 16-Aug-05 RMS Fixed C++ declaration and cast problems
32 22-Jul-05 RMS Fixed warning from Solaris C (from Doug Gwyn)
33 30-Sep-04 RMS Revised Unibus interface
34 12-Jun-04 RMS Fixed bug in reporting write protect (reported by Lyle Bickley)
35 18-Apr-04 RMS Fixed TQK70 media ID and model byte (found by Robert Schaffrath)
36 26-Mar-04 RMS Fixed warnings with -std=c99
37 25-Jan-04 RMS Revised for device debug support
38 19-May-03 RMS Revised for new conditional compilation scheme
39 25-Apr-03 RMS Revised for extended file support
40 28-Mar-03 RMS Added multiformat support
41 28-Feb-03 RMS Added variable controller, user-defined drive support
42 26-Feb-03 RMS Fixed bug in vector calculation for VAXen
43 22-Feb-03 RMS Fixed ordering bug in queue process
44 Fixed flags table to allow MD_CSE everywhere
45 09-Jan-03 RMS Fixed bug in transfer end packet status
46 17-Oct-02 RMS Fixed bug in read reverse (found by Hans Pufal)
49 #if defined (VM_PDP10) /* PDP10 version */
50 #error "TQK50 not supported on PDP-10!"
52 #elif defined (VM_VAX) /* VAX version */
55 #define INIT_TYPE TQ8_TYPE
56 #define INIT_CAP TQ8_CAP
58 #define INIT_TYPE TQ5_TYPE
59 #define INIT_CAP TQ5_CAP
62 #else /* PDP-11 version */
63 #include "pdp11_defs.h"
64 #define INIT_TYPE TQ5_TYPE
65 #define INIT_CAP TQ5_CAP
69 #include "pdp11_uqssp.h"
70 #include "pdp11_mscp.h"
73 #define UF_MSK (UF_SCH|UF_VSS|UF_CMR|UF_CMW) /* settable flags */
75 #define TQ_SH_MAX 24 /* max display wds */
76 #define TQ_SH_PPL 8 /* wds per line */
77 #define TQ_SH_DPL 4 /* desc per line */
78 #define TQ_SH_RI 001 /* show rings */
79 #define TQ_SH_FR 002 /* show free q */
80 #define TQ_SH_RS 004 /* show resp q */
81 #define TQ_SH_UN 010 /* show unit q's */
82 #define TQ_SH_ALL 017 /* show all */
84 #define TQ_CLASS 1 /* TQK50 class */
85 #define TQ_DHTMO 0 /* def host timeout */
86 #define TQ_DCTMO 120 /* def ctrl timeout */
87 #define TQ_NUMDR 4 /* # drives */
88 #define TQ_MAXFR (1 << 16) /* max xfer */
90 #define UNIT_V_ONL (MTUF_V_UF + 0) /* online */
91 #define UNIT_V_ATP (MTUF_V_UF + 1) /* attn pending */
92 #define UNIT_V_SXC (MTUF_V_UF + 2) /* serious exc */
93 #define UNIT_V_POL (MTUF_V_UF + 3) /* position lost */
94 #define UNIT_V_TMK (MTUF_V_UF + 4) /* tape mark seen */
95 #define UNIT_ONL (1 << UNIT_V_ONL)
96 #define UNIT_ATP (1 << UNIT_V_ATP)
97 #define UNIT_SXC (1 << UNIT_V_SXC)
98 #define UNIT_POL (1 << UNIT_V_POL)
99 #define UNIT_TMK (1 << UNIT_V_TMK)
100 #define cpkt u3 /* current packet */
101 #define pktq u4 /* packet queue */
102 #define uf buf /* settable unit flags */
103 #define objp wait /* object position */
104 #define TQ_WPH(u) ((sim_tape_wrp (u))? UF_WPH: 0)
106 #define CST_S1 0 /* init stage 1 */
107 #define CST_S1_WR 1 /* stage 1 wrap */
108 #define CST_S2 2 /* init stage 2 */
109 #define CST_S3 3 /* init stage 3 */
110 #define CST_S3_PPA 4 /* stage 3 sa wait */
111 #define CST_S3_PPB 5 /* stage 3 ip wait */
112 #define CST_S4 6 /* stage 4 */
113 #define CST_UP 7 /* online */
114 #define CST_DEAD 8 /* fatal error */
116 #define tq_comm tq_rq.ba
118 #define ERR 0 /* must be SCPE_OK! */
121 #define CMF_IMM 0x10000 /* immediate */
122 #define CMF_SEQ 0x20000 /* sequential */
123 #define CMF_WR 0x40000 /* write */
124 #define CMF_RW 0x80000 /* resp to GCS */
126 /* Internal packet management */
128 #define TQ_NPKTS 32 /* # packets (pwr of 2) */
129 #define TQ_M_NPKTS (TQ_NPKTS - 1) /* mask */
130 #define TQ_PKT_SIZE_W 32 /* payload size (wds) */
131 #define TQ_PKT_SIZE (TQ_PKT_SIZE_W * sizeof (int16))
134 int16 link
; /* link to next */
135 uint16 d
[TQ_PKT_SIZE_W
]; /* data */
138 /* Packet payload extraction and insertion */
140 #define GETP(p,w,f) ((tq_pkt[p].d[w] >> w##_V_##f) & w##_M_##f)
141 #define GETP32(p,w) (((uint32) tq_pkt[p].d[w]) | \
142 (((uint32) tq_pkt[p].d[(w)+1]) << 16))
143 #define PUTP32(p,w,x) tq_pkt[p].d[w] = (x) & 0xFFFF; \
144 tq_pkt[p].d[(w)+1] = ((x) >> 16) & 0xFFFF
146 /* Controller and device types - TQK50 must be swre rev 5 or later */
148 #define TQ5_TYPE 0 /* TK50 */
149 #define TQ5_UQPM 3 /* UQ port ID */
150 #define TQ5_CMOD 9 /* ctrl ID */
151 #define TQ5_UMOD 3 /* unit ID */
152 #define TQ5_MED 0x6D68B032 /* media ID */
153 #define TQ5_CREV ((1 << 8) | 5) /* ctrl revs */
154 #define TQ5_FREV 0 /* formatter revs */
155 #define TQ5_UREV 0 /* unit revs */
156 #define TQ5_CAP (94 * (1 << 20)) /* capacity */
157 #define TQ5_FMT (TF_CTP|TF_CTP_LO) /* menu */
159 #define TQ7_TYPE 1 /* TK70 */
160 #define TQ7_UQPM 14 /* UQ port ID */
161 #define TQ7_CMOD 14 /* ctrl ID */
162 #define TQ7_UMOD 14 /* unit ID */
163 #define TQ7_MED 0x6D68B046 /* media ID */
164 #define TQ7_CREV ((1 << 8) | 5) /* ctrl revs */
165 #define TQ7_FREV 0 /* formatter revs */
166 #define TQ7_UREV 0 /* unit revs */
167 #define TQ7_CAP (300 * (1 << 20)) /* capacity */
168 #define TQ7_FMT (TF_CTP|TF_CTP_LO) /* menu */
170 #define TQ8_TYPE 2 /* TU81 */
171 #define TQ8_UQPM 5 /* UQ port ID */
172 #define TQ8_CMOD 5 /* ctrl ID */
173 #define TQ8_UMOD 2 /* unit ID */
174 #define TQ8_MED 0x6D695051 /* media ID */
175 #define TQ8_CREV ((1 << 8) | 5) /* ctrl revs */
176 #define TQ8_FREV 0 /* formatter revs */
177 #define TQ8_UREV 0 /* unit revs */
178 #define TQ8_CAP (180 * (1 << 20)) /* capacity */
179 #define TQ8_FMT (TF_9TK|TF_9TK_GRP) /* menu */
181 #define TQU_TYPE 3 /* TKuser defined */
182 #define TQU_UQPM 3 /* UQ port ID */
183 #define TQU_CMOD 9 /* ctrl ID */
184 #define TQU_UMOD 3 /* unit ID */
185 #define TQU_MED 0x6D68B032 /* media ID */
186 #define TQU_CREV ((1 << 8) | 5) /* ctrl revs */
187 #define TQU_FREV 0 /* formatter revs */
188 #define TQU_UREV 0 /* unit revs */
189 #define TQU_CAP (94 * (1 << 20)) /* capacity */
190 #define TQU_FMT (TF_CTP|TF_CTP_LO) /* menu */
191 #define TQU_MINC 30 /* min cap MB */
192 #define TQU_MAXC 2000 /* max cap MB */
193 #define TQU_EMAXC 2000000000 /* ext max cap MB */
197 d##_CMOD, d##_MED, d##_FMT, d##_CAP, \
198 d##_UMOD, d##_CREV, d##_FREV, d##_UREV
200 #define TEST_EOT(u) (sim_tape_eot (u))
203 uint32 uqpm
; /* UQ port model */
204 uint32 cmod
; /* ctrl model */
205 uint32 med
; /* MSCP media */
206 uint32 fmt
; /* flags */
207 t_addr cap
; /* capacity */
208 uint32 umod
; /* unit model */
215 static struct drvtyp drv_tab
[] = {
216 { TQ_DRV (TQ5
), "TK50" },
217 { TQ_DRV (TQ7
), "TK70" },
218 { TQ_DRV (TQ8
), "TU81" },
219 { TQ_DRV (TQU
), "TKUSER" },
224 extern int32 int_req
[IPL_HLVL
];
225 extern int32 tmr_poll
, clk_tps
;
226 extern UNIT cpu_unit
;
227 extern FILE *sim_deb
;
228 extern uint32 sim_taddr_64
;
230 uint8
*tqxb
= NULL
; /* xfer buffer */
231 uint32 tq_sa
= 0; /* status, addr */
232 uint32 tq_saw
= 0; /* written data */
233 uint32 tq_s1dat
= 0; /* S1 data */
234 uint32 tq_csta
= 0; /* ctrl state */
235 uint32 tq_perr
= 0; /* last error */
236 uint32 tq_cflgs
= 0; /* ctrl flags */
237 uint32 tq_prgi
= 0; /* purge int */
238 uint32 tq_pip
= 0; /* poll in progress */
239 struct uq_ring tq_cq
= { 0 }; /* cmd ring */
240 struct uq_ring tq_rq
= { 0 }; /* rsp ring */
241 struct tqpkt tq_pkt
[TQ_NPKTS
]; /* packet queue */
242 int32 tq_freq
= 0; /* free list */
243 int32 tq_rspq
= 0; /* resp list */
244 uint32 tq_pbsy
= 0; /* #busy pkts */
245 uint32 tq_credits
= 0; /* credits */
246 uint32 tq_hat
= 0; /* host timer */
247 uint32 tq_htmo
= TQ_DHTMO
; /* host timeout */
248 int32 tq_itime
= 200; /* init time, except */
249 int32 tq_itime4
= 10; /* stage 4 */
250 int32 tq_qtime
= 200; /* queue time */
251 int32 tq_xtime
= 500; /* transfer time */
252 int32 tq_typ
= INIT_TYPE
; /* device type */
254 /* Command table - legal modifiers (low 16b) and flags (high 16b) */
256 static uint32 tq_cmf
[64] = {
259 CMF_IMM
|MD_CSE
, /* get cmd status */
260 CMF_IMM
|MD_CSE
|MD_NXU
, /* get unit status */
261 CMF_IMM
|MD_CSE
, /* set ctrl char */
263 CMF_SEQ
|MD_ACL
|MD_CDL
|MD_CSE
|MD_EXA
|MD_UNL
, /* available */
264 CMF_SEQ
|MD_CDL
|MD_CSE
|MD_SWP
|MD_EXA
, /* online */
265 CMF_SEQ
|MD_CDL
|MD_CSE
|MD_SWP
|MD_EXA
, /* set unit char */
266 CMF_IMM
, /* define acc paths */
267 0, 0, 0, 0, /* 12-15 */
268 CMF_SEQ
|CMF_RW
|MD_CDL
|MD_CSE
|MD_REV
| /* access */
269 MD_SCH
|MD_SEC
|MD_SER
,
271 CMF_SEQ
|CMF_WR
|MD_CDL
|MD_CSE
|MD_IMM
, /* erase */
272 CMF_SEQ
|CMF_WR
|MD_CDL
|MD_CSE
, /* flush */
274 CMF_SEQ
|CMF_WR
|MD_CDL
|MD_CSE
|MD_IMM
, /* erase gap */
275 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 22-31 */
276 CMF_SEQ
|CMF_RW
|MD_CDL
|MD_CSE
|MD_REV
| /* compare */
277 MD_SCH
|MD_SEC
|MD_SER
,
278 CMF_SEQ
|CMF_RW
|MD_CDL
|MD_CSE
|MD_REV
|MD_CMP
| /* read */
279 MD_SCH
|MD_SEC
|MD_SER
,
280 CMF_SEQ
|CMF_RW
|CMF_WR
|MD_CDL
|MD_CSE
|MD_IMM
| /* write */
281 MD_CMP
|MD_ERW
|MD_SEC
|MD_SER
,
283 CMF_SEQ
|MD_CDL
|MD_CSE
|MD_IMM
, /* wr tape mark */
284 CMF_SEQ
|MD_CDL
|MD_CSE
|MD_IMM
|MD_OBC
| /* reposition */
285 MD_REV
|MD_RWD
|MD_DLE
|
286 MD_SCH
|MD_SEC
|MD_SER
,
287 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 38-47 */
288 0, 0, 0, 0, 0, 0, 0, 0,
289 0, 0, 0, 0, 0, 0, 0, 0
292 /* Forward references */
296 t_stat
tq_rd (int32
*data
, int32 PA
, int32 access
);
297 t_stat
tq_wr (int32 data
, int32 PA
, int32 access
);
298 t_stat
tq_inta (void);
299 t_stat
tq_svc (UNIT
*uptr
);
300 t_stat
tq_tmrsvc (UNIT
*uptr
);
301 t_stat
tq_quesvc (UNIT
*uptr
);
302 t_stat
tq_reset (DEVICE
*dptr
);
303 t_stat
tq_attach (UNIT
*uptr
, char *cptr
);
304 t_stat
tq_detach (UNIT
*uptr
);
305 t_stat
tq_boot (int32 unitno
, DEVICE
*dptr
);
306 t_stat
tq_set_wlk (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
);
307 t_stat
tq_set_size (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
);
308 t_stat
tq_show_ctrl (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
);
309 t_stat
tq_show_unitq (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
);
310 t_stat
tq_set_type (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
);
311 t_stat
tq_show_type (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
);
313 t_bool
tq_step4 (void);
314 t_bool
tq_mscp (int32 pkt
, t_bool q
);
315 t_bool
tq_abo (int32 pkt
);
316 t_bool
tq_avl (int32 pkt
);
317 t_bool
tq_erase (int32 pkt
);
318 t_bool
tq_flu (int32 pkt
);
319 t_bool
tq_gcs (int32 pkt
);
320 t_bool
tq_gus (int32 pkt
);
321 t_bool
tq_onl (int32 pkt
);
322 t_bool
tq_pos (int32 pkt
);
323 t_bool
tq_rw (int32 pkt
);
324 t_bool
tq_scc (int32 pkt
);
325 t_bool
tq_suc (int32 pkt
);
326 t_bool
tq_wtm (int32 pkt
);
327 t_bool
tq_plf (uint32 err
);
328 t_bool
tq_dte (UNIT
*uptr
, uint32 err
);
329 t_bool
tq_hbe (UNIT
*uptr
, uint32 ba
);
330 t_bool
tq_una (UNIT
*uptr
);
331 uint32
tq_map_status (UNIT
*uptr
, t_stat st
);
332 uint32
tq_spacef (UNIT
*uptr
, uint32 cnt
, uint32
*skipped
, t_bool qrec
);
333 uint32
tq_skipff (UNIT
*uptr
, uint32 cnt
, uint32
*skipped
);
334 uint32
tq_rdbuff (UNIT
*uptr
, t_mtrlnt
*tbc
);
335 uint32
tq_spacer (UNIT
*uptr
, uint32 cnt
, uint32
*skipped
, t_bool qrec
);
336 uint32
tq_skipfr (UNIT
*uptr
, uint32 cnt
, uint32
*skipped
);
337 uint32
tq_rdbufr (UNIT
*uptr
, t_mtrlnt
*tbc
);
338 t_bool
tq_deqf (int32
*pkt
);
339 int32
tq_deqh (int32
*lh
);
340 void tq_enqh (int32
*lh
, int32 pkt
);
341 void tq_enqt (int32
*lh
, int32 pkt
);
342 t_bool
tq_getpkt (int32
*pkt
);
343 t_bool
tq_putpkt (int32 pkt
, t_bool qt
);
344 t_bool
tq_getdesc (struct uq_ring
*ring
, uint32
*desc
);
345 t_bool
tq_putdesc (struct uq_ring
*ring
, uint32 desc
);
346 int32
tq_mot_valid (UNIT
*uptr
, uint32 cmd
);
347 t_stat
tq_mot_err (UNIT
*uptr
, uint32 rsiz
);
348 t_bool
tq_mot_end (UNIT
*uptr
, uint32 flg
, uint32 sts
, uint32 rsiz
);
349 void tq_putr (int32 pkt
, uint32 cmd
, uint32 flg
, uint32 sts
, uint32 lnt
, uint32 typ
);
350 void tq_putr_unit (int32 pkt
, UNIT
*uptr
, uint32 lu
, t_bool all
);
351 void tq_setf_unit (int32 pkt
, UNIT
*uptr
);
352 uint32
tq_efl (UNIT
*uptr
);
353 void tq_init_int (void);
354 void tq_ring_int (struct uq_ring
*ring
);
355 t_bool
tq_fatal (uint32 err
);
356 UNIT
*tq_getucb (uint32 lu
);
358 /* TQ data structures
360 tq_dev TQ device descriptor
362 tq_reg TQ register list
363 tq_mod TQ modifier list
367 IOBA_TQ
, IOLN_TQ
, &tq_rd
, &tq_wr
,
368 1, IVCL (TQ
), 0, { &tq_inta
}
372 { UDATA (&tq_svc
, UNIT_ATTABLE
+UNIT_DISABLE
+UNIT_ROABLE
, 0), INIT_CAP
},
373 { UDATA (&tq_svc
, UNIT_ATTABLE
+UNIT_DISABLE
+UNIT_ROABLE
, 0), INIT_CAP
},
374 { UDATA (&tq_svc
, UNIT_ATTABLE
+UNIT_DISABLE
+UNIT_ROABLE
, 0), INIT_CAP
},
375 { UDATA (&tq_svc
, UNIT_ATTABLE
+UNIT_DISABLE
+UNIT_ROABLE
, 0), INIT_CAP
},
376 { UDATA (&tq_tmrsvc
, UNIT_DIS
, 0) },
377 { UDATA (&tq_quesvc
, UNIT_DIS
, 0) }
380 #define TQ_TIMER (TQ_NUMDR)
381 #define TQ_QUEUE (TQ_TIMER + 1)
384 { GRDATA (SA
, tq_sa
, DEV_RDX
, 16, 0) },
385 { GRDATA (SAW
, tq_saw
, DEV_RDX
, 16, 0) },
386 { GRDATA (S1DAT
, tq_s1dat
, DEV_RDX
, 16, 0) },
387 { GRDATA (CQBA
, tq_cq
.ba
, DEV_RDX
, 22, 0) },
388 { GRDATA (CQLNT
, tq_cq
.lnt
, DEV_RDX
, 8, 2), REG_NZ
},
389 { GRDATA (CQIDX
, tq_cq
.idx
, DEV_RDX
, 8, 2) },
390 { GRDATA (TQBA
, tq_rq
.ba
, DEV_RDX
, 22, 0) },
391 { GRDATA (TQLNT
, tq_rq
.lnt
, DEV_RDX
, 8, 2), REG_NZ
},
392 { GRDATA (TQIDX
, tq_rq
.idx
, DEV_RDX
, 8, 2) },
393 { DRDATA (FREE
, tq_freq
, 5) },
394 { DRDATA (RESP
, tq_rspq
, 5) },
395 { DRDATA (PBSY
, tq_pbsy
, 5) },
396 { GRDATA (CFLGS
, tq_cflgs
, DEV_RDX
, 16, 0) },
397 { GRDATA (CSTA
, tq_csta
, DEV_RDX
, 4, 0) },
398 { GRDATA (PERR
, tq_perr
, DEV_RDX
, 9, 0) },
399 { DRDATA (CRED
, tq_credits
, 5) },
400 { DRDATA (HAT
, tq_hat
, 17) },
401 { DRDATA (HTMO
, tq_htmo
, 17) },
402 { URDATA (CPKT
, tq_unit
[0].cpkt
, 10, 5, 0, TQ_NUMDR
, 0) },
403 { URDATA (PKTQ
, tq_unit
[0].pktq
, 10, 5, 0, TQ_NUMDR
, 0) },
404 { URDATA (UFLG
, tq_unit
[0].uf
, DEV_RDX
, 16, 0, TQ_NUMDR
, 0) },
405 { URDATA (POS
, tq_unit
[0].pos
, 10, T_ADDR_W
, 0, TQ_NUMDR
, 0) },
406 { URDATA (OBJP
, tq_unit
[0].objp
, 10, 32, 0, TQ_NUMDR
, 0) },
407 { FLDATA (PRGI
, tq_prgi
, 0), REG_HIDDEN
},
408 { FLDATA (PIP
, tq_pip
, 0), REG_HIDDEN
},
409 { FLDATA (INT
, IREQ (TQ
), INT_V_TQ
) },
410 { DRDATA (ITIME
, tq_itime
, 24), PV_LEFT
+ REG_NZ
},
411 { DRDATA (I4TIME
, tq_itime4
, 24), PV_LEFT
+ REG_NZ
},
412 { DRDATA (QTIME
, tq_qtime
, 24), PV_LEFT
+ REG_NZ
},
413 { DRDATA (XTIME
, tq_xtime
, 24), PV_LEFT
+ REG_NZ
},
414 { BRDATA (PKTS
, tq_pkt
, DEV_RDX
, 16, TQ_NPKTS
* (TQ_PKT_SIZE_W
+ 1)) },
415 { DRDATA (DEVTYPE
, tq_typ
, 2), REG_HRO
},
416 { DRDATA (DEVCAP
, drv_tab
[TQU_TYPE
].cap
, T_ADDR_W
), PV_LEFT
| REG_HRO
},
417 { GRDATA (DEVADDR
, tq_dib
.ba
, DEV_RDX
, 32, 0), REG_HRO
},
418 { GRDATA (DEVVEC
, tq_dib
.vec
, DEV_RDX
, 16, 0), REG_HRO
},
423 { MTUF_WLK
, 0, "write enabled", "WRITEENABLED", NULL
},
424 { MTUF_WLK
, MTUF_WLK
, "write locked", "LOCKED", NULL
},
425 { MTAB_XTD
| MTAB_VDV
, TQ5_TYPE
, NULL
, "TK50",
426 &tq_set_type
, NULL
, NULL
},
427 { MTAB_XTD
| MTAB_VDV
, TQ7_TYPE
, NULL
, "TK70",
428 &tq_set_type
, NULL
, NULL
},
429 { MTAB_XTD
| MTAB_VDV
, TQ8_TYPE
, NULL
, "TU81",
430 &tq_set_type
, NULL
, NULL
},
431 { MTAB_XTD
| MTAB_VDV
, TQU_TYPE
, NULL
, "TKUSER",
432 &tq_set_type
, NULL
, NULL
},
433 { MTAB_XTD
| MTAB_VDV
, 0, "TYPE", NULL
,
434 NULL
, &tq_show_type
, NULL
},
435 { MTAB_XTD
| MTAB_VDV
| MTAB_NMO
, TQ_SH_RI
, "RINGS", NULL
,
436 NULL
, &tq_show_ctrl
, NULL
},
437 { MTAB_XTD
| MTAB_VDV
| MTAB_NMO
, TQ_SH_FR
, "FREEQ", NULL
,
438 NULL
, &tq_show_ctrl
, NULL
},
439 { MTAB_XTD
| MTAB_VDV
| MTAB_NMO
, TQ_SH_RS
, "RESPQ", NULL
,
440 NULL
, &tq_show_ctrl
, NULL
},
441 { MTAB_XTD
| MTAB_VDV
| MTAB_NMO
, TQ_SH_UN
, "UNITQ", NULL
,
442 NULL
, &tq_show_ctrl
, NULL
},
443 { MTAB_XTD
| MTAB_VDV
| MTAB_NMO
, TQ_SH_ALL
, "ALL", NULL
,
444 NULL
, &tq_show_ctrl
, NULL
},
445 { MTAB_XTD
| MTAB_VUN
| MTAB_NMO
, 0, "UNITQ", NULL
,
446 NULL
, &tq_show_unitq
, NULL
},
447 { MTAB_XTD
|MTAB_VUN
, 0, "FORMAT", "FORMAT",
448 &sim_tape_set_fmt
, &sim_tape_show_fmt
, NULL
},
449 #if defined (VM_PDP11)
450 { MTAB_XTD
|MTAB_VDV
, 004, "ADDRESS", "ADDRESS",
451 &set_addr
, &show_addr
, NULL
},
453 { MTAB_XTD
|MTAB_VDV
, 004, "ADDRESS", NULL
,
454 NULL
, &show_addr
, NULL
},
456 { MTAB_XTD
|MTAB_VDV
, 0, "VECTOR", NULL
,
457 NULL
, &show_vec
, NULL
},
462 "TQ", tq_unit
, tq_reg
, tq_mod
,
463 TQ_NUMDR
+ 2, 10, T_ADDR_W
, 1, DEV_RDX
, 8,
464 NULL
, NULL
, &tq_reset
,
465 &tq_boot
, &tq_attach
, &tq_detach
,
466 &tq_dib
, DEV_DISABLE
| DEV_UBUS
| DEV_QBUS
| DEV_DEBUG
469 /* I/O dispatch routines, I/O addresses 17772150 - 17772152
471 17772150 IP read/write
472 17772152 SA read/write
475 t_stat
tq_rd (int32
*data
, int32 PA
, int32 access
)
477 switch ((PA
>> 1) & 01) { /* decode PA<1> */
479 *data
= 0; /* reads zero */
480 if (tq_csta
== CST_S3_PPB
) tq_step4 (); /* waiting for poll? */
481 else if (tq_csta
== CST_UP
) { /* if up */
482 tq_pip
= 1; /* poll host */
483 sim_activate (&tq_unit
[TQ_QUEUE
], tq_qtime
);
495 t_stat
tq_wr (int32 data
, int32 PA
, int32 access
)
497 switch ((PA
>> 1) & 01) { /* decode PA<1> */
500 tq_reset (&tq_dev
); /* init device */
501 if (DEBUG_PRS (tq_dev
)) fprintf (sim_deb
,
502 ">>TQ: initialization started, time=%.0f\n", sim_gtime ());
507 if (tq_csta
< CST_S4
) /* stages 1-3 */
508 sim_activate (&tq_unit
[TQ_QUEUE
], tq_itime
);
509 else if (tq_csta
== CST_S4
) /* stage 4 (fast) */
510 sim_activate (&tq_unit
[TQ_QUEUE
], tq_itime4
);
517 /* Transition to step 4 - init communications region */
519 t_bool
tq_step4 (void)
523 uint16 zero
[SA_COMM_MAX
>> 1];
525 tq_rq
.ioff
= SA_COMM_RI
; /* set intr offset */
526 tq_rq
.ba
= tq_comm
; /* set rsp q base */
527 tq_rq
.lnt
= SA_S1H_RQ (tq_s1dat
) << 2; /* get resp q len */
528 tq_cq
.ioff
= SA_COMM_CI
; /* set intr offset */
529 tq_cq
.ba
= tq_comm
+ tq_rq
.lnt
; /* set cmd q base */
530 tq_cq
.lnt
= SA_S1H_CQ (tq_s1dat
) << 2; /* get cmd q len */
531 tq_cq
.idx
= tq_rq
.idx
= 0; /* clear q idx's */
532 if (tq_prgi
) base
= tq_comm
+ SA_COMM_QQ
;
533 else base
= tq_comm
+ SA_COMM_CI
;
534 lnt
= tq_comm
+ tq_cq
.lnt
+ tq_rq
.lnt
- base
; /* comm lnt */
535 if (lnt
> SA_COMM_MAX
) lnt
= SA_COMM_MAX
; /* paranoia */
536 for (i
= 0; i
< (lnt
>> 1); i
++) zero
[i
] = 0; /* clr buffer */
537 if (Map_WriteW (base
, lnt
, zero
)) /* zero comm area */
538 return tq_fatal (PE_QWE
); /* error? */
539 tq_sa
= SA_S4
| (drv_tab
[tq_typ
].uqpm
<< SA_S4C_V_MOD
) |/* send step 4 */
540 ((drv_tab
[tq_typ
].cver
& 0xFF) << SA_S4C_V_VER
);
541 tq_csta
= CST_S4
; /* set step 4 */
542 tq_init_int (); /* poke host */
546 /* Queue service - invoked when any of the queues (host queue, unit
547 queues, response queue) require servicing. Also invoked during
548 initialization to provide some delay to the next step.
550 Process at most one item off each unit queue
551 If the unit queues were empty, process at most one item off the host queue
552 Process at most one item off the response queue
554 If all queues are idle, terminate thread
557 t_stat
tq_quesvc (UNIT
*uptr
)
563 if (tq_csta
< CST_UP
) { /* still init? */
564 switch (tq_csta
) { /* controller state? */
566 case CST_S1
: /* need S1 reply */
567 if (tq_saw
& SA_S1H_VL
) { /* valid? */
568 if (tq_saw
& SA_S1H_WR
) { /* wrap? */
569 tq_sa
= tq_saw
; /* echo data */
570 tq_csta
= CST_S1_WR
; /* endless loop */
573 tq_s1dat
= tq_saw
; /* save data */
574 tq_dib
.vec
= (tq_s1dat
& SA_S1H_VEC
) << 2; /* get vector */
575 if (tq_dib
.vec
) tq_dib
.vec
= tq_dib
.vec
+ VEC_Q
; /* if nz, bias */
576 tq_sa
= SA_S2
| SA_S2C_PT
| SA_S2C_EC (tq_s1dat
);
577 tq_csta
= CST_S2
; /* now in step 2 */
578 tq_init_int (); /* intr if req */
583 case CST_S1_WR
: /* wrap mode */
584 tq_sa
= tq_saw
; /* echo data */
587 case CST_S2
: /* need S2 reply */
588 tq_comm
= tq_saw
& SA_S2H_CLO
; /* get low addr */
589 tq_prgi
= tq_saw
& SA_S2H_PI
; /* get purge int */
590 tq_sa
= SA_S3
| SA_S3C_EC (tq_s1dat
);
591 tq_csta
= CST_S3
; /* now in step 3 */
592 tq_init_int (); /* intr if req */
595 case CST_S3
: /* need S3 reply */
596 tq_comm
= ((tq_saw
& SA_S3H_CHI
) << 16) | tq_comm
;
597 if (tq_saw
& SA_S3H_PP
) { /* purge/poll test? */
598 tq_sa
= 0; /* put 0 */
599 tq_csta
= CST_S3_PPA
; /* wait for 0 write */
601 else tq_step4 (); /* send step 4 */
604 case CST_S3_PPA
: /* need purge test */
605 if (tq_saw
) tq_fatal (PE_PPF
); /* data not zero? */
606 else tq_csta
= CST_S3_PPB
; /* wait for poll */
609 case CST_S4
: /* need S4 reply */
610 if (tq_saw
& SA_S4H_GO
) { /* go set? */
611 if (DEBUG_PRS (tq_dev
)) fprintf (sim_deb
,
612 ">>TQ: initialization complete\n");
613 tq_csta
= CST_UP
; /* we're up */
614 tq_sa
= 0; /* clear SA */
615 sim_activate (&tq_unit
[TQ_TIMER
], tmr_poll
* clk_tps
);
616 if ((tq_saw
& SA_S4H_LF
) && tq_perr
) tq_plf (tq_perr
);
624 for (i
= 0; i
< TQ_NUMDR
; i
++) { /* chk unit q's */
625 nuptr
= tq_dev
.units
+ i
; /* ptr to unit */
626 if (nuptr
->cpkt
|| (nuptr
->pktq
== 0)) continue;
627 pkt
= tq_deqh (&nuptr
->pktq
); /* get top of q */
628 if (!tq_mscp (pkt
, FALSE
)) return SCPE_OK
; /* process */
630 if ((pkt
== 0) && tq_pip
) { /* polling? */
631 if (!tq_getpkt (&pkt
)) return SCPE_OK
; /* get host pkt */
632 if (pkt
) { /* got one? */
633 if (DEBUG_PRS (tq_dev
)) {
634 UNIT
*up
= tq_getucb (tq_pkt
[pkt
].d
[CMD_UN
]);
635 fprintf (sim_deb
, ">>TQ: cmd=%04X, mod=%04X, unit=%d, ",
636 tq_pkt
[pkt
].d
[CMD_OPC
], tq_pkt
[pkt
].d
[CMD_MOD
], tq_pkt
[pkt
].d
[CMD_UN
]);
637 fprintf (sim_deb
, "bc=%04X%04X, ma=%04X%04X",
638 tq_pkt
[pkt
].d
[RW_BCH
], tq_pkt
[pkt
].d
[RW_BCL
],
639 tq_pkt
[pkt
].d
[RW_BAH
], tq_pkt
[pkt
].d
[RW_BAL
]);
640 if (up
) fprintf (sim_deb
, ", pos=%d, obj=%d\n", up
->pos
, up
->objp
);
641 else fprintf (sim_deb
, "\n");
644 if (GETP (pkt
, UQ_HCTC
, TYP
) != UQ_TYP_SEQ
) /* seq packet? */
645 return tq_fatal (PE_PIE
); /* no, term thread */
646 cnid
= GETP (pkt
, UQ_HCTC
, CID
); /* get conn ID */
647 if (cnid
== UQ_CID_TMSCP
) { /* TMSCP packet? */
648 if (!tq_mscp (pkt
, TRUE
)) return SCPE_OK
; /* proc, q non-seq */
650 else if (cnid
== UQ_CID_DUP
) { /* DUP packet? */
651 tq_putr (pkt
, OP_END
, 0, ST_CMD
| I_OPCD
, RSP_LNT
, UQ_TYP_SEQ
);
652 if (!tq_putpkt (pkt
, TRUE
)) return SCPE_OK
; /* ill cmd */
654 else return tq_fatal (PE_ICI
); /* no, term thread */
656 else tq_pip
= 0; /* discontinue poll */
658 if (tq_rspq
) { /* resp q? */
659 pkt
= tq_deqh (&tq_rspq
); /* get top of q */
660 if (!tq_putpkt (pkt
, FALSE
)) return SCPE_OK
; /* send to host */
661 } /* end if resp q */
662 if (pkt
) sim_activate (&tq_unit
[TQ_QUEUE
], tq_qtime
); /* more to do? */
663 return SCPE_OK
; /* done */
666 /* Clock service (roughly once per second) */
668 t_stat
tq_tmrsvc (UNIT
*uptr
)
673 sim_activate (uptr
, tmr_poll
* clk_tps
); /* reactivate */
674 for (i
= 0; i
< TQ_NUMDR
; i
++) { /* poll */
675 nuptr
= tq_dev
.units
+ i
;
676 if ((nuptr
->flags
& UNIT_ATP
) && /* ATN pending? */
677 (nuptr
->flags
& UNIT_ATT
) && /* still online? */
678 (tq_cflgs
& CF_ATN
)) { /* wanted? */
679 if (!tq_una (nuptr
)) return SCPE_OK
;
681 nuptr
->flags
= nuptr
->flags
& ~UNIT_ATP
;
683 if ((tq_hat
> 0) && (--tq_hat
== 0)) /* host timeout? */
684 tq_fatal (PE_HAT
); /* fatal err */
688 /* MSCP packet handling */
690 t_bool
tq_mscp (int32 pkt
, t_bool q
)
693 uint32 cmd
= GETP (pkt
, CMD_OPC
, OPC
); /* command */
694 uint32 flg
= GETP (pkt
, CMD_OPC
, FLG
); /* flags */
695 uint32 mdf
= tq_pkt
[pkt
].d
[CMD_MOD
]; /* modifier */
696 uint32 lu
= tq_pkt
[pkt
].d
[CMD_UN
]; /* unit # */
699 if ((cmd
>= 64) || (tq_cmf
[cmd
] == 0)) { /* invalid cmd? */
700 cmd
= OP_END
; /* set end op */
701 sts
= ST_CMD
| I_OPCD
; /* ill op */
703 else if (flg
) { /* flags? */
704 cmd
= cmd
| OP_END
; /* set end flag */
705 sts
= ST_CMD
| I_FLAG
; /* ill flags */
707 else if (mdf
& ~tq_cmf
[cmd
]) { /* invalid mod? */
708 cmd
= cmd
| OP_END
; /* set end flag */
709 sts
= ST_CMD
| I_MODF
; /* ill mods */
711 else { /* valid cmd */
712 if (uptr
= tq_getucb (lu
)) { /* valid unit? */
713 if (q
&& (tq_cmf
[cmd
] & CMF_SEQ
) && /* queueing, seq, */
714 (uptr
->cpkt
|| uptr
->pktq
)) { /* and active? */
715 tq_enqt (&uptr
->pktq
, pkt
); /* do later */
718 /* if (tq_cmf[cmd] & MD_CDL) /* clr cch lost? */
719 /* uptr->flags = uptr->flags & ~UNIT_CDL; */
720 if (tq_cmf
[cmd
] & MD_CSE
) /* clr ser exc? */
721 uptr
->flags
= uptr
->flags
& ~UNIT_SXC
;
725 case OP_ABO
: /* abort */
728 case OP_AVL
: /* avail */
731 case OP_GCS
: /* get cmd status */
734 case OP_GUS
: /* get unit status */
737 case OP_ONL
: /* online */
740 case OP_SCC
: /* set ctrl char */
743 case OP_SUC
: /* set unit char */
746 case OP_ERS
: /* erase */
747 case OP_ERG
: /* erase gap */
748 return tq_erase (pkt
);
750 case OP_FLU
: /* flush */
753 case OP_POS
: /* position */
756 case OP_WTM
: /* write tape mark */
759 case OP_ACC
: /* access */
760 case OP_CMP
: /* compare */
761 case OP_RD
: /* read */
762 case OP_WR
: /* write */
766 cmd
= cmd
| OP_END
; /* set end flag */
767 sts
= ST_SUC
; /* success */
771 cmd
= OP_END
; /* set end op */
772 sts
= ST_CMD
| I_OPCD
; /* ill op */
776 tq_putr (pkt
, cmd
, 0, sts
, RSP_LNT
, UQ_TYP_SEQ
);
777 return tq_putpkt (pkt
, TRUE
);
780 /* Abort a command - 1st parameter is ref # of cmd to abort */
782 t_bool
tq_abo (int32 pkt
)
784 uint32 lu
= tq_pkt
[pkt
].d
[CMD_UN
]; /* unit # */
785 uint32 ref
= GETP32 (pkt
, ABO_REFL
); /* cmd ref # */
789 tpkt
= 0; /* set no mtch */
790 if (uptr
= tq_getucb (lu
)) { /* get unit */
791 if (uptr
->cpkt
&& /* curr pkt? */
792 (GETP32 (uptr
->cpkt
, CMD_REFL
) == ref
)) { /* match ref? */
793 tpkt
= uptr
->cpkt
; /* save match */
794 uptr
->cpkt
= 0; /* gonzo */
795 sim_cancel (uptr
); /* cancel unit */
796 sim_activate (&tq_unit
[TQ_QUEUE
], tq_qtime
);
798 else if (uptr
->pktq
&& /* head of q? */
799 (GETP32 (uptr
->pktq
, CMD_REFL
) == ref
)) { /* match ref? */
800 tpkt
= uptr
->pktq
; /* save match */
801 uptr
->pktq
= tq_pkt
[tpkt
].link
; /* unlink */
803 else if (prv
= uptr
->pktq
) { /* srch pkt q */
804 while (tpkt
= tq_pkt
[prv
].link
) { /* walk list */
805 if (GETP32 (tpkt
, RSP_REFL
) == ref
) { /* match ref? */
806 tq_pkt
[prv
].link
= tq_pkt
[tpkt
].link
; /* unlink */
811 if (tpkt
) { /* found target? */
812 uint32 tcmd
= GETP (tpkt
, CMD_OPC
, OPC
); /* get opcode */
813 tq_putr (tpkt
, tcmd
| OP_END
, 0, ST_ABO
, RSP_LNT
, UQ_TYP_SEQ
);
814 if (!tq_putpkt (tpkt
, TRUE
)) return ERR
;
817 tq_putr (pkt
, OP_ABO
| OP_END
, 0, ST_SUC
, ABO_LNT
, UQ_TYP_SEQ
);
818 return tq_putpkt (pkt
, TRUE
);
821 /* Unit available - set unit status to available
822 Deferred if q'd cmds, bypassed if ser exc */
824 t_bool
tq_avl (int32 pkt
)
826 uint32 lu
= tq_pkt
[pkt
].d
[CMD_UN
]; /* unit # */
827 uint32 mdf
= tq_pkt
[pkt
].d
[CMD_MOD
]; /* modifiers */
831 if (uptr
= tq_getucb (lu
)) { /* unit exist? */
832 if (uptr
->flags
& UNIT_SXC
) sts
= ST_SXC
; /* ser exc pending? */
834 uptr
->flags
= uptr
->flags
& ~(UNIT_ONL
| UNIT_TMK
| UNIT_POL
);
835 sim_tape_rewind (uptr
); /* rewind */
836 uptr
->uf
= uptr
->objp
= 0; /* clr flags */
837 if (uptr
->flags
& UNIT_ATT
) { /* attached? */
838 sts
= ST_SUC
; /* success */
839 if (mdf
& MD_UNL
) tq_detach (uptr
); /* unload? */
841 else sts
= ST_OFL
| SB_OFL_NV
; /* no, offline */
844 else sts
= ST_OFL
; /* offline */
845 tq_putr (pkt
, OP_AVL
| OP_END
, tq_efl (uptr
), sts
, AVL_LNT
, UQ_TYP_SEQ
);
846 return tq_putpkt (pkt
, TRUE
);
849 /* Get command status - only interested in active xfr cmd */
851 t_bool
tq_gcs (int32 pkt
)
853 uint32 lu
= tq_pkt
[pkt
].d
[CMD_UN
]; /* unit # */
854 uint32 ref
= GETP32 (pkt
, GCS_REFL
); /* ref # */
858 if ((uptr
= tq_getucb (lu
)) && /* valid lu? */
859 (tpkt
= uptr
->cpkt
) && /* queued pkt? */
860 (GETP32 (tpkt
, CMD_REFL
) == ref
) && /* match ref? */
861 (tq_cmf
[GETP (tpkt
, CMD_OPC
, OPC
)] & CMF_RW
)) { /* rd/wr cmd? */
862 tq_pkt
[pkt
].d
[GCS_STSL
] = tq_pkt
[tpkt
].d
[RW_BCL
];
863 tq_pkt
[pkt
].d
[GCS_STSH
] = tq_pkt
[tpkt
].d
[RW_BCH
];
865 else tq_pkt
[pkt
].d
[GCS_STSL
] = tq_pkt
[pkt
].d
[GCS_STSH
] = 0;
866 tq_putr (pkt
, OP_GCS
| OP_END
, 0, ST_SUC
, GCS_LNT
, UQ_TYP_SEQ
);
867 return tq_putpkt (pkt
, TRUE
);
870 /* Get unit status */
872 t_bool
tq_gus (int32 pkt
)
874 uint32 lu
= tq_pkt
[pkt
].d
[CMD_UN
]; /* unit # */
878 if (tq_pkt
[pkt
].d
[CMD_MOD
] & MD_NXU
) { /* next unit? */
879 if (lu
>= TQ_NUMDR
) { /* end of range? */
880 lu
= 0; /* reset to 0 */
881 tq_pkt
[pkt
].d
[RSP_UN
] = lu
;
884 if (uptr
= tq_getucb (lu
)) { /* unit exist? */
885 if ((uptr
->flags
& UNIT_ATT
) == 0) /* not attached? */
886 sts
= ST_OFL
| SB_OFL_NV
; /* offl no vol */
887 else if (uptr
->flags
& UNIT_ONL
) sts
= ST_SUC
; /* online */
888 else sts
= ST_AVL
; /* avail */
889 tq_putr_unit (pkt
, uptr
, lu
, FALSE
); /* fill unit fields */
890 tq_pkt
[pkt
].d
[GUS_MENU
] = drv_tab
[tq_typ
].fmt
; /* format menu */
891 tq_pkt
[pkt
].d
[GUS_CAP
] = 0; /* free capacity */
892 tq_pkt
[pkt
].d
[GUS_FVER
] = drv_tab
[tq_typ
].fver
; /* formatter version */
893 tq_pkt
[pkt
].d
[GUS_UVER
] = drv_tab
[tq_typ
].uver
; /* unit version */
895 else sts
= ST_OFL
; /* offline */
896 tq_putr (pkt
, OP_GUS
| OP_END
, tq_efl (uptr
), sts
, GUS_LNT_T
, UQ_TYP_SEQ
);
897 return tq_putpkt (pkt
, TRUE
);
900 /* Unit online - deferred if q'd commands */
902 t_bool
tq_onl (int32 pkt
)
904 uint32 lu
= tq_pkt
[pkt
].d
[CMD_UN
]; /* unit # */
908 if (uptr
= tq_getucb (lu
)) { /* unit exist? */
909 if ((uptr
->flags
& UNIT_ATT
) == 0) /* not attached? */
910 sts
= ST_OFL
| SB_OFL_NV
; /* offl no vol */
911 else if (uptr
->flags
& UNIT_ONL
) /* already online? */
912 sts
= ST_SUC
| SB_SUC_ON
;
914 sts
= ST_SUC
; /* mark online */
915 sim_tape_rewind (uptr
); /* rewind */
916 uptr
->objp
= 0; /* clear flags */
917 uptr
->flags
= (uptr
->flags
| UNIT_ONL
) &
918 ~(UNIT_TMK
| UNIT_POL
); /* onl, pos ok */
919 tq_setf_unit (pkt
, uptr
); /* hack flags */
921 tq_putr_unit (pkt
, uptr
, lu
, TRUE
); /* set fields */
923 else sts
= ST_OFL
; /* offline */
924 tq_putr (pkt
, OP_ONL
| OP_END
, tq_efl (uptr
), sts
, ONL_LNT
, UQ_TYP_SEQ
);
925 return tq_putpkt (pkt
, TRUE
);
928 /* Set controller characteristics */
930 t_bool
tq_scc (int32 pkt
)
932 if (tq_pkt
[pkt
].d
[SCC_MSV
]) /* MSCP ver = 0? */
933 tq_putr (pkt
, 0, 0, ST_CMD
| I_VRSN
, SCC_LNT
, UQ_TYP_SEQ
);
935 tq_cflgs
= (tq_cflgs
& CF_RPL
) | /* hack ctrl flgs */
936 tq_pkt
[pkt
].d
[SCC_CFL
];
937 if (tq_htmo
= tq_pkt
[pkt
].d
[SCC_TMO
]) /* set timeout */
938 tq_htmo
= tq_htmo
+ 2; /* if nz, round up */
939 tq_pkt
[pkt
].d
[SCC_CFL
] = tq_cflgs
; /* return flags */
940 tq_pkt
[pkt
].d
[SCC_TMO
] = TQ_DCTMO
; /* ctrl timeout */
941 tq_pkt
[pkt
].d
[SCC_VER
] = drv_tab
[tq_typ
].cver
; /* ctrl version */
942 tq_pkt
[pkt
].d
[SCC_CIDA
] = 0; /* ctrl ID */
943 tq_pkt
[pkt
].d
[SCC_CIDB
] = 0;
944 tq_pkt
[pkt
].d
[SCC_CIDC
] = 0;
945 tq_pkt
[pkt
].d
[SCC_CIDD
] = (TQ_CLASS
<< SCC_CIDD_V_CLS
) |
946 (drv_tab
[tq_typ
].cmod
<< SCC_CIDD_V_MOD
);
947 PUTP32 (pkt
, SCC_MBCL
, TQ_MAXFR
); /* max bc */
948 tq_putr (pkt
, OP_SCC
| OP_END
, 0, ST_SUC
, SCC_LNT
, UQ_TYP_SEQ
);
950 return tq_putpkt (pkt
, TRUE
);
953 /* Set unit characteristics - defer if q'd commands */
955 t_bool
tq_suc (int32 pkt
)
957 uint32 lu
= tq_pkt
[pkt
].d
[CMD_UN
]; /* unit # */
961 if (uptr
= tq_getucb (lu
)) { /* unit exist? */
962 if ((uptr
->flags
& UNIT_ATT
) == 0) /* not attached? */
963 sts
= ST_OFL
| SB_OFL_NV
; /* offl no vol */
965 sts
= ST_SUC
; /* avail or onl */
966 tq_setf_unit (pkt
, uptr
); /* hack flags */
968 tq_putr_unit (pkt
, uptr
, lu
, TRUE
); /* set fields */
970 else sts
= ST_OFL
; /* offline */
971 tq_putr (pkt
, OP_SUC
| OP_END
, 0, sts
, SUC_LNT
, UQ_TYP_SEQ
);
972 return tq_putpkt (pkt
, TRUE
);
975 /* Flush - sequential nop - deferred if q'd cmds, bypassed if ser exc */
977 t_bool
tq_flu (int32 pkt
)
979 uint32 lu
= tq_pkt
[pkt
].d
[CMD_UN
]; /* unit # */
983 if (uptr
= tq_getucb (lu
)) /* unit exist? */
984 sts
= tq_mot_valid (uptr
, OP_FLU
); /* validate req */
985 else sts
= ST_OFL
; /* offline */
986 tq_putr (pkt
, OP_FLU
| OP_END
, tq_efl (uptr
), sts
, FLU_LNT
, UQ_TYP_SEQ
);
987 return tq_putpkt (pkt
, TRUE
);
990 /* Erase, erase gap - deferred if q'd cmds, bypassed if ser exc */
992 t_bool
tq_erase (int32 pkt
)
994 uint32 lu
= tq_pkt
[pkt
].d
[CMD_UN
]; /* unit # */
995 uint32 cmd
= GETP (pkt
, CMD_OPC
, OPC
); /* opcode */
999 if (uptr
= tq_getucb (lu
)) { /* unit exist? */
1000 sts
= tq_mot_valid (uptr
, cmd
); /* validity checks */
1001 if (sts
== ST_SUC
) { /* ok? */
1002 uptr
->cpkt
= pkt
; /* op in progress */
1003 sim_activate (uptr
, tq_xtime
); /* activate */
1004 return OK
; /* done */
1007 else sts
= ST_OFL
; /* offline */
1008 tq_putr (pkt
, cmd
| OP_END
, tq_efl (uptr
), sts
, ERS_LNT
, UQ_TYP_SEQ
);
1009 return tq_putpkt (pkt
, TRUE
);
1012 /* Write tape mark - deferred if q'd cmds, bypassed if ser exc */
1014 t_bool
tq_wtm (int32 pkt
)
1016 uint32 lu
= tq_pkt
[pkt
].d
[CMD_UN
]; /* unit # */
1017 uint32 sts
, objp
= 0;
1020 if (uptr
= tq_getucb (lu
)) { /* unit exist? */
1021 objp
= uptr
->objp
; /* position op */
1022 sts
= tq_mot_valid (uptr
, OP_WTM
); /* validity checks */
1023 if (sts
== ST_SUC
) { /* ok? */
1024 uptr
->cpkt
= pkt
; /* op in progress */
1025 sim_activate (uptr
, tq_xtime
); /* activate */
1026 return OK
; /* done */
1029 else sts
= ST_OFL
; /* offline */
1030 PUTP32 (pkt
, WTM_POSL
, objp
); /* set obj pos */
1031 tq_putr (pkt
, OP_WTM
| OP_END
, tq_efl (uptr
), sts
, WTM_LNT
, UQ_TYP_SEQ
);
1032 return tq_putpkt (pkt
, TRUE
);
1035 /* Position - deferred if q'd cmds, bypassed if ser exc */
1037 t_bool
tq_pos (int32 pkt
)
1039 uint32 lu
= tq_pkt
[pkt
].d
[CMD_UN
]; /* unit # */
1040 uint32 sts
, objp
= 0;
1043 if (uptr
= tq_getucb (lu
)) { /* unit exist? */
1044 objp
= uptr
->objp
; /* position op */
1045 sts
= tq_mot_valid (uptr
, OP_POS
); /* validity checks */
1046 if (sts
== ST_SUC
) { /* ok? */
1047 uptr
->cpkt
= pkt
; /* op in progress */
1048 sim_activate (uptr
, tq_xtime
); /* activate */
1049 return OK
; /* done */
1052 else sts
= ST_OFL
; /* offline */
1053 PUTP32 (pkt
, POS_RCL
, 0); /* clear #skipped */
1054 PUTP32 (pkt
, POS_TMCL
, 0);
1055 PUTP32 (pkt
, POS_POSL
, objp
); /* set obj pos */
1056 tq_putr (pkt
, OP_POS
| OP_END
, tq_efl (uptr
), sts
, POS_LNT
, UQ_TYP_SEQ
);
1057 return tq_putpkt (pkt
, TRUE
);
1060 /* Data transfer commands - deferred if q'd commands, bypassed if ser exc */
1062 t_bool
tq_rw (int32 pkt
)
1064 uint32 lu
= tq_pkt
[pkt
].d
[CMD_UN
]; /* unit # */
1065 uint32 cmd
= GETP (pkt
, CMD_OPC
, OPC
); /* opcode */
1066 uint32 bc
= GETP32 (pkt
, RW_BCL
); /* byte count */
1067 uint32 sts
, objp
= 0;
1070 if (uptr
= tq_getucb (lu
)) { /* unit exist? */
1071 objp
= uptr
->objp
; /* position op */
1072 sts
= tq_mot_valid (uptr
, cmd
); /* validity checks */
1073 if (sts
== ST_SUC
) { /* ok? */
1074 if ((bc
== 0) || (bc
> TQ_MAXFR
)) { /* invalid? */
1075 uptr
->flags
= uptr
->flags
| UNIT_SXC
; /* set ser exc */
1076 sts
= ST_CMD
| I_BCNT
;
1079 uptr
->cpkt
= pkt
; /* op in progress */
1080 sim_activate (uptr
, tq_xtime
); /* activate */
1081 return OK
; /* done */
1085 else sts
= ST_OFL
; /* offline */
1086 PUTP32 (pkt
, RW_BCL
, 0); /* no bytes processed */
1087 PUTP32 (pkt
, RW_POSL
, objp
); /* set obj pos */
1088 PUTP32 (pkt
, RW_RSZL
, 0); /* clr rec size */
1089 tq_putr (pkt
, cmd
| OP_END
, tq_efl (uptr
), sts
, RW_LNT_T
, UQ_TYP_SEQ
);
1090 return tq_putpkt (pkt
, TRUE
);
1093 /* Validity checks */
1095 int32
tq_mot_valid (UNIT
*uptr
, uint32 cmd
)
1097 if (uptr
->flags
& UNIT_SXC
) return ST_SXC
; /* ser exc pend? */
1098 if ((uptr
->flags
& UNIT_ATT
) == 0) /* not attached? */
1099 return (ST_OFL
| SB_OFL_NV
); /* offl no vol */
1100 if ((uptr
->flags
& UNIT_ONL
) == 0) /* not online? */
1101 return ST_AVL
; /* only avail */
1102 if (tq_cmf
[cmd
] & CMF_WR
) { /* write op? */
1103 if (uptr
->uf
& UF_WPS
) { /* swre wlk? */
1104 uptr
->flags
= uptr
->flags
| UNIT_SXC
; /* set ser exc */
1105 return (ST_WPR
| SB_WPR_SW
);
1107 if (TQ_WPH (uptr
)) { /* hwre wlk? */
1108 uptr
->flags
= uptr
->flags
| UNIT_SXC
; /* set ser exc */
1109 return (ST_WPR
| SB_WPR_HW
);
1112 return ST_SUC
; /* success! */
1115 /* Unit service for motion commands */
1117 t_stat
tq_svc (UNIT
*uptr
)
1119 uint32 t
, sts
, sktmk
, skrec
;
1120 t_mtrlnt i
, tbc
, wbc
;
1121 int32 pkt
= uptr
->cpkt
; /* get packet */
1122 uint32 cmd
= GETP (pkt
, CMD_OPC
, OPC
); /* get cmd */
1123 uint32 mdf
= tq_pkt
[pkt
].d
[CMD_MOD
]; /* modifier */
1124 uint32 ba
= GETP32 (pkt
, RW_BAL
); /* buf addr */
1125 t_mtrlnt bc
= GETP32 (pkt
, RW_BCL
); /* byte count */
1126 uint32 nrec
= GETP32 (pkt
, POS_RCL
); /* #rec to skip */
1127 uint32 ntmk
= GETP32 (pkt
, POS_TMCL
); /* #tmk to skp */
1129 if (pkt
== 0) return SCPE_IERR
; /* what??? */
1130 if ((uptr
->flags
& UNIT_ATT
) == 0) { /* not attached? */
1131 tq_mot_end (uptr
, 0, ST_OFL
| SB_OFL_NV
, 0); /* offl no vol */
1135 if (tq_cmf
[cmd
] & CMF_WR
) { /* write op? */
1136 if (TQ_WPH (uptr
)) { /* hwre write prot? */
1137 uptr
->flags
= uptr
->flags
| UNIT_SXC
; /* set ser exc */
1138 tq_mot_end (uptr
, 0, ST_WPR
| SB_WPR_HW
, 0);
1141 if (uptr
->uf
& UF_WPS
) { /* swre write prot? */
1142 uptr
->flags
= uptr
->flags
| UNIT_SXC
; /* set ser exc */
1143 tq_mot_end (uptr
, 0, ST_WPR
| SB_WPR_SW
, 0);
1147 sts
= ST_SUC
; /* assume success */
1148 tbc
= 0; /* assume zero rec */
1149 switch (cmd
) { /* case on command */
1151 case OP_RD
:case OP_ACC
:case OP_CMP
: /* read-like op */
1152 if (mdf
& MD_REV
) sts
= tq_rdbufr (uptr
, &tbc
); /* read record */
1153 else sts
= tq_rdbuff (uptr
, &tbc
);
1154 if (sts
== ST_DRV
) { /* read error? */
1155 PUTP32 (pkt
, RW_BCL
, 0); /* no bytes processed */
1156 return tq_mot_err (uptr
, tbc
); /* log, done */
1158 if ((sts
!= ST_SUC
) || (cmd
== OP_ACC
)) { /* error or access? */
1159 PUTP32 (pkt
, RW_BCL
, 0); /* no bytes processed */
1162 if (tbc
> bc
) { /* tape rec > buf? */
1163 uptr
->flags
= uptr
->flags
| UNIT_SXC
; /* serious exc */
1164 sts
= ST_RDT
; /* data truncated */
1165 wbc
= bc
; /* set working bc */
1168 if (cmd
== OP_RD
) { /* read? */
1169 if (t
= Map_WriteB (ba
, wbc
, tqxb
)) { /* store, nxm? */
1170 PUTP32 (pkt
, RW_BCL
, wbc
- t
); /* adj bc */
1171 if (tq_hbe (uptr
, ba
+ wbc
- t
)) /* post err log */
1172 tq_mot_end (uptr
, EF_LOG
, ST_HST
| SB_HST_NXM
, tbc
);
1173 return SCPE_OK
; /* end if nxm */
1176 else { /* compare */
1179 for (i
= 0; i
< wbc
; i
++) { /* loop */
1180 if (mdf
& MD_REV
) { /* reverse? */
1181 mba
= ba
+ bc
- 1 - i
; /* mem addr */
1182 dby
= tqxb
[tbc
- 1 - i
]; /* byte */
1188 if (Map_ReadB (mba
, 1, &mby
)) { /* fetch, nxm? */
1189 PUTP32 (pkt
, RW_BCL
, i
); /* adj bc */
1190 if (tq_hbe (uptr
, mba
)) /* post err log */
1191 tq_mot_end (uptr
, EF_LOG
, ST_HST
| SB_HST_NXM
, tbc
);
1194 if (mby
!= dby
) { /* cmp err? */
1195 uptr
->flags
= uptr
->flags
| UNIT_SXC
; /* ser exc */
1196 PUTP32 (pkt
, RW_BCL
, i
); /* adj bc */
1197 tq_mot_end (uptr
, 0, ST_CMP
, tbc
);
1198 return SCPE_OK
; /* exit */
1201 } /* end if compare */
1202 PUTP32 (pkt
, RW_BCL
, wbc
); /* bytes read/cmp'd */
1205 case OP_WR
: /* write */
1206 if (t
= Map_ReadB (ba
, bc
, tqxb
)) { /* fetch buf, nxm? */
1207 PUTP32 (pkt
, RW_BCL
, 0); /* no bytes xfer'd */
1208 if (tq_hbe (uptr
, ba
+ bc
- t
)) /* post err log */
1209 tq_mot_end (uptr
, EF_LOG
, ST_HST
| SB_HST_NXM
, bc
);
1210 return SCPE_OK
; /* end else wr */
1212 if (sim_tape_wrrecf (uptr
, tqxb
, bc
)) /* write rec fwd, err? */
1213 return tq_mot_err (uptr
, bc
); /* log, end */
1214 uptr
->objp
= uptr
->objp
+ 1; /* upd obj pos */
1215 if (TEST_EOT (uptr
)) /* EOT on write? */
1216 uptr
->flags
= uptr
->flags
| UNIT_SXC
;
1217 uptr
->flags
= uptr
->flags
& ~UNIT_TMK
; /* disable LEOT */
1218 tbc
= bc
; /* RW_BC is ok */
1221 case OP_WTM
: /* write tape mark */
1222 if (sim_tape_wrtmk (uptr
)) /* write tmk, err? */
1223 return tq_mot_err (uptr
, 0); /* log, end */
1224 uptr
->objp
= uptr
->objp
+ 1; /* incr obj cnt */
1225 case OP_ERG
: /* erase gap */
1226 if (TEST_EOT (uptr
)) /* EOT on write? */
1227 uptr
->flags
= uptr
->flags
| UNIT_SXC
;
1228 uptr
->flags
= uptr
->flags
& ~UNIT_TMK
; /* disable LEOT */
1231 case OP_ERS
: /* erase */
1232 if (sim_tape_wreom (uptr
)) /* write eom, err? */
1233 return tq_mot_err (uptr
, 0); /* log, end */
1234 sim_tape_rewind (uptr
); /* rewind */
1236 uptr
->flags
= uptr
->flags
& ~(UNIT_TMK
| UNIT_POL
);
1239 case OP_POS
: /* position */
1240 sktmk
= skrec
= 0; /* clr skipped */
1241 if (mdf
& MD_RWD
) { /* rewind? */
1242 sim_tape_rewind (uptr
);
1243 uptr
->objp
= 0; /* clr flags */
1244 uptr
->flags
= uptr
->flags
& ~(UNIT_TMK
| UNIT_POL
);
1246 if (mdf
& MD_OBC
) { /* skip obj? */
1247 if (mdf
& MD_REV
) /* reverse? */
1248 sts
= tq_spacer (uptr
, nrec
, &skrec
, FALSE
);
1249 else sts
= tq_spacef (uptr
, nrec
, &skrec
, FALSE
);
1251 else { /* skip tmk, rec */
1252 if (mdf
& MD_REV
) sts
= tq_skipfr (uptr
, ntmk
, &sktmk
);
1253 else sts
= tq_skipff (uptr
, ntmk
, &sktmk
);
1254 if (sts
== ST_SUC
) { /* tmk succeed? */
1255 if (mdf
& MD_REV
) /* reverse? */
1256 sts
= tq_spacer (uptr
, nrec
, &skrec
, TRUE
);
1257 else sts
= tq_spacef (uptr
, nrec
, &skrec
, TRUE
);
1258 if (sts
== ST_TMK
) sktmk
= sktmk
+ 1;
1261 PUTP32 (pkt
, POS_RCL
, skrec
); /* #rec skipped */
1262 PUTP32 (pkt
, POS_TMCL
, sktmk
); /* #tmk skipped */
1269 tq_mot_end (uptr
, 0, sts
, tbc
); /* done */
1273 /* Motion command drive error */
1275 t_stat
tq_mot_err (UNIT
*uptr
, uint32 rsiz
)
1277 uptr
->flags
= (uptr
->flags
| UNIT_SXC
) & ~UNIT_TMK
; /* serious exception */
1278 if (tq_dte (uptr
, ST_DRV
)) /* post err log */
1279 tq_mot_end (uptr
, EF_LOG
, ST_DRV
, rsiz
); /* if ok, report err */
1280 perror ("TQ I/O error");
1281 clearerr (uptr
->fileref
);
1285 /* Motion command complete */
1287 t_bool
tq_mot_end (UNIT
*uptr
, uint32 flg
, uint32 sts
, uint32 rsiz
)
1289 int32 pkt
= uptr
->cpkt
; /* packet */
1290 uint32 cmd
= GETP (pkt
, CMD_OPC
, OPC
); /* get cmd */
1291 uint32 lnt
= RW_LNT_T
; /* assume rw */
1293 if (cmd
== OP_ERG
) lnt
= ERG_LNT
; /* set pkt lnt */
1294 else if (cmd
== OP_ERS
) lnt
= ERS_LNT
;
1295 else if (cmd
== OP_WTM
) lnt
= WTM_LNT
;
1296 else if (cmd
== OP_POS
) lnt
= POS_LNT
;
1298 uptr
->cpkt
= 0; /* done */
1299 if (lnt
> ERG_LNT
) { /* xfer cmd? */
1300 PUTP32 (pkt
, RW_POSL
, uptr
->objp
); /* position */
1301 PUTP32 (pkt
, RW_RSZL
, rsiz
); /* record size */
1303 tq_putr (pkt
, cmd
| OP_END
, flg
| tq_efl (uptr
), sts
, lnt
, UQ_TYP_SEQ
);
1304 if (!tq_putpkt (pkt
, TRUE
)) return ERR
; /* send pkt */
1305 if (uptr
->pktq
) /* more to do? */
1306 sim_activate (&tq_unit
[TQ_QUEUE
], tq_qtime
); /* activate thread */
1310 /* Tape motion routines */
1312 uint32
tq_map_status (UNIT
*uptr
, t_stat st
)
1320 uptr
->flags
= uptr
->flags
| UNIT_SXC
;
1321 return (ST_OFL
| SB_OFL_NV
);
1324 uptr
->flags
= uptr
->flags
| UNIT_SXC
;
1328 uptr
->flags
= uptr
->flags
| UNIT_SXC
;
1332 uptr
->flags
= uptr
->flags
| UNIT_SXC
| UNIT_POL
;
1337 uptr
->flags
= uptr
->flags
| UNIT_SXC
| UNIT_POL
;
1341 uptr
->flags
= uptr
->flags
| UNIT_SXC
| UNIT_POL
;
1345 uptr
->flags
= (uptr
->flags
| UNIT_SXC
) & ~UNIT_POL
;
1349 uptr
->flags
= uptr
->flags
| UNIT_SXC
;
1356 uint32
tq_spacef (UNIT
*uptr
, uint32 cnt
, uint32
*skipped
, t_bool qrec
)
1362 while (*skipped
< cnt
) { /* loop */
1363 st
= sim_tape_sprecf (uptr
, &tbc
); /* space rec fwd */
1364 if ((st
!= MTSE_OK
) && (st
!= MTSE_TMK
)) /* real error? */
1365 return tq_map_status (uptr
, st
); /* map status */
1366 uptr
->objp
= uptr
->objp
+ 1; /* upd obj cnt */
1367 if (st
== MTSE_TMK
) { /* tape mark? */
1368 int32 pkt
= uptr
->cpkt
; /* get pkt */
1369 if ((tq_pkt
[pkt
].d
[CMD_MOD
] & MD_DLE
) && /* LEOT? */
1370 (uptr
->flags
& UNIT_TMK
)) {
1371 sim_tape_sprecr (uptr
, &tbc
); /* rev over tmk */
1372 uptr
->flags
= uptr
->flags
| UNIT_SXC
; /* serious exc */
1375 uptr
->flags
= uptr
->flags
| UNIT_TMK
; /* set TM seen */
1376 if (qrec
) return ST_TMK
; /* rec spc? stop */
1378 else uptr
->flags
= uptr
->flags
& ~UNIT_TMK
; /* clr TM seen */
1379 *skipped
= *skipped
+ 1; /* # obj skipped */
1384 uint32
tq_skipff (UNIT
*uptr
, uint32 cnt
, uint32
*skipped
)
1389 while (*skipped
< cnt
) { /* loop */
1390 st
= tq_spacef (uptr
, 0x7FFFFFFF, &skrec
, TRUE
); /* rec spc fwd */
1391 if (st
== ST_TMK
) *skipped
= *skipped
+ 1; /* count files */
1392 else if (st
!= ST_SUC
) return st
;
1397 uint32
tq_spacer (UNIT
*uptr
, uint32 cnt
, uint32
*skipped
, t_bool qrec
)
1403 while (*skipped
< cnt
) { /* loop */
1404 st
= sim_tape_sprecr (uptr
, &tbc
); /* spc rec rev */
1405 if ((st
!= MTSE_OK
) && (st
!= MTSE_TMK
)) /* real error? */
1406 return tq_map_status (uptr
, st
); /* map status */
1407 uptr
->objp
= uptr
->objp
- 1; /* upd obj cnt */
1408 if ((st
== MTSE_TMK
) && qrec
) return ST_TMK
; /* tape mark, stop? */
1409 *skipped
= *skipped
+ 1; /* # obj skipped */
1414 uint32
tq_skipfr (UNIT
*uptr
, uint32 cnt
, uint32
*skipped
)
1419 while (*skipped
< cnt
) { /* loopo */
1420 st
= tq_spacer (uptr
, 0x7FFFFFFF, &skrec
, TRUE
); /* rec spc rev */
1421 if (st
== ST_TMK
) *skipped
= *skipped
+ 1; /* tape mark? */
1422 else if (st
!= 0) return st
; /* error? */
1427 /* Read buffer - can return ST_TMK, ST_FMT, or ST_DRV */
1429 uint32
tq_rdbuff (UNIT
*uptr
, t_mtrlnt
*tbc
)
1433 st
= sim_tape_rdrecf (uptr
, tqxb
, tbc
, MT_MAXFR
); /* read rec fwd */
1434 if (st
== MTSE_TMK
) { /* tape mark? */
1435 uptr
->flags
= uptr
->flags
| UNIT_SXC
| UNIT_TMK
; /* serious exc */
1436 uptr
->objp
= uptr
->objp
+ 1; /* update obj cnt */
1439 if (st
!= MTSE_OK
) return tq_map_status (uptr
, st
); /* other error? */
1440 uptr
->flags
= uptr
->flags
& ~UNIT_TMK
; /* clr tape mark */
1441 uptr
->objp
= uptr
->objp
+ 1; /* upd obj cnt */
1445 uint32
tq_rdbufr (UNIT
*uptr
, t_mtrlnt
*tbc
)
1449 st
= sim_tape_rdrecr (uptr
, tqxb
, tbc
, MT_MAXFR
); /* read rec rev */
1450 if (st
== MTSE_TMK
) { /* tape mark? */
1451 uptr
->flags
= uptr
->flags
| UNIT_SXC
; /* serious exc */
1452 uptr
->objp
= uptr
->objp
- 1; /* update obj cnt */
1455 if (st
!= MTSE_OK
) return tq_map_status (uptr
, st
); /* other error? */
1456 uptr
->objp
= uptr
->objp
- 1; /* upd obj cnt */
1460 /* Data transfer error log packet */
1462 t_bool
tq_dte (UNIT
*uptr
, uint32 err
)
1467 if ((tq_cflgs
& CF_THS
) == 0) return OK
; /* logging? */
1468 if (!tq_deqf (&pkt
)) return ERR
; /* get log pkt */
1469 tpkt
= uptr
->cpkt
; /* rw pkt */
1470 lu
= tq_pkt
[tpkt
].d
[CMD_UN
]; /* unit # */
1472 tq_pkt
[pkt
].d
[ELP_REFL
] = tq_pkt
[tpkt
].d
[CMD_REFL
]; /* copy cmd ref */
1473 tq_pkt
[pkt
].d
[ELP_REFH
] = tq_pkt
[tpkt
].d
[CMD_REFH
]; /* copy cmd ref */
1474 tq_pkt
[pkt
].d
[ELP_UN
] = lu
; /* copy unit */
1475 tq_pkt
[pkt
].d
[ELP_SEQ
] = 0; /* clr seq # */
1476 tq_pkt
[pkt
].d
[DTE_CIDA
] = 0; /* ctrl ID */
1477 tq_pkt
[pkt
].d
[DTE_CIDB
] = 0;
1478 tq_pkt
[pkt
].d
[DTE_CIDC
] = 0;
1479 tq_pkt
[pkt
].d
[DTE_CIDD
] = (TQ_CLASS
<< DTE_CIDD_V_CLS
) |
1480 (drv_tab
[tq_typ
].cmod
<< DTE_CIDD_V_MOD
);
1481 tq_pkt
[pkt
].d
[DTE_VER
] = drv_tab
[tq_typ
].cver
; /* ctrl ver */
1482 tq_pkt
[pkt
].d
[DTE_MLUN
] = lu
; /* MLUN */
1483 tq_pkt
[pkt
].d
[DTE_UIDA
] = lu
; /* unit ID */
1484 tq_pkt
[pkt
].d
[DTE_UIDB
] = 0;
1485 tq_pkt
[pkt
].d
[DTE_UIDC
] = 0;
1486 tq_pkt
[pkt
].d
[DTE_UIDD
] = (UID_TAPE
<< DTE_UIDD_V_CLS
) |
1487 (drv_tab
[tq_typ
].umod
<< DTE_UIDD_V_MOD
);
1488 tq_pkt
[pkt
].d
[DTE_UVER
] = drv_tab
[tq_typ
].uver
; /* unit ver */
1489 PUTP32 (pkt
, DTE_POSL
, uptr
->objp
); /* position */
1490 tq_pkt
[pkt
].d
[DTE_FVER
] = drv_tab
[tq_typ
].fver
; /* fmtr ver */
1491 tq_putr (pkt
, FM_TAP
, LF_SNR
, err
, DTE_LNT
, UQ_TYP_DAT
);
1492 return tq_putpkt (pkt
, TRUE
);
1495 /* Host bus error log packet */
1497 t_bool
tq_hbe (UNIT
*uptr
, uint32 ba
)
1501 if ((tq_cflgs
& CF_THS
) == 0) return OK
; /* logging? */
1502 if (!tq_deqf (&pkt
)) return ERR
; /* get log pkt */
1503 tpkt
= uptr
->cpkt
; /* rw pkt */
1504 tq_pkt
[pkt
].d
[ELP_REFL
] = tq_pkt
[tpkt
].d
[CMD_REFL
]; /* copy cmd ref */
1505 tq_pkt
[pkt
].d
[ELP_REFH
] = tq_pkt
[tpkt
].d
[CMD_REFH
]; /* copy cmd ref */
1506 tq_pkt
[pkt
].d
[ELP_UN
] = tq_pkt
[tpkt
].d
[CMD_UN
]; /* copy unit */
1507 tq_pkt
[pkt
].d
[ELP_SEQ
] = 0; /* clr seq # */
1508 tq_pkt
[pkt
].d
[HBE_CIDA
] = 0; /* ctrl ID */
1509 tq_pkt
[pkt
].d
[HBE_CIDB
] = 0;
1510 tq_pkt
[pkt
].d
[HBE_CIDC
] = 0;
1511 tq_pkt
[pkt
].d
[DTE_CIDD
] = (TQ_CLASS
<< DTE_CIDD_V_CLS
) |
1512 (drv_tab
[tq_typ
].cmod
<< DTE_CIDD_V_MOD
);
1513 tq_pkt
[pkt
].d
[HBE_VER
] = drv_tab
[tq_typ
].cver
; /* ctrl ver */
1514 tq_pkt
[pkt
].d
[HBE_RSV
] = 0;
1515 PUTP32 (pkt
, HBE_BADL
, ba
); /* bad addr */
1516 tq_putr (pkt
, FM_BAD
, LF_SNR
, ST_HST
| SB_HST_NXM
, HBE_LNT
, UQ_TYP_DAT
);
1517 return tq_putpkt (pkt
, TRUE
);
1520 /* Port last failure error log packet */
1522 t_bool
tq_plf (uint32 err
)
1526 if (!tq_deqf (&pkt
)) return ERR
; /* get log pkt */
1527 tq_pkt
[pkt
].d
[ELP_REFL
] = tq_pkt
[pkt
].d
[ELP_REFH
] = 0; /* ref = 0 */
1528 tq_pkt
[pkt
].d
[ELP_UN
] = tq_pkt
[pkt
].d
[ELP_SEQ
] = 0; /* no unit, seq */
1529 tq_pkt
[pkt
].d
[PLF_CIDA
] = 0; /* cntl ID */
1530 tq_pkt
[pkt
].d
[PLF_CIDB
] = 0;
1531 tq_pkt
[pkt
].d
[PLF_CIDC
] = 0;
1532 tq_pkt
[pkt
].d
[PLF_CIDD
] = (TQ_CLASS
<< PLF_CIDD_V_CLS
) |
1533 (drv_tab
[tq_typ
].cmod
<< PLF_CIDD_V_MOD
);
1534 tq_pkt
[pkt
].d
[PLF_VER
] = drv_tab
[tq_typ
].cver
;
1535 tq_pkt
[pkt
].d
[PLF_ERR
] = err
;
1536 tq_putr (pkt
, FM_CNT
, LF_SNR
, ST_CNT
, PLF_LNT
, UQ_TYP_DAT
);
1537 tq_pkt
[pkt
].d
[UQ_HCTC
] |= (UQ_CID_DIAG
<< UQ_HCTC_V_CID
);
1538 return tq_putpkt (pkt
, TRUE
);
1541 /* Unit now available attention packet */
1543 int32
tq_una (UNIT
*uptr
)
1548 if (!tq_deqf (&pkt
)) return ERR
; /* get log pkt */
1549 lu
= (uint32
) (uptr
- tq_dev
.units
); /* get unit */
1550 tq_pkt
[pkt
].d
[RSP_REFL
] = tq_pkt
[pkt
].d
[RSP_REFH
] = 0; /* ref = 0 */
1551 tq_pkt
[pkt
].d
[RSP_UN
] = lu
;
1552 tq_pkt
[pkt
].d
[RSP_RSV
] = 0;
1553 tq_putr_unit (pkt
, uptr
, lu
, FALSE
); /* fill unit fields */
1554 tq_putr (pkt
, OP_AVA
, 0, 0, UNA_LNT
, UQ_TYP_SEQ
); /* fill std fields */
1555 return tq_putpkt (pkt
, TRUE
);
1560 tq_deqf - dequeue head of free list (fatal err if none)
1561 tq_deqh - dequeue head of list
1562 tq_enqh - enqueue at head of list
1563 tq_enqt - enqueue at tail of list
1566 t_bool
tq_deqf (int32
*pkt
)
1568 if (tq_freq
== 0) return tq_fatal (PE_NSR
); /* no free pkts?? */
1569 tq_pbsy
= tq_pbsy
+ 1; /* cnt busy pkts */
1570 *pkt
= tq_freq
; /* head of list */
1571 tq_freq
= tq_pkt
[tq_freq
].link
; /* next */
1575 int32
tq_deqh (int32
*lh
)
1577 int32 ptr
= *lh
; /* head of list */
1579 if (ptr
) *lh
= tq_pkt
[ptr
].link
; /* next */
1583 void tq_enqh (int32
*lh
, int32 pkt
)
1585 if (pkt
== 0) return; /* any pkt? */
1586 tq_pkt
[pkt
].link
= *lh
; /* link is old lh */
1587 *lh
= pkt
; /* pkt is new lh */
1591 void tq_enqt (int32
*lh
, int32 pkt
)
1593 if (pkt
== 0) return; /* any pkt? */
1594 tq_pkt
[pkt
].link
= 0; /* it will be tail */
1595 if (*lh
== 0) *lh
= pkt
; /* if empty, enqh */
1597 uint32 ptr
= *lh
; /* chase to end */
1598 while (tq_pkt
[ptr
].link
) ptr
= tq_pkt
[ptr
].link
;
1599 tq_pkt
[ptr
].link
= pkt
; /* enq at tail */
1604 /* Packet and descriptor handling */
1606 /* Get packet from command ring */
1608 t_bool
tq_getpkt (int32
*pkt
)
1612 if (!tq_getdesc (&tq_cq
, &desc
)) return ERR
; /* get cmd desc */
1613 if ((desc
& UQ_DESC_OWN
) == 0) { /* none */
1614 *pkt
= 0; /* pkt = 0 */
1615 return OK
; /* no error */
1617 if (!tq_deqf (pkt
)) return ERR
; /* get cmd pkt */
1618 tq_hat
= 0; /* dsbl hst timer */
1619 addr
= desc
& UQ_ADDR
; /* get Q22 addr */
1620 if (Map_ReadW (addr
+ UQ_HDR_OFF
, TQ_PKT_SIZE
, tq_pkt
[*pkt
].d
))
1621 return tq_fatal (PE_PRE
); /* read pkt */
1622 return tq_putdesc (&tq_cq
, desc
); /* release desc */
1625 /* Put packet to response ring - note the clever hack about credits.
1626 The controller sends all its credits to the host. Thereafter, it
1627 supplies one credit for every response packet sent over. Simple!
1630 t_bool
tq_putpkt (int32 pkt
, t_bool qt
)
1632 uint32 addr
, desc
, lnt
, cr
;
1634 if (pkt
== 0) return OK
; /* any packet? */
1635 if (DEBUG_PRS (tq_dev
)) {
1636 UNIT
*up
= tq_getucb (tq_pkt
[pkt
].d
[CMD_UN
]);
1637 fprintf (sim_deb
, ">>TQ: rsp=%04X, sts=%04X",
1638 tq_pkt
[pkt
].d
[RSP_OPF
], tq_pkt
[pkt
].d
[RSP_STS
]);
1639 if (up
) fprintf (sim_deb
, ", pos=%d, obj=%d\n", up
->pos
, up
->objp
);
1640 else fprintf (sim_deb
, "\n");
1643 if (!tq_getdesc (&tq_rq
, &desc
)) return ERR
; /* get rsp desc */
1644 if ((desc
& UQ_DESC_OWN
) == 0) { /* not valid? */
1645 if (qt
) tq_enqt (&tq_rspq
, pkt
); /* normal? q tail */
1646 else tq_enqh (&tq_rspq
, pkt
); /* resp q call */
1647 sim_activate (&tq_unit
[TQ_QUEUE
], tq_qtime
); /* activate q thrd */
1650 addr
= desc
& UQ_ADDR
; /* get Q22 addr */
1651 lnt
= tq_pkt
[pkt
].d
[UQ_HLNT
] - UQ_HDR_OFF
; /* size, with hdr */
1652 if ((GETP (pkt
, UQ_HCTC
, TYP
) == UQ_TYP_SEQ
) && /* seq packet? */
1653 (GETP (pkt
, CMD_OPC
, OPC
) & OP_END
)) { /* end packet? */
1654 cr
= (tq_credits
>= 14)? 14: tq_credits
; /* max 14 credits */
1655 tq_credits
= tq_credits
- cr
; /* decr credits */
1656 tq_pkt
[pkt
].d
[UQ_HCTC
] |= ((cr
+ 1) << UQ_HCTC_V_CR
);
1658 if (Map_WriteW (addr
+ UQ_HDR_OFF
, lnt
, tq_pkt
[pkt
].d
))
1659 return tq_fatal (PE_PWE
); /* write pkt */
1660 tq_enqh (&tq_freq
, pkt
); /* pkt is free */
1661 tq_pbsy
= tq_pbsy
- 1; /* decr busy cnt */
1662 if (tq_pbsy
== 0) tq_hat
= tq_htmo
; /* idle? strt hst tmr */
1663 return tq_putdesc (&tq_rq
, desc
); /* release desc */
1666 /* Get a descriptor from the host */
1668 t_bool
tq_getdesc (struct uq_ring
*ring
, uint32
*desc
)
1670 uint32 addr
= ring
->ba
+ ring
->idx
;
1673 if (Map_ReadW (addr
, 4, d
)) /* fetch desc */
1674 return tq_fatal (PE_QRE
); /* err? dead */
1675 *desc
= ((uint32
) d
[0]) | (((uint32
) d
[1]) << 16);
1679 /* Return a descriptor to the host, clearing owner bit
1680 If rings transitions from "empty" to "not empty" or "full" to
1681 "not full", and interrupt bit was set, interrupt the host.
1682 Actually, test whether previous ring entry was owned by host.
1685 t_bool
tq_putdesc (struct uq_ring
*ring
, uint32 desc
)
1687 uint32 prvd
, newd
= (desc
& ~UQ_DESC_OWN
) | UQ_DESC_F
;
1688 uint32 prva
, addr
= ring
->ba
+ ring
->idx
;
1691 d
[0] = newd
& 0xFFFF; /* 32b to 16b */
1692 d
[1] = (newd
>> 16) & 0xFFFF;
1693 if (Map_WriteW (addr
, 4, d
)) /* store desc */
1694 return tq_fatal (PE_QWE
); /* err? dead */
1695 if (desc
& UQ_DESC_F
) { /* was F set? */
1696 if (ring
->lnt
<= 4) tq_ring_int (ring
); /* lnt = 1? intr */
1698 prva
= ring
->ba
+ /* prv desc */
1699 ((ring
->idx
- 4) & (ring
->lnt
- 1));
1700 if (Map_ReadW (prva
, 4, d
)) /* read prv */
1701 return tq_fatal (PE_QRE
);
1702 prvd
= ((uint32
) d
[0]) | (((uint32
) d
[1]) << 16);
1703 if (prvd
& UQ_DESC_OWN
) tq_ring_int (ring
);
1706 ring
->idx
= (ring
->idx
+ 4) & (ring
->lnt
- 1);
1710 /* Get unit descriptor for logical unit - trivial now,
1711 but eventually, hide multiboard complexities here */
1713 UNIT
*tq_getucb (uint32 lu
)
1717 if (lu
>= TQ_NUMDR
) return NULL
;
1718 uptr
= tq_dev
.units
+ lu
;
1719 if (uptr
->flags
& UNIT_DIS
) return NULL
;
1723 /* Hack unit flags */
1725 void tq_setf_unit (int32 pkt
, UNIT
*uptr
)
1727 uptr
->uf
= tq_pkt
[pkt
].d
[ONL_UFL
] & UF_MSK
; /* settable flags */
1728 if ((tq_pkt
[pkt
].d
[CMD_MOD
] & MD_SWP
) && /* swre wrp enb? */
1729 (tq_pkt
[pkt
].d
[ONL_UFL
] & UF_WPS
)) /* swre wrp on? */
1730 uptr
->uf
= uptr
->uf
| UF_WPS
; /* simon says... */
1734 /* Hack end flags */
1736 uint32
tq_efl (UNIT
*uptr
)
1740 if (uptr
) { /* any unit? */
1741 if (uptr
->flags
& UNIT_POL
) t
= t
| EF_PLS
; /* note pos lost */
1742 if (uptr
->flags
& UNIT_SXC
) t
= t
| EF_SXC
; /* note ser exc */
1743 if (TEST_EOT (uptr
)) t
= t
| EF_EOT
; /* note EOT */
1748 /* Unit response fields */
1750 void tq_putr_unit (int32 pkt
, UNIT
*uptr
, uint32 lu
, t_bool all
)
1752 tq_pkt
[pkt
].d
[ONL_MLUN
] = lu
; /* multi-unit */
1753 tq_pkt
[pkt
].d
[ONL_UFL
] = uptr
->uf
| TQ_WPH (uptr
); /* unit flags */
1754 tq_pkt
[pkt
].d
[ONL_RSVL
] = tq_pkt
[pkt
].d
[ONL_RSVH
] = 0; /* reserved */
1755 tq_pkt
[pkt
].d
[ONL_UIDA
] = lu
; /* UID low */
1756 tq_pkt
[pkt
].d
[ONL_UIDB
] = 0;
1757 tq_pkt
[pkt
].d
[ONL_UIDC
] = 0;
1758 tq_pkt
[pkt
].d
[ONL_UIDD
] = (UID_TAPE
<< ONL_UIDD_V_CLS
) |
1759 (drv_tab
[tq_typ
].umod
<< ONL_UIDD_V_MOD
); /* UID hi */
1760 PUTP32 (pkt
, ONL_MEDL
, drv_tab
[tq_typ
].med
); /* media type */
1761 if (all
) { /* if long form */
1762 tq_pkt
[pkt
].d
[ONL_FMT
] = drv_tab
[tq_typ
].fmt
; /* format */
1763 tq_pkt
[pkt
].d
[ONL_SPD
] = 0; /* speed */
1764 PUTP32 (pkt
, ONL_MAXL
, TQ_MAXFR
); /* max xfr */
1765 tq_pkt
[pkt
].d
[ONL_NREC
] = 0; /* noise rec */
1766 tq_pkt
[pkt
].d
[ONL_RSVE
] = 0; /* reserved */
1771 /* UQ_HDR and RSP_OP fields */
1773 void tq_putr (int32 pkt
, uint32 cmd
, uint32 flg
, uint32 sts
, uint32 lnt
, uint32 typ
)
1775 tq_pkt
[pkt
].d
[RSP_OPF
] = (cmd
<< RSP_OPF_V_OPC
) | /* set cmd, flg */
1776 (flg
<< RSP_OPF_V_FLG
);
1777 tq_pkt
[pkt
].d
[RSP_STS
] = sts
;
1778 tq_pkt
[pkt
].d
[UQ_HLNT
] = lnt
; /* length */
1779 tq_pkt
[pkt
].d
[UQ_HCTC
] = (typ
<< UQ_HCTC_V_TYP
) | /* type, cid */
1780 (UQ_CID_TMSCP
<< UQ_HCTC_V_CID
); /* clr credits */
1784 /* Post interrupt during init */
1786 void tq_init_int (void)
1788 if ((tq_s1dat
& SA_S1H_IE
) && tq_dib
.vec
) SET_INT (TQ
);
1792 /* Post interrupt during putpkt - note that NXMs are ignored! */
1794 void tq_ring_int (struct uq_ring
*ring
)
1796 uint32 iadr
= tq_comm
+ ring
->ioff
; /* addr intr wd */
1799 Map_WriteW (iadr
, 2, &flag
); /* write flag */
1800 if (tq_dib
.vec
) SET_INT (TQ
); /* if enb, intr */
1804 /* Return interrupt vector */
1806 int32
tq_inta (void)
1808 return tq_dib
.vec
; /* prog vector */
1813 t_bool
tq_fatal (uint32 err
)
1815 if (DEBUG_PRS (tq_dev
)) fprintf (sim_deb
, ">>TQ: fatal err=%X\n", err
);
1816 tq_reset (&tq_dev
); /* reset device */
1817 tq_sa
= SA_ER
| err
; /* SA = dead code */
1818 tq_csta
= CST_DEAD
; /* state = dead */
1819 tq_perr
= err
; /* save error */
1825 t_stat
tq_attach (UNIT
*uptr
, char *cptr
)
1829 r
= sim_tape_attach (uptr
, cptr
);
1830 if (r
!= SCPE_OK
) return r
;
1831 if (tq_csta
== CST_UP
) uptr
->flags
= (uptr
->flags
| UNIT_ATP
) &
1832 ~(UNIT_SXC
| UNIT_POL
| UNIT_TMK
);
1838 t_stat
tq_detach (UNIT
*uptr
)
1842 r
= sim_tape_detach (uptr
); /* detach unit */
1843 if (r
!= SCPE_OK
) return r
;
1844 uptr
->flags
= uptr
->flags
& ~(UNIT_ONL
| UNIT_ATP
| UNIT_SXC
| UNIT_POL
| UNIT_TMK
);
1845 uptr
->uf
= 0; /* clr unit flgs */
1851 t_stat
tq_reset (DEVICE
*dptr
)
1856 tq_csta
= CST_S1
; /* init stage 1 */
1857 tq_s1dat
= 0; /* no S1 data */
1858 tq_dib
.vec
= 0; /* no vector */
1859 if (UNIBUS
) tq_sa
= SA_S1
| SA_S1C_DI
| SA_S1C_MP
; /* Unibus? */
1860 else tq_sa
= SA_S1
| SA_S1C_Q22
| SA_S1C_DI
| SA_S1C_MP
; /* init SA val */
1861 tq_cflgs
= CF_RPL
; /* ctrl flgs off */
1862 tq_htmo
= TQ_DHTMO
; /* default timeout */
1863 tq_hat
= tq_htmo
; /* default timer */
1864 tq_cq
.ba
= tq_cq
.lnt
= tq_cq
.idx
= 0; /* clr cmd ring */
1865 tq_rq
.ba
= tq_rq
.lnt
= tq_rq
.idx
= 0; /* clr rsp ring */
1866 tq_credits
= (TQ_NPKTS
/ 2) - 1; /* init credits */
1867 tq_freq
= 1; /* init free list */
1868 for (i
= 0; i
< TQ_NPKTS
; i
++) { /* all pkts free */
1869 if (i
) tq_pkt
[i
].link
= (i
+ 1) & TQ_M_NPKTS
;
1870 else tq_pkt
[i
].link
= 0;
1871 for (j
= 0; j
< TQ_PKT_SIZE_W
; j
++) tq_pkt
[i
].d
[j
] = 0;
1873 tq_rspq
= 0; /* no q'd rsp pkts */
1874 tq_pbsy
= 0; /* all pkts free */
1875 tq_pip
= 0; /* not polling */
1876 CLR_INT (TQ
); /* clr intr req */
1877 for (i
= 0; i
< TQ_NUMDR
+ 2; i
++) { /* init units */
1878 uptr
= tq_dev
.units
+ i
;
1879 sim_cancel (uptr
); /* clr activity */
1880 sim_tape_reset (uptr
);
1881 uptr
->flags
= uptr
->flags
& /* not online */
1882 ~(UNIT_ONL
|UNIT_ATP
|UNIT_SXC
|UNIT_POL
|UNIT_TMK
);
1883 uptr
->uf
= 0; /* clr unit flags */
1884 uptr
->cpkt
= uptr
->pktq
= 0; /* clr pkt q's */
1886 if (tqxb
== NULL
) tqxb
= (uint8
*) calloc (TQ_MAXFR
, sizeof (uint8
));
1887 if (tqxb
== NULL
) return SCPE_MEM
;
1891 /* Device bootstrap */
1893 #if defined (VM_PDP11)
1895 #define BOOT_START 016000 /* start */
1896 #define BOOT_ENTRY (BOOT_START + 002) /* entry */
1897 #define BOOT_UNIT (BOOT_START + 010) /* unit number */
1898 #define BOOT_CSR (BOOT_START + 014) /* CSR */
1899 #define BOOT_LEN (sizeof (boot_rom) / sizeof (int16))
1901 /* Data structure definitions */
1903 #define B_CMDINT (BOOT_START - 01000) /* cmd int */
1904 #define B_RSPINT (B_CMDINT + 002) /* rsp int */
1905 #define B_RING (B_RSPINT + 002) /* ring base */
1906 #define B_RSPH (B_RING + 010) /* resp pkt hdr */
1907 #define B_TKRSP (B_RSPH + 004) /* resp pkt */
1908 #define B_CMDH (B_TKRSP + 060) /* cmd pkt hdr */
1909 #define B_TKCMD (B_CMDH + 004) /* cmd pkt */
1910 #define B_UNIT (B_TKCMD + 004) /* unit # */
1912 static const uint16 boot_rom
[] = {
1914 0046525, /* ST: "UM" */
1916 0012706, 0016000, /* mov #st,sp */
1917 0012700, 0000000, /* mov #unitno,r0 */
1918 0012701, 0174500, /* mov #174500,r1 ; ip addr */
1919 0005021, /* clr (r1)+ ; init */
1920 0012704, 0004000, /* mov #4000,r4 ; s1 mask */
1921 0005002, /* clr r2 */
1922 0005022, /* 10$: clr (r2)+ ; clr up to boot */
1923 0020237, BOOT_START
- 2, /* cmp r2,#st-2 */
1924 0103774, /* blo 10$ */
1925 0012705, BOOT_START
+0312, /* mov #cmdtbl,r5 ; addr of tbl */
1927 /* Four step init process */
1929 0005711, /* 20$: tst (r1) ; err? */
1930 0100001, /* bpl 30$ */
1932 0030411, /* 30$: bit r4,(r1) ; step set? */
1933 0001773, /* beq 20$ ; wait */
1934 0012511, /* mov (r5)+,(r1) ; send next */
1935 0006304, /* asl r4 ; next mask */
1936 0100370, /* bpl 20$ ; s4 done? */
1938 /* Set up rings, issue ONLINE, REWIND, READ */
1940 0012737, 0000400, B_CMDH
+ 2, /* mov #400,cmdh+2 ; VCID = 1 */
1941 0012737, 0000044, B_CMDH
, /* mov #36.,cmdh ; cmd pkt lnt */
1942 0010037, B_UNIT
, /* mov r0,unit ; unit # */
1943 0012737, 0000011, B_TKCMD
+ 8, /* mov #11,tkcmd+8. ; online op */
1944 0012737, 0020000, B_TKCMD
+ 10, /* mov #20000,tkcmd+10. ; clr ser ex */
1945 0012702, B_RING
, /* mov #ring,r2 ; init rings */
1946 0012722, B_TKRSP
, /* mov #tkrsp,(r2)+ ; rsp pkt addr */
1947 0010203, /* mov r2,r3 ; save ring+2 */
1948 0010423, /* mov r4,(r3)+ ; set TK own */
1949 0012723, B_TKCMD
, /* mov #tkcmd,(r3)+ ; cmd pkt addr */
1950 0010423, /* mov r4,(r3)+ ; set TK own */
1951 0005741, /* tst -(r1) ; start poll */
1952 0005712, /* 40$: tst (r2) ; wait for resp */
1953 0100776, /* bmi 40$ */
1954 0105737, B_TKRSP
+ 10, /* tstb tkrsp+10. ; check stat */
1955 0001401, /* beq 50$ */
1957 0012703, B_TKCMD
+ 8, /* 50$: mov #tkcmd+8.,r3 */
1958 0012723, 0000045, /* mov #45,(r3)+ ; reposition */
1959 0012723, 0020002, /* mov #20002,(r3)+ ; rew, clr exc */
1960 0012723, 0000001, /* mov #1,(r3)+ ; lo rec skp */
1961 0005023, /* clr (r3)+ ; hi rec skp */
1962 0005023, /* clr (r3)+ ; lo tmk skp */
1963 0005023, /* clr (r3)+ ; hi tmk skp */
1964 0010412, /* mov r4,(r2) ; TK own rsp */
1965 0010437, B_RING
+ 6, /* mov r4,ring+6 ; TK own cmd */
1966 0005711, /* tst (r1) ; start poll */
1967 0005712, /* 60$: tst (r2) ; wait for resp */
1968 0100776, /* bmi 60$ */
1969 0105737, B_TKRSP
+ 10, /* tstb tkrsp+10. ; check stat */
1970 0001401, /* beq 70$ */
1972 0012703, B_TKCMD
+ 8, /* 70$: mov #tkcmd+8.,r3 */
1973 0012723, 0000041, /* mov #41,(r3)+ ; read */
1974 0012723, 0020000, /* mov #20000,(r3)+ ; clr exc */
1975 0012723, 0001000, /* mov #512.,(r3)+ ; bc = 512 */
1976 0005023, /* clr (r3)+ ; clr args */
1977 0005023, /* clr (r3)+ ; ba = 0 */
1978 0010412, /* mov r4,(r2) ; TK own rsp */
1979 0010437, B_RING
+ 6, /* mov r4,ring+6 ; TK own cmd */
1980 0005711, /* tst (r1) ; start poll */
1981 0005712, /* 80$: tst (r2) ; wait for resp */
1982 0100776, /* bmi 80$ */
1983 0105737, B_TKRSP
+ 10, /* tstb tkrsp+10. ; check stat */
1984 0001401, /* beq 90$ */
1987 /* Boot block read in, jump to 0 - leave controller init'd */
1989 0005003, /* clr r3 */
1990 0012704, BOOT_START
+020, /* mov #st+020,r4 */
1991 0005005, /* clr r5 */
1992 0005007, /* clr pc */
1994 0100000, /* cmdtbl: init step 1 */
1995 B_RING
, /* ring base */
1996 0000000, /* high ring base */
2000 t_stat
tq_boot (int32 unitno
, DEVICE
*dptr
)
2003 extern int32 saved_PC
;
2006 for (i
= 0; i
< BOOT_LEN
; i
++) M
[(BOOT_START
>> 1) + i
] = boot_rom
[i
];
2007 M
[BOOT_UNIT
>> 1] = unitno
& 3;
2008 M
[BOOT_CSR
>> 1] = tq_dib
.ba
& DMASK
;
2009 saved_PC
= BOOT_ENTRY
;
2015 t_stat
tq_boot (int32 unitno
, DEVICE
*dptr
)
2022 /* Special show commands */
2024 void tq_show_ring (FILE *st
, struct uq_ring
*rp
)
2029 #if defined (VM_PDP11)
2030 fprintf (st
, "ring, base = %o, index = %d, length = %d\n",
2031 rp
->ba
, rp
->idx
>> 2, rp
->lnt
>> 2);
2033 fprintf (st
, "ring, base = %x, index = %d, length = %d\n",
2034 rp
->ba
, rp
->idx
>> 2, rp
->lnt
>> 2);
2036 for (i
= 0; i
< (rp
->lnt
>> 2); i
++) {
2037 if (Map_ReadW (rp
->ba
+ (i
<< 2), 4, d
)) {
2038 fprintf (st
, " %3d: non-existent memory\n", i
);
2041 desc
= ((uint32
) d
[0]) | (((uint32
) d
[1]) << 16);
2042 #if defined (VM_PDP11)
2043 fprintf (st
, " %3d: %011o\n", i
, desc
);
2045 fprintf (st
, " %3d: %08x\n", i
, desc
);
2051 void tq_show_pkt (FILE *st
, int32 pkt
)
2054 uint32 cr
= GETP (pkt
, UQ_HCTC
, CR
);
2055 uint32 typ
= GETP (pkt
, UQ_HCTC
, TYP
);
2056 uint32 cid
= GETP (pkt
, UQ_HCTC
, CID
);
2058 fprintf (st
, "packet %d, credits = %d, type = %d, cid = %d\n",
2060 for (i
= 0; i
< TQ_SH_MAX
; i
= i
+ TQ_SH_PPL
) {
2061 fprintf (st
, " %2d:", i
);
2062 for (j
= i
; j
< (i
+ TQ_SH_PPL
); j
++)
2063 #if defined (VM_PDP11)
2064 fprintf (st
, " %06o", tq_pkt
[pkt
].d
[j
]);
2066 fprintf (st
, " %04x", tq_pkt
[pkt
].d
[j
]);
2073 t_stat
tq_show_unitq (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
2075 int32 pkt
, u
= uptr
- tq_dev
.units
;
2077 if (tq_csta
!= CST_UP
) {
2078 fprintf (st
, "Controller is not initialized\n");
2081 if ((uptr
->flags
& UNIT_ONL
) == 0) {
2082 if (uptr
->flags
& UNIT_ATT
)
2083 fprintf (st
, "Unit %d is available\n", u
);
2084 else fprintf (st
, "Unit %d is offline\n", u
);
2088 fprintf (st
, "Unit %d current ", u
);
2089 tq_show_pkt (st
, uptr
->cpkt
);
2090 if (pkt
= uptr
->pktq
) {
2092 fprintf (st
, "Unit %d queued ", u
);
2093 tq_show_pkt (st
, pkt
);
2094 } while (pkt
= tq_pkt
[pkt
].link
);
2097 else fprintf (st
, "Unit %d queues are empty\n", u
);
2101 t_stat
tq_show_ctrl (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
2105 if (tq_csta
!= CST_UP
) {
2106 fprintf (st
, "Controller is not initialized\n");
2109 if (val
& TQ_SH_RI
) {
2110 if (tq_pip
) fprintf (st
, "Polling in progress, host timer = %d\n", tq_hat
);
2111 else fprintf (st
, "Host timer = %d\n", tq_hat
);
2112 fprintf (st
, "Command ");
2113 tq_show_ring (st
, &tq_cq
);
2114 fprintf (st
, "Response ");
2115 tq_show_ring (st
, &tq_rq
);
2117 if (val
& TQ_SH_FR
) {
2118 if (pkt
= tq_freq
) {
2119 for (i
= 0; pkt
!= 0; i
++, pkt
= tq_pkt
[pkt
].link
) {
2120 if (i
== 0) fprintf (st
, "Free queue = %d", pkt
);
2121 else if ((i
% 16) == 0) fprintf (st
, ",\n %d", pkt
);
2122 else fprintf (st
, ", %d", pkt
);
2126 else fprintf (st
, "Free queue is empty\n");
2128 if (val
& TQ_SH_RS
) {
2129 if (pkt
= tq_rspq
) {
2131 fprintf (st
, "Response ");
2132 tq_show_pkt (st
, pkt
);
2133 } while (pkt
= tq_pkt
[pkt
].link
);
2135 else fprintf (st
, "Response queue is empty\n");
2137 if (val
& TQ_SH_UN
) {
2138 for (i
= 0; i
< TQ_NUMDR
; i
++)
2139 tq_show_unitq (st
, &tq_unit
[i
], 0, NULL
);
2144 /* Set controller type (and capacity for user-defined type) */
2146 t_stat
tq_set_type (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
2149 uint32 max
= sim_taddr_64
? TQU_EMAXC
: TQU_MAXC
;
2152 if ((val
< 0) || (val
> TQU_TYPE
) || ((val
!= TQU_TYPE
) && cptr
))
2154 for (i
= 0; i
< TQ_NUMDR
; i
++) {
2155 if (tq_unit
[i
].flags
& UNIT_ATT
) return SCPE_ALATT
;
2158 cap
= (uint32
) get_uint (cptr
, 10, max
, &r
);
2159 if ((r
!= SCPE_OK
) || (cap
< TQU_MINC
)) return SCPE_ARG
;
2160 drv_tab
[TQU_TYPE
].cap
= ((t_addr
) cap
) << 20;
2163 for (i
= 0; i
< TQ_NUMDR
; i
++)
2164 tq_unit
[i
].capac
= drv_tab
[tq_typ
].cap
;
2168 /* Show controller type and capacity */
2170 t_stat
tq_show_type (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
2172 fprintf (st
, "%s (%dMB)", drv_tab
[tq_typ
].name
, (uint32
) (drv_tab
[tq_typ
].cap
>> 20));