1 /* pdp11_tq.c: TMSCP tape controller simulator
2 
3    Copyright (c) 2002-2011, 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    17-Aug-11    RMS     Added CAPACITY modifier
29    14-Jan-11    MP      Various fixes discovered while exploring Ultrix issue:
30                         - Set UNIT_SXC flag when a tape mark is encountered
31                           during forward motion read operations
32                         - Fixed logic which clears UNIT_SXC to check command
33                           modifier
34                         - Added CMF_WR flag to tq_cmf entry for OP_WTM
35                         - Made non-immediate rewind positioning operations
36                           take 2 seconds
37                         - Added UNIT_IDLE flag to tq units
38                         - Fixed debug output of tape file positions when they
39                           are 64b
40                         - Added more debug output after positioning operations.
41                         - Added textual display of the command being performed
42    23-Dec-10    RMS     Fixed comments about register addresses
43    18-Jun-07    RMS     Added UNIT_IDLE flag to timer thread
44    16-Feb-06    RMS     Revised for new magtape capacity checking
45    31-Oct-05    RMS     Fixed address width for large files
46    16-Aug-05    RMS     Fixed C++ declaration and cast problems
47    22-Jul-05    RMS     Fixed warning from Solaris C (Doug Gwyn)
48    30-Sep-04    RMS     Revised Unibus interface
49    12-Jun-04    RMS     Fixed bug in reporting write protect (Lyle Bickley)
50    18-Apr-04    RMS     Fixed TQK70 media ID and model byte (Robert Schaffrath)
51    26-Mar-04    RMS     Fixed warnings with -std=c99
52    25-Jan-04    RMS     Revised for device debug support
53    19-May-03    RMS     Revised for new conditional compilation scheme
54    25-Apr-03    RMS     Revised for extended file support
55    28-Mar-03    RMS     Added multiformat support
56    28-Feb-03    RMS     Added variable controller, user-defined drive support
57    26-Feb-03    RMS     Fixed bug in vector calculation for VAXen
58    22-Feb-03    RMS     Fixed ordering bug in queue process
59                         Fixed flags table to allow MD_CSE everywhere
60    09-Jan-03    RMS     Fixed bug in transfer end packet status
61    17-Oct-02    RMS     Fixed bug in read reverse (Hans Pufal)
62 */
63 
64 #if defined (VM_PDP10)                                  /* PDP10 version */
65 #error "TQK50 not supported on PDP-10!"
66 
67 #elif defined (VM_VAX)                                  /* VAX version */
68 #include "vax_defs.h"
69 #if (UNIBUS)
70 #define INIT_TYPE       TQ8_TYPE
71 #define INIT_CAP        TQ8_CAP
72 #else
73 #define INIT_TYPE       TQ5_TYPE
74 #define INIT_CAP        TQ5_CAP
75 #endif
76 
77 #else                                                   /* PDP-11 version */
78 #include "pdp11_defs.h"
79 #define INIT_TYPE       TQ5_TYPE
80 #define INIT_CAP        TQ5_CAP
81 extern uint32 cpu_opt;
82 #endif
83 
84 #include "pdp11_uqssp.h"
85 #include "pdp11_mscp.h"
86 #include "sim_tape.h"
87 
88 #define UF_MSK          (UF_SCH|UF_VSS|UF_CMR|UF_CMW)   /* settable flags */
89 
90 #define TQ_SH_MAX       24                              /* max display wds */
91 #define TQ_SH_PPL       8                               /* wds per line */
92 #define TQ_SH_DPL       4                               /* desc per line */
93 #define TQ_SH_RI        001                             /* show rings */
94 #define TQ_SH_FR        002                             /* show free q */
95 #define TQ_SH_RS        004                             /* show resp q */
96 #define TQ_SH_UN        010                             /* show unit q's */
97 #define TQ_SH_ALL       017                             /* show all */
98 
99 #define TQ_CLASS        1                               /* TQK50 class */
100 #define TQ_DHTMO        0                               /* def host timeout */
101 #define TQ_DCTMO        120                             /* def ctrl timeout */
102 #define TQ_NUMDR        4                               /* # drives */
103 #define TQ_MAXFR        (1 << 16)                       /* max xfer */
104 
105 #define UNIT_V_ONL      (MTUF_V_UF + 0)                 /* online */
106 #define UNIT_V_ATP      (MTUF_V_UF + 1)                 /* attn pending */
107 #define UNIT_V_SXC      (MTUF_V_UF + 2)                 /* serious exc */
108 #define UNIT_V_POL      (MTUF_V_UF + 3)                 /* position lost */
109 #define UNIT_V_TMK      (MTUF_V_UF + 4)                 /* tape mark seen */
110 #define UNIT_ONL        (1 << UNIT_V_ONL)
111 #define UNIT_ATP        (1 << UNIT_V_ATP)
112 #define UNIT_SXC        (1 << UNIT_V_SXC)
113 #define UNIT_POL        (1 << UNIT_V_POL)
114 #define UNIT_TMK        (1 << UNIT_V_TMK)
115 #define cpkt            u3                              /* current packet */
116 #define pktq            u4                              /* packet queue */
117 #define uf              buf                             /* settable unit flags */
118 #define objp            wait                            /* object position */
119 #define TQ_WPH(u)       ((sim_tape_wrp (u))? UF_WPH: 0)
120 
121 #define CST_S1          0                               /* init stage 1 */
122 #define CST_S1_WR       1                               /* stage 1 wrap */
123 #define CST_S2          2                               /* init stage 2 */
124 #define CST_S3          3                               /* init stage 3 */
125 #define CST_S3_PPA      4                               /* stage 3 sa wait */
126 #define CST_S3_PPB      5                               /* stage 3 ip wait */
127 #define CST_S4          6                               /* stage 4 */
128 #define CST_UP          7                               /* online */
129 #define CST_DEAD        8                               /* fatal error */
130 
131 #define tq_comm         tq_rq.ba
132 
133 #define ERR             0                               /* must be SCPE_OK! */
134 #define OK              1
135 
136 #define CMF_IMM         0x10000                         /* immediate */
137 #define CMF_SEQ         0x20000                         /* sequential */
138 #define CMF_WR          0x40000                         /* write */
139 #define CMF_RW          0x80000                         /* resp to GCS */
140 
141 /* Internal packet management */
142 
143 #define TQ_NPKTS        32                              /* # packets (pwr of 2) */
144 #define TQ_M_NPKTS      (TQ_NPKTS - 1)                  /* mask */
145 #define TQ_PKT_SIZE_W   32                              /* payload size (wds) */
146 #define TQ_PKT_SIZE     (TQ_PKT_SIZE_W * sizeof (int16))
147 
148 struct tqpkt {
149     int16       link;                                   /* link to next */
150     uint16      d[TQ_PKT_SIZE_W];                       /* data */
151     };
152 
153 /* Packet payload extraction and insertion */
154 
155 #define GETP(p,w,f)     ((tq_pkt[p].d[w] >> w##_V_##f) & w##_M_##f)
156 #define GETP32(p,w)     (((uint32) tq_pkt[p].d[w]) | \
157                         (((uint32) tq_pkt[p].d[(w)+1]) << 16))
158 #define PUTP32(p,w,x)   tq_pkt[p].d[w] = (x) & 0xFFFF; \
159                         tq_pkt[p].d[(w)+1] = ((x) >> 16) & 0xFFFF
160 
161 /* Controller and device types - TQK50 must be swre rev 5 or later */
162 
163 #define TQ5_TYPE        0                               /* TK50 */
164 #define TQ5_UQPM        3                               /* UQ port ID */
165 #define TQ5_CMOD        9                               /* ctrl ID */
166 #define TQ5_UMOD        3                               /* unit ID */
167 #define TQ5_MED         0x6D68B032                      /* media ID */
168 #define TQ5_CREV        ((1 << 8) | 5)                  /* ctrl revs */
169 #define TQ5_FREV        0                               /* formatter revs */
170 #define TQ5_UREV        0                               /* unit revs */
171 #define TQ5_CAP         (94 * (1 << 20))                /* capacity */
172 #define TQ5_FMT         (TF_CTP|TF_CTP_LO)              /* menu */
173 
174 #define TQ7_TYPE        1                               /* TK70 */
175 #define TQ7_UQPM        14                              /* UQ port ID */
176 #define TQ7_CMOD        14                              /* ctrl ID */
177 #define TQ7_UMOD        14                              /* unit ID */
178 #define TQ7_MED         0x6D68B046                      /* media ID */
179 #define TQ7_CREV        ((1 << 8) | 5)                  /* ctrl revs */
180 #define TQ7_FREV        0                               /* formatter revs */
181 #define TQ7_UREV        0                               /* unit revs */
182 #define TQ7_CAP         (300 * (1 << 20))               /* capacity */
183 #define TQ7_FMT         (TF_CTP|TF_CTP_LO)              /* menu */
184 
185 #define TQ8_TYPE        2                               /* TU81 */
186 #define TQ8_UQPM        5                               /* UQ port ID */
187 #define TQ8_CMOD        5                               /* ctrl ID */
188 #define TQ8_UMOD        2                               /* unit ID */
189 #define TQ8_MED         0x6D695051                      /* media ID */
190 #define TQ8_CREV        ((1 << 8) | 5)                  /* ctrl revs */
191 #define TQ8_FREV        0                               /* formatter revs */
192 #define TQ8_UREV        0                               /* unit revs */
193 #define TQ8_CAP         (180 * (1 << 20))               /* capacity */
194 #define TQ8_FMT         (TF_9TK|TF_9TK_GRP)             /* menu */
195 
196 #define TQU_TYPE        3                               /* TKuser defined */
197 #define TQU_UQPM        3                               /* UQ port ID */
198 #define TQU_CMOD        9                               /* ctrl ID */
199 #define TQU_UMOD        3                               /* unit ID */
200 #define TQU_MED         0x6D68B032                      /* media ID */
201 #define TQU_CREV        ((1 << 8) | 5)                  /* ctrl revs */
202 #define TQU_FREV        0                               /* formatter revs */
203 #define TQU_UREV        0                               /* unit revs */
204 #define TQU_CAP         (94 * (1 << 20))                /* capacity */
205 #define TQU_FMT         (TF_CTP|TF_CTP_LO)              /* menu */
206 #define TQU_MINC        30                              /* min cap MB */
207 #define TQU_MAXC        2000                            /* max cap MB */
208 #define TQU_EMAXC       2000000000                      /* ext max cap MB */
209 
210 #define TQ_DRV(d) \
211     d##_UQPM, \
212     d##_CMOD, d##_MED,  d##_FMT,  d##_CAP, \
213     d##_UMOD, d##_CREV, d##_FREV, d##_UREV
214 
215 #define TEST_EOT(u)     (sim_tape_eot (u))
216 
217 struct drvtyp {
218     uint32      uqpm;                                   /* UQ port model */
219     uint32      cmod;                                   /* ctrl model */
220     uint32      med;                                    /* MSCP media */
221     uint32      fmt;                                    /* flags */
222     t_addr      cap;                                    /* capacity */
223     uint32      umod;                                   /* unit model */
224     uint32      cver;
225     uint32      fver;
226     uint32      uver;
227     char        *name;
228     };
229 
230 static struct drvtyp drv_tab[] = {
231     { TQ_DRV (TQ5), "TK50" },
232     { TQ_DRV (TQ7), "TK70" },
233     { TQ_DRV (TQ8), "TU81" },
234     { TQ_DRV (TQU), "TKUSER" },
235     };
236 
237 /* Data */
238 
239 extern int32 int_req[IPL_HLVL];
240 extern int32 tmr_poll, clk_tps;
241 extern FILE *sim_deb;
242 extern uint32 sim_taddr_64;
243 
244 uint8 *tqxb = NULL;                                     /* xfer buffer */
245 uint32 tq_sa = 0;                                       /* status, addr */
246 uint32 tq_saw = 0;                                      /* written data */
247 uint32 tq_s1dat = 0;                                    /* S1 data */
248 uint32 tq_csta = 0;                                     /* ctrl state */
249 uint32 tq_perr = 0;                                     /* last error */
250 uint32 tq_cflgs = 0;                                    /* ctrl flags */
251 uint32 tq_prgi = 0;                                     /* purge int */
252 uint32 tq_pip = 0;                                      /* poll in progress */
253 struct uq_ring tq_cq = { 0 };                           /* cmd ring */
254 struct uq_ring tq_rq = { 0 };                           /* rsp ring */
255 struct tqpkt tq_pkt[TQ_NPKTS];                          /* packet queue */
256 int32 tq_freq = 0;                                      /* free list */
257 int32 tq_rspq = 0;                                      /* resp list */
258 uint32 tq_pbsy = 0;                                     /* #busy pkts */
259 uint32 tq_credits = 0;                                  /* credits */
260 uint32 tq_hat = 0;                                      /* host timer */
261 uint32 tq_htmo = TQ_DHTMO;                              /* host timeout */
262 int32 tq_itime = 200;                                   /* init time, except */
263 int32 tq_itime4 = 10;                                   /* stage 4 */
264 int32 tq_qtime = 200;                                   /* queue time */
265 int32 tq_xtime = 500;                                   /* transfer time */
266 int32 tq_rwtime = 2000000;                              /* rewind time 2 sec (adjusted later) */
267 int32 tq_typ = INIT_TYPE;                               /* device type */
268 
269 /* Command table - legal modifiers (low 16b) and flags (high 16b) */
270 
271 static uint32 tq_cmf[64] = {
272     0,                                                  /* 0 */
273     CMF_IMM,                                            /* abort */
274     CMF_IMM|MD_CSE,                                     /* get cmd status */
275     CMF_IMM|MD_CSE|MD_NXU,                              /* get unit status */
276     CMF_IMM|MD_CSE,                                     /* set ctrl char */
277     0, 0, 0,                                            /* 5-7 */
278     CMF_SEQ|MD_ACL|MD_CDL|MD_CSE|MD_EXA|MD_UNL,         /* available */
279     CMF_SEQ|MD_CDL|MD_CSE|MD_SWP|MD_EXA,                /* online */
280     CMF_SEQ|MD_CDL|MD_CSE|MD_SWP|MD_EXA,                /* set unit char */
281     CMF_IMM,                                            /* define acc paths */
282     0, 0, 0, 0,                                         /* 12-15 */
283     CMF_SEQ|CMF_RW|MD_CDL|MD_CSE|MD_REV|                /* access */
284             MD_SCH|MD_SEC|MD_SER,
285     0,                                                  /* 17 */
286     CMF_SEQ|CMF_WR|MD_CDL|MD_CSE|MD_IMM,                /* erase */
287     CMF_SEQ|CMF_WR|MD_CDL|MD_CSE,                       /* flush */
288     0, 0,                                               /* 20-21 */
289     CMF_SEQ|CMF_WR|MD_CDL|MD_CSE|MD_IMM,                /* erase gap */
290     0, 0, 0, 0, 0, 0, 0, 0, 0,                          /* 22-31 */
291     CMF_SEQ|CMF_RW|MD_CDL|MD_CSE|MD_REV|                /* compare */
292             MD_SCH|MD_SEC|MD_SER,
293     CMF_SEQ|CMF_RW|MD_CDL|MD_CSE|MD_REV|MD_CMP|         /* read */
294             MD_SCH|MD_SEC|MD_SER,
295     CMF_SEQ|CMF_RW|CMF_WR|MD_CDL|MD_CSE|MD_IMM|         /* write */
296             MD_CMP|MD_ERW|MD_SEC|MD_SER,
297     0,                                                  /* 35 */
298     CMF_SEQ|CMF_WR|MD_CDL|MD_CSE|MD_IMM,                /* wr tape mark */
299     CMF_SEQ|MD_CDL|MD_CSE|MD_IMM|MD_OBC|                /* reposition */
300             MD_REV|MD_RWD|MD_DLE|
301             MD_SCH|MD_SEC|MD_SER,
302     0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                       /* 38-47 */
303     0, 0, 0, 0, 0, 0, 0, 0,
304     0, 0, 0, 0, 0, 0, 0, 0
305     };
306 
307 static char *tq_cmdname[] = {
308     "",                                                 /*  0 */
309     "ABO",                                              /*  1 b: abort */
310     "GCS",                                              /*  2 b: get command status */
311     "GUS",                                              /*  3 b: get unit status */
312     "SCC",                                              /*  4 b: set controller char */
313     "","","",                                           /*  5-7 */
314     "AVL",                                              /*  8 b: available */
315     "ONL",                                              /*  9 b: online */
316     "SUC",                                              /* 10 b: set unit char */
317     "DAP",                                              /* 11 b: det acc paths - nop */
318     "","","","",                                        /* 12-15 */
319     "ACC",                                              /* 16 b: access */
320     "CCD",                                              /* 17 d: compare - nop */
321     "ERS",                                              /* 18 b: erase */
322     "FLU",                                              /* 19 d: flush - nop */
323     "","",                                              /* 20-21 */
324     "ERG",                                              /* 22 t: erase gap */
325     "","","","","","","","","",                         /* 23-31 */
326     "CMP",                                              /* 32 b: compare */
327     "RD",                                               /* 33 b: read */
328     "WR",                                               /* 34 b: write */
329     "",                                                 /* 35 */
330     "WTM",                                              /* 36 t: write tape mark */
331     "POS",                                              /* 37 t: reposition */
332     "","","","","","","","","",                         /* 38-46 */
333     "FMT",                                              /* 47 d: format */
334     "","","","","","","","","","","","","","","","",    /* 48-63 */
335     "AVA",                                              /* 64 b: unit now avail */
336     };
337 
338 /* Forward references */
339 
340 DEVICE tq_dev;
341 
342 t_stat tq_rd (int32 *data, int32 PA, int32 access);
343 t_stat tq_wr (int32 data, int32 PA, int32 access);
344 t_stat tq_inta (void);
345 t_stat tq_svc (UNIT *uptr);
346 t_stat tq_tmrsvc (UNIT *uptr);
347 t_stat tq_quesvc (UNIT *uptr);
348 t_stat tq_reset (DEVICE *dptr);
349 t_stat tq_attach (UNIT *uptr, char *cptr);
350 t_stat tq_detach (UNIT *uptr);
351 t_stat tq_boot (int32 unitno, DEVICE *dptr);
352 t_stat tq_set_wlk (UNIT *uptr, int32 val, char *cptr, void *desc);
353 t_stat tq_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
354 t_stat tq_show_ctrl (FILE *st, UNIT *uptr, int32 val, void *desc);
355 t_stat tq_show_unitq (FILE *st, UNIT *uptr, int32 val, void *desc);
356 t_stat tq_set_type (UNIT *uptr, int32 val, char *cptr, void *desc);
357 t_stat tq_show_type (FILE *st, UNIT *uptr, int32 val, void *desc);
358 
359 t_bool tq_step4 (void);
360 t_bool tq_mscp (int32 pkt, t_bool q);
361 t_bool tq_abo (int32 pkt);
362 t_bool tq_avl (int32 pkt);
363 t_bool tq_erase (int32 pkt);
364 t_bool tq_flu (int32 pkt);
365 t_bool tq_gcs (int32 pkt);
366 t_bool tq_gus (int32 pkt);
367 t_bool tq_onl (int32 pkt);
368 t_bool tq_pos (int32 pkt);
369 t_bool tq_rw (int32 pkt);
370 t_bool tq_scc (int32 pkt);
371 t_bool tq_suc (int32 pkt);
372 t_bool tq_wtm (int32 pkt);
373 t_bool tq_plf (uint32 err);
374 t_bool tq_dte (UNIT *uptr, uint32 err);
375 t_bool tq_hbe (UNIT *uptr, uint32 ba);
376 t_bool tq_una (UNIT *uptr);
377 uint32 tq_map_status (UNIT *uptr, t_stat st);
378 uint32 tq_spacef (UNIT *uptr, uint32 cnt, uint32 *skipped, t_bool qrec);
379 uint32 tq_skipff (UNIT *uptr, uint32 cnt, uint32 *skipped);
380 uint32 tq_rdbuff (UNIT *uptr, t_mtrlnt *tbc);
381 uint32 tq_spacer (UNIT *uptr, uint32 cnt, uint32 *skipped, t_bool qrec);
382 uint32 tq_skipfr (UNIT *uptr, uint32 cnt, uint32 *skipped);
383 uint32 tq_rdbufr (UNIT *uptr, t_mtrlnt *tbc);
384 t_bool tq_deqf (int32 *pkt);
385 int32 tq_deqh (int32 *lh);
386 void tq_enqh (int32 *lh, int32 pkt);
387 void tq_enqt (int32 *lh, int32 pkt);
388 t_bool tq_getpkt (int32 *pkt);
389 t_bool tq_putpkt (int32 pkt, t_bool qt);
390 t_bool tq_getdesc (struct uq_ring *ring, uint32 *desc);
391 t_bool tq_putdesc (struct uq_ring *ring, uint32 desc);
392 int32 tq_mot_valid (UNIT *uptr, uint32 cmd);
393 t_stat tq_mot_err (UNIT *uptr, uint32 rsiz);
394 t_bool tq_mot_end (UNIT *uptr, uint32 flg, uint32 sts, uint32 rsiz);
395 void tq_putr (int32 pkt, uint32 cmd, uint32 flg, uint32 sts, uint32 lnt, uint32 typ);
396 void tq_putr_unit (int32 pkt, UNIT *uptr, uint32 lu, t_bool all);
397 void tq_setf_unit (int32 pkt, UNIT *uptr);
398 uint32 tq_efl (UNIT *uptr);
399 void tq_init_int (void);
400 void tq_ring_int (struct uq_ring *ring);
401 t_bool tq_fatal (uint32 err);
402 UNIT *tq_getucb (uint32 lu);
403 
404 /* TQ data structures
405 
406    tq_dev       TQ device descriptor
407    tq_unit      TQ unit list
408    tq_reg       TQ register list
409    tq_mod       TQ modifier list
410 */
411 
412 DIB tq_dib = {
413     IOBA_TQ, IOLN_TQ, &tq_rd, &tq_wr,
414     1, IVCL (TQ), 0, { &tq_inta }
415     };
416 
417 UNIT tq_unit[] = {
418     { UDATA (&tq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE|UNIT_ROABLE, INIT_CAP) },
419     { UDATA (&tq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE|UNIT_ROABLE, INIT_CAP) },
420     { UDATA (&tq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE|UNIT_ROABLE, INIT_CAP) },
421     { UDATA (&tq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE|UNIT_ROABLE, INIT_CAP) },
422     { UDATA (&tq_tmrsvc, UNIT_IDLE|UNIT_DIS, 0) },
423     { UDATA (&tq_quesvc, UNIT_IDLE|UNIT_DIS, 0) }
424     };
425 
426 #define TQ_TIMER        (TQ_NUMDR)
427 #define TQ_QUEUE        (TQ_TIMER + 1)
428 
429 REG tq_reg[] = {
430     { GRDATA (SA, tq_sa, DEV_RDX, 16, 0) },
431     { GRDATA (SAW, tq_saw, DEV_RDX, 16, 0) },
432     { GRDATA (S1DAT, tq_s1dat, DEV_RDX, 16, 0) },
433     { GRDATA (CQBA, tq_cq.ba, DEV_RDX, 22, 0) },
434     { GRDATA (CQLNT, tq_cq.lnt, DEV_RDX, 8, 2), REG_NZ },
435     { GRDATA (CQIDX, tq_cq.idx, DEV_RDX, 8, 2) },
436     { GRDATA (TQBA, tq_rq.ba, DEV_RDX, 22, 0) },
437     { GRDATA (TQLNT, tq_rq.lnt, DEV_RDX, 8, 2), REG_NZ },
438     { GRDATA (TQIDX, tq_rq.idx, DEV_RDX, 8, 2) },
439     { DRDATA (FREE, tq_freq, 5) },
440     { DRDATA (RESP, tq_rspq, 5) },
441     { DRDATA (PBSY, tq_pbsy, 5) },
442     { GRDATA (CFLGS, tq_cflgs, DEV_RDX, 16, 0) },
443     { GRDATA (CSTA, tq_csta, DEV_RDX, 4, 0) },
444     { GRDATA (PERR, tq_perr, DEV_RDX, 9, 0) },
445     { DRDATA (CRED, tq_credits, 5) },
446     { DRDATA (HAT, tq_hat, 17) },
447     { DRDATA (HTMO, tq_htmo, 17) },
448     { URDATA (CPKT, tq_unit[0].cpkt, 10, 5, 0, TQ_NUMDR, 0) },
449     { URDATA (PKTQ, tq_unit[0].pktq, 10, 5, 0, TQ_NUMDR, 0) },
450     { URDATA (UFLG, tq_unit[0].uf, DEV_RDX, 16, 0, TQ_NUMDR, 0) },
451     { URDATA (POS, tq_unit[0].pos, 10, T_ADDR_W, 0, TQ_NUMDR, 0) },
452     { URDATA (OBJP, tq_unit[0].objp, 10, 32, 0, TQ_NUMDR, 0) },
453     { FLDATA (PRGI, tq_prgi, 0), REG_HIDDEN },
454     { FLDATA (PIP, tq_pip, 0), REG_HIDDEN },
455     { FLDATA (INT, IREQ (TQ), INT_V_TQ) },
456     { DRDATA (ITIME, tq_itime, 24), PV_LEFT + REG_NZ },
457     { DRDATA (I4TIME, tq_itime4, 24), PV_LEFT + REG_NZ },
458     { DRDATA (QTIME, tq_qtime, 24), PV_LEFT + REG_NZ },
459     { DRDATA (XTIME, tq_xtime, 24), PV_LEFT + REG_NZ },
460     { DRDATA (RWTIME, tq_rwtime, 32), PV_LEFT + REG_NZ },
461     { BRDATA (PKTS, tq_pkt, DEV_RDX, 16, TQ_NPKTS * (TQ_PKT_SIZE_W + 1)) },
462     { DRDATA (DEVTYPE, tq_typ, 2), REG_HRO },
463     { DRDATA (DEVCAP, drv_tab[TQU_TYPE].cap, T_ADDR_W), PV_LEFT | REG_HRO },
464     { GRDATA (DEVADDR, tq_dib.ba, DEV_RDX, 32, 0), REG_HRO },
465     { GRDATA (DEVVEC, tq_dib.vec, DEV_RDX, 16, 0), REG_HRO },
466     { NULL }
467     };
468 
469 MTAB tq_mod[] = {
470     { MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL },
471     { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL },
472     { MTAB_XTD | MTAB_VDV, TQ5_TYPE, NULL, "TK50",
473       &tq_set_type, NULL, NULL },
474     { MTAB_XTD | MTAB_VDV, TQ7_TYPE, NULL, "TK70",
475       &tq_set_type, NULL, NULL },
476     { MTAB_XTD | MTAB_VDV, TQ8_TYPE, NULL, "TU81",
477       &tq_set_type, NULL, NULL },
478     { MTAB_XTD | MTAB_VDV, TQU_TYPE, NULL, "TKUSER",
479       &tq_set_type, NULL, NULL },
480     { MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL,
481       NULL, &tq_show_type, NULL },
482     { MTAB_XTD | MTAB_VDV | MTAB_NMO, TQ_SH_RI, "RINGS", NULL,
483       NULL, &tq_show_ctrl, NULL },
484     { MTAB_XTD | MTAB_VDV | MTAB_NMO, TQ_SH_FR, "FREEQ", NULL,
485       NULL, &tq_show_ctrl, NULL },
486     { MTAB_XTD | MTAB_VDV | MTAB_NMO, TQ_SH_RS, "RESPQ", NULL,
487       NULL, &tq_show_ctrl, NULL },
488     { MTAB_XTD | MTAB_VDV | MTAB_NMO, TQ_SH_UN, "UNITQ", NULL,
489       NULL, &tq_show_ctrl, NULL },
490     { MTAB_XTD | MTAB_VDV | MTAB_NMO, TQ_SH_ALL, "ALL", NULL,
491       NULL, &tq_show_ctrl, NULL },
492     { MTAB_XTD | MTAB_VUN | MTAB_NMO, 0, "UNITQ", NULL,
493       NULL, &tq_show_unitq, NULL },
494     { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT",
495       &sim_tape_set_fmt, &sim_tape_show_fmt, NULL },
496     { MTAB_XTD|MTAB_VUN, 0, "CAPACITY", "CAPACITY",
497       &sim_tape_set_capac, &sim_tape_show_capac, NULL },
498 #if defined (VM_PDP11)
499     { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS",
500       &set_addr, &show_addr, NULL },
501     { MTAB_XTD | MTAB_VDV, 0, NULL, "AUTOCONFIGURE",
502       &set_addr_flt, NULL, NULL },
503 #else
504     { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", NULL,
505       NULL, &show_addr, NULL },
506 #endif
507     { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL,
508       NULL, &show_vec, NULL },
509     { 0 }
510     };
511 
512 DEVICE tq_dev = {
513     "TQ", tq_unit, tq_reg, tq_mod,
514     TQ_NUMDR + 2, 10, T_ADDR_W, 1, DEV_RDX, 8,
515     NULL, NULL, &tq_reset,
516     &tq_boot, &tq_attach, &tq_detach,
517     &tq_dib, DEV_DISABLE | DEV_UBUS | DEV_QBUS | DEV_DEBUG
518     };
519 
520 /* I/O dispatch routines, I/O addresses 17774500 - 17774502
521 
522    17774500     IP      read/write
523    17774502     SA      read/write
524 */
525 
tq_rd(int32 * data,int32 PA,int32 access)526 t_stat tq_rd (int32 *data, int32 PA, int32 access)
527 {
528 switch ((PA >> 1) & 01) {                               /* decode PA<1> */
529     case 0:                                             /* IP */
530         *data = 0;                                      /* reads zero */
531         if (tq_csta == CST_S3_PPB)                      /* waiting for poll? */
532             tq_step4 ();
533         else if (tq_csta == CST_UP) {                   /* if up */
534             tq_pip = 1;                                 /* poll host */
535             sim_activate (&tq_unit[TQ_QUEUE], tq_qtime);
536             }
537         break;
538 
539     case 1:                                             /* SA */
540         *data = tq_sa;
541         break;
542         }
543 
544 return SCPE_OK;
545 }
546 
tq_wr(int32 data,int32 PA,int32 access)547 t_stat tq_wr (int32 data, int32 PA, int32 access)
548 {
549 switch ((PA >> 1) & 01) {                               /* decode PA<1> */
550 
551     case 0:                                             /* IP */
552         tq_reset (&tq_dev);                             /* init device */
553         if (DEBUG_PRS (tq_dev))
554             fprintf (sim_deb, ">>TQ: initialization started, time=%.0f\n",
555                      sim_gtime ());
556         break;
557 
558     case 1:                                             /* SA */
559         tq_saw = data;
560         if (tq_csta < CST_S4)                           /* stages 1-3 */
561             sim_activate (&tq_unit[TQ_QUEUE], tq_itime);
562         else if (tq_csta == CST_S4)                     /* stage 4 (fast) */
563             sim_activate (&tq_unit[TQ_QUEUE], tq_itime4);
564         break;
565         }
566 
567 return SCPE_OK;
568 }
569 
570 /* Transition to step 4 - init communications region */
571 
tq_step4(void)572 t_bool tq_step4 (void)
573 {
574 int32 i, lnt;
575 uint32 base;
576 uint16 zero[SA_COMM_MAX >> 1];
577 
578 tq_rq.ioff = SA_COMM_RI;                                /* set intr offset */
579 tq_rq.ba = tq_comm;                                     /* set rsp q base */
580 tq_rq.lnt = SA_S1H_RQ (tq_s1dat) << 2;                  /* get resp q len */
581 tq_cq.ioff = SA_COMM_CI;                                /* set intr offset */
582 tq_cq.ba = tq_comm + tq_rq.lnt;                         /* set cmd q base */
583 tq_cq.lnt = SA_S1H_CQ (tq_s1dat) << 2;                  /* get cmd q len */
584 tq_cq.idx = tq_rq.idx = 0;                              /* clear q idx's */
585 if (tq_prgi)
586     base = tq_comm + SA_COMM_QQ;
587 else base = tq_comm + SA_COMM_CI;
588 lnt = tq_comm + tq_cq.lnt + tq_rq.lnt - base;           /* comm lnt */
589 if (lnt > SA_COMM_MAX)                                  /* paranoia */
590     lnt = SA_COMM_MAX;
591 for (i = 0; i < (lnt >> 1); i++)                        /* clr buffer */
592     zero[i] = 0;
593 if (Map_WriteW (base, lnt, zero))                       /* zero comm area */
594     return tq_fatal (PE_QWE);                           /* error? */
595 tq_sa = SA_S4 | (drv_tab[tq_typ].uqpm << SA_S4C_V_MOD) |/* send step 4 */
596     ((drv_tab[tq_typ].cver & 0xFF) << SA_S4C_V_VER);
597 tq_csta = CST_S4;                                       /* set step 4 */
598 tq_init_int ();                                         /* poke host */
599 return OK;
600 }
601 
602 /* Queue service - invoked when any of the queues (host queue, unit
603    queues, response queue) require servicing.  Also invoked during
604    initialization to provide some delay to the next step.
605 
606    Process at most one item off each unit queue
607    If the unit queues were empty, process at most one item off the host queue
608    Process at most one item off the response queue
609 
610    If all queues are idle, terminate thread
611 */
612 
tq_quesvc(UNIT * uptr)613 t_stat tq_quesvc (UNIT *uptr)
614 {
615 int32 i, cnid;
616 int32 pkt = 0;
617 UNIT *nuptr;
618 
619 if (tq_csta < CST_UP) {                                 /* still init? */
620     switch (tq_csta) {                                  /* controller state? */
621 
622     case CST_S1:                                        /* need S1 reply */
623         if (tq_saw & SA_S1H_VL) {                       /* valid? */
624             if (tq_saw & SA_S1H_WR) {                   /* wrap? */
625                 tq_sa = tq_saw;                         /* echo data */
626                 tq_csta = CST_S1_WR;                    /* endless loop */
627                 }
628             else {
629                 tq_s1dat = tq_saw;                      /* save data */
630                 tq_dib.vec = (tq_s1dat & SA_S1H_VEC) << 2; /* get vector */
631                 if (tq_dib.vec)                         /* if nz, bias */
632                     tq_dib.vec = tq_dib.vec + VEC_Q;
633                 tq_sa = SA_S2 | SA_S2C_PT | SA_S2C_EC (tq_s1dat);
634                 tq_csta = CST_S2;                       /* now in step 2 */
635                 tq_init_int ();                         /* intr if req */
636                 }
637             }                                           /* end if valid */
638         break;
639 
640     case CST_S1_WR:                                     /* wrap mode */
641         tq_sa = tq_saw;                                 /* echo data */
642         break;
643 
644     case CST_S2:                                        /* need S2 reply */
645         tq_comm = tq_saw & SA_S2H_CLO;                  /* get low addr */
646         tq_prgi = tq_saw & SA_S2H_PI;                   /* get purge int */
647         tq_sa = SA_S3 | SA_S3C_EC (tq_s1dat);
648         tq_csta = CST_S3;                               /* now in step 3 */
649         tq_init_int ();                                 /* intr if req */
650         break;
651 
652     case CST_S3:                                        /* need S3 reply */
653         tq_comm = ((tq_saw & SA_S3H_CHI) << 16) | tq_comm;
654         if (tq_saw & SA_S3H_PP) {                       /* purge/poll test? */
655             tq_sa = 0;                                  /* put 0 */
656             tq_csta = CST_S3_PPA;                       /* wait for 0 write */
657             }
658         else tq_step4 ();                               /* send step 4 */
659         break;
660 
661     case CST_S3_PPA:                                    /* need purge test */
662         if (tq_saw)                                     /* data not zero? */
663             tq_fatal (PE_PPF);
664         else tq_csta = CST_S3_PPB;                      /* wait for poll */
665         break;
666 
667     case CST_S4:                                        /* need S4 reply */
668         if (tq_saw & SA_S4H_GO) {                       /* go set? */
669             if (DEBUG_PRS (tq_dev))
670                 fprintf (sim_deb, ">>TQ: initialization complete\n");
671             tq_csta = CST_UP;                           /* we're up */
672             tq_sa = 0;                                  /* clear SA */
673             sim_activate (&tq_unit[TQ_TIMER], tmr_poll * clk_tps);
674             if ((tq_saw & SA_S4H_LF) && tq_perr)
675                 tq_plf (tq_perr);
676             tq_perr = 0;
677             }
678         break;
679         }                                               /* end switch */
680     return SCPE_OK;
681     }                                                   /* end if */
682 
683 for (i = 0; i < TQ_NUMDR; i++) {                        /* chk unit q's */
684     nuptr = tq_dev.units + i;                           /* ptr to unit */
685     if (nuptr->cpkt || (nuptr->pktq == 0))
686         continue;
687     pkt = tq_deqh (&nuptr->pktq);                       /* get top of q */
688     if (!tq_mscp (pkt, FALSE))                          /* process */
689         return SCPE_OK;
690     }
691 if ((pkt == 0) && tq_pip) {                             /* polling? */
692     if (!tq_getpkt (&pkt))                              /* get host pkt */
693         return SCPE_OK;
694     if (pkt) {                                          /* got one? */
695         if (DEBUG_PRS (tq_dev)) {
696             UNIT *up = tq_getucb (tq_pkt[pkt].d[CMD_UN]);
697             fprintf (sim_deb, ">>TQ: cmd=%04X(%3s), mod=%04X, unit=%d, ",
698                 tq_pkt[pkt].d[CMD_OPC], tq_cmdname[tq_pkt[pkt].d[CMD_OPC]&0x3f], tq_pkt[pkt].d[CMD_MOD], tq_pkt[pkt].d[CMD_UN]);
699             fprintf (sim_deb, "bc=%04X%04X, ma=%04X%04X",
700                 tq_pkt[pkt].d[RW_BCH], tq_pkt[pkt].d[RW_BCL],
701                 tq_pkt[pkt].d[RW_BAH], tq_pkt[pkt].d[RW_BAL]);
702             if (up) {
703                 fprintf (sim_deb, ", pos=");
704                 fprint_val (sim_deb, up->pos, 10, T_ADDR_W, PV_LEFT);
705                 fprintf (sim_deb, ", obj=%d\n", up->objp);
706                 }
707             else fprintf (sim_deb, "\n");
708             fflush (sim_deb);
709             }
710         if (GETP (pkt, UQ_HCTC, TYP) != UQ_TYP_SEQ)     /* seq packet? */
711             return tq_fatal (PE_PIE);                   /* no, term thread */
712         cnid = GETP (pkt, UQ_HCTC, CID);                /* get conn ID */
713         if (cnid == UQ_CID_TMSCP) {                     /* TMSCP packet? */
714             if (!tq_mscp (pkt, TRUE))                   /* proc, q non-seq */
715                 return SCPE_OK;
716             }
717         else if (cnid == UQ_CID_DUP) {                  /* DUP packet? */
718             tq_putr (pkt, OP_END, 0, ST_CMD | I_OPCD, RSP_LNT, UQ_TYP_SEQ);
719             if (!tq_putpkt (pkt, TRUE))                 /* ill cmd */
720                 return SCPE_OK;
721             }
722         else return tq_fatal (PE_ICI);                  /* no, term thread */
723         }                                               /* end if pkt */
724     else tq_pip = 0;                                    /* discontinue poll */
725     }                                                   /* end if pip */
726 if (tq_rspq) {                                          /* resp q? */
727     pkt = tq_deqh (&tq_rspq);                           /* get top of q */
728     if (!tq_putpkt (pkt, FALSE))                        /* send to host */
729         return SCPE_OK;
730     }                                                   /* end if resp q */
731 if (pkt)                                                /* more to do? */
732     sim_activate (&tq_unit[TQ_QUEUE], tq_qtime);
733 return SCPE_OK;                                         /* done */
734 }
735 
736 /* Clock service (roughly once per second) */
737 
tq_tmrsvc(UNIT * uptr)738 t_stat tq_tmrsvc (UNIT *uptr)
739 {
740 int32 i;
741 UNIT *nuptr;
742 
743 sim_activate (uptr, tmr_poll * clk_tps);                /* reactivate */
744 for (i = 0; i < TQ_NUMDR; i++) {                        /* poll */
745     nuptr = tq_dev.units + i;
746     if ((nuptr->flags & UNIT_ATP) &&                    /* ATN pending? */
747         (nuptr->flags & UNIT_ATT) &&                    /* still online? */
748         (tq_cflgs & CF_ATN)) {                          /* wanted? */
749         if (!tq_una (nuptr))
750             return SCPE_OK;
751         }
752     nuptr->flags = nuptr->flags & ~UNIT_ATP;
753     }
754 if ((tq_hat > 0) && (--tq_hat == 0))                    /* host timeout? */
755     tq_fatal (PE_HAT);                                  /* fatal err */
756 return SCPE_OK;
757 }
758 
759 /* MSCP packet handling */
760 
tq_mscp(int32 pkt,t_bool q)761 t_bool tq_mscp (int32 pkt, t_bool q)
762 {
763 uint32 sts;
764 uint32 cmd = GETP (pkt, CMD_OPC, OPC);                  /* command */
765 uint32 flg = GETP (pkt, CMD_OPC, FLG);                  /* flags */
766 uint32 mdf = tq_pkt[pkt].d[CMD_MOD];                    /* modifier */
767 uint32 lu = tq_pkt[pkt].d[CMD_UN];                      /* unit # */
768 UNIT *uptr;
769 
770 if ((cmd >= 64) || (tq_cmf[cmd] == 0)) {                /* invalid cmd? */
771     cmd = OP_END;                                       /* set end op */
772     sts = ST_CMD | I_OPCD;                              /* ill op */
773     }
774 else if (flg) {                                         /* flags? */
775     cmd = cmd | OP_END;                                 /* set end flag */
776     sts = ST_CMD | I_FLAG;                              /* ill flags */
777     }
778 else if (mdf & ~tq_cmf[cmd]) {                          /* invalid mod? */
779     cmd = cmd | OP_END;                                 /* set end flag */
780     sts = ST_CMD | I_MODF;                              /* ill mods */
781     }
782 else {                                                  /* valid cmd */
783     if ((uptr = tq_getucb (lu))) {                      /* valid unit? */
784         if (q && (tq_cmf[cmd] & CMF_SEQ) &&             /* queueing, seq, */
785             (uptr->cpkt || uptr->pktq)) {               /* and active? */
786             tq_enqt (&uptr->pktq, pkt);                 /* do later */
787             return OK;
788             }
789 /*      if (tq_cmf[cmd] & MD_CDL)                       /* clr cch lost? */
790 /*          uptr->flags = uptr->flags & ~UNIT_CDL; */
791         if ((mdf & MD_CSE) && (uptr->flags & UNIT_SXC)) /* clr ser exc? */
792             uptr->flags = uptr->flags & ~UNIT_SXC;
793         }
794     switch (cmd) {
795 
796     case OP_ABO:                                        /* abort */
797         return tq_abo (pkt);
798 
799     case OP_AVL:                                        /* avail */
800         return tq_avl (pkt);
801 
802     case OP_GCS:                                        /* get cmd status */
803         return tq_gcs (pkt);
804 
805     case OP_GUS:                                        /* get unit status */
806         return tq_gus (pkt);
807 
808     case OP_ONL:                                        /* online */
809         return tq_onl (pkt);
810 
811     case OP_SCC:                                        /* set ctrl char */
812         return tq_scc (pkt);
813 
814     case OP_SUC:                                        /* set unit char */
815         return tq_suc (pkt);
816 
817     case OP_ERS:                                        /* erase */
818     case OP_ERG:                                        /* erase gap */
819         return tq_erase (pkt);
820 
821     case OP_FLU:                                        /* flush */
822         return tq_flu (pkt);
823 
824     case OP_POS:                                        /* position */
825         return tq_pos (pkt);
826 
827     case OP_WTM:                                        /* write tape mark */
828         return tq_wtm (pkt);
829 
830     case OP_ACC:                                        /* access */
831     case OP_CMP:                                        /* compare */
832     case OP_RD:                                         /* read */
833     case OP_WR:                                         /* write */
834         return tq_rw (pkt);
835 
836     case OP_DAP:
837         cmd = cmd | OP_END;                             /* set end flag */
838         sts = ST_SUC;                                   /* success */
839         break;
840 
841     default:
842         cmd = OP_END;                                   /* set end op */
843         sts = ST_CMD | I_OPCD;                          /* ill op */
844         break;
845         }                                               /* end switch */
846     }                                                   /* end else */
847 tq_putr (pkt, cmd, 0, sts, RSP_LNT, UQ_TYP_SEQ);
848 return tq_putpkt (pkt, TRUE);
849 }
850 
851 /* Abort a command - 1st parameter is ref # of cmd to abort */
852 
tq_abo(int32 pkt)853 t_bool tq_abo (int32 pkt)
854 {
855 uint32 lu = tq_pkt[pkt].d[CMD_UN];                      /* unit # */
856 uint32 ref = GETP32 (pkt, ABO_REFL);                    /* cmd ref # */
857 int32 tpkt, prv;
858 UNIT *uptr;
859 
860 tpkt = 0;                                               /* set no mtch */
861 if ((uptr = tq_getucb (lu))) {                          /* get unit */
862     if (uptr->cpkt &&                                   /* curr pkt? */
863         (GETP32 (uptr->cpkt, CMD_REFL) == ref)) {       /* match ref? */
864         tpkt = uptr->cpkt;                              /* save match */
865         uptr->cpkt = 0;                                 /* gonzo */
866         sim_cancel (uptr);                              /* cancel unit */
867         sim_activate (&tq_unit[TQ_QUEUE], tq_qtime);
868         }
869     else if (uptr->pktq &&                              /* head of q? */
870         (GETP32 (uptr->pktq, CMD_REFL) == ref)) {       /* match ref? */
871         tpkt = uptr->pktq;                              /* save match */
872         uptr->pktq = tq_pkt[tpkt].link;                 /* unlink */
873         }
874     else if ((prv = uptr->pktq)) {                      /* srch pkt q */
875         while ((tpkt = tq_pkt[prv].link)) {             /* walk list */
876             if (GETP32 (tpkt, RSP_REFL) == ref) {       /* match ref? */
877                 tq_pkt[prv].link = tq_pkt[tpkt].link;   /* unlink */
878                     break;
879                 }
880             }
881         }
882     if (tpkt) {                                         /* found target? */
883         uint32 tcmd = GETP (tpkt, CMD_OPC, OPC);        /* get opcode */
884         tq_putr (tpkt, tcmd | OP_END, 0, ST_ABO, RSP_LNT, UQ_TYP_SEQ);
885         if (!tq_putpkt (tpkt, TRUE))
886             return ERR;
887         }
888     }                                                   /* end if unit */
889 tq_putr (pkt, OP_ABO | OP_END, 0, ST_SUC, ABO_LNT, UQ_TYP_SEQ);
890 return tq_putpkt (pkt, TRUE);
891 }
892 
893 /* Unit available - set unit status to available
894    Deferred if q'd cmds, bypassed if ser exc */
895 
tq_avl(int32 pkt)896 t_bool tq_avl (int32 pkt)
897 {
898 uint32 lu = tq_pkt[pkt].d[CMD_UN];                      /* unit # */
899 uint32 mdf = tq_pkt[pkt].d[CMD_MOD];                    /* modifiers */
900 uint32 sts;
901 UNIT *uptr;
902 
903 if ((uptr = tq_getucb (lu))) {                          /* unit exist? */
904     if (uptr->flags & UNIT_SXC)                         /* ser exc pending? */
905         sts = ST_SXC;
906     else {
907         uptr->flags = uptr->flags & ~(UNIT_ONL | UNIT_TMK | UNIT_POL);
908         sim_tape_rewind (uptr);                         /* rewind */
909         uptr->uf = uptr->objp = 0;                      /* clr flags */
910         if (uptr->flags & UNIT_ATT) {                   /* attached? */
911             sts = ST_SUC;                               /* success */
912             if (mdf & MD_UNL)                           /* unload? */
913                 tq_detach (uptr);
914             }
915         else sts = ST_OFL | SB_OFL_NV;                  /* no, offline */
916         }
917     }
918 else sts = ST_OFL;                                      /* offline */
919 tq_putr (pkt, OP_AVL | OP_END, tq_efl (uptr), sts, AVL_LNT, UQ_TYP_SEQ);
920 return tq_putpkt (pkt, TRUE);
921 }
922 
923 /* Get command status - only interested in active xfr cmd */
924 
tq_gcs(int32 pkt)925 t_bool tq_gcs (int32 pkt)
926 {
927 uint32 lu = tq_pkt[pkt].d[CMD_UN];                      /* unit # */
928 uint32 ref = GETP32 (pkt, GCS_REFL);                    /* ref # */
929 int32 tpkt;
930 UNIT *uptr;
931 
932 if ((uptr = tq_getucb (lu)) &&                          /* valid lu? */
933     (tpkt = uptr->cpkt) &&                              /* queued pkt? */
934     (GETP32 (tpkt, CMD_REFL) == ref) &&                 /* match ref? */
935     (tq_cmf[GETP (tpkt, CMD_OPC, OPC)] & CMF_RW)) {     /* rd/wr cmd? */
936     tq_pkt[pkt].d[GCS_STSL] = tq_pkt[tpkt].d[RW_BCL];
937     tq_pkt[pkt].d[GCS_STSH] = tq_pkt[tpkt].d[RW_BCH];
938     }
939 else tq_pkt[pkt].d[GCS_STSL] = tq_pkt[pkt].d[GCS_STSH] = 0;
940 tq_putr (pkt, OP_GCS | OP_END, 0, ST_SUC, GCS_LNT, UQ_TYP_SEQ);
941 return tq_putpkt (pkt, TRUE);
942 }
943 
944 /* Get unit status */
945 
tq_gus(int32 pkt)946 t_bool tq_gus (int32 pkt)
947 {
948 uint32 lu = tq_pkt[pkt].d[CMD_UN];                      /* unit # */
949 uint32 sts;
950 UNIT *uptr;
951 
952 if (tq_pkt[pkt].d[CMD_MOD] & MD_NXU) {                  /* next unit? */
953     if (lu >= TQ_NUMDR) {                               /* end of range? */
954         lu = 0;                                         /* reset to 0 */
955         tq_pkt[pkt].d[RSP_UN] = lu;
956         }
957     }
958 if ((uptr = tq_getucb (lu))) {                          /* unit exist? */
959     if ((uptr->flags & UNIT_ATT) == 0)                  /* not attached? */
960             sts = ST_OFL | SB_OFL_NV;                   /* offl no vol */
961     else if (uptr->flags & UNIT_ONL)                    /* online */
962         sts = ST_SUC;
963     else sts = ST_AVL;                                  /* avail */
964     tq_putr_unit (pkt, uptr, lu, FALSE);                /* fill unit fields */
965     tq_pkt[pkt].d[GUS_MENU] = drv_tab[tq_typ].fmt;      /* format menu */
966     tq_pkt[pkt].d[GUS_CAP] = 0;                         /* free capacity */
967     tq_pkt[pkt].d[GUS_FVER] = drv_tab[tq_typ].fver;     /* formatter version */
968     tq_pkt[pkt].d[GUS_UVER] = drv_tab[tq_typ].uver;     /* unit version */
969     }
970 else sts = ST_OFL;                                      /* offline */
971 tq_putr (pkt, OP_GUS | OP_END, tq_efl (uptr), sts, GUS_LNT_T, UQ_TYP_SEQ);
972 return tq_putpkt (pkt, TRUE);
973 }
974 
975 /* Unit online - deferred if q'd commands */
976 
tq_onl(int32 pkt)977 t_bool tq_onl (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     if ((uptr->flags & UNIT_ATT) == 0)                  /* not attached? */
985         sts = ST_OFL | SB_OFL_NV;                       /* offl no vol */
986     else if (uptr->flags & UNIT_ONL)                    /* already online? */
987         sts = ST_SUC | SB_SUC_ON;
988     else {
989         sts = ST_SUC;                                   /* mark online */
990         sim_tape_rewind (uptr);                         /* rewind */
991         uptr->objp = 0;                                 /* clear flags */
992         uptr->flags = (uptr->flags | UNIT_ONL) &
993             ~(UNIT_TMK | UNIT_POL);                     /* onl, pos ok */
994         tq_setf_unit (pkt, uptr);                       /* hack flags */
995         }
996     tq_putr_unit (pkt, uptr, lu, TRUE);                 /* set fields */
997     }
998 else sts = ST_OFL;                                      /* offline */
999 tq_putr (pkt, OP_ONL | OP_END, tq_efl (uptr), sts, ONL_LNT, UQ_TYP_SEQ);
1000 return tq_putpkt (pkt, TRUE);
1001 }
1002 
1003 /* Set controller characteristics */
1004 
tq_scc(int32 pkt)1005 t_bool tq_scc (int32 pkt)
1006 {
1007 if (tq_pkt[pkt].d[SCC_MSV])                             /* MSCP ver = 0? */
1008     tq_putr (pkt, 0, 0, ST_CMD | I_VRSN, SCC_LNT, UQ_TYP_SEQ);
1009 else {
1010     tq_cflgs = (tq_cflgs & CF_RPL) |                    /* hack ctrl flgs */
1011         tq_pkt[pkt].d[SCC_CFL];
1012     if ((tq_htmo = tq_pkt[pkt].d[SCC_TMO]))             /* set timeout */
1013         tq_htmo = tq_htmo + 2;                          /* if nz, round up */
1014     tq_pkt[pkt].d[SCC_CFL] = tq_cflgs;                  /* return flags */
1015     tq_pkt[pkt].d[SCC_TMO] = TQ_DCTMO;                  /* ctrl timeout */
1016     tq_pkt[pkt].d[SCC_VER] = drv_tab[tq_typ].cver;      /* ctrl version */
1017     tq_pkt[pkt].d[SCC_CIDA] = 0;                        /* ctrl ID */
1018     tq_pkt[pkt].d[SCC_CIDB] = 0;
1019     tq_pkt[pkt].d[SCC_CIDC] = 0;
1020     tq_pkt[pkt].d[SCC_CIDD] = (TQ_CLASS << SCC_CIDD_V_CLS) |
1021         (drv_tab[tq_typ].cmod << SCC_CIDD_V_MOD);
1022     PUTP32 (pkt, SCC_MBCL, TQ_MAXFR);                   /* max bc */
1023     tq_putr (pkt, OP_SCC | OP_END, 0, ST_SUC, SCC_LNT, UQ_TYP_SEQ);
1024     }
1025 return tq_putpkt (pkt, TRUE);
1026 }
1027 
1028 /* Set unit characteristics - defer if q'd commands */
1029 
tq_suc(int32 pkt)1030 t_bool tq_suc (int32 pkt)
1031 {
1032 uint32 lu = tq_pkt[pkt].d[CMD_UN];                      /* unit # */
1033 uint32 sts;
1034 UNIT *uptr;
1035 
1036 if ((uptr = tq_getucb (lu))) {                          /* unit exist? */
1037     if ((uptr->flags & UNIT_ATT) == 0)                  /* not attached? */
1038         sts = ST_OFL | SB_OFL_NV;                       /* offl no vol */
1039     else {
1040         sts = ST_SUC;                                   /* avail or onl */
1041         tq_setf_unit (pkt, uptr);                       /* hack flags */
1042         }
1043     tq_putr_unit (pkt, uptr, lu, TRUE);                 /* set fields */
1044     }
1045 else sts = ST_OFL;                                      /* offline */
1046 tq_putr (pkt, OP_SUC | OP_END, 0, sts, SUC_LNT, UQ_TYP_SEQ);
1047 return tq_putpkt (pkt, TRUE);
1048 }
1049 
1050 /* Flush - sequential nop - deferred if q'd cmds, bypassed if ser exc */
1051 
tq_flu(int32 pkt)1052 t_bool tq_flu (int32 pkt)
1053 {
1054 uint32 lu = tq_pkt[pkt].d[CMD_UN];                      /* unit # */
1055 uint32 sts;
1056 UNIT *uptr;
1057 
1058 if ((uptr = tq_getucb (lu)))                            /* unit exist? */
1059     sts = tq_mot_valid (uptr, OP_FLU);                  /* validate req */
1060 else sts = ST_OFL;                                      /* offline */
1061 tq_putr (pkt, OP_FLU | OP_END, tq_efl (uptr), sts, FLU_LNT, UQ_TYP_SEQ);
1062 return tq_putpkt (pkt, TRUE);
1063 }
1064 
1065 /* Erase, erase gap - deferred if q'd cmds, bypassed if ser exc */
1066 
tq_erase(int32 pkt)1067 t_bool tq_erase (int32 pkt)
1068 {
1069 uint32 lu = tq_pkt[pkt].d[CMD_UN];                      /* unit # */
1070 uint32 cmd = GETP (pkt, CMD_OPC, OPC);                  /* opcode */
1071 uint32 sts;
1072 UNIT *uptr;
1073 
1074 if ((uptr = tq_getucb (lu))) {                          /* unit exist? */
1075     sts = tq_mot_valid (uptr, cmd);                     /* validity checks */
1076     if (sts == ST_SUC) {                                /* ok? */
1077         uptr->cpkt = pkt;                               /* op in progress */
1078         sim_activate (uptr, tq_xtime);                  /* activate */
1079         return OK;                                      /* done */
1080         }
1081     }
1082 else sts = ST_OFL;                                      /* offline */
1083 tq_putr (pkt, cmd | OP_END, tq_efl (uptr), sts, ERS_LNT, UQ_TYP_SEQ);
1084 return tq_putpkt (pkt, TRUE);
1085 }
1086 
1087 /* Write tape mark - deferred if q'd cmds, bypassed if ser exc */
1088 
tq_wtm(int32 pkt)1089 t_bool tq_wtm (int32 pkt)
1090 {
1091 uint32 lu = tq_pkt[pkt].d[CMD_UN];                      /* unit # */
1092 uint32 sts, objp = 0;
1093 UNIT *uptr;
1094 
1095 if ((uptr = tq_getucb (lu))) {                          /* unit exist? */
1096     objp = uptr->objp;                                  /* position op */
1097     sts = tq_mot_valid (uptr, OP_WTM);                  /* validity checks */
1098     if (sts == ST_SUC) {                                /* ok? */
1099         uptr->cpkt = pkt;                               /* op in progress */
1100         sim_activate (uptr, tq_xtime);                  /* activate */
1101         return OK;                                      /* done */
1102         }
1103     }
1104 else sts = ST_OFL;                                      /* offline */
1105 PUTP32 (pkt, WTM_POSL, objp);                           /* set obj pos */
1106 tq_putr (pkt, OP_WTM | OP_END, tq_efl (uptr), sts, WTM_LNT, UQ_TYP_SEQ);
1107 return tq_putpkt (pkt, TRUE);
1108 }
1109 
1110 /* Position - deferred if q'd cmds, bypassed if ser exc */
1111 
tq_pos(int32 pkt)1112 t_bool tq_pos (int32 pkt)
1113 {
1114 uint32 lu = tq_pkt[pkt].d[CMD_UN];                      /* unit # */
1115 uint32 sts, objp = 0;
1116 UNIT *uptr;
1117 
1118 if ((uptr = tq_getucb (lu))) {                          /* unit exist? */
1119     objp = uptr->objp;                                  /* position op */
1120     sts = tq_mot_valid (uptr, OP_POS);                  /* validity checks */
1121     if (sts == ST_SUC) {                                /* ok? */
1122         uptr->cpkt = pkt;                               /* op in progress */
1123         tq_rwtime = 2 * tmr_poll * clk_tps;             /* 2 second rewind time */
1124         if ((tq_pkt[pkt].d[CMD_MOD] & MD_RWD) &&        /* rewind? */
1125             (!(tq_pkt[pkt].d[CMD_MOD] & MD_IMM)))       /* !immediate? */
1126             sim_activate (uptr, tq_rwtime);             /* use 2 sec rewind execute time */
1127         else                                            /* otherwise */
1128             sim_activate (uptr, tq_xtime);              /* use normal execute time */
1129         return OK;                                      /* done */
1130         }
1131     }
1132 else sts = ST_OFL;                                      /* offline */
1133 PUTP32 (pkt, POS_RCL, 0);                               /* clear #skipped */
1134 PUTP32 (pkt, POS_TMCL, 0);
1135 PUTP32 (pkt, POS_POSL, objp);                           /* set obj pos */
1136 tq_putr (pkt, OP_POS | OP_END, tq_efl (uptr), sts, POS_LNT, UQ_TYP_SEQ);
1137 return tq_putpkt (pkt, TRUE);
1138 }
1139 
1140 /* Data transfer commands - deferred if q'd commands, bypassed if ser exc */
1141 
tq_rw(int32 pkt)1142 t_bool tq_rw (int32 pkt)
1143 {
1144 uint32 lu = tq_pkt[pkt].d[CMD_UN];                      /* unit # */
1145 uint32 cmd = GETP (pkt, CMD_OPC, OPC);                  /* opcode */
1146 uint32 bc = GETP32 (pkt, RW_BCL);                       /* byte count */
1147 uint32 sts, objp = 0;
1148 UNIT *uptr;
1149 
1150 if ((uptr = tq_getucb (lu))) {                          /* unit exist? */
1151     objp = uptr->objp;                                  /* position op */
1152     sts = tq_mot_valid (uptr, cmd);                     /* validity checks */
1153     if (sts == ST_SUC) {                                /* ok? */
1154         if ((bc == 0) || (bc > TQ_MAXFR)) {             /* invalid? */
1155             uptr->flags = uptr->flags | UNIT_SXC;       /* set ser exc */
1156             sts = ST_CMD | I_BCNT;
1157             }
1158         else {
1159             uptr->cpkt = pkt;                           /* op in progress */
1160             sim_activate (uptr, tq_xtime);              /* activate */
1161             return OK;                                  /* done */
1162             }
1163         }
1164     }
1165 else sts = ST_OFL;                                      /* offline */
1166 PUTP32 (pkt, RW_BCL, 0);                                /* no bytes processed */
1167 PUTP32 (pkt, RW_POSL, objp);                            /* set obj pos */
1168 PUTP32 (pkt, RW_RSZL, 0);                               /* clr rec size */
1169 tq_putr (pkt, cmd | OP_END, tq_efl (uptr), sts, RW_LNT_T, UQ_TYP_SEQ);
1170 return tq_putpkt (pkt, TRUE);
1171 }
1172 
1173 /* Validity checks */
1174 
tq_mot_valid(UNIT * uptr,uint32 cmd)1175 int32 tq_mot_valid (UNIT *uptr, uint32 cmd)
1176 {
1177 if (uptr->flags & UNIT_SXC)                             /* ser exc pend? */
1178     return ST_SXC;
1179 if ((uptr->flags & UNIT_ATT) == 0)                      /* not attached? */
1180     return (ST_OFL | SB_OFL_NV);                        /* offl no vol */
1181 if ((uptr->flags & UNIT_ONL) == 0)                      /* not online? */
1182     return ST_AVL;                                      /* only avail */
1183 if (tq_cmf[cmd] & CMF_WR) {                             /* write op? */
1184     if (uptr->uf & UF_WPS) {                            /* swre wlk? */
1185         uptr->flags = uptr->flags | UNIT_SXC;           /* set ser exc */
1186         return (ST_WPR | SB_WPR_SW);
1187         }
1188     if (TQ_WPH (uptr)) {                                /* hwre wlk? */
1189         uptr->flags = uptr->flags | UNIT_SXC;           /* set ser exc */
1190         return (ST_WPR | SB_WPR_HW);
1191         }
1192     }
1193 return ST_SUC;                                          /* success! */
1194 }
1195 
1196 /* Unit service for motion commands */
1197 
tq_svc(UNIT * uptr)1198 t_stat tq_svc (UNIT *uptr)
1199 {
1200 uint32 t, sts, sktmk, skrec;
1201 t_mtrlnt i, tbc, wbc;
1202 int32 pkt = uptr->cpkt;                                 /* get packet */
1203 uint32 cmd = GETP (pkt, CMD_OPC, OPC);                  /* get cmd */
1204 uint32 mdf = tq_pkt[pkt].d[CMD_MOD];                    /* modifier */
1205 uint32 ba = GETP32 (pkt, RW_BAL);                       /* buf addr */
1206 t_mtrlnt bc = GETP32 (pkt, RW_BCL);                     /* byte count */
1207 uint32 nrec = GETP32 (pkt, POS_RCL);                    /* #rec to skip */
1208 uint32 ntmk = GETP32 (pkt, POS_TMCL);                   /* #tmk to skp */
1209 
1210 if (pkt == 0)                                           /* what??? */
1211     return SCPE_IERR;
1212 if ((uptr->flags & UNIT_ATT) == 0) {                    /* not attached? */
1213     tq_mot_end (uptr, 0, ST_OFL | SB_OFL_NV, 0);        /* offl no vol */
1214     return SCPE_OK;
1215     }
1216 
1217 if (tq_cmf[cmd] & CMF_WR) {                             /* write op? */
1218     if (TQ_WPH (uptr)) {                                /* hwre write prot? */
1219         uptr->flags = uptr->flags | UNIT_SXC;           /* set ser exc */
1220         tq_mot_end (uptr, 0, ST_WPR | SB_WPR_HW, 0);
1221         return SCPE_OK;
1222         }
1223     if (uptr->uf & UF_WPS) {                            /* swre write prot? */
1224         uptr->flags = uptr->flags | UNIT_SXC;           /* set ser exc */
1225         tq_mot_end (uptr, 0, ST_WPR | SB_WPR_SW, 0);
1226         return SCPE_OK;
1227         }
1228     }
1229 sts = ST_SUC;                                           /* assume success */
1230 tbc = 0;                                                /* assume zero rec */
1231 switch (cmd) {                                          /* case on command */
1232 
1233     case OP_RD:case OP_ACC:case OP_CMP:                 /* read-like op */
1234         if (mdf & MD_REV)                               /* read record */
1235             sts = tq_rdbufr (uptr, &tbc);
1236         else sts = tq_rdbuff (uptr, &tbc);
1237         if (sts == ST_DRV) {                            /* read error? */
1238             PUTP32 (pkt, RW_BCL, 0);                    /* no bytes processed */
1239             return tq_mot_err (uptr, tbc);              /* log, done */
1240             }
1241         if ((sts != ST_SUC) || (cmd == OP_ACC)) {       /* error or access? */
1242             if (sts == ST_TMK)
1243                 uptr->flags = uptr->flags | UNIT_SXC;   /* set ser exc */
1244             PUTP32 (pkt, RW_BCL, 0);                    /* no bytes processed */
1245             break;
1246             }
1247         if (tbc > bc) {                                 /* tape rec > buf? */
1248             uptr->flags = uptr->flags | UNIT_SXC;       /* serious exc */
1249             sts = ST_RDT;                               /* data truncated */
1250             wbc = bc;                                   /* set working bc */
1251             }
1252         else wbc = tbc;
1253         if (cmd == OP_RD) {                             /* read? */
1254             if ((t = Map_WriteB (ba, wbc, tqxb))) {     /* store, nxm? */
1255                 PUTP32 (pkt, RW_BCL, wbc - t);          /* adj bc */
1256                 if (tq_hbe (uptr, ba + wbc - t))        /* post err log */
1257                     tq_mot_end (uptr, EF_LOG, ST_HST | SB_HST_NXM, tbc);
1258                 return SCPE_OK;                         /* end if nxm */
1259                 }
1260             }                                           /* end if read */
1261         else {                                          /* compare */
1262             uint8 mby, dby;
1263             uint32 mba;
1264             for (i = 0; i < wbc; i++) {                 /* loop */
1265                 if (mdf & MD_REV) {                     /* reverse? */
1266                     mba = ba + bc - 1 - i;              /* mem addr */
1267                     dby = tqxb[tbc - 1 - i];            /* byte */
1268                     }
1269                 else {
1270                     mba = ba + i;
1271                     dby = tqxb[i];
1272                     }
1273                 if (Map_ReadB (mba, 1, &mby)) {         /* fetch, nxm? */
1274                     PUTP32 (pkt, RW_BCL, i);            /* adj bc */
1275                     if (tq_hbe (uptr, mba))             /* post err log */
1276                         tq_mot_end (uptr, EF_LOG, ST_HST | SB_HST_NXM, tbc);
1277                     return SCPE_OK;
1278                     }
1279                 if (mby != dby) {                       /* cmp err? */
1280                     uptr->flags = uptr->flags | UNIT_SXC; /* ser exc */
1281                     PUTP32 (pkt, RW_BCL, i);            /* adj bc */
1282                     tq_mot_end (uptr, 0, ST_CMP, tbc);
1283                     return SCPE_OK;                     /* exit */
1284                     }
1285                 }                                       /* end for */
1286             }                                           /* end if compare */
1287         PUTP32 (pkt, RW_BCL, wbc);                      /* bytes read/cmp'd */
1288         break;
1289 
1290     case OP_WR:                                         /* write */
1291         if ((t = Map_ReadB (ba, bc, tqxb))) {           /* fetch buf, nxm? */
1292             PUTP32 (pkt, RW_BCL, 0);                    /* no bytes xfer'd */
1293             if (tq_hbe (uptr, ba + bc - t))             /* post err log */
1294                 tq_mot_end (uptr, EF_LOG, ST_HST | SB_HST_NXM, bc);
1295             return SCPE_OK;                             /* end else wr */
1296             }
1297         if (sim_tape_wrrecf (uptr, tqxb, bc))           /* write rec fwd, err? */
1298             return tq_mot_err (uptr, bc);               /* log, end */
1299         uptr->objp = uptr->objp + 1;                    /* upd obj pos */
1300         if (TEST_EOT (uptr))                            /* EOT on write? */
1301             uptr->flags = uptr->flags | UNIT_SXC;
1302         uptr->flags = uptr->flags & ~UNIT_TMK;          /* disable LEOT */
1303         tbc = bc;                                       /* RW_BC is ok */
1304         break;
1305 
1306     case OP_WTM:                                        /* write tape mark */
1307         if (sim_tape_wrtmk (uptr))                      /* write tmk, err? */
1308             return tq_mot_err (uptr, 0);                /* log, end */
1309         uptr->objp = uptr->objp + 1;                    /* incr obj cnt */
1310     case OP_ERG:                                        /* erase gap */
1311         if (TEST_EOT (uptr))                            /* EOT on write? */
1312             uptr->flags = uptr->flags | UNIT_SXC;
1313         uptr->flags = uptr->flags & ~UNIT_TMK;          /* disable LEOT */
1314         break;
1315 
1316     case OP_ERS:                                        /* erase */
1317         if (sim_tape_wreom (uptr))                      /* write eom, err? */
1318             return tq_mot_err (uptr, 0);                /* log, end */
1319         sim_tape_rewind (uptr);                         /* rewind */
1320         uptr->objp = 0;
1321         uptr->flags = uptr->flags & ~(UNIT_TMK | UNIT_POL);
1322         break;
1323 
1324     case OP_POS:                                        /* position */
1325         sktmk = skrec = 0;                              /* clr skipped */
1326         if (mdf & MD_RWD) {                             /* rewind? */
1327             sim_tape_rewind (uptr);
1328             uptr->objp = 0;                             /* clr flags */
1329             uptr->flags = uptr->flags & ~(UNIT_TMK | UNIT_POL);
1330             }
1331         if (mdf & MD_OBC) {                             /* skip obj? */
1332             if (mdf & MD_REV)                           /* reverse? */
1333                 sts = tq_spacer (uptr, nrec, &skrec, FALSE);
1334             else sts = tq_spacef (uptr, nrec, &skrec, FALSE);
1335             }
1336         else {                                          /* skip tmk, rec */
1337             if (mdf & MD_REV)
1338                 sts = tq_skipfr (uptr, ntmk, &sktmk);
1339             else sts = tq_skipff (uptr, ntmk, &sktmk);
1340             if (sts == ST_SUC) {                        /* tmk succeed? */
1341                 if (mdf & MD_REV)                       /* reverse? */
1342                     sts = tq_spacer (uptr, nrec, &skrec, TRUE);
1343                 else sts = tq_spacef (uptr, nrec, &skrec, TRUE);
1344                 if (sts == ST_TMK)
1345                     sktmk = sktmk + 1;
1346                 }
1347             }
1348         PUTP32 (pkt, POS_RCL, skrec);                   /* #rec skipped */
1349         PUTP32 (pkt, POS_TMCL, sktmk);                  /* #tmk skipped */
1350         if (DEBUG_PRS (tq_dev)) {
1351             fprintf (sim_deb, ">>TQ: Position Done: mdf=%04X, nrec=%04X, ntmk=%04X, skrec=%04X, sktmk=%04X\n",
1352                 mdf, nrec, ntmk, skrec, sktmk);
1353             fflush (sim_deb);
1354             }
1355         break;
1356 
1357     default:
1358         return SCPE_IERR;
1359         }
1360 
1361 tq_mot_end (uptr, 0, sts, tbc);                         /* done */
1362 return SCPE_OK;
1363 }
1364 
1365 /* Motion command drive error */
1366 
tq_mot_err(UNIT * uptr,uint32 rsiz)1367 t_stat tq_mot_err (UNIT *uptr, uint32 rsiz)
1368 {
1369 uptr->flags = (uptr->flags | UNIT_SXC) & ~UNIT_TMK;     /* serious exception */
1370 if (tq_dte (uptr, ST_DRV))                              /* post err log */
1371     tq_mot_end (uptr, EF_LOG, ST_DRV, rsiz);            /* if ok, report err */
1372 perror ("TQ I/O error");
1373 clearerr (uptr->fileref);
1374 return SCPE_IOERR;
1375 }
1376 
1377 /* Motion command complete */
1378 
tq_mot_end(UNIT * uptr,uint32 flg,uint32 sts,uint32 rsiz)1379 t_bool tq_mot_end (UNIT *uptr, uint32 flg, uint32 sts, uint32 rsiz)
1380 {
1381 int32 pkt = uptr->cpkt;                                 /* packet */
1382 uint32 cmd = GETP (pkt, CMD_OPC, OPC);                  /* get cmd */
1383 uint32 lnt = RW_LNT_T;                                  /* assume rw */
1384 
1385 if (cmd == OP_ERG)                                      /* set pkt lnt */
1386     lnt = ERG_LNT;
1387 else if (cmd == OP_ERS)
1388     lnt = ERS_LNT;
1389 else if (cmd == OP_WTM)
1390     lnt = WTM_LNT;
1391 else if (cmd == OP_POS)
1392     lnt = POS_LNT;
1393 
1394 uptr->cpkt = 0;                                         /* done */
1395 if (lnt > ERG_LNT) {                                    /* xfer cmd? */
1396     PUTP32 (pkt, RW_POSL, uptr->objp);                  /* position */
1397     PUTP32 (pkt, RW_RSZL, rsiz);                        /* record size */
1398     }
1399 tq_putr (pkt, cmd | OP_END, flg | tq_efl (uptr), sts, lnt, UQ_TYP_SEQ);
1400 if (!tq_putpkt (pkt, TRUE))                             /* send pkt */
1401     return ERR;
1402 if (uptr->pktq)                                         /* more to do? */
1403     sim_activate (&tq_unit[TQ_QUEUE], tq_qtime);        /* activate thread */
1404 return OK;
1405 }
1406 
1407 /* Tape motion routines */
1408 
tq_map_status(UNIT * uptr,t_stat st)1409 uint32 tq_map_status (UNIT *uptr, t_stat st)
1410 {
1411 switch (st) {
1412 
1413     case MTSE_OK:
1414         break;
1415 
1416     case MTSE_UNATT:
1417         uptr->flags = uptr->flags | UNIT_SXC;
1418         return (ST_OFL | SB_OFL_NV);
1419 
1420     case MTSE_FMT:
1421         uptr->flags = uptr->flags | UNIT_SXC;
1422         return ST_MFE;
1423 
1424     case MTSE_TMK:
1425         uptr->flags = uptr->flags | UNIT_SXC;
1426         return ST_TMK;
1427 
1428     case MTSE_INVRL:
1429         uptr->flags = uptr->flags | UNIT_SXC | UNIT_POL;
1430         return ST_FMT;
1431 
1432     case MTSE_RECE:
1433     case MTSE_IOERR:
1434         uptr->flags = uptr->flags | UNIT_SXC | UNIT_POL;
1435         return ST_DRV;
1436 
1437     case MTSE_EOM:
1438         uptr->flags = uptr->flags | UNIT_SXC | UNIT_POL;
1439         return ST_DAT;
1440 
1441     case MTSE_BOT:
1442         uptr->flags = (uptr->flags | UNIT_SXC) & ~UNIT_POL;
1443         return ST_BOT;
1444 
1445     case MTSE_WRP:
1446         uptr->flags = uptr->flags | UNIT_SXC;
1447         return ST_WPR;
1448         }
1449 
1450 return ST_SUC;
1451 }
1452 
tq_spacef(UNIT * uptr,uint32 cnt,uint32 * skipped,t_bool qrec)1453 uint32 tq_spacef (UNIT *uptr, uint32 cnt, uint32 *skipped, t_bool qrec)
1454 {
1455 t_stat st;
1456 t_mtrlnt tbc;
1457 
1458 *skipped = 0;
1459 while (*skipped < cnt) {                                /* loop */
1460     st = sim_tape_sprecf (uptr, &tbc);                  /* space rec fwd */
1461     if ((st != MTSE_OK) && (st != MTSE_TMK))            /* real error? */
1462         return tq_map_status (uptr, st);                /* map status */
1463     uptr->objp = uptr->objp + 1;                        /* upd obj cnt */
1464     if (st == MTSE_TMK) {                               /* tape mark? */
1465         int32 pkt = uptr->cpkt;                         /* get pkt */
1466         if ((tq_pkt[pkt].d[CMD_MOD] & MD_DLE) &&        /* LEOT? */
1467             (uptr->flags & UNIT_TMK)) {
1468             sim_tape_sprecr (uptr, &tbc);               /* rev over tmk */
1469             uptr->flags = uptr->flags | UNIT_SXC;       /* serious exc */
1470             return ST_LED;
1471             }
1472         uptr->flags = uptr->flags | UNIT_TMK;           /* set TM seen */
1473         if (qrec)                                       /* rec spc? stop */
1474             return ST_TMK;
1475         }
1476     else uptr->flags = uptr->flags & ~UNIT_TMK;         /* clr TM seen */
1477     *skipped = *skipped + 1;                            /* # obj skipped */
1478     }
1479 return ST_SUC;
1480 }
1481 
tq_skipff(UNIT * uptr,uint32 cnt,uint32 * skipped)1482 uint32 tq_skipff (UNIT *uptr, uint32 cnt, uint32 *skipped)
1483 {
1484 uint32 st, skrec;
1485 
1486 *skipped = 0;
1487 while (*skipped < cnt) {                                /* loop */
1488     st = tq_spacef (uptr, 0x7FFFFFFF, &skrec, TRUE);    /* rec spc fwd */
1489     if (st == ST_TMK)                                   /* count files */
1490         *skipped = *skipped + 1;
1491     else if (st != ST_SUC)
1492         return st;
1493     }
1494 return ST_SUC;
1495 }
1496 
tq_spacer(UNIT * uptr,uint32 cnt,uint32 * skipped,t_bool qrec)1497 uint32 tq_spacer (UNIT *uptr, uint32 cnt, uint32 *skipped, t_bool qrec)
1498 {
1499 t_stat st;
1500 t_mtrlnt tbc;
1501 
1502 *skipped = 0;
1503 while (*skipped < cnt) {                                /* loop */
1504     st = sim_tape_sprecr (uptr, &tbc);                  /* spc rec rev */
1505     if ((st != MTSE_OK) && (st != MTSE_TMK))            /* real error? */
1506         return tq_map_status (uptr, st);                /* map status */
1507     uptr->objp = uptr->objp - 1;                        /* upd obj cnt */
1508     if ((st == MTSE_TMK) && qrec)                       /* tape mark, stop? */
1509         return ST_TMK;
1510     *skipped = *skipped + 1;                            /* # obj skipped */
1511     }
1512 return ST_SUC;
1513 }
1514 
tq_skipfr(UNIT * uptr,uint32 cnt,uint32 * skipped)1515 uint32 tq_skipfr (UNIT *uptr, uint32 cnt, uint32 *skipped)
1516 {
1517 uint32 st, skrec;
1518 
1519 *skipped = 0;
1520 while (*skipped < cnt) {                                /* loopo */
1521     st = tq_spacer (uptr, 0x7FFFFFFF, &skrec, TRUE);    /* rec spc rev */
1522     if (st == ST_TMK)                                   /* tape mark? */
1523         *skipped = *skipped + 1;
1524     else if (st != 0)                                   /* error? */
1525         return st;
1526     }
1527 return ST_SUC;
1528 }
1529 
1530 /* Read buffer - can return ST_TMK, ST_FMT, or ST_DRV */
1531 
tq_rdbuff(UNIT * uptr,t_mtrlnt * tbc)1532 uint32 tq_rdbuff (UNIT *uptr, t_mtrlnt *tbc)
1533 {
1534 t_stat st;
1535 
1536 st = sim_tape_rdrecf (uptr, tqxb, tbc, MT_MAXFR);       /* read rec fwd */
1537 if (st == MTSE_TMK) {                                   /* tape mark? */
1538     uptr->flags = uptr->flags | UNIT_SXC | UNIT_TMK;    /* serious exc */
1539     uptr->objp = uptr->objp + 1;                        /* update obj cnt */
1540     return ST_TMK;
1541     }
1542 if (st != MTSE_OK)                                      /* other error? */
1543     return tq_map_status (uptr, st);
1544 uptr->flags = uptr->flags & ~UNIT_TMK;                  /* clr tape mark */
1545 uptr->objp = uptr->objp + 1;                            /* upd obj cnt */
1546 return ST_SUC;
1547 }
1548 
tq_rdbufr(UNIT * uptr,t_mtrlnt * tbc)1549 uint32 tq_rdbufr (UNIT *uptr, t_mtrlnt *tbc)
1550 {
1551 t_stat st;
1552 
1553 st = sim_tape_rdrecr (uptr, tqxb, tbc, MT_MAXFR);       /* read rec rev */
1554 if (st == MTSE_TMK) {                                   /* tape mark? */
1555     uptr->flags = uptr->flags | UNIT_SXC;               /* serious exc */
1556     uptr->objp = uptr->objp - 1;                        /* update obj cnt */
1557     return ST_TMK;
1558     }
1559 if (st != MTSE_OK)                                      /* other error? */
1560     return tq_map_status (uptr, st);
1561 uptr->objp = uptr->objp - 1;                            /* upd obj cnt */
1562 return ST_SUC;
1563 }
1564 
1565 /* Data transfer error log packet */
1566 
tq_dte(UNIT * uptr,uint32 err)1567 t_bool tq_dte (UNIT *uptr, uint32 err)
1568 {
1569 int32 pkt, tpkt;
1570 uint32 lu;
1571 
1572 if ((tq_cflgs & CF_THS) == 0)                           /* logging? */
1573     return OK;
1574 if (!tq_deqf (&pkt))                                    /* get log pkt */
1575     return ERR;
1576 tpkt = uptr->cpkt;                                      /* rw pkt */
1577 lu = tq_pkt[tpkt].d[CMD_UN];                            /* unit # */
1578 
1579 tq_pkt[pkt].d[ELP_REFL] = tq_pkt[tpkt].d[CMD_REFL];     /* copy cmd ref */
1580 tq_pkt[pkt].d[ELP_REFH] = tq_pkt[tpkt].d[CMD_REFH];     /* copy cmd ref */
1581 tq_pkt[pkt].d[ELP_UN] = lu;                             /* copy unit */
1582 tq_pkt[pkt].d[ELP_SEQ] = 0;                             /* clr seq # */
1583 tq_pkt[pkt].d[DTE_CIDA] = 0;                            /* ctrl ID */
1584 tq_pkt[pkt].d[DTE_CIDB] = 0;
1585 tq_pkt[pkt].d[DTE_CIDC] = 0;
1586 tq_pkt[pkt].d[DTE_CIDD] = (TQ_CLASS << DTE_CIDD_V_CLS) |
1587     (drv_tab[tq_typ].cmod << DTE_CIDD_V_MOD);
1588 tq_pkt[pkt].d[DTE_VER] = drv_tab[tq_typ].cver;          /* ctrl ver */
1589 tq_pkt[pkt].d[DTE_MLUN] = lu;                           /* MLUN */
1590 tq_pkt[pkt].d[DTE_UIDA] = lu;                           /* unit ID */
1591 tq_pkt[pkt].d[DTE_UIDB] = 0;
1592 tq_pkt[pkt].d[DTE_UIDC] = 0;
1593 tq_pkt[pkt].d[DTE_UIDD] = (UID_TAPE << DTE_UIDD_V_CLS) |
1594     (drv_tab[tq_typ].umod << DTE_UIDD_V_MOD);
1595 tq_pkt[pkt].d[DTE_UVER] = drv_tab[tq_typ].uver;         /* unit ver */
1596 PUTP32 (pkt, DTE_POSL, uptr->objp);                     /* position */
1597 tq_pkt[pkt].d[DTE_FVER] = drv_tab[tq_typ].fver;         /* fmtr ver */
1598 tq_putr (pkt, FM_TAP, LF_SNR, err, DTE_LNT, UQ_TYP_DAT);
1599 return tq_putpkt (pkt, TRUE);
1600 }
1601 
1602 /* Host bus error log packet */
1603 
tq_hbe(UNIT * uptr,uint32 ba)1604 t_bool tq_hbe (UNIT *uptr, uint32 ba)
1605 {
1606 int32 pkt, tpkt;
1607 
1608 if ((tq_cflgs & CF_THS) == 0)                           /* logging? */
1609     return OK;
1610 if (!tq_deqf (&pkt))                                    /* get log pkt */
1611     return ERR;
1612 tpkt = uptr->cpkt;                                      /* rw pkt */
1613 tq_pkt[pkt].d[ELP_REFL] = tq_pkt[tpkt].d[CMD_REFL];     /* copy cmd ref */
1614 tq_pkt[pkt].d[ELP_REFH] = tq_pkt[tpkt].d[CMD_REFH];     /* copy cmd ref */
1615 tq_pkt[pkt].d[ELP_UN] = tq_pkt[tpkt].d[CMD_UN];         /* copy unit */
1616 tq_pkt[pkt].d[ELP_SEQ] = 0;                             /* clr seq # */
1617 tq_pkt[pkt].d[HBE_CIDA] = 0;                            /* ctrl ID */
1618 tq_pkt[pkt].d[HBE_CIDB] = 0;
1619 tq_pkt[pkt].d[HBE_CIDC] = 0;
1620 tq_pkt[pkt].d[DTE_CIDD] = (TQ_CLASS << DTE_CIDD_V_CLS) |
1621     (drv_tab[tq_typ].cmod << DTE_CIDD_V_MOD);
1622 tq_pkt[pkt].d[HBE_VER] = drv_tab[tq_typ].cver;          /* ctrl ver */
1623 tq_pkt[pkt].d[HBE_RSV] = 0;
1624 PUTP32 (pkt, HBE_BADL, ba);                             /* bad addr */
1625 tq_putr (pkt, FM_BAD, LF_SNR, ST_HST | SB_HST_NXM, HBE_LNT, UQ_TYP_DAT);
1626 return tq_putpkt (pkt, TRUE);
1627 }
1628 
1629 /* Port last failure error log packet */
1630 
tq_plf(uint32 err)1631 t_bool tq_plf (uint32 err)
1632 {
1633 int32 pkt;
1634 
1635 if (!tq_deqf (&pkt))                                    /* get log pkt */
1636     return ERR;
1637 tq_pkt[pkt].d[ELP_REFL] = tq_pkt[pkt].d[ELP_REFH] = 0;  /* ref = 0 */
1638 tq_pkt[pkt].d[ELP_UN] = tq_pkt[pkt].d[ELP_SEQ] = 0;     /* no unit, seq */
1639 tq_pkt[pkt].d[PLF_CIDA] = 0;                            /* cntl ID */
1640 tq_pkt[pkt].d[PLF_CIDB] = 0;
1641 tq_pkt[pkt].d[PLF_CIDC] = 0;
1642 tq_pkt[pkt].d[PLF_CIDD] = (TQ_CLASS << PLF_CIDD_V_CLS) |
1643     (drv_tab[tq_typ].cmod << PLF_CIDD_V_MOD);
1644 tq_pkt[pkt].d[PLF_VER] = drv_tab[tq_typ].cver;
1645 tq_pkt[pkt].d[PLF_ERR] = err;
1646 tq_putr (pkt, FM_CNT, LF_SNR, ST_CNT, PLF_LNT, UQ_TYP_DAT);
1647 tq_pkt[pkt].d[UQ_HCTC] |= (UQ_CID_DIAG << UQ_HCTC_V_CID);
1648 return tq_putpkt (pkt, TRUE);
1649 }
1650 
1651 /* Unit now available attention packet */
1652 
tq_una(UNIT * uptr)1653 int32 tq_una (UNIT *uptr)
1654 {
1655 int32 pkt;
1656 uint32 lu;
1657 
1658 if (!tq_deqf (&pkt))                                    /* get log pkt */
1659     return ERR;
1660 lu = (uint32) (uptr - tq_dev.units);                    /* get unit */
1661 tq_pkt[pkt].d[RSP_REFL] = tq_pkt[pkt].d[RSP_REFH] = 0;  /* ref = 0 */
1662 tq_pkt[pkt].d[RSP_UN] = lu;
1663 tq_pkt[pkt].d[RSP_RSV] = 0;
1664 tq_putr_unit (pkt, uptr, lu, FALSE);                    /* fill unit fields */
1665 tq_putr (pkt, OP_AVA, 0, 0, UNA_LNT, UQ_TYP_SEQ);       /* fill std fields */
1666 return tq_putpkt (pkt, TRUE);
1667 }
1668 
1669 /* List handling
1670 
1671    tq_deqf      -       dequeue head of free list (fatal err if none)
1672    tq_deqh      -       dequeue head of list
1673    tq_enqh      -       enqueue at head of list
1674    tq_enqt      -       enqueue at tail of list
1675 */
1676 
tq_deqf(int32 * pkt)1677 t_bool tq_deqf (int32 *pkt)
1678 {
1679 if (tq_freq == 0)                                       /* no free pkts?? */
1680     return tq_fatal (PE_NSR);
1681 tq_pbsy = tq_pbsy + 1;                                  /* cnt busy pkts */
1682 *pkt = tq_freq;                                         /* head of list */
1683 tq_freq = tq_pkt[tq_freq].link;                         /* next */
1684 return OK;
1685 }
1686 
tq_deqh(int32 * lh)1687 int32 tq_deqh (int32 *lh)
1688 {
1689 int32 ptr = *lh;                                        /* head of list */
1690 
1691 if (ptr)                                                /* next */
1692     *lh = tq_pkt[ptr].link;
1693 return ptr;
1694 }
1695 
tq_enqh(int32 * lh,int32 pkt)1696 void tq_enqh (int32 *lh, int32 pkt)
1697 {
1698 if (pkt == 0)                                           /* any pkt? */
1699     return;
1700 tq_pkt[pkt].link = *lh;                                 /* link is old lh */
1701 *lh = pkt;                                              /* pkt is new lh */
1702 return;
1703 }
1704 
tq_enqt(int32 * lh,int32 pkt)1705 void tq_enqt (int32 *lh, int32 pkt)
1706 {
1707 if (pkt == 0)                                           /* any pkt? */
1708     return;
1709 tq_pkt[pkt].link = 0;                                   /* it will be tail */
1710 if (*lh == 0)                                           /* if empty, enqh */
1711     *lh = pkt;
1712 else {
1713     uint32 ptr = *lh;                                   /* chase to end */
1714     while (tq_pkt[ptr].link)
1715         ptr = tq_pkt[ptr].link;
1716     tq_pkt[ptr].link = pkt;                             /* enq at tail */
1717     }
1718 return;
1719 }
1720 
1721 /* Packet and descriptor handling */
1722 
1723 /* Get packet from command ring */
1724 
tq_getpkt(int32 * pkt)1725 t_bool tq_getpkt (int32 *pkt)
1726 {
1727 uint32 addr, desc;
1728 
1729 if (!tq_getdesc (&tq_cq, &desc))                        /* get cmd desc */
1730     return ERR;
1731 if ((desc & UQ_DESC_OWN) == 0) {                        /* none */
1732     *pkt = 0;                                           /* pkt = 0 */
1733     return OK;                                          /* no error */
1734     }
1735 if (!tq_deqf (pkt))                                     /* get cmd pkt */
1736     return ERR;
1737 tq_hat = 0;                                             /* dsbl hst timer */
1738 addr = desc & UQ_ADDR;                                  /* get Q22 addr */
1739 if (Map_ReadW (addr + UQ_HDR_OFF, TQ_PKT_SIZE, tq_pkt[*pkt].d))
1740     return tq_fatal (PE_PRE);                           /* read pkt */
1741 return tq_putdesc (&tq_cq, desc);                       /* release desc */
1742 }
1743 
1744 /* Put packet to response ring - note the clever hack about credits.
1745    The controller sends all its credits to the host.  Thereafter, it
1746    supplies one credit for every response packet sent over.  Simple!
1747 */
1748 
tq_putpkt(int32 pkt,t_bool qt)1749 t_bool tq_putpkt (int32 pkt, t_bool qt)
1750 {
1751 uint32 addr, desc, lnt, cr;
1752 
1753 if (pkt == 0)                                           /* any packet? */
1754     return OK;
1755 if (DEBUG_PRS (tq_dev)) {
1756     UNIT *up = tq_getucb (tq_pkt[pkt].d[CMD_UN]);
1757     fprintf (sim_deb, ">>TQ: rsp=%04X, sts=%04X",
1758         tq_pkt[pkt].d[RSP_OPF], tq_pkt[pkt].d[RSP_STS]);
1759     if (up) {
1760         fprintf (sim_deb, ", pos=");
1761         fprint_val (sim_deb, up->pos, 10, T_ADDR_W, PV_LEFT);
1762         fprintf (sim_deb, ", obj=%d\n", up->objp);
1763         }
1764     else fprintf (sim_deb, "\n");
1765     fflush (sim_deb);
1766     }
1767 if (!tq_getdesc (&tq_rq, &desc))                        /* get rsp desc */
1768     return ERR;
1769 if ((desc & UQ_DESC_OWN) == 0) {                        /* not valid? */
1770     if (qt)                                             /* normal? q tail */
1771         tq_enqt (&tq_rspq, pkt);
1772     else tq_enqh (&tq_rspq, pkt);                       /* resp q call */
1773     sim_activate (&tq_unit[TQ_QUEUE], tq_qtime);        /* activate q thrd */
1774     return OK;
1775     }
1776 addr = desc & UQ_ADDR;                                  /* get Q22 addr */
1777 lnt = tq_pkt[pkt].d[UQ_HLNT] - UQ_HDR_OFF;              /* size, with hdr */
1778 if ((GETP (pkt, UQ_HCTC, TYP) == UQ_TYP_SEQ) &&         /* seq packet? */
1779     (GETP (pkt, CMD_OPC, OPC) & OP_END)) {              /* end packet? */
1780     cr = (tq_credits >= 14)? 14: tq_credits;            /* max 14 credits */
1781     tq_credits = tq_credits - cr;                       /* decr credits */
1782     tq_pkt[pkt].d[UQ_HCTC] |= ((cr + 1) << UQ_HCTC_V_CR);
1783     }
1784 if (Map_WriteW (addr + UQ_HDR_OFF, lnt, tq_pkt[pkt].d))
1785     return tq_fatal (PE_PWE);                           /* write pkt */
1786 tq_enqh (&tq_freq, pkt);                                /* pkt is free */
1787 tq_pbsy = tq_pbsy - 1;                                  /* decr busy cnt */
1788 if (tq_pbsy == 0)                                       /* idle? strt hst tmr */
1789     tq_hat = tq_htmo;
1790 return tq_putdesc (&tq_rq, desc);                       /* release desc */
1791 }
1792 
1793 /* Get a descriptor from the host */
1794 
tq_getdesc(struct uq_ring * ring,uint32 * desc)1795 t_bool tq_getdesc (struct uq_ring *ring, uint32 *desc)
1796 {
1797 uint32 addr = ring->ba + ring->idx;
1798 uint16 d[2];
1799 
1800 if (Map_ReadW (addr, 4, d))                             /* fetch desc */
1801     return tq_fatal (PE_QRE);                           /* err? dead */
1802 *desc = ((uint32) d[0]) | (((uint32) d[1]) << 16);
1803 return OK;
1804 }
1805 
1806 /* Return a descriptor to the host, clearing owner bit
1807    If rings transitions from "empty" to "not empty" or "full" to
1808    "not full", and interrupt bit was set, interrupt the host.
1809    Actually, test whether previous ring entry was owned by host.
1810 */
1811 
tq_putdesc(struct uq_ring * ring,uint32 desc)1812 t_bool tq_putdesc (struct uq_ring *ring, uint32 desc)
1813 {
1814 uint32 prvd, newd = (desc & ~UQ_DESC_OWN) | UQ_DESC_F;
1815 uint32 prva, addr = ring->ba + ring->idx;
1816 uint16 d[2];
1817 
1818 d[0] = newd & 0xFFFF;                                   /* 32b to 16b */
1819 d[1] = (newd >> 16) & 0xFFFF;
1820 if (Map_WriteW (addr, 4, d))                            /* store desc */
1821     return tq_fatal (PE_QWE);                           /* err? dead */
1822 if (desc & UQ_DESC_F) {                                 /* was F set? */
1823     if (ring->lnt <= 4)                                 /* lnt = 1? intr */
1824         tq_ring_int (ring);
1825     else {
1826         prva = ring->ba +                               /* prv desc */
1827             ((ring->idx - 4) & (ring->lnt - 1));
1828         if (Map_ReadW (prva, 4, d))                     /* read prv */
1829             return tq_fatal (PE_QRE);
1830         prvd = ((uint32) d[0]) | (((uint32) d[1]) << 16);
1831         if (prvd & UQ_DESC_OWN)
1832             tq_ring_int (ring);
1833         }
1834     }
1835 ring->idx = (ring->idx + 4) & (ring->lnt - 1);
1836 return OK;
1837 }
1838 
1839 /* Get unit descriptor for logical unit - trivial now,
1840    but eventually, hide multiboard complexities here */
1841 
tq_getucb(uint32 lu)1842 UNIT *tq_getucb (uint32 lu)
1843 {
1844 UNIT *uptr;
1845 
1846 if (lu >= TQ_NUMDR)
1847     return NULL;
1848 uptr = tq_dev.units + lu;
1849 if (uptr->flags & UNIT_DIS)
1850     return NULL;
1851 return uptr;
1852 }
1853 
1854 /* Hack unit flags */
1855 
tq_setf_unit(int32 pkt,UNIT * uptr)1856 void tq_setf_unit (int32 pkt, UNIT *uptr)
1857 {
1858 uptr->uf = tq_pkt[pkt].d[ONL_UFL] & UF_MSK;             /* settable flags */
1859 if ((tq_pkt[pkt].d[CMD_MOD] & MD_SWP) &&                /* swre wrp enb? */
1860     (tq_pkt[pkt].d[ONL_UFL] & UF_WPS))                  /* swre wrp on? */
1861     uptr->uf = uptr->uf | UF_WPS;                       /* simon says... */
1862 return;
1863 }
1864 
1865 /* Hack end flags */
1866 
tq_efl(UNIT * uptr)1867 uint32 tq_efl (UNIT *uptr)
1868 {
1869 uint32 t = 0;
1870 
1871 if (uptr) {                                             /* any unit? */
1872     if (uptr->flags & UNIT_POL)                         /* note pos lost */
1873         t = t | EF_PLS;
1874     if (uptr->flags & UNIT_SXC)                         /* note ser exc */
1875         t = t | EF_SXC;
1876     if (TEST_EOT (uptr))                                /* note EOT */
1877         t = t | EF_EOT;
1878     }
1879 return t;
1880 }
1881 
1882 /* Unit response fields */
1883 
tq_putr_unit(int32 pkt,UNIT * uptr,uint32 lu,t_bool all)1884 void tq_putr_unit (int32 pkt, UNIT *uptr, uint32 lu, t_bool all)
1885 {
1886 tq_pkt[pkt].d[ONL_MLUN] = lu;                           /* multi-unit */
1887 tq_pkt[pkt].d[ONL_UFL] = uptr->uf | TQ_WPH (uptr);      /* unit flags */
1888 tq_pkt[pkt].d[ONL_UFL] |= tq_efl (uptr);                /* end flags accordingly */
1889 tq_pkt[pkt].d[ONL_RSVL] = tq_pkt[pkt].d[ONL_RSVH] = 0;  /* reserved */
1890 tq_pkt[pkt].d[ONL_UIDA] = lu;                           /* UID low */
1891 tq_pkt[pkt].d[ONL_UIDB] = 0;
1892 tq_pkt[pkt].d[ONL_UIDC] = 0;
1893 tq_pkt[pkt].d[ONL_UIDD] = (UID_TAPE << ONL_UIDD_V_CLS) |
1894     (drv_tab[tq_typ].umod << ONL_UIDD_V_MOD);           /* UID hi */
1895 PUTP32 (pkt, ONL_MEDL, drv_tab[tq_typ].med);            /* media type */
1896 if (all) {                                              /* if long form */
1897     tq_pkt[pkt].d[ONL_FMT] = drv_tab[tq_typ].fmt;       /* format */
1898     tq_pkt[pkt].d[ONL_SPD] = 0;                         /* speed */
1899     PUTP32 (pkt, ONL_MAXL, TQ_MAXFR);                   /* max xfr */
1900     tq_pkt[pkt].d[ONL_NREC] = 0;                        /* noise rec */
1901     tq_pkt[pkt].d[ONL_RSVE] = 0;                        /* reserved */
1902     }
1903 return;
1904 }
1905 
1906 /* UQ_HDR and RSP_OP fields */
1907 
tq_putr(int32 pkt,uint32 cmd,uint32 flg,uint32 sts,uint32 lnt,uint32 typ)1908 void tq_putr (int32 pkt, uint32 cmd, uint32 flg, uint32 sts, uint32 lnt, uint32 typ)
1909 {
1910 tq_pkt[pkt].d[RSP_OPF] = (cmd << RSP_OPF_V_OPC) |       /* set cmd, flg */
1911     (flg << RSP_OPF_V_FLG);
1912 tq_pkt[pkt].d[RSP_STS] = sts;
1913 tq_pkt[pkt].d[UQ_HLNT] = lnt;                           /* length */
1914 tq_pkt[pkt].d[UQ_HCTC] = (typ << UQ_HCTC_V_TYP) |       /* type, cid */
1915     (UQ_CID_TMSCP << UQ_HCTC_V_CID);                    /* clr credits */
1916 return;
1917 }
1918 
1919 /* Post interrupt during init */
1920 
tq_init_int(void)1921 void tq_init_int (void)
1922 {
1923 if ((tq_s1dat & SA_S1H_IE) && tq_dib.vec)
1924     SET_INT (TQ);
1925 return;
1926 }
1927 
1928 /* Post interrupt during putpkt - note that NXMs are ignored! */
1929 
tq_ring_int(struct uq_ring * ring)1930 void tq_ring_int (struct uq_ring *ring)
1931 {
1932 uint32 iadr = tq_comm + ring->ioff;                     /* addr intr wd */
1933 uint16 flag = 1;
1934 
1935 Map_WriteW (iadr, 2, &flag);                            /* write flag */
1936 if (tq_dib.vec)                                         /* if enb, intr */
1937     SET_INT (TQ);
1938 return;
1939 }
1940 
1941 /* Return interrupt vector */
1942 
tq_inta(void)1943 int32 tq_inta (void)
1944 {
1945 return tq_dib.vec;                                      /* prog vector */
1946 }
1947 
1948 /* Fatal error */
1949 
tq_fatal(uint32 err)1950 t_bool tq_fatal (uint32 err)
1951 {
1952 if (DEBUG_PRS (tq_dev))
1953     fprintf (sim_deb, ">>TQ: fatal err=%X\n", err);
1954 tq_reset (&tq_dev);                                     /* reset device */
1955 tq_sa = SA_ER | err;                                    /* SA = dead code */
1956 tq_csta = CST_DEAD;                                     /* state = dead */
1957 tq_perr = err;                                          /* save error */
1958 return ERR;
1959 }
1960 
1961 /* Device attach */
1962 
tq_attach(UNIT * uptr,char * cptr)1963 t_stat tq_attach (UNIT *uptr, char *cptr)
1964 {
1965 t_stat r;
1966 
1967 r = sim_tape_attach (uptr, cptr);
1968 if (r != SCPE_OK)
1969     return r;
1970 if (tq_csta == CST_UP)
1971     uptr->flags = (uptr->flags | UNIT_ATP) & ~(UNIT_SXC | UNIT_POL | UNIT_TMK);
1972 return SCPE_OK;
1973 }
1974 
1975 /* Device detach */
1976 
tq_detach(UNIT * uptr)1977 t_stat tq_detach (UNIT *uptr)
1978 {
1979 t_stat r;
1980 
1981 r = sim_tape_detach (uptr);                             /* detach unit */
1982 if (r != SCPE_OK)
1983     return r;
1984 uptr->flags = uptr->flags & ~(UNIT_ONL | UNIT_ATP | UNIT_SXC | UNIT_POL | UNIT_TMK);
1985 uptr->uf = 0;                                           /* clr unit flgs */
1986 return SCPE_OK;
1987 }
1988 
1989 /* Device reset */
1990 
tq_reset(DEVICE * dptr)1991 t_stat tq_reset (DEVICE *dptr)
1992 {
1993 int32 i, j;
1994 UNIT *uptr;
1995 
1996 tq_csta = CST_S1;                                       /* init stage 1 */
1997 tq_s1dat = 0;                                           /* no S1 data */
1998 tq_dib.vec = 0;                                         /* no vector */
1999 if (UNIBUS)                                             /* Unibus? */
2000     tq_sa = SA_S1 | SA_S1C_DI | SA_S1C_MP;
2001 else tq_sa = SA_S1 | SA_S1C_Q22 | SA_S1C_DI | SA_S1C_MP; /* init SA val */
2002 tq_cflgs = CF_RPL;                                      /* ctrl flgs off */
2003 tq_htmo = TQ_DHTMO;                                     /* default timeout */
2004 tq_hat = tq_htmo;                                       /* default timer */
2005 tq_cq.ba = tq_cq.lnt = tq_cq.idx = 0;                   /* clr cmd ring */
2006 tq_rq.ba = tq_rq.lnt = tq_rq.idx = 0;                   /* clr rsp ring */
2007 tq_credits = (TQ_NPKTS / 2) - 1;                        /* init credits */
2008 tq_freq = 1;                                            /* init free list */
2009 for (i = 0; i < TQ_NPKTS; i++) {                        /* all pkts free */
2010     if (i)
2011         tq_pkt[i].link = (i + 1) & TQ_M_NPKTS;
2012     else tq_pkt[i].link = 0;
2013     for (j = 0; j < TQ_PKT_SIZE_W; j++)
2014         tq_pkt[i].d[j] = 0;
2015     }
2016 tq_rspq = 0;                                            /* no q'd rsp pkts */
2017 tq_pbsy = 0;                                            /* all pkts free */
2018 tq_pip = 0;                                             /* not polling */
2019 CLR_INT (TQ);                                           /* clr intr req */
2020 for (i = 0; i < TQ_NUMDR + 2; i++) {                    /* init units */
2021     uptr = tq_dev.units + i;
2022     sim_cancel (uptr);                                  /* clr activity */
2023     sim_tape_reset (uptr);
2024     uptr->flags = uptr->flags &                         /* not online */
2025         ~(UNIT_ONL|UNIT_ATP|UNIT_SXC|UNIT_POL|UNIT_TMK);
2026     uptr->uf = 0;                                       /* clr unit flags */
2027     uptr->cpkt = uptr->pktq = 0;                        /* clr pkt q's */
2028     }
2029 if (tqxb == NULL)
2030     tqxb = (uint8 *) calloc (TQ_MAXFR, sizeof (uint8));
2031 if (tqxb == NULL)
2032     return SCPE_MEM;
2033 return SCPE_OK;
2034 }
2035 
2036 /* Device bootstrap */
2037 
2038 #if defined (VM_PDP11)
2039 
2040 #define BOOT_START      016000                          /* start */
2041 #define BOOT_ENTRY      (BOOT_START + 002)              /* entry */
2042 #define BOOT_UNIT       (BOOT_START + 010)              /* unit number */
2043 #define BOOT_CSR        (BOOT_START + 014)              /* CSR */
2044 #define BOOT_LEN        (sizeof (boot_rom) / sizeof (int16))
2045 
2046 /* Data structure definitions */
2047 
2048 #define B_CMDINT        (BOOT_START - 01000)            /* cmd int */
2049 #define B_RSPINT        (B_CMDINT + 002)                /* rsp int */
2050 #define B_RING          (B_RSPINT + 002)                /* ring base */
2051 #define B_RSPH          (B_RING + 010)                  /* resp pkt hdr */
2052 #define B_TKRSP         (B_RSPH + 004)                  /* resp pkt */
2053 #define B_CMDH          (B_TKRSP + 060)                 /* cmd pkt hdr */
2054 #define B_TKCMD         (B_CMDH + 004)                  /* cmd pkt */
2055 #define B_UNIT          (B_TKCMD + 004)                 /* unit # */
2056 
2057 static const uint16 boot_rom[] = {
2058 
2059     0046525,                        /* ST: "UM" */
2060 
2061     0012706, 0016000,               /*   mov  #st,sp */
2062     0012700, 0000000,               /*   mov  #unitno,r0 */
2063     0012701, 0174500,               /*   mov  #174500,r1    ; ip addr */
2064     0005021,                        /*   clr  (r1)+         ; init */
2065     0012704, 0004000,               /*   mov  #4000,r4      ; s1 mask */
2066     0005002,                        /*   clr  r2 */
2067     0005022,                        /* 10$: clr (r2)+       ; clr up to boot */
2068     0020237, BOOT_START - 2,        /*   cmp  r2,#st-2 */
2069     0103774,                        /*   blo  10$ */
2070     0012705, BOOT_START+0312,       /*   mov  #cmdtbl,r5    ; addr of tbl */
2071 
2072                                     /* Four step init process */
2073 
2074     0005711,                        /* 20$: tst (r1)        ; err? */
2075     0100001,                        /*   bpl  30$ */
2076     0000000,                        /*   halt */
2077     0030411,                        /* 30$: bit r4,(r1)     ; step set? */
2078     0001773,                        /*   beq  20$           ; wait */
2079     0012511,                        /*   mov  (r5)+,(r1)    ; send next */
2080     0006304,                        /*   asl  r4            ; next mask */
2081     0100370,                        /*   bpl  20$           ; s4 done? */
2082 
2083                                     /* Set up rings, issue ONLINE, REWIND, READ */
2084 
2085     0012737, 0000400, B_CMDH + 2,   /*   mov  #400,cmdh+2   ; VCID = 1 */
2086     0012737, 0000044, B_CMDH,       /*   mov  #36.,cmdh     ; cmd pkt lnt */
2087     0010037, B_UNIT,                /*   mov  r0,unit       ; unit # */
2088     0012737, 0000011, B_TKCMD + 8,  /*   mov  #11,tkcmd+8.  ; online op */
2089     0012737, 0020000, B_TKCMD + 10, /*   mov  #20000,tkcmd+10. ; clr ser ex */
2090     0012702, B_RING,                /*   mov  #ring,r2      ; init rings */
2091     0012722, B_TKRSP,               /*   mov  #tkrsp,(r2)+  ; rsp pkt addr */
2092     0010203,                        /*   mov  r2,r3         ; save ring+2 */
2093     0010423,                        /*   mov  r4,(r3)+      ; set TK own */
2094     0012723, B_TKCMD,               /*   mov  #tkcmd,(r3)+  ; cmd pkt addr */
2095     0010423,                        /*   mov  r4,(r3)+      ; set TK own */
2096     0005741,                        /*   tst  -(r1)         ; start poll */
2097     0005712,                        /* 40$: tst (r2)        ; wait for resp */
2098     0100776,                        /*   bmi  40$ */
2099     0105737, B_TKRSP + 10,          /*   tstb tkrsp+10.     ; check stat */
2100     0001401,                        /*   beq  50$ */
2101     0000000,                        /*   halt */
2102     0012703, B_TKCMD + 8,           /* 50$: mov #tkcmd+8.,r3 */
2103     0012723, 0000045,               /*   mov  #45,(r3)+     ; reposition */
2104     0012723, 0020002,               /*   mov  #20002,(r3)+  ; rew, clr exc */
2105     0012723, 0000001,               /*   mov  #1,(r3)+      ; lo rec skp */
2106     0005023,                        /*   clr  (r3)+         ; hi rec skp */
2107     0005023,                        /*   clr  (r3)+         ; lo tmk skp */
2108     0005023,                        /*   clr  (r3)+         ; hi tmk skp */
2109     0010412,                        /*   mov  r4,(r2)       ; TK own rsp */
2110     0010437, B_RING + 6,            /*   mov  r4,ring+6     ; TK own cmd */
2111     0005711,                        /*   tst  (r1)          ; start poll */
2112     0005712,                        /* 60$: tst (r2)        ; wait for resp */
2113     0100776,                        /*   bmi  60$ */
2114     0105737, B_TKRSP + 10,          /*   tstb tkrsp+10.     ; check stat */
2115     0001401,                        /*   beq  70$ */
2116     0000000,                        /*   halt */
2117     0012703, B_TKCMD + 8,           /* 70$: mov #tkcmd+8.,r3 */
2118     0012723, 0000041,               /*   mov  #41,(r3)+     ; read */
2119     0012723, 0020000,               /*   mov  #20000,(r3)+  ; clr exc */
2120     0012723, 0001000,               /*   mov  #512.,(r3)+   ; bc = 512 */
2121     0005023,                        /*   clr  (r3)+         ; clr args */
2122     0005023,                        /*   clr  (r3)+         ; ba = 0 */
2123     0010412,                        /*   mov  r4,(r2)       ; TK own rsp */
2124     0010437, B_RING + 6,            /*   mov  r4,ring+6     ; TK own cmd */
2125     0005711,                        /*   tst  (r1)          ; start poll */
2126     0005712,                        /* 80$: tst (r2)        ; wait for resp */
2127     0100776,                        /*   bmi  80$ */
2128     0105737, B_TKRSP + 10,          /*   tstb tkrsp+10.     ; check stat */
2129     0001401,                        /*   beq  90$ */
2130     0000000,                        /*   halt */
2131 
2132                                     /* Boot block read in, jump to 0 - leave controller init'd */
2133 
2134     0005003,                        /*   clr  r3 */
2135     0012704, BOOT_START+020,        /*   mov  #st+020,r4 */
2136     0005005,                        /*   clr  r5 */
2137     0005007,                        /*   clr  pc */
2138 
2139     0100000,                        /* cmdtbl: init step 1 */
2140     B_RING,                         /* ring base */
2141     0000000,                        /* high ring base */
2142     0000001                         /* go */
2143     };
2144 
tq_boot(int32 unitno,DEVICE * dptr)2145 t_stat tq_boot (int32 unitno, DEVICE *dptr)
2146 {
2147 int32 i;
2148 extern int32 saved_PC;
2149 extern uint16 *M;
2150 
2151 for (i = 0; i < BOOT_LEN; i++)
2152     M[(BOOT_START >> 1) + i] = boot_rom[i];
2153 M[BOOT_UNIT >> 1] = unitno & 3;
2154 M[BOOT_CSR >> 1] = tq_dib.ba & DMASK;
2155 saved_PC = BOOT_ENTRY;
2156 return SCPE_OK;
2157 }
2158 
2159 #else
2160 
tq_boot(int32 unitno,DEVICE * dptr)2161 t_stat tq_boot (int32 unitno, DEVICE *dptr)
2162 {
2163 return SCPE_NOFNC;
2164 }
2165 
2166 #endif
2167 
2168 /* Special show commands */
2169 
tq_show_ring(FILE * st,struct uq_ring * rp)2170 void tq_show_ring (FILE *st, struct uq_ring *rp)
2171 {
2172 uint32 i, desc;
2173 uint16 d[2];
2174 
2175 #if defined (VM_PDP11)
2176 fprintf (st, "ring, base = %o, index = %d, length = %d\n",
2177      rp->ba, rp->idx >> 2, rp->lnt >> 2);
2178 #else
2179 fprintf (st, "ring, base = %x, index = %d, length = %d\n",
2180      rp->ba, rp->idx >> 2, rp->lnt >> 2);
2181 #endif
2182 for (i = 0; i < (rp->lnt >> 2); i++) {
2183     if (Map_ReadW (rp->ba + (i << 2), 4, d)) {
2184         fprintf (st, " %3d: non-existent memory\n", i);
2185         break;
2186         }
2187     desc = ((uint32) d[0]) | (((uint32) d[1]) << 16);
2188 #if defined (VM_PDP11)
2189     fprintf (st, " %3d: %011o\n", i, desc);
2190 #else
2191     fprintf (st, " %3d: %08x\n", i, desc);
2192 #endif
2193     }
2194 return;
2195 }
2196 
tq_show_pkt(FILE * st,int32 pkt)2197 void tq_show_pkt (FILE *st, int32 pkt)
2198 {
2199 int32 i, j;
2200 uint32 cr = GETP (pkt, UQ_HCTC, CR);
2201 uint32 typ = GETP (pkt, UQ_HCTC, TYP);
2202 uint32 cid = GETP (pkt, UQ_HCTC, CID);
2203 
2204 fprintf (st, "packet %d, credits = %d, type = %d, cid = %d\n",
2205     pkt, cr, typ, cid);
2206 for (i = 0; i < TQ_SH_MAX; i = i + TQ_SH_PPL) {
2207     fprintf (st, " %2d:", i);
2208     for (j = i; j < (i + TQ_SH_PPL); j++)
2209 #if defined (VM_PDP11)
2210     fprintf (st, " %06o", tq_pkt[pkt].d[j]);
2211 #else
2212     fprintf (st, " %04x", tq_pkt[pkt].d[j]);
2213 #endif
2214     fprintf (st, "\n");
2215     }
2216 return;
2217 }
2218 
tq_show_unitq(FILE * st,UNIT * uptr,int32 val,void * desc)2219 t_stat tq_show_unitq (FILE *st, UNIT *uptr, int32 val, void *desc)
2220 {
2221 int32 pkt, u = uptr - tq_dev.units;
2222 
2223 if (tq_csta != CST_UP) {
2224     fprintf (st, "Controller is not initialized\n");
2225     return SCPE_OK;
2226     }
2227 if ((uptr->flags & UNIT_ONL) == 0) {
2228     if (uptr->flags & UNIT_ATT)
2229         fprintf (st, "Unit %d is available\n", u);
2230     else fprintf (st, "Unit %d is offline\n", u);
2231     return SCPE_OK;
2232     }
2233 if (uptr->cpkt) {
2234     fprintf (st, "Unit %d current ", u);
2235     tq_show_pkt (st, uptr->cpkt);
2236     if ((pkt = uptr->pktq)) {
2237         do {
2238             fprintf (st, "Unit %d queued ", u);
2239             tq_show_pkt (st, pkt);
2240             } while ((pkt = tq_pkt[pkt].link));
2241         }
2242     }
2243 else fprintf (st, "Unit %d queues are empty\n", u);
2244 return SCPE_OK;
2245 }
2246 
tq_show_ctrl(FILE * st,UNIT * uptr,int32 val,void * desc)2247 t_stat tq_show_ctrl (FILE *st, UNIT *uptr, int32 val, void *desc)
2248 {
2249 int32 i, pkt;
2250 
2251 if (tq_csta != CST_UP) {
2252     fprintf (st, "Controller is not initialized\n");
2253     return SCPE_OK;
2254     }
2255 if (val & TQ_SH_RI) {
2256     if (tq_pip)
2257         fprintf (st, "Polling in progress, host timer = %d\n", tq_hat);
2258     else fprintf (st, "Host timer = %d\n", tq_hat);
2259     fprintf (st, "Command ");
2260     tq_show_ring (st, &tq_cq);
2261     fprintf (st, "Response ");
2262     tq_show_ring (st, &tq_rq);
2263     }
2264 if (val & TQ_SH_FR) {
2265     if ((pkt = tq_freq)) {
2266         for (i = 0; pkt != 0; i++, pkt = tq_pkt[pkt].link) {
2267             if (i == 0)
2268                 fprintf (st, "Free queue = %d", pkt);
2269             else if ((i % 16) == 0)
2270                 fprintf (st, ",\n %d", pkt);
2271             else fprintf (st, ", %d", pkt);
2272             }
2273         fprintf (st, "\n");
2274         }
2275     else fprintf (st, "Free queue is empty\n");
2276     }
2277 if (val & TQ_SH_RS) {
2278     if ((pkt = tq_rspq)) {
2279         do {
2280             fprintf (st, "Response ");
2281             tq_show_pkt (st, pkt);
2282             } while ((pkt = tq_pkt[pkt].link));
2283         }
2284     else fprintf (st, "Response queue is empty\n");
2285     }
2286 if (val & TQ_SH_UN) {
2287     for (i = 0; i < TQ_NUMDR; i++)
2288         tq_show_unitq (st, &tq_unit[i], 0, NULL);
2289     }
2290 return SCPE_OK;
2291 }
2292 
2293 /* Set controller type (and capacity for user-defined type) */
2294 
tq_set_type(UNIT * uptr,int32 val,char * cptr,void * desc)2295 t_stat tq_set_type (UNIT *uptr, int32 val, char *cptr, void *desc)
2296 {
2297 uint32 i, cap;
2298 uint32 max = sim_taddr_64? TQU_EMAXC: TQU_MAXC;
2299 t_stat r;
2300 
2301 if ((val < 0) || (val > TQU_TYPE) || ((val != TQU_TYPE) && cptr))
2302     return SCPE_ARG;
2303 for (i = 0; i < TQ_NUMDR; i++) {
2304     if (tq_unit[i].flags & UNIT_ATT)
2305         return SCPE_ALATT;
2306     }
2307 if (cptr) {
2308     cap = (uint32) get_uint (cptr, 10, max, &r);
2309     if ((r != SCPE_OK) || (cap < TQU_MINC))
2310         return SCPE_ARG;
2311     drv_tab[TQU_TYPE].cap = ((t_addr) cap) << 20;
2312     }
2313 tq_typ = val;
2314 for (i = 0; i < TQ_NUMDR; i++)
2315     tq_unit[i].capac = drv_tab[tq_typ].cap;
2316 return SCPE_OK;
2317 }
2318 
2319 /* Show controller type and capacity */
2320 
tq_show_type(FILE * st,UNIT * uptr,int32 val,void * desc)2321 t_stat tq_show_type (FILE *st, UNIT *uptr, int32 val, void *desc)
2322 {
2323 fprintf (st, "%s (%dMB)", drv_tab[tq_typ].name, (uint32) (drv_tab[tq_typ].cap >> 20));
2324 return SCPE_OK;
2325 }
2326