First Commit of my working state
[simh.git] / PDP11 / pdp11_tq.c
1 /* pdp11_tq.c: TMSCP tape controller simulator
2
3 Copyright (c) 2002-2007, Robert M Supnik
4
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:
11
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
14
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.
21
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.
25
26 tq TQK50 tape controller
27
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)
47 */
48
49 #if defined (VM_PDP10) /* PDP10 version */
50 #error "TQK50 not supported on PDP-10!"
51
52 #elif defined (VM_VAX) /* VAX version */
53 #include "vax_defs.h"
54 #if (UNIBUS)
55 #define INIT_TYPE TQ8_TYPE
56 #define INIT_CAP TQ8_CAP
57 #else
58 #define INIT_TYPE TQ5_TYPE
59 #define INIT_CAP TQ5_CAP
60 #endif
61
62 #else /* PDP-11 version */
63 #include "pdp11_defs.h"
64 #define INIT_TYPE TQ5_TYPE
65 #define INIT_CAP TQ5_CAP
66 extern int32 cpu_opt;
67 #endif
68
69 #include "pdp11_uqssp.h"
70 #include "pdp11_mscp.h"
71 #include "sim_tape.h"
72
73 #define UF_MSK (UF_SCH|UF_VSS|UF_CMR|UF_CMW) /* settable flags */
74
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 */
83
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 */
89
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)
105
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 */
115
116 #define tq_comm tq_rq.ba
117
118 #define ERR 0 /* must be SCPE_OK! */
119 #define OK 1
120
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 */
125
126 /* Internal packet management */
127
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))
132
133 struct tqpkt {
134 int16 link; /* link to next */
135 uint16 d[TQ_PKT_SIZE_W]; /* data */
136 };
137
138 /* Packet payload extraction and insertion */
139
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
145
146 /* Controller and device types - TQK50 must be swre rev 5 or later */
147
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 */
158
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 */
169
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 */
180
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 */
194
195 #define TQ_DRV(d) \
196 d##_UQPM, \
197 d##_CMOD, d##_MED, d##_FMT, d##_CAP, \
198 d##_UMOD, d##_CREV, d##_FREV, d##_UREV
199
200 #define TEST_EOT(u) (sim_tape_eot (u))
201
202 struct drvtyp {
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 */
209 uint32 cver;
210 uint32 fver;
211 uint32 uver;
212 char *name;
213 };
214
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" },
220 };
221
222 /* Data */
223
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;
229
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 */
253
254 /* Command table - legal modifiers (low 16b) and flags (high 16b) */
255
256 static uint32 tq_cmf[64] = {
257 0, /* 0 */
258 CMF_IMM, /* abort */
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 */
262 0, 0, 0, /* 5-7 */
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,
270 0, /* 17 */
271 CMF_SEQ|CMF_WR|MD_CDL|MD_CSE|MD_IMM, /* erase */
272 CMF_SEQ|CMF_WR|MD_CDL|MD_CSE, /* flush */
273 0, 0, /* 20-21 */
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,
282 0, /* 35 */
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
290 };
291
292 /* Forward references */
293
294 DEVICE tq_dev;
295
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);
312
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);
357
358 /* TQ data structures
359
360 tq_dev TQ device descriptor
361 tq_unit TQ unit list
362 tq_reg TQ register list
363 tq_mod TQ modifier list
364 */
365
366 DIB tq_dib = {
367 IOBA_TQ, IOLN_TQ, &tq_rd, &tq_wr,
368 1, IVCL (TQ), 0, { &tq_inta }
369 };
370
371 UNIT tq_unit[] = {
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) }
378 };
379
380 #define TQ_TIMER (TQ_NUMDR)
381 #define TQ_QUEUE (TQ_TIMER + 1)
382
383 REG tq_reg[] = {
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 },
419 { NULL }
420 };
421
422 MTAB tq_mod[] = {
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 },
452 #else
453 { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", NULL,
454 NULL, &show_addr, NULL },
455 #endif
456 { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL,
457 NULL, &show_vec, NULL },
458 { 0 }
459 };
460
461 DEVICE tq_dev = {
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
467 };
468
469 /* I/O dispatch routines, I/O addresses 17772150 - 17772152
470
471 17772150 IP read/write
472 17772152 SA read/write
473 */
474
475 t_stat tq_rd (int32 *data, int32 PA, int32 access)
476 {
477 switch ((PA >> 1) & 01) { /* decode PA<1> */
478 case 0: /* IP */
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);
484 }
485 break;
486
487 case 1: /* SA */
488 *data = tq_sa;
489 break;
490 }
491
492 return SCPE_OK;
493 }
494
495 t_stat tq_wr (int32 data, int32 PA, int32 access)
496 {
497 switch ((PA >> 1) & 01) { /* decode PA<1> */
498
499 case 0: /* IP */
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 ());
503 break;
504
505 case 1: /* SA */
506 tq_saw = data;
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);
511 break;
512 }
513
514 return SCPE_OK;
515 }
516
517 /* Transition to step 4 - init communications region */
518
519 t_bool tq_step4 (void)
520 {
521 int32 i, lnt;
522 uint32 base;
523 uint16 zero[SA_COMM_MAX >> 1];
524
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 */
543 return OK;
544 }
545
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.
549
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
553
554 If all queues are idle, terminate thread
555 */
556
557 t_stat tq_quesvc (UNIT *uptr)
558 {
559 int32 i, cnid;
560 int32 pkt = 0;
561 UNIT *nuptr;
562
563 if (tq_csta < CST_UP) { /* still init? */
564 switch (tq_csta) { /* controller state? */
565
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 */
571 }
572 else {
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 */
579 }
580 } /* end if valid */
581 break;
582
583 case CST_S1_WR: /* wrap mode */
584 tq_sa = tq_saw; /* echo data */
585 break;
586
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 */
593 break;
594
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 */
600 }
601 else tq_step4 (); /* send step 4 */
602 break;
603
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 */
607 break;
608
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);
617 tq_perr = 0;
618 }
619 break;
620 } /* end switch */
621 return SCPE_OK;
622 } /* end if */
623
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 */
629 }
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");
642 fflush (sim_deb);
643 }
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 */
649 }
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 */
653 }
654 else return tq_fatal (PE_ICI); /* no, term thread */
655 } /* end if pkt */
656 else tq_pip = 0; /* discontinue poll */
657 } /* end if pip */
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 */
664 }
665
666 /* Clock service (roughly once per second) */
667
668 t_stat tq_tmrsvc (UNIT *uptr)
669 {
670 int32 i;
671 UNIT *nuptr;
672
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;
680 }
681 nuptr->flags = nuptr->flags & ~UNIT_ATP;
682 }
683 if ((tq_hat > 0) && (--tq_hat == 0)) /* host timeout? */
684 tq_fatal (PE_HAT); /* fatal err */
685 return SCPE_OK;
686 }
687
688 /* MSCP packet handling */
689
690 t_bool tq_mscp (int32 pkt, t_bool q)
691 {
692 uint32 sts;
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 # */
697 UNIT *uptr;
698
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 */
702 }
703 else if (flg) { /* flags? */
704 cmd = cmd | OP_END; /* set end flag */
705 sts = ST_CMD | I_FLAG; /* ill flags */
706 }
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 */
710 }
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 */
716 return OK;
717 }
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;
722 }
723 switch (cmd) {
724
725 case OP_ABO: /* abort */
726 return tq_abo (pkt);
727
728 case OP_AVL: /* avail */
729 return tq_avl (pkt);
730
731 case OP_GCS: /* get cmd status */
732 return tq_gcs (pkt);
733
734 case OP_GUS: /* get unit status */
735 return tq_gus (pkt);
736
737 case OP_ONL: /* online */
738 return tq_onl (pkt);
739
740 case OP_SCC: /* set ctrl char */
741 return tq_scc (pkt);
742
743 case OP_SUC: /* set unit char */
744 return tq_suc (pkt);
745
746 case OP_ERS: /* erase */
747 case OP_ERG: /* erase gap */
748 return tq_erase (pkt);
749
750 case OP_FLU: /* flush */
751 return tq_flu (pkt);
752
753 case OP_POS: /* position */
754 return tq_pos (pkt);
755
756 case OP_WTM: /* write tape mark */
757 return tq_wtm (pkt);
758
759 case OP_ACC: /* access */
760 case OP_CMP: /* compare */
761 case OP_RD: /* read */
762 case OP_WR: /* write */
763 return tq_rw (pkt);
764
765 case OP_DAP:
766 cmd = cmd | OP_END; /* set end flag */
767 sts = ST_SUC; /* success */
768 break;
769
770 default:
771 cmd = OP_END; /* set end op */
772 sts = ST_CMD | I_OPCD; /* ill op */
773 break;
774 } /* end switch */
775 } /* end else */
776 tq_putr (pkt, cmd, 0, sts, RSP_LNT, UQ_TYP_SEQ);
777 return tq_putpkt (pkt, TRUE);
778 }
779
780 /* Abort a command - 1st parameter is ref # of cmd to abort */
781
782 t_bool tq_abo (int32 pkt)
783 {
784 uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */
785 uint32 ref = GETP32 (pkt, ABO_REFL); /* cmd ref # */
786 int32 tpkt, prv;
787 UNIT *uptr;
788
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);
797 }
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 */
802 }
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 */
807 break;
808 }
809 }
810 }
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;
815 }
816 } /* end if unit */
817 tq_putr (pkt, OP_ABO | OP_END, 0, ST_SUC, ABO_LNT, UQ_TYP_SEQ);
818 return tq_putpkt (pkt, TRUE);
819 }
820
821 /* Unit available - set unit status to available
822 Deferred if q'd cmds, bypassed if ser exc */
823
824 t_bool tq_avl (int32 pkt)
825 {
826 uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */
827 uint32 mdf = tq_pkt[pkt].d[CMD_MOD]; /* modifiers */
828 uint32 sts;
829 UNIT *uptr;
830
831 if (uptr = tq_getucb (lu)) { /* unit exist? */
832 if (uptr->flags & UNIT_SXC) sts = ST_SXC; /* ser exc pending? */
833 else {
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? */
840 }
841 else sts = ST_OFL | SB_OFL_NV; /* no, offline */
842 }
843 }
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);
847 }
848
849 /* Get command status - only interested in active xfr cmd */
850
851 t_bool tq_gcs (int32 pkt)
852 {
853 uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */
854 uint32 ref = GETP32 (pkt, GCS_REFL); /* ref # */
855 int32 tpkt;
856 UNIT *uptr;
857
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];
864 }
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);
868 }
869
870 /* Get unit status */
871
872 t_bool tq_gus (int32 pkt)
873 {
874 uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */
875 uint32 sts;
876 UNIT *uptr;
877
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;
882 }
883 }
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 */
894 }
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);
898 }
899
900 /* Unit online - deferred if q'd commands */
901
902 t_bool tq_onl (int32 pkt)
903 {
904 uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */
905 uint32 sts;
906 UNIT *uptr;
907
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;
913 else {
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 */
920 }
921 tq_putr_unit (pkt, uptr, lu, TRUE); /* set fields */
922 }
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);
926 }
927
928 /* Set controller characteristics */
929
930 t_bool tq_scc (int32 pkt)
931 {
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);
934 else {
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);
949 }
950 return tq_putpkt (pkt, TRUE);
951 }
952
953 /* Set unit characteristics - defer if q'd commands */
954
955 t_bool tq_suc (int32 pkt)
956 {
957 uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */
958 uint32 sts;
959 UNIT *uptr;
960
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 */
964 else {
965 sts = ST_SUC; /* avail or onl */
966 tq_setf_unit (pkt, uptr); /* hack flags */
967 }
968 tq_putr_unit (pkt, uptr, lu, TRUE); /* set fields */
969 }
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);
973 }
974
975 /* Flush - sequential nop - deferred if q'd cmds, bypassed if ser exc */
976
977 t_bool tq_flu (int32 pkt)
978 {
979 uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */
980 uint32 sts;
981 UNIT *uptr;
982
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);
988 }
989
990 /* Erase, erase gap - deferred if q'd cmds, bypassed if ser exc */
991
992 t_bool tq_erase (int32 pkt)
993 {
994 uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */
995 uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */
996 uint32 sts;
997 UNIT *uptr;
998
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 */
1005 }
1006 }
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);
1010 }
1011
1012 /* Write tape mark - deferred if q'd cmds, bypassed if ser exc */
1013
1014 t_bool tq_wtm (int32 pkt)
1015 {
1016 uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */
1017 uint32 sts, objp = 0;
1018 UNIT *uptr;
1019
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 */
1027 }
1028 }
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);
1033 }
1034
1035 /* Position - deferred if q'd cmds, bypassed if ser exc */
1036
1037 t_bool tq_pos (int32 pkt)
1038 {
1039 uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */
1040 uint32 sts, objp = 0;
1041 UNIT *uptr;
1042
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 */
1050 }
1051 }
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);
1058 }
1059
1060 /* Data transfer commands - deferred if q'd commands, bypassed if ser exc */
1061
1062 t_bool tq_rw (int32 pkt)
1063 {
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;
1068 UNIT *uptr;
1069
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;
1077 }
1078 else {
1079 uptr->cpkt = pkt; /* op in progress */
1080 sim_activate (uptr, tq_xtime); /* activate */
1081 return OK; /* done */
1082 }
1083 }
1084 }
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);
1091 }
1092
1093 /* Validity checks */
1094
1095 int32 tq_mot_valid (UNIT *uptr, uint32 cmd)
1096 {
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);
1106 }
1107 if (TQ_WPH (uptr)) { /* hwre wlk? */
1108 uptr->flags = uptr->flags | UNIT_SXC; /* set ser exc */
1109 return (ST_WPR | SB_WPR_HW);
1110 }
1111 }
1112 return ST_SUC; /* success! */
1113 }
1114
1115 /* Unit service for motion commands */
1116
1117 t_stat tq_svc (UNIT *uptr)
1118 {
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 */
1128
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 */
1132 return SCPE_OK;
1133 }
1134
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);
1139 return SCPE_OK;
1140 }
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);
1144 return SCPE_OK;
1145 }
1146 }
1147 sts = ST_SUC; /* assume success */
1148 tbc = 0; /* assume zero rec */
1149 switch (cmd) { /* case on command */
1150
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 */
1157 }
1158 if ((sts != ST_SUC) || (cmd == OP_ACC)) { /* error or access? */
1159 PUTP32 (pkt, RW_BCL, 0); /* no bytes processed */
1160 break;
1161 }
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 */
1166 }
1167 else wbc = tbc;
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 */
1174 }
1175 } /* end if read */
1176 else { /* compare */
1177 uint8 mby, dby;
1178 uint32 mba;
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 */
1183 }
1184 else {
1185 mba = ba + i;
1186 dby = tqxb[i];
1187 }
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);
1192 return SCPE_OK;
1193 }
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 */
1199 }
1200 } /* end for */
1201 } /* end if compare */
1202 PUTP32 (pkt, RW_BCL, wbc); /* bytes read/cmp'd */
1203 break;
1204
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 */
1211 }
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 */
1219 break;
1220
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 */
1229 break;
1230
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 */
1235 uptr->objp = 0;
1236 uptr->flags = uptr->flags & ~(UNIT_TMK | UNIT_POL);
1237 break;
1238
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);
1245 }
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);
1250 }
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;
1259 }
1260 }
1261 PUTP32 (pkt, POS_RCL, skrec); /* #rec skipped */
1262 PUTP32 (pkt, POS_TMCL, sktmk); /* #tmk skipped */
1263 break;
1264
1265 default:
1266 return SCPE_IERR;
1267 }
1268
1269 tq_mot_end (uptr, 0, sts, tbc); /* done */
1270 return SCPE_OK;
1271 }
1272
1273 /* Motion command drive error */
1274
1275 t_stat tq_mot_err (UNIT *uptr, uint32 rsiz)
1276 {
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);
1282 return SCPE_IOERR;
1283 }
1284
1285 /* Motion command complete */
1286
1287 t_bool tq_mot_end (UNIT *uptr, uint32 flg, uint32 sts, uint32 rsiz)
1288 {
1289 int32 pkt = uptr->cpkt; /* packet */
1290 uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* get cmd */
1291 uint32 lnt = RW_LNT_T; /* assume rw */
1292
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;
1297
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 */
1302 }
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 */
1307 return OK;
1308 }
1309
1310 /* Tape motion routines */
1311
1312 uint32 tq_map_status (UNIT *uptr, t_stat st)
1313 {
1314 switch (st) {
1315
1316 case MTSE_OK:
1317 break;
1318
1319 case MTSE_UNATT:
1320 uptr->flags = uptr->flags | UNIT_SXC;
1321 return (ST_OFL | SB_OFL_NV);
1322
1323 case MTSE_FMT:
1324 uptr->flags = uptr->flags | UNIT_SXC;
1325 return ST_MFE;
1326
1327 case MTSE_TMK:
1328 uptr->flags = uptr->flags | UNIT_SXC;
1329 return ST_TMK;
1330
1331 case MTSE_INVRL:
1332 uptr->flags = uptr->flags | UNIT_SXC | UNIT_POL;
1333 return ST_FMT;
1334
1335 case MTSE_RECE:
1336 case MTSE_IOERR:
1337 uptr->flags = uptr->flags | UNIT_SXC | UNIT_POL;
1338 return ST_DRV;
1339
1340 case MTSE_EOM:
1341 uptr->flags = uptr->flags | UNIT_SXC | UNIT_POL;
1342 return ST_DAT;
1343
1344 case MTSE_BOT:
1345 uptr->flags = (uptr->flags | UNIT_SXC) & ~UNIT_POL;
1346 return ST_BOT;
1347
1348 case MTSE_WRP:
1349 uptr->flags = uptr->flags | UNIT_SXC;
1350 return ST_WPR;
1351 }
1352
1353 return ST_SUC;
1354 }
1355
1356 uint32 tq_spacef (UNIT *uptr, uint32 cnt, uint32 *skipped, t_bool qrec)
1357 {
1358 t_stat st;
1359 t_mtrlnt tbc;
1360
1361 *skipped = 0;
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 */
1373 return ST_LED;
1374 }
1375 uptr->flags = uptr->flags | UNIT_TMK; /* set TM seen */
1376 if (qrec) return ST_TMK; /* rec spc? stop */
1377 }
1378 else uptr->flags = uptr->flags & ~UNIT_TMK; /* clr TM seen */
1379 *skipped = *skipped + 1; /* # obj skipped */
1380 }
1381 return ST_SUC;
1382 }
1383
1384 uint32 tq_skipff (UNIT *uptr, uint32 cnt, uint32 *skipped)
1385 {
1386 uint32 st, skrec;
1387
1388 *skipped = 0;
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;
1393 }
1394 return ST_SUC;
1395 }
1396
1397 uint32 tq_spacer (UNIT *uptr, uint32 cnt, uint32 *skipped, t_bool qrec)
1398 {
1399 t_stat st;
1400 t_mtrlnt tbc;
1401
1402 *skipped = 0;
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 */
1410 }
1411 return ST_SUC;
1412 }
1413
1414 uint32 tq_skipfr (UNIT *uptr, uint32 cnt, uint32 *skipped)
1415 {
1416 uint32 st, skrec;
1417
1418 *skipped = 0;
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? */
1423 }
1424 return ST_SUC;
1425 }
1426
1427 /* Read buffer - can return ST_TMK, ST_FMT, or ST_DRV */
1428
1429 uint32 tq_rdbuff (UNIT *uptr, t_mtrlnt *tbc)
1430 {
1431 t_stat st;
1432
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 */
1437 return ST_TMK;
1438 }
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 */
1442 return ST_SUC;
1443 }
1444
1445 uint32 tq_rdbufr (UNIT *uptr, t_mtrlnt *tbc)
1446 {
1447 t_stat st;
1448
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 */
1453 return ST_TMK;
1454 }
1455 if (st != MTSE_OK) return tq_map_status (uptr, st); /* other error? */
1456 uptr->objp = uptr->objp - 1; /* upd obj cnt */
1457 return ST_SUC;
1458 }
1459
1460 /* Data transfer error log packet */
1461
1462 t_bool tq_dte (UNIT *uptr, uint32 err)
1463 {
1464 int32 pkt, tpkt;
1465 uint32 lu;
1466
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 # */
1471
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);
1493 }
1494
1495 /* Host bus error log packet */
1496
1497 t_bool tq_hbe (UNIT *uptr, uint32 ba)
1498 {
1499 int32 pkt, tpkt;
1500
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);
1518 }
1519
1520 /* Port last failure error log packet */
1521
1522 t_bool tq_plf (uint32 err)
1523 {
1524 int32 pkt;
1525
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);
1539 }
1540
1541 /* Unit now available attention packet */
1542
1543 int32 tq_una (UNIT *uptr)
1544 {
1545 int32 pkt;
1546 uint32 lu;
1547
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);
1556 }
1557
1558 /* List handling
1559
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
1564 */
1565
1566 t_bool tq_deqf (int32 *pkt)
1567 {
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 */
1572 return OK;
1573 }
1574
1575 int32 tq_deqh (int32 *lh)
1576 {
1577 int32 ptr = *lh; /* head of list */
1578
1579 if (ptr) *lh = tq_pkt[ptr].link; /* next */
1580 return ptr;
1581 }
1582
1583 void tq_enqh (int32 *lh, int32 pkt)
1584 {
1585 if (pkt == 0) return; /* any pkt? */
1586 tq_pkt[pkt].link = *lh; /* link is old lh */
1587 *lh = pkt; /* pkt is new lh */
1588 return;
1589 }
1590
1591 void tq_enqt (int32 *lh, int32 pkt)
1592 {
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 */
1596 else {
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 */
1600 }
1601 return;
1602 }
1603
1604 /* Packet and descriptor handling */
1605
1606 /* Get packet from command ring */
1607
1608 t_bool tq_getpkt (int32 *pkt)
1609 {
1610 uint32 addr, desc;
1611
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 */
1616 }
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 */
1623 }
1624
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!
1628 */
1629
1630 t_bool tq_putpkt (int32 pkt, t_bool qt)
1631 {
1632 uint32 addr, desc, lnt, cr;
1633
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");
1641 fflush (sim_deb);
1642 }
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 */
1648 return OK;
1649 }
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);
1657 }
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 */
1664 }
1665
1666 /* Get a descriptor from the host */
1667
1668 t_bool tq_getdesc (struct uq_ring *ring, uint32 *desc)
1669 {
1670 uint32 addr = ring->ba + ring->idx;
1671 uint16 d[2];
1672
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);
1676 return OK;
1677 }
1678
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.
1683 */
1684
1685 t_bool tq_putdesc (struct uq_ring *ring, uint32 desc)
1686 {
1687 uint32 prvd, newd = (desc & ~UQ_DESC_OWN) | UQ_DESC_F;
1688 uint32 prva, addr = ring->ba + ring->idx;
1689 uint16 d[2];
1690
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 */
1697 else {
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);
1704 }
1705 }
1706 ring->idx = (ring->idx + 4) & (ring->lnt - 1);
1707 return OK;
1708 }
1709
1710 /* Get unit descriptor for logical unit - trivial now,
1711 but eventually, hide multiboard complexities here */
1712
1713 UNIT *tq_getucb (uint32 lu)
1714 {
1715 UNIT *uptr;
1716
1717 if (lu >= TQ_NUMDR) return NULL;
1718 uptr = tq_dev.units + lu;
1719 if (uptr->flags & UNIT_DIS) return NULL;
1720 return uptr;
1721 }
1722
1723 /* Hack unit flags */
1724
1725 void tq_setf_unit (int32 pkt, UNIT *uptr)
1726 {
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... */
1731 return;
1732 }
1733
1734 /* Hack end flags */
1735
1736 uint32 tq_efl (UNIT *uptr)
1737 {
1738 uint32 t = 0;
1739
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 */
1744 }
1745 return t;
1746 }
1747
1748 /* Unit response fields */
1749
1750 void tq_putr_unit (int32 pkt, UNIT *uptr, uint32 lu, t_bool all)
1751 {
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 */
1767 }
1768 return;
1769 }
1770
1771 /* UQ_HDR and RSP_OP fields */
1772
1773 void tq_putr (int32 pkt, uint32 cmd, uint32 flg, uint32 sts, uint32 lnt, uint32 typ)
1774 {
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 */
1781 return;
1782 }
1783
1784 /* Post interrupt during init */
1785
1786 void tq_init_int (void)
1787 {
1788 if ((tq_s1dat & SA_S1H_IE) && tq_dib.vec) SET_INT (TQ);
1789 return;
1790 }
1791
1792 /* Post interrupt during putpkt - note that NXMs are ignored! */
1793
1794 void tq_ring_int (struct uq_ring *ring)
1795 {
1796 uint32 iadr = tq_comm + ring->ioff; /* addr intr wd */
1797 uint16 flag = 1;
1798
1799 Map_WriteW (iadr, 2, &flag); /* write flag */
1800 if (tq_dib.vec) SET_INT (TQ); /* if enb, intr */
1801 return;
1802 }
1803
1804 /* Return interrupt vector */
1805
1806 int32 tq_inta (void)
1807 {
1808 return tq_dib.vec; /* prog vector */
1809 }
1810
1811 /* Fatal error */
1812
1813 t_bool tq_fatal (uint32 err)
1814 {
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 */
1820 return ERR;
1821 }
1822
1823 /* Device attach */
1824
1825 t_stat tq_attach (UNIT *uptr, char *cptr)
1826 {
1827 t_stat r;
1828
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);
1833 return SCPE_OK;
1834 }
1835
1836 /* Device detach */
1837
1838 t_stat tq_detach (UNIT *uptr)
1839 {
1840 t_stat r;
1841
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 */
1846 return SCPE_OK;
1847 }
1848
1849 /* Device reset */
1850
1851 t_stat tq_reset (DEVICE *dptr)
1852 {
1853 int32 i, j;
1854 UNIT *uptr;
1855
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;
1872 }
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 */
1885 }
1886 if (tqxb == NULL) tqxb = (uint8 *) calloc (TQ_MAXFR, sizeof (uint8));
1887 if (tqxb == NULL) return SCPE_MEM;
1888 return SCPE_OK;
1889 }
1890
1891 /* Device bootstrap */
1892
1893 #if defined (VM_PDP11)
1894
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))
1900
1901 /* Data structure definitions */
1902
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 # */
1911
1912 static const uint16 boot_rom[] = {
1913
1914 0046525, /* ST: "UM" */
1915
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 */
1926
1927 /* Four step init process */
1928
1929 0005711, /* 20$: tst (r1) ; err? */
1930 0100001, /* bpl 30$ */
1931 0000000, /* halt */
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? */
1937
1938 /* Set up rings, issue ONLINE, REWIND, READ */
1939
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$ */
1956 0000000, /* halt */
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$ */
1971 0000000, /* halt */
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$ */
1985 0000000, /* halt */
1986
1987 /* Boot block read in, jump to 0 - leave controller init'd */
1988
1989 0005003, /* clr r3 */
1990 0012704, BOOT_START+020, /* mov #st+020,r4 */
1991 0005005, /* clr r5 */
1992 0005007, /* clr pc */
1993
1994 0100000, /* cmdtbl: init step 1 */
1995 B_RING, /* ring base */
1996 0000000, /* high ring base */
1997 0000001 /* go */
1998 };
1999
2000 t_stat tq_boot (int32 unitno, DEVICE *dptr)
2001 {
2002 int32 i;
2003 extern int32 saved_PC;
2004 extern uint16 *M;
2005
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;
2010 return SCPE_OK;
2011 }
2012
2013 #else
2014
2015 t_stat tq_boot (int32 unitno, DEVICE *dptr)
2016 {
2017 return SCPE_NOFNC;
2018 }
2019
2020 #endif
2021
2022 /* Special show commands */
2023
2024 void tq_show_ring (FILE *st, struct uq_ring *rp)
2025 {
2026 uint32 i, desc;
2027 uint16 d[2];
2028
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);
2032 #else
2033 fprintf (st, "ring, base = %x, index = %d, length = %d\n",
2034 rp->ba, rp->idx >> 2, rp->lnt >> 2);
2035 #endif
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);
2039 break;
2040 }
2041 desc = ((uint32) d[0]) | (((uint32) d[1]) << 16);
2042 #if defined (VM_PDP11)
2043 fprintf (st, " %3d: %011o\n", i, desc);
2044 #else
2045 fprintf (st, " %3d: %08x\n", i, desc);
2046 #endif
2047 }
2048 return;
2049 }
2050
2051 void tq_show_pkt (FILE *st, int32 pkt)
2052 {
2053 int32 i, j;
2054 uint32 cr = GETP (pkt, UQ_HCTC, CR);
2055 uint32 typ = GETP (pkt, UQ_HCTC, TYP);
2056 uint32 cid = GETP (pkt, UQ_HCTC, CID);
2057
2058 fprintf (st, "packet %d, credits = %d, type = %d, cid = %d\n",
2059 pkt, cr, typ, cid);
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]);
2065 #else
2066 fprintf (st, " %04x", tq_pkt[pkt].d[j]);
2067 #endif
2068 fprintf (st, "\n");
2069 }
2070 return;
2071 }
2072
2073 t_stat tq_show_unitq (FILE *st, UNIT *uptr, int32 val, void *desc)
2074 {
2075 int32 pkt, u = uptr - tq_dev.units;
2076
2077 if (tq_csta != CST_UP) {
2078 fprintf (st, "Controller is not initialized\n");
2079 return SCPE_OK;
2080 }
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);
2085 return SCPE_OK;
2086 }
2087 if (uptr->cpkt) {
2088 fprintf (st, "Unit %d current ", u);
2089 tq_show_pkt (st, uptr->cpkt);
2090 if (pkt = uptr->pktq) {
2091 do {
2092 fprintf (st, "Unit %d queued ", u);
2093 tq_show_pkt (st, pkt);
2094 } while (pkt = tq_pkt[pkt].link);
2095 }
2096 }
2097 else fprintf (st, "Unit %d queues are empty\n", u);
2098 return SCPE_OK;
2099 }
2100
2101 t_stat tq_show_ctrl (FILE *st, UNIT *uptr, int32 val, void *desc)
2102 {
2103 int32 i, pkt;
2104
2105 if (tq_csta != CST_UP) {
2106 fprintf (st, "Controller is not initialized\n");
2107 return SCPE_OK;
2108 }
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);
2116 }
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);
2123 }
2124 fprintf (st, "\n");
2125 }
2126 else fprintf (st, "Free queue is empty\n");
2127 }
2128 if (val & TQ_SH_RS) {
2129 if (pkt = tq_rspq) {
2130 do {
2131 fprintf (st, "Response ");
2132 tq_show_pkt (st, pkt);
2133 } while (pkt = tq_pkt[pkt].link);
2134 }
2135 else fprintf (st, "Response queue is empty\n");
2136 }
2137 if (val & TQ_SH_UN) {
2138 for (i = 0; i < TQ_NUMDR; i++)
2139 tq_show_unitq (st, &tq_unit[i], 0, NULL);
2140 }
2141 return SCPE_OK;
2142 }
2143
2144 /* Set controller type (and capacity for user-defined type) */
2145
2146 t_stat tq_set_type (UNIT *uptr, int32 val, char *cptr, void *desc)
2147 {
2148 uint32 i, cap;
2149 uint32 max = sim_taddr_64? TQU_EMAXC: TQU_MAXC;
2150 t_stat r;
2151
2152 if ((val < 0) || (val > TQU_TYPE) || ((val != TQU_TYPE) && cptr))
2153 return SCPE_ARG;
2154 for (i = 0; i < TQ_NUMDR; i++) {
2155 if (tq_unit[i].flags & UNIT_ATT) return SCPE_ALATT;
2156 }
2157 if (cptr) {
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;
2161 }
2162 tq_typ = val;
2163 for (i = 0; i < TQ_NUMDR; i++)
2164 tq_unit[i].capac = drv_tab[tq_typ].cap;
2165 return SCPE_OK;
2166 }
2167
2168 /* Show controller type and capacity */
2169
2170 t_stat tq_show_type (FILE *st, UNIT *uptr, int32 val, void *desc)
2171 {
2172 fprintf (st, "%s (%dMB)", drv_tab[tq_typ].name, (uint32) (drv_tab[tq_typ].cap >> 20));
2173 return SCPE_OK;
2174 }