1 /* pdp11_vh.c: DHQ11 asynchronous terminal multiplexor simulator
3 Copyright (c) 2004-2006, John A. Dundas III
4 Portions derived from work by Robert M Supnik
6 Permission is hereby granted, free of charge, to any person obtaining a
7 copy of this software and associated documentation files (the "Software"),
8 to deal in the Software without restriction, including without limitation
9 the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 and/or sell copies of the Software, and to permit persons to whom the
11 Software is furnished to do so, subject to the following conditions:
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 Except as contained in this notice, the name of the Author shall not be
24 used in advertising or otherwise to promote the sale, use or other dealings
25 in this Software without prior written authorization from the Author.
27 vh DHQ11 asynch multiplexor for SIMH
29 18-Jun-07 RMS Added UNIT_IDLE flag
30 29-Oct-06 RMS Synced poll and clock
31 07-Jul-05 RMS Removed extraneous externs
32 15-Jun-05 RMS Revised for new autoconfigure interface
33 Fixed bug in vector display routine
34 12-Jun-04 RMS Repair MS2SIMH macro to avoid divide by 0 bug
35 08-Jun-04 JAD Repair vh_dev initialization; remove unused
36 variables, cast to avoid conversion confusion
37 07-Jun-04 JAD Complete function prototypes of forward declarations.
38 Repair broken prototypes of vh_rd() and vh_wr()
39 Explicitly size integer declarations
40 4-Jun-04 JAD Preliminary code: If operating in a PDP-11 Unibus
41 environment, force DHU mode
42 29-May-04 JAD Make certain RX.TIMER is within allowable range
43 25-May-04 JAD All time-based operations are scaled by tmxr_poll units
44 23-May-04 JAD Change to fifo_get() and dq_tx_report() to avoid
45 gratuitous stack manipulation
46 20-May-04 JAD Made modem control and auto-hangup unit flags
47 19-May-04 JAD Fix problem with modem status where the line number
48 was not being included
49 12-May-04 JAD Revised for updated tmxr interfaces
50 28-Jan-04 JAD Original creation and testing
54 CSR 17 760 440 (float)
63 /* MANY constants needed! */
67 extern int32 int_req
[IPL_HLVL
];
70 #if defined (VM_PDP11)
71 #include "pdp11_defs.h"
72 extern int32 int_req
[IPL_HLVL
];
79 /* imports from pdp11_stddev.c: */
80 extern int32 tmxr_poll
, clk_tps
;
81 /* convert ms to SIMH time units based on tmxr_poll polls per second */
82 #define MS2SIMH(ms) (((ms) * clk_tps) / 1000)
88 #define VH_MNOMASK (VH_MUXES - 1)
92 #define UNIT_V_MODEDHU (UNIT_V_UF + 0)
93 #define UNIT_V_FASTDMA (UNIT_V_UF + 1)
94 #define UNIT_V_MODEM (UNIT_V_UF + 2)
95 #define UNIT_V_HANGUP (UNIT_V_UF + 3)
96 #define UNIT_MODEDHU (1 << UNIT_V_MODEDHU)
97 #define UNIT_FASTDMA (1 << UNIT_V_FASTDMA)
98 #define UNIT_MODEM (1 << UNIT_V_MODEM)
99 #define UNIT_HANGUP (1 << UNIT_V_HANGUP)
101 /* VHCSR - 160440 - Control and Status Register */
103 #define CSR_M_IND_ADDR (017)
104 #define CSR_SKIP (1 << 4)
105 #define CSR_MASTER_RESET (1 << 5)
106 #define CSR_RXIE (1 << 6)
107 #define CSR_RX_DATA_AVAIL (1 << 7)
108 #define CSR_M_TX_LINE (017)
109 #define CSR_V_TX_LINE (8)
110 #define CSR_TX_DMA_ERR (1 << 12)
111 #define CSR_DIAG_FAIL (1 << 13)
112 #define CSR_TXIE (1 << 14)
113 #define CSR_TX_ACTION (1 << 15)
114 #define CSR_GETCHAN(x) ((x) & CSR_M_IND_ADDR)
116 (CSR_TXIE|CSR_RXIE|CSR_SKIP|CSR_M_IND_ADDR|CSR_MASTER_RESET)
117 #define RESET_ABORT (052525)
119 /* Receive Buffer (RBUF) */
121 #define FIFO_SIZE (256)
122 #define FIFO_ALARM (191)
123 #define FIFO_HALF (FIFO_SIZE / 2)
124 #define RBUF_M_RX_CHAR (0377)
125 #define RBUF_M_RX_LINE (07)
126 #define RBUF_V_RX_LINE (8)
127 #define RBUF_PARITY_ERR (1 << 12)
128 #define RBUF_FRAME_ERR (1 << 13)
129 #define RBUF_OVERRUN_ERR (1 << 14)
130 #define RBUF_DATA_VALID (1 << 15)
131 #define RBUF_GETLINE(x) (((x) >> RBUF_V_RX_LINE) & RBUF_M_RX_LINE)
132 #define RBUF_PUTLINE(x) ((x) << RBUF_V_RX_LINE)
134 (RBUF_PARITY_ERR|RBUF_FRAME_ERR|RBUF_OVERRUN_ERR)
138 /* Transmit Character Register (TXCHAR) */
140 #define TXCHAR_M_CHAR (0377)
141 #define TXCHAR_TX_DATA_VALID (1 << 15)
143 /* Receive Timer Register (RXTIMER) */
145 #define RXTIMER_M_RX_TIMER (0377)
147 /* Line-Parameter Register (LPR) */
149 #define LPR_DISAB_XRPT (1 << 0) /* not impl. in real DHU */
150 #define LPR_V_DIAG (1)
151 #define LPR_M_DIAG (03)
152 #define LPR_V_CHAR_LGTH (3)
153 #define LPR_M_CHAR_LGTH (03)
154 #define LPR_PARITY_ENAB (1 << 5)
155 #define LPR_EVEN_PARITY (1 << 6)
156 #define LPR_STOP_CODE (1 << 7)
157 #define LPR_V_RX_SPEED (8)
158 #define LPR_M_RX_SPEED (017)
159 #define LPR_V_TX_SPEED (12)
160 #define LPR_M_TX_SPEED (017)
169 #define RATE_1200 (7)
170 #define RATE_1800 (8)
171 #define RATE_2000 (9)
172 #define RATE_2400 (10)
173 #define RATE_4800 (11)
174 #define RATE_7200 (12)
175 #define RATE_9600 (13)
176 #define RATE_19200 (14)
177 #define RATE_38400 (15)
179 /* Line-Status Register (STAT) */
181 #define STAT_DHUID (1 << 8) /* mode: 0=DHV, 1=DHU */
182 #define STAT_MDL (1 << 9) /* always 0, has modem support */
183 #define STAT_CTS (1 << 11) /* CTS from modem */
184 #define STAT_DCD (1 << 12) /* DCD from modem */
185 #define STAT_RI (1 << 13) /* RI from modem */
186 #define STAT_DSR (1 << 15) /* DSR from modem */
188 /* FIFO Size Register (FIFOSIZE) */
190 #define FIFOSIZE_M_SIZE (0377)
192 /* FIFO Data Register (FIFODATA) */
194 #define FIFODATA_W0 (0377)
195 #define FIFODATA_V_W1 (8)
196 #define FIFODATA_M_W1 (0377)
198 /* Line-Control Register (LNCTRL) */
200 #define LNCTRL_TX_ABORT (1 << 0)
201 #define LNCTRL_IAUTO (1 << 1)
202 #define LNCTRL_RX_ENA (1 << 2)
203 #define LNCTRL_BREAK (1 << 3)
204 #define LNCTRL_OAUTO (1 << 4)
205 #define LNCTRL_FORCE_XOFF (1 << 5)
206 #define LNCTRL_V_MAINT (6)
207 #define LNCTRL_M_MAINT (03)
208 #define LNCTRL_LINK_TYPE (1 << 8) /* 0=data leads only, 1=modem */
209 #define LNCTRL_DTR (1 << 9) /* DTR to modem */
210 #define LNCTRL_RTS (1 << 12) /* RTS to modem */
212 /* Transmit Buffer Address Register Number 1 (TBUFFAD1) */
214 /* Transmit Buffer Address Register Number 2 (TBUFFAD2) */
216 #define TB2_M_TBUFFAD (077)
217 #define TB2_TX_DMA_START (1 << 7)
218 #define TB2_TX_ENA (1 << 15)
220 /* Transmit DMA Buffer Counter (TBUFFCT) */
222 /* Self-Test Error Codes */
224 #define SELF_NULL (0201)
225 #define SELF_SKIP (0203)
226 #define SELF_OCT (0211)
227 #define SELF_RAM (0225)
228 #define SELF_RCD (0231)
229 #define SELF_DRD (0235)
231 #define BMP_OK (0305)
232 #define BMP_BAD (0307)
236 #define LOOP_NONE (0)
237 #define LOOP_H325 (1)
238 #define LOOP_H3101 (2) /* p.2-13 DHQ manual */
241 static uint16 vh_csr
[VH_MUXES
] = { 0 }; /* CSRs */
242 static uint16 vh_timer
[VH_MUXES
] = { 1 }; /* controller timeout */
243 static uint16 vh_mcount
[VH_MUXES
] = { 0 };
244 static uint32 vh_timeo
[VH_MUXES
] = { 0 };
245 static uint32 vh_ovrrun
[VH_MUXES
] = { 0 }; /* line overrun bits */
246 /* XOFF'd channels, one bit/channel */
247 static uint32 vh_stall
[VH_MUXES
] = { 0 };
248 static uint16 vh_loop
[VH_MUXES
] = { 0 }; /* loopback status */
250 /* One bit per controller: */
251 static uint32 vh_rxi
= 0; /* rcv interrupts */
252 static uint32 vh_txi
= 0; /* xmt interrupts */
253 static uint32 vh_crit
= 0; /* FIFO.CRIT */
255 static const int32 bitmask
[4] = { 037, 077, 0177, 0377 };
259 static int32 rbuf_idx
[VH_MUXES
] = { 0 };/* index into vh_rbuf */
260 static uint32 vh_rbuf
[VH_MUXES
][FIFO_SIZE
] = { 0 };
264 #define TXQ_SIZE (16)
265 static int32 txq_idx
[VH_MUXES
] = { 0 };
266 static uint32 vh_txq
[VH_MUXES
][TXQ_SIZE
] = { 0 };
268 /* Need to extend the TMLN structure */
272 uint16 lpr
; /* line parameters */
273 uint16 lnctrl
; /* line control */
274 uint16 lstat
; /* line modem status */
275 uint16 tbuffct
; /* remaining character count */
278 uint16 txchar
; /* single character I/O */
281 static TMLN vh_ldsc
[VH_MUXES
* VH_LINES
] = { 0 };
282 static TMXR vh_desc
= { VH_MUXES
* VH_LINES
, 0, 0, vh_ldsc
};
283 static TMLX vh_parm
[VH_MUXES
* VH_LINES
] = { 0 };
285 /* Forward references */
286 static t_stat
vh_rd (int32
*data
, int32 PA
, int32 access
);
287 static t_stat
vh_wr (int32 data
, int32 PA
, int32 access
);
288 static t_stat
vh_svc (UNIT
*uptr
);
289 static int32
vh_rxinta (void);
290 static int32
vh_txinta (void);
291 static t_stat
vh_clear (int32 vh
, t_bool flag
);
292 static t_stat
vh_reset (DEVICE
*dptr
);
293 static t_stat
vh_attach (UNIT
*uptr
, char *cptr
);
294 static t_stat
vh_detach (UNIT
*uptr
);
295 static t_stat
vh_show_vec (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
);
296 static t_stat
vh_show (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
);
297 static t_stat
vh_show_debug (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
);
298 static t_stat
vh_show_rbuf (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
);
299 static t_stat
vh_show_txq (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
);
300 static t_stat
vh_putc (int32 vh
, TMLX
*lp
, int32 chan
, int32 data
);
301 static void doDMA (int32 vh
, int32 chan
);
302 static t_stat
vh_summ (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
);
304 int32
tmxr_send_buffered_data (TMLN
*lp
);
306 /* SIMH I/O Structures */
308 static DIB vh_dib
= {
313 2, /* # of vectors */
316 { &vh_rxinta
, &vh_txinta
} /* int. ack. routines */
319 static UNIT vh_unit
[VH_MUXES
] = {
320 { UDATA (&vh_svc
, UNIT_IDLE
|UNIT_ATTABLE
, 0) },
321 { UDATA (&vh_svc
, UNIT_IDLE
|UNIT_ATTABLE
, 0) },
322 { UDATA (&vh_svc
, UNIT_IDLE
|UNIT_ATTABLE
, 0) },
323 { UDATA (&vh_svc
, UNIT_IDLE
|UNIT_ATTABLE
, 0) },
326 static const REG vh_nlreg
= { DRDATA (NLINES
, vh_desc
.lines
, 6), PV_LEFT
};
328 static const REG vh_reg
[] = {
329 { BRDATA (CSR
, vh_csr
, DEV_RDX
, 16, VH_MUXES
) },
330 { GRDATA (DEVADDR
, vh_dib
.ba
, DEV_RDX
, 32, 0), REG_HRO
},
331 { GRDATA (DEVVEC
, vh_dib
.vec
, DEV_RDX
, 16, 0), REG_HRO
},
335 static const MTAB vh_mod
[] = {
336 { UNIT_MODEDHU
, 0, "DHV mode", "DHV", NULL
},
337 { UNIT_MODEDHU
, UNIT_MODEDHU
, "DHU mode", "DHU", NULL
},
338 { UNIT_FASTDMA
, 0, NULL
, "NORMAL", NULL
},
339 { UNIT_FASTDMA
, UNIT_FASTDMA
, "fast DMA", "FASTDMA", NULL
},
340 { UNIT_MODEM
, 0, NULL
, "NOMODEM", NULL
},
341 { UNIT_MODEM
, UNIT_MODEM
, "modem", "MODEM", NULL
},
342 { UNIT_HANGUP
, 0, NULL
, "NOHANGUP", NULL
},
343 { UNIT_HANGUP
, UNIT_HANGUP
, "hangup", "HANGUP", NULL
},
344 { MTAB_XTD
|MTAB_VDV
, 020, "ADDRESS", "ADDRESS",
345 &set_addr
, &show_addr
, NULL
},
346 { MTAB_XTD
|MTAB_VDV
, 0, "VECTOR", "VECTOR",
347 &set_vec
, &vh_show_vec
, NULL
},
348 { MTAB_XTD
|MTAB_VDV
, 0, NULL
, "AUTOCONFIGURE",
349 &set_addr_flt
, NULL
, NULL
},
350 /* this one is dangerous, don't use yet */
351 { MTAB_XTD
|MTAB_VDV
|MTAB_VAL
, 0, "lines", "LINES",
352 NULL
, NULL
, (REG
*)&vh_nlreg
},
353 { UNIT_ATT
, UNIT_ATT
, "connections", NULL
, NULL
, &vh_summ
},
354 { MTAB_XTD
| MTAB_VDV
| MTAB_NMO
, 1, "CONNECTIONS", NULL
,
355 NULL
, &vh_show
, NULL
},
356 { MTAB_XTD
| MTAB_VDV
| MTAB_NMO
, 0, "STATISTICS", NULL
,
357 NULL
, &vh_show
, NULL
},
358 { MTAB_XTD
| MTAB_VDV
, 1, NULL
, "DISCONNECT",
359 &tmxr_dscln
, NULL
, &vh_desc
},
360 { MTAB_XTD
| MTAB_VDV
| MTAB_NMO
, 0, "DEBUG", NULL
,
361 NULL
, &vh_show_debug
, NULL
},
362 { MTAB_XTD
| MTAB_VDV
| MTAB_NMO
, 0, "RBUF", NULL
,
363 NULL
, &vh_show_rbuf
, NULL
},
364 { MTAB_XTD
| MTAB_VDV
| MTAB_NMO
, 0, "TXQ", NULL
,
365 NULL
, &vh_show_txq
, NULL
},
372 (REG
*)vh_reg
, /* registers */
373 (MTAB
*)vh_mod
, /* modifiers */
374 VH_MUXES
, /* # units */
375 DEV_RDX
, /* address radix */
376 8, /* address width */
377 1, /* address increment */
378 DEV_RDX
, /* data radix */
380 NULL
, /* examine routine */
381 NULL
, /* deposit routine */
382 &vh_reset
, /* reset routine */
383 NULL
, /* boot routine */
384 &vh_attach
, /* attach routine */
385 &vh_detach
, /* detach routine */
386 (void *)&vh_dib
, /* context */
387 DEV_FLTA
| DEV_DISABLE
| DEV_DIS
|DEV_NET
| DEV_QBUS
| DEV_UBUS
, /* flags */
390 /* Interrupt routines */
392 static void vh_clr_rxint ( int32 vh
)
394 vh_rxi
&= ~(1 << vh
);
401 static void vh_set_rxint ( int32 vh
)
407 /* RX interrupt ack. (bus cycle) */
409 static int32
vh_rxinta (void)
413 for (vh
= 0; vh
< VH_MUXES
; vh
++) {
414 if (vh_rxi
& (1 << vh
)) {
416 return (vh_dib
.vec
+ (vh
* 010));
422 static void vh_clr_txint ( int32 vh
)
424 vh_txi
&= ~(1 << vh
);
431 static void vh_set_txint ( int32 vh
)
437 /* TX interrupt ack. (bus cycle) */
439 static int32
vh_txinta (void)
443 for (vh
= 0; vh
< VH_MUXES
; vh
++) {
444 if (vh_txi
& (1 << vh
)) {
446 return (vh_dib
.vec
+ 4 + (vh
* 010));
451 /* RX FIFO get/put routines */
453 /* return 0 on success, -1 on FIFO overflow */
455 static int32
fifo_put ( int32 vh
,
463 /* this might have to move to vh_getc() */
464 if ((lp
->lnctrl
& LNCTRL_OAUTO
) && ((data
& RBUF_DIAG
) == 0)) {
466 /* implement transmitted data flow control */
467 switch (data
& 0377) {
469 lp
->tbuf2
|= TB2_TX_ENA
;
472 lp
->tbuf2
&= ~TB2_TX_ENA
;
474 /* find line 0 for this controller */
475 l0p
= &vh_parm
[vh
* VH_LINES
];
476 if (l0p
->lpr
& LPR_DISAB_XRPT
)
483 /* BUG: which of the following 2 is correct? */
484 /* if ((data & RBUF_DIAG) == RBUF_DIAG) */
485 if (data
& RBUF_DIAG
)
487 if (((lp
->lnctrl
>> LNCTRL_V_MAINT
) & LNCTRL_M_MAINT
) == 2)
489 if (!(lp
->lnctrl
& LNCTRL_RX_ENA
))
492 vh_csr
[vh
] |= CSR_RX_DATA_AVAIL
;
493 if (rbuf_idx
[vh
] < FIFO_SIZE
) {
494 vh_rbuf
[vh
][rbuf_idx
[vh
]] = data
;
497 vh_ovrrun
[vh
] |= (1 << RBUF_GETLINE (data
));
500 if (vh_csr
[vh
] & CSR_RXIE
) {
501 if (vh_unit
[vh
].flags
& UNIT_MODEDHU
) {
502 /* was it a modem status change? */
503 if ((data
& RBUF_DIAG
) == RBUF_DIAG
)
505 /* look for FIFO alarm @ 3/4 full */
506 else if (rbuf_idx
[vh
] == FIFO_ALARM
)
508 else if (vh_timer
[vh
] == 0)
509 ; /* nothing, infinite timeout */
510 else if (vh_timer
[vh
] == 1)
512 else if (vh_timeo
[vh
] == 0)
513 vh_timeo
[vh
] = MS2SIMH (vh_timer
[vh
]) + 1;
515 /* Interrupt on transition _from_ an empty FIFO */
516 if (rbuf_idx
[vh
] == 1)
520 if (rbuf_idx
[vh
] > FIFO_ALARM
)
521 vh_crit
|= (1 << vh
);
522 /* Implement RX FIFO-level flow control */
524 if ((lp
->lnctrl
& LNCTRL_FORCE_XOFF
) ||
525 ((vh_crit
& (1 << vh
)) && (lp
->lnctrl
& LNCTRL_IAUTO
))) {
526 int32 chan
= RBUF_GETLINE(data
);
527 vh_stall
[vh
] ^= (1 << chan
);
528 /* send XOFF every other character received */
529 if (vh_stall
[vh
] & (1 << chan
))
530 vh_putc (vh
, lp
, chan
, XOFF
);
536 static int32
fifo_get ( int32 vh
)
540 if (rbuf_idx
[vh
] == 0) {
541 vh_csr
[vh
] &= ~CSR_RX_DATA_AVAIL
;
544 /* pick off the first character, mark valid */
545 data
= vh_rbuf
[vh
][0] | RBUF_DATA_VALID
;
546 /* move the remainder up */
548 for (i
= 0; i
< rbuf_idx
[vh
]; i
++)
549 vh_rbuf
[vh
][i
] = vh_rbuf
[vh
][i
+ 1];
550 /* rbuf_idx[vh] -= 1; */
551 /* look for any previous overruns */
553 for (i
= 0; i
< VH_LINES
; i
++) {
554 if (vh_ovrrun
[vh
] & (1 << i
)) {
555 fifo_put (vh
, NULL
, RBUF_OVERRUN_ERR
|
557 vh_ovrrun
[vh
] &= ~(1 << i
);
562 /* recompute FIFO alarm condition */
563 if ((rbuf_idx
[vh
] < FIFO_HALF
) && (vh_crit
& (1 << vh
))) {
564 vh_crit
&= ~(1 << vh
);
565 /* send XON to all XOFF'd channels on this controller */
566 for (i
= 0; i
< VH_LINES
; i
++) {
567 TMLX
*lp
= &vh_parm
[(vh
* VH_LINES
) + i
];
568 if (lp
->lnctrl
& LNCTRL_FORCE_XOFF
)
570 if (vh_stall
[vh
] & (1 << i
)) {
571 vh_putc (vh
, NULL
, i
, XON
);
572 vh_stall
[vh
] &= ~(1 << i
);
576 return (data
& 0177777);
578 /* TX Q manipulation */
580 static int32
dq_tx_report ( int32 vh
)
584 if (txq_idx
[vh
] == 0)
586 data
= vh_txq
[vh
][0];
588 for (i
= 0; i
< txq_idx
[vh
]; i
++)
589 vh_txq
[vh
][i
] = vh_txq
[vh
][i
+ 1];
590 /* txq_idx[vh] -= 1; */
591 return (data
& 0177777);
594 static void q_tx_report ( int32 vh
,
597 if (vh_csr
[vh
] & CSR_TXIE
)
599 if (txq_idx
[vh
] >= TXQ_SIZE
) {
600 /* BUG: which of the following 2 is correct? */
604 vh_txq
[vh
][txq_idx
[vh
]] = CSR_TX_ACTION
| data
;
607 /* Channel get/put routines */
609 static void HangupModem ( int32 vh
,
613 if (vh_unit
[vh
].flags
& UNIT_MODEM
)
614 lp
->lstat
&= ~(STAT_DCD
|STAT_DSR
|STAT_CTS
|STAT_RI
);
615 if (lp
->lnctrl
& LNCTRL_LINK_TYPE
)
616 /* RBUF<0> = 0 for modem status */
617 fifo_put (vh
, lp
, RBUF_DIAG
|
618 RBUF_PUTLINE (chan
) |
619 ((lp
->lstat
>> 8) & 0376));
620 /* BUG: check for overflow above */
623 /* TX a character on a line, regardless of the TX enable state */
625 static t_stat
vh_putc ( int32 vh
,
631 t_stat status
= SCPE_OK
;
633 /* truncate to desired character length */
634 data
&= bitmask
[(lp
->lpr
>> LPR_V_CHAR_LGTH
) & LPR_M_CHAR_LGTH
];
635 switch ((lp
->lnctrl
>> LNCTRL_V_MAINT
) & LNCTRL_M_MAINT
) {
638 /* check for (external) loopback setting */
639 switch (vh_loop
[vh
]) {
645 status
= tmxr_putc_ln (lp
->tmln
, data
);
646 if (status
== SCPE_LOST
) {
647 tmxr_reset_ln (lp
->tmln
);
648 HangupModem (vh
, lp
, chan
);
649 } else if (status
== SCPE_STALL
) {
650 /* let's flush and try again */
651 tmxr_send_buffered_data (lp
->tmln
);
652 status
= tmxr_putc_ln (lp
->tmln
, data
);
655 case 1: /* auto echo */
657 case 2: /* local loopback */
658 if (lp
->lnctrl
& LNCTRL_BREAK
)
659 val
= fifo_put (vh
, lp
,
660 RBUF_FRAME_ERR
| RBUF_PUTLINE (chan
));
662 val
= fifo_put (vh
, lp
,
663 RBUF_PUTLINE (chan
) | data
);
664 status
= (val
< 0) ? SCPE_TTMO
: SCPE_OK
;
666 default: /* remote loopback */
672 /* Retrieve all stored input from TMXR and place in RX FIFO */
674 static void vh_getc ( int32 vh
)
679 for (i
= 0; i
< VH_LINES
; i
++) {
680 lp
= &vh_parm
[(vh
* VH_LINES
) + i
];
681 while (c
= tmxr_getc_ln (lp
->tmln
)) {
682 if (c
& SCPE_BREAK
) {
684 RBUF_FRAME_ERR
| RBUF_PUTLINE (i
));
685 /* BUG: check for overflow above */
687 c
&= bitmask
[(lp
->lpr
>> LPR_V_CHAR_LGTH
) &
689 fifo_put (vh
, lp
, RBUF_PUTLINE (i
) | c
);
690 /* BUG: check for overflow above */
696 /* I/O dispatch routines */
698 static t_stat
vh_rd ( int32
*data
,
702 int32 vh
= ((PA
- vh_dib
.ba
) >> 4) & VH_MNOMASK
, line
;
705 switch ((PA
>> 1) & 7) {
707 *data
= vh_csr
[vh
] | dq_tx_report (vh
);
708 vh_csr
[vh
] &= ~0117400; /* clear the read-once bits */
711 *data
= fifo_get (vh
);
714 if (CSR_GETCHAN (vh_csr
[vh
]) >= VH_LINES
) {
718 line
= (vh
* VH_LINES
) + CSR_GETCHAN (vh_csr
[vh
]);
722 case 3: /* STAT/FIFOSIZE */
723 if (CSR_GETCHAN (vh_csr
[vh
]) >= VH_LINES
) {
727 line
= (vh
* VH_LINES
) + CSR_GETCHAN (vh_csr
[vh
]);
729 *data
= (lp
->lstat
& ~0377) | /* modem status */
731 (64 - tmxr_tqln (lp
->tmln
));
732 fprintf (stderr
, "\rtqln %d\n", 64 - tmxr_tqln (lp
->tmln
));
738 if (CSR_GETCHAN (vh_csr
[vh
]) >= VH_LINES
) {
742 line
= (vh
* VH_LINES
) + CSR_GETCHAN (vh_csr
[vh
]);
746 case 5: /* TBUFFAD1 */
747 if (CSR_GETCHAN (vh_csr
[vh
]) >= VH_LINES
) {
751 line
= (vh
* VH_LINES
) + CSR_GETCHAN (vh_csr
[vh
]);
755 case 6: /* TBUFFAD2 */
756 if (CSR_GETCHAN (vh_csr
[vh
]) >= VH_LINES
) {
760 line
= (vh
* VH_LINES
) + CSR_GETCHAN (vh_csr
[vh
]);
764 case 7: /* TBUFFCT */
765 if (CSR_GETCHAN (vh_csr
[vh
]) >= VH_LINES
) {
769 line
= (vh
* VH_LINES
) + CSR_GETCHAN (vh_csr
[vh
]);
780 static t_stat
vh_wr ( int32 data
,
784 int32 vh
= ((PA
- vh_dib
.ba
) >> 4) & VH_MNOMASK
, line
;
787 switch ((PA
>> 1) & 7) {
788 case 0: /* CSR, but no read-modify-write */
789 if (access
== WRITEB
)
791 (vh_csr
[vh
] & 0377) | (data
<< 8) :
792 (vh_csr
[vh
] & ~0377) | data
& 0377;
793 if (data
& CSR_MASTER_RESET
) {
794 if ((vh_unit
[vh
].flags
& UNIT_MODEDHU
) && (data
& CSR_SKIP
))
795 data
&= ~CSR_MASTER_RESET
;
796 sim_activate (&vh_unit
[vh
], clk_cosched (tmxr_poll
));
797 /* vh_mcount[vh] = 72; */ /* 1.2 seconds */
798 vh_mcount
[vh
] = MS2SIMH (1200); /* 1.2 seconds */
800 if ((data
& CSR_RXIE
) == 0)
802 /* catch the RXIE transition if the FIFO is not empty */
803 else if (((vh_csr
[vh
] & CSR_RXIE
) == 0) &&
804 (rbuf_idx
[vh
] != 0)) {
805 if (vh_unit
[vh
].flags
& UNIT_MODEDHU
) {
806 if (rbuf_idx
[vh
] > FIFO_ALARM
)
808 else if (vh_timer
[vh
] == 0)
810 else if (vh_timer
[vh
] == 1)
812 else if (vh_timeo
[vh
] == 0)
813 vh_timeo
[vh
] = MS2SIMH (vh_timer
[vh
]) + 1;
818 if ((data
& CSR_TXIE
) == 0)
820 else if (((vh_csr
[vh
] & CSR_TXIE
) == 0) &&
823 vh_csr
[vh
] = (vh_csr
[vh
] & ~((uint16
) CSR_RW
)) | (data
& (uint16
) CSR_RW
);
825 case 1: /* TXCHAR/RXTIMER */
826 if (CSR_GETCHAN (vh_csr
[vh
]) >= VH_LINES
)
828 if ((data
== RESET_ABORT
) && (vh_csr
[vh
] & CSR_MASTER_RESET
)) {
832 if (vh_unit
[vh
].flags
& UNIT_MODEDHU
) {
833 if (CSR_GETCHAN (vh_csr
[vh
]) != 0)
835 if (access
== WRITEB
)
837 (vh_timer
[vh
] & 0377) | (data
<< 8) :
838 (vh_timer
[vh
] & ~0377) | (data
& 0377);
839 vh_timer
[vh
] = data
& 0377;
841 if (vh_csr
[vh
] & CSR_RXIE
) {
842 if (rbuf_idx
[vh
] > FIFO_ALARM
)
844 else if (vh_timer
[vh
] == 0)
846 else if (vh_timer
[vh
] == 1)
848 else if (vh_timeo
[vh
] == 0)
849 vh_timeo
[vh
] = MS2SIMH (vh_timer
[vh
]) + 1;
853 line
= (vh
* VH_LINES
) + CSR_GETCHAN (vh_csr
[vh
]);
855 if (access
== WRITEB
)
857 (lp
->txchar
& 0377) | (data
<< 8) :
858 (lp
->txchar
& ~0377) | (data
& 0377);
859 lp
->txchar
= data
; /* TXCHAR */
860 if (lp
->txchar
& TXCHAR_TX_DATA_VALID
) {
861 if (lp
->tbuf2
& TB2_TX_ENA
)
863 CSR_GETCHAN (vh_csr
[vh
]),
866 CSR_GETCHAN (vh_csr
[vh
]) << CSR_V_TX_LINE
);
867 lp
->txchar
&= ~TXCHAR_TX_DATA_VALID
;
872 if ((data
== RESET_ABORT
) && (vh_csr
[vh
] & CSR_MASTER_RESET
)) {
876 if (CSR_GETCHAN (vh_csr
[vh
]) >= VH_LINES
)
878 line
= (vh
* VH_LINES
) + CSR_GETCHAN (vh_csr
[vh
]);
880 if (access
== WRITEB
)
882 (lp
->lpr
& 0377) | (data
<< 8) :
883 (lp
->lpr
& ~0377) | data
& 0377;
884 /* Modify only if CSR<3:0> == 0 */
885 if (CSR_GETCHAN (vh_csr
[vh
]) != 0)
886 data
&= ~LPR_DISAB_XRPT
;
888 if (((lp
->lpr
>> LPR_V_DIAG
) & LPR_M_DIAG
) == 1) {
891 RBUF_PUTLINE (CSR_GETCHAN (vh_csr
[vh
])) |
893 /* BUG: check for overflow above */
894 lp
->lpr
&= ~(LPR_M_DIAG
<< LPR_V_DIAG
);
897 case 3: /* STAT/FIFODATA */
898 if ((data
== RESET_ABORT
) && (vh_csr
[vh
] & CSR_MASTER_RESET
)) {
902 if (CSR_GETCHAN (vh_csr
[vh
]) >= VH_LINES
)
904 line
= (vh
* VH_LINES
) + CSR_GETCHAN (vh_csr
[vh
]);
906 if (vh_unit
[vh
].flags
& UNIT_MODEDHU
) {
907 /* high byte writes not allowed */
910 /* transmit 1 or 2 characters */
911 if (!(lp
->tbuf2
& TB2_TX_ENA
))
913 vh_putc (vh
, lp
, CSR_GETCHAN (vh_csr
[vh
]), data
);
914 q_tx_report (vh
, CSR_GETCHAN (vh_csr
[vh
]) << CSR_V_TX_LINE
);
915 if (access
!= WRITEB
)
916 vh_putc (vh
, lp
, CSR_GETCHAN (vh_csr
[vh
]),
921 if ((data
== RESET_ABORT
) && (vh_csr
[vh
] & CSR_MASTER_RESET
)) {
925 if (CSR_GETCHAN (vh_csr
[vh
]) >= VH_LINES
)
927 line
= (vh
* VH_LINES
) + CSR_GETCHAN (vh_csr
[vh
]);
929 if (access
== WRITEB
)
931 (lp
->lnctrl
& 0377) | (data
<< 8) :
932 (lp
->lnctrl
& ~0377) | data
& 0377;
933 /* catch the abort TX transition */
934 if (!(lp
->lnctrl
& LNCTRL_TX_ABORT
) &&
935 (data
& LNCTRL_TX_ABORT
)) {
936 if ((lp
->tbuf2
& TB2_TX_ENA
) &&
937 (lp
->tbuf2
& TB2_TX_DMA_START
)) {
938 lp
->tbuf2
&= ~TB2_TX_DMA_START
;
939 q_tx_report (vh
, CSR_GETCHAN (vh_csr
[vh
]) << CSR_V_TX_LINE
);
942 /* Implement program-initiated flow control */
943 if ( (data
& LNCTRL_FORCE_XOFF
) &&
944 !(lp
->lnctrl
& LNCTRL_FORCE_XOFF
) ) {
945 if (!(lp
->lnctrl
& LNCTRL_IAUTO
))
946 vh_putc (vh
, lp
, CSR_GETCHAN (vh_csr
[vh
]), XOFF
);
947 } else if ( !(data
& LNCTRL_FORCE_XOFF
) &&
948 (lp
->lnctrl
& LNCTRL_FORCE_XOFF
) ) {
949 if (!(lp
->lnctrl
& LNCTRL_IAUTO
))
950 vh_putc (vh
, lp
, CSR_GETCHAN (vh_csr
[vh
]), XON
);
951 else if (!(vh_crit
& (1 << vh
)) &&
952 (vh_stall
[vh
] & (1 << CSR_GETCHAN (vh_csr
[vh
]))))
953 vh_putc (vh
, lp
, CSR_GETCHAN (vh_csr
[vh
]), XON
);
955 if ( (data
& LNCTRL_IAUTO
) && /* IAUTO 0->1 */
956 !(lp
->lnctrl
& LNCTRL_IAUTO
) ) {
957 if (!(lp
->lnctrl
& LNCTRL_FORCE_XOFF
)) {
958 if (vh_crit
& (1 << vh
)) {
960 CSR_GETCHAN (vh_csr
[vh
]), XOFF
);
961 vh_stall
[vh
] |= (1 << CSR_GETCHAN (vh_csr
[vh
]));
964 /* vh_stall[vh] |= (1 << CSR_GETCHAN (vh_csr[vh])) */;
966 } else if ( !(data
& LNCTRL_IAUTO
) &&
967 (lp
->lnctrl
& LNCTRL_IAUTO
) ) {
968 if (!(lp
->lnctrl
& LNCTRL_FORCE_XOFF
))
969 vh_putc (vh
, lp
, CSR_GETCHAN (vh_csr
[vh
]), XON
);
971 /* check modem control bits */
972 if ( !(data
& LNCTRL_DTR
) && /* DTR 1->0 */
973 (lp
->lnctrl
& LNCTRL_DTR
)) {
974 if ((lp
->tmln
->conn
) && (vh_unit
[vh
].flags
& UNIT_HANGUP
)) {
975 tmxr_linemsg (lp
->tmln
, "\r\nLine hangup\r\n");
976 tmxr_reset_ln (lp
->tmln
);
978 HangupModem (vh
, lp
, CSR_GETCHAN (vh_csr
[vh
]));
981 lp
->tmln
->rcve
= (data
& LNCTRL_RX_ENA
) ? 1 : 0;
982 tmxr_poll_rx (&vh_desc
);
984 if (lp
->lnctrl
& LNCTRL_BREAK
)
985 vh_putc (vh
, lp
, CSR_GETCHAN (vh_csr
[vh
]), 0);
987 case 5: /* TBUFFAD1 */
988 if ((data
== RESET_ABORT
) && (vh_csr
[vh
] & CSR_MASTER_RESET
)) {
992 if (CSR_GETCHAN (vh_csr
[vh
]) >= VH_LINES
)
994 line
= (vh
* VH_LINES
) + CSR_GETCHAN (vh_csr
[vh
]);
996 if (access
== WRITEB
)
998 (lp
->tbuf1
& 0377) | (data
<< 8) :
999 (lp
->tbuf1
& ~0377) | data
& 0377;
1002 case 6: /* TBUFFAD2 */
1003 if ((data
== RESET_ABORT
) && (vh_csr
[vh
] & CSR_MASTER_RESET
)) {
1007 if (CSR_GETCHAN (vh_csr
[vh
]) >= VH_LINES
)
1009 line
= (vh
* VH_LINES
) + CSR_GETCHAN (vh_csr
[vh
]);
1010 lp
= &vh_parm
[line
];
1011 if (access
== WRITEB
)
1013 (lp
->tbuf2
& 0377) | (data
<< 8) :
1014 (lp
->tbuf2
& ~0377) | data
& 0377;
1016 /* if starting a DMA, clear DMA_ERR */
1017 if (vh_unit
[vh
].flags
& UNIT_FASTDMA
) {
1018 doDMA (vh
, CSR_GETCHAN (vh_csr
[vh
]));
1019 tmxr_send_buffered_data (lp
->tmln
);
1022 case 7: /* TBUFFCT */
1023 if ((data
== RESET_ABORT
) && (vh_csr
[vh
] & CSR_MASTER_RESET
)) {
1027 if (CSR_GETCHAN (vh_csr
[vh
]) >= VH_LINES
)
1029 line
= (vh
* VH_LINES
) + CSR_GETCHAN (vh_csr
[vh
]);
1030 lp
= &vh_parm
[line
];
1031 if (access
== WRITEB
)
1033 (lp
->tbuffct
& 0377) | (data
<< 8) :
1034 (lp
->tbuffct
& ~0377) | data
& 0377;
1044 static void doDMA ( int32 vh
,
1051 line
= (vh
* VH_LINES
) + chan
;
1052 lp
= &vh_parm
[line
];
1053 if ((lp
->tbuf2
& TB2_TX_ENA
) && (lp
->tbuf2
& TB2_TX_DMA_START
)) {
1054 /* BUG: should compare against available xmit buffer space */
1056 pa
|= (lp
->tbuf2
& TB2_M_TBUFFAD
) << 16;
1057 status
= chan
<< CSR_V_TX_LINE
;
1058 while (lp
->tbuffct
) {
1060 if (Map_ReadB (pa
, 1, &buf
)) {
1061 status
|= CSR_TX_DMA_ERR
;
1065 if (vh_putc (vh
, lp
, chan
, buf
) != SCPE_OK
)
1067 /* pa = (pa + 1) & PAMASK; */
1068 pa
= (pa
+ 1) & ((1 << 22) - 1);
1071 lp
->tbuf1
= pa
& 0177777;
1072 lp
->tbuf2
= (lp
->tbuf2
& ~TB2_M_TBUFFAD
) |
1073 ((pa
>> 16) & TB2_M_TBUFFAD
);
1074 if (lp
->tbuffct
== 0) {
1075 lp
->tbuf2
&= ~TB2_TX_DMA_START
;
1076 q_tx_report (vh
, status
);
1081 /* Perform many of the functions of PROC2 */
1083 static t_stat
vh_svc ( UNIT
*uptr
)
1087 /* scan all muxes for countdown reset */
1088 for (vh
= 0; vh
< VH_MUXES
; vh
++) {
1089 if (vh_csr
[vh
] & CSR_MASTER_RESET
) {
1090 if (vh_mcount
[vh
] != 0)
1093 vh_clear (vh
, FALSE
);
1096 /* sample every 10ms for modem changes (new connections) */
1097 newln
= tmxr_poll_conn (&vh_desc
);
1101 vh
= newln
/ VH_LINES
; /* determine which mux */
1102 line
= newln
- (vh
* VH_LINES
);
1103 lp
= &vh_parm
[newln
];
1104 lp
->lstat
|= STAT_DSR
| STAT_DCD
| STAT_CTS
;
1105 if (!(lp
->lnctrl
& LNCTRL_DTR
))
1106 lp
->lstat
|= STAT_RI
;
1107 if (lp
->lnctrl
& LNCTRL_LINK_TYPE
)
1108 fifo_put (vh
, lp
, RBUF_DIAG
|
1109 RBUF_PUTLINE (line
) |
1110 ((lp
->lstat
>> 8) & 0376));
1111 /* BUG: should check for overflow above */
1113 /* scan all muxes, lines for DMA to complete; start every 3.12ms */
1114 for (vh
= 0; vh
< VH_MUXES
; vh
++) {
1115 for (i
= 0; i
< VH_LINES
; i
++)
1118 /* interrupt driven in a real DHQ */
1119 tmxr_poll_rx (&vh_desc
);
1120 for (vh
= 0; vh
< VH_MUXES
; vh
++)
1122 tmxr_poll_tx (&vh_desc
);
1123 /* scan all DHU-mode muxes for RX FIFO timeout */
1124 for (vh
= 0; vh
< VH_MUXES
; vh
++) {
1125 if (vh_unit
[vh
].flags
& UNIT_MODEDHU
) {
1126 if (vh_timeo
[vh
] && (vh_csr
[vh
] & CSR_RXIE
)) {
1128 if ((vh_timeo
[vh
] == 0) && rbuf_idx
[vh
])
1133 sim_activate (uptr
, tmxr_poll
); /* requeue ourselves */
1137 /* init a channel on a controller */
1150 link type set to data-leads only
1152 DMA character counter 0
1153 DMA start address registers 0
1156 auto-flow reports enabled
1160 static void vh_init_chan ( int32 vh
,
1166 line
= (vh
* VH_LINES
) + chan
;
1167 lp
= &vh_parm
[line
];
1168 lp
->lpr
= (RATE_9600
<< LPR_V_TX_SPEED
) |
1169 (RATE_9600
<< LPR_V_RX_SPEED
) |
1170 (03 << LPR_V_CHAR_LGTH
);
1172 lp
->lstat
&= ~(STAT_MDL
| STAT_DHUID
| STAT_RI
);
1173 if (vh_unit
[vh
].flags
& UNIT_MODEDHU
)
1174 lp
->lstat
|= STAT_DHUID
| 64;
1175 if (!(vh_unit
[vh
].flags
& UNIT_MODEM
))
1176 lp
->lstat
|= STAT_DSR
| STAT_DCD
| STAT_CTS
;
1181 lp
->tbuf2
= TB2_TX_ENA
;
1185 /* init a controller; flag true if BINIT, false if master.reset */
1187 static t_stat
vh_clear ( int32 vh
,
1194 /* put 8 diag bytes in FIFO: 6 SELF_x, 2 circuit revision codes */
1195 if (vh_csr
[vh
] & CSR_SKIP
) {
1196 fifo_put (vh
, NULL
, RBUF_DIAG
| RBUF_PUTLINE(0) | SELF_SKIP
);
1197 fifo_put (vh
, NULL
, RBUF_DIAG
| RBUF_PUTLINE(1) | SELF_SKIP
);
1198 fifo_put (vh
, NULL
, RBUF_DIAG
| RBUF_PUTLINE(2) | SELF_SKIP
);
1199 fifo_put (vh
, NULL
, RBUF_DIAG
| RBUF_PUTLINE(3) | SELF_SKIP
);
1200 fifo_put (vh
, NULL
, RBUF_DIAG
| RBUF_PUTLINE(4) | SELF_SKIP
);
1201 fifo_put (vh
, NULL
, RBUF_DIAG
| RBUF_PUTLINE(5) | SELF_SKIP
);
1202 fifo_put (vh
, NULL
, RBUF_DIAG
| RBUF_PUTLINE(6) | 0107);
1203 fifo_put (vh
, NULL
, RBUF_DIAG
| RBUF_PUTLINE(7) | 0105);
1205 fifo_put (vh
, NULL
, RBUF_DIAG
| RBUF_PUTLINE(0) | SELF_NULL
);
1206 fifo_put (vh
, NULL
, RBUF_DIAG
| RBUF_PUTLINE(1) | SELF_NULL
);
1207 fifo_put (vh
, NULL
, RBUF_DIAG
| RBUF_PUTLINE(2) | SELF_NULL
);
1208 fifo_put (vh
, NULL
, RBUF_DIAG
| RBUF_PUTLINE(3) | SELF_NULL
);
1209 fifo_put (vh
, NULL
, RBUF_DIAG
| RBUF_PUTLINE(4) | SELF_NULL
);
1210 fifo_put (vh
, NULL
, RBUF_DIAG
| RBUF_PUTLINE(5) | SELF_NULL
);
1212 fifo_put (vh
, NULL
, RBUF_DIAG
| RBUF_PUTLINE(6) | 0107);
1214 fifo_put (vh
, NULL
, RBUF_DIAG
| RBUF_PUTLINE(7) | 0105);
1216 vh_csr
[vh
] &= ~(CSR_TX_ACTION
|CSR_DIAG_FAIL
|CSR_MASTER_RESET
);
1218 vh_csr
[vh
] &= ~(CSR_TXIE
|CSR_RXIE
|CSR_SKIP
);
1219 vh_csr
[vh
] |= CSR_TX_DMA_ERR
| (CSR_M_TX_LINE
<< CSR_V_TX_LINE
);
1225 for (i
= 0; i
< VH_LINES
; i
++)
1226 vh_init_chan (vh
, i
);
1227 vh_crit
&= ~(1 << vh
);
1229 vh_loop
[vh
] = LOOP_NONE
;
1233 /* Reset all controllers. Used by BINIT and RESET. */
1235 static t_stat
vh_reset ( DEVICE
*dptr
)
1239 for (i
= 0; i
< (VH_MUXES
* VH_LINES
); i
++)
1240 vh_parm
[i
].tmln
= &vh_ldsc
[i
];
1241 for (i
= 0; i
< VH_MUXES
; i
++) {
1242 #if defined (VM_PDP11)
1243 /* if Unibus, force DHU mode */
1245 vh_unit
[i
].flags
|= UNIT_MODEDHU
;
1249 vh_rxi
= vh_txi
= 0;
1252 for (i
= 0; i
< VH_MUXES
; i
++)
1253 sim_cancel (&vh_unit
[i
]);
1254 return (auto_config (dptr
->name
, (dptr
->flags
& DEV_DIS
) ? 0 : VH_MUXES
));
1258 static t_stat
vh_attach ( UNIT
*uptr
,
1261 if (uptr
== &vh_unit
[0])
1262 return (tmxr_attach (&vh_desc
, uptr
, cptr
));
1263 return (SCPE_NOATT
);
1266 static t_stat
vh_detach ( UNIT
*uptr
)
1268 return (tmxr_detach (&vh_desc
, uptr
));
1271 static t_stat
vh_summ ( FILE *st
,
1278 for (i
= t
= 0; i
< vh_desc
.lines
; i
++) { /* get num conn */
1279 if (vh_ldsc
[i
].conn
) t
= t
+ 1; }
1280 fprintf (st
, "%d %s", t
, (t
== 1) ? "connection" : "connections");
1284 static t_stat
vh_show (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
1288 for (i
= t
= 0; i
< vh_desc
.lines
; i
++) { /* loop thru conn */
1289 if (vh_ldsc
[i
].conn
) {
1291 if (val
) tmxr_fconns (st
, &vh_ldsc
[i
], i
);
1292 else tmxr_fstats (st
, &vh_ldsc
[i
], i
); } }
1293 if (t
== 0) fprintf (st
, "all disconnected\n");
1297 static t_stat
vh_show_vec ( FILE *st
,
1302 return (show_vec (st
, uptr
, ((vh_desc
.lines
* 2) / VH_LINES
), desc
));
1305 static void debug_line ( FILE *st
,
1312 line
= (vh
* VH_LINES
) + chan
;
1313 lp
= &vh_parm
[line
];
1314 fprintf (st
, "\tline %d\tlpr %06o, lnctrl %06o, lstat %06o\n",
1315 chan
, lp
->lpr
, lp
->lnctrl
, lp
->lstat
);
1316 fprintf (st
, "\t\ttbuffct %06o, tbuf1 %06o, tbuf2 %06o, txchar %06o\n",
1317 lp
->tbuffct
, lp
->tbuf1
, lp
->tbuf2
, lp
->txchar
);
1318 fprintf (st
, "\t\ttmln rcve %d xmte %d\n",
1319 lp
->tmln
->rcve
, lp
->tmln
->xmte
);
1322 static t_stat
vh_show_debug ( FILE *st
,
1329 fprintf (st
, "VH:\trxi %d, txi %d\n", vh_rxi
, vh_txi
);
1330 for (i
= 0; i
< VH_MUXES
; i
++) {
1331 fprintf (st
, "VH%d:\tmode %s, crit %d\n", i
,
1332 vh_unit
[i
].flags
& UNIT_MODEDHU
? "DHU" : "DHV",
1333 vh_crit
& (1 << i
));
1334 fprintf (st
, "\tCSR %06o, mcount %d, rbuf_idx %d, txq_idx %d\n",
1335 vh_csr
[i
], vh_mcount
[i
], rbuf_idx
[i
], txq_idx
[i
]);
1336 for (j
= 0; j
< VH_LINES
; j
++)
1337 debug_line (st
, i
, j
);
1342 static t_stat
vh_show_rbuf ( FILE *st
,
1349 for (i
= 0; i
< rbuf_idx
[0]; i
++)
1350 fprintf (st
, "%03d: %06o\n", i
, vh_rbuf
[0][i
]);
1354 static t_stat
vh_show_txq ( FILE *st
,
1361 for (i
= 0; i
< txq_idx
[0]; i
++)
1362 fprintf (st
, "%02d: %06o\n\r", i
, vh_txq
[0][i
]);