1 /* pdp11_vh.c: DHQ11 asynchronous terminal multiplexor simulator
2 
3    Copyright (c) 2004-2012, John A. Dundas III
4    Portions derived from work by Robert M Supnik
5 
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:
12 
13    The above copyright notice and this permission notice shall be included in
14    all copies or substantial portions of the Software.
15 
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.
22 
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.
26 
27    vh           DHQ11 asynch multiplexor for SIMH
28 
29    02-Jun-11    MP      Added debugging support to trace register, interrupt
30                         and data traffic (SET VH DEBUG[=REG;INT;XMT;RCV])
31                         Added SET LOG and SET NOLOG support for logging mux
32                         traffic
33                         Fixed SET VH LINES=n to correctly adjust the number
34                         of lines available to be 8, 16, 24, or 32.
35                         Fixed performance issue avoiding redundant polling
36    03-Jan-10    JAD     Eliminate gcc warnings
37    19-Nov-08    RMS     Revised for common TMXR show routines
38    18-Jun-07    RMS     Added UNIT_IDLE flag
39    29-Oct-06    RMS     Synced poll and clock
40    07-Jul-05    RMS     Removed extraneous externs
41    15-Jun-05    RMS     Revised for new autoconfigure interface
42                         Fixed bug in vector display routine
43    12-Jun-04    RMS     Repair MS2SIMH macro to avoid divide by 0 bug
44    08-Jun-04    JAD     Repair vh_dev initialization; remove unused
45                         variables, cast to avoid conversion confusion
46    07-Jun-04    JAD     Complete function prototypes of forward declarations.
47                         Repair broken prototypes of vh_rd() and vh_wr()
48                         Explicitly size integer declarations
49    4-Jun-04     JAD     Preliminary code: If operating in a PDP-11 Unibus
50                         environment, force DHU mode
51    29-May-04    JAD     Make certain RX.TIMER is within allowable range
52    25-May-04    JAD     All time-based operations are scaled by tmxr_poll units
53    23-May-04    JAD     Change to fifo_get() and dq_tx_report() to avoid
54                         gratuitous stack manipulation
55    20-May-04    JAD     Made modem control and auto-hangup unit flags
56    19-May-04    JAD     Fix problem with modem status where the line number
57                         was not being included
58    12-May-04    JAD     Revised for updated tmxr interfaces
59    28-Jan-04    JAD     Original creation and testing
60 
61 I/O Page Registers
62 
63 CSR 17 760 440 (float)
64 
65 Vector: 300 (float)
66 
67 Priority:   BR4
68 
69 Rank:       32
70 
71 */
72 /* MANY constants needed! */
73 
74 #if defined (VM_VAX)
75 #include "vax_defs.h"
76 extern int32    int_req[IPL_HLVL];
77 #endif
78 
79 #if defined (VM_PDP11)
80 #include "pdp11_defs.h"
81 extern int32    int_req[IPL_HLVL];
82 extern uint32    cpu_opt;
83 #endif
84 
85 #include "sim_sock.h"
86 #include "sim_tmxr.h"
87 
88 /* imports from pdp11_stddev.c: */
89 extern int32    tmxr_poll, clk_tps;
90 /* convert ms to SIMH time units based on tmxr_poll polls per second */
91 #define MS2SIMH(ms) (((ms) * clk_tps) / 1000)
92 
93 #ifndef VH_MUXES
94 #define VH_MUXES    (4)
95 #endif
96 #define VH_MNOMASK  (VH_MUXES - 1)
97 
98 #define VH_LINES    (8)
99 
100 #define UNIT_V_MODEDHU  (UNIT_V_UF + 0)
101 #define UNIT_V_FASTDMA  (UNIT_V_UF + 1)
102 #define UNIT_V_MODEM    (UNIT_V_UF + 2)
103 #define UNIT_V_HANGUP   (UNIT_V_UF + 3)
104 #define UNIT_MODEDHU    (1 << UNIT_V_MODEDHU)
105 #define UNIT_FASTDMA    (1 << UNIT_V_FASTDMA)
106 #define UNIT_MODEM  (1 << UNIT_V_MODEM)
107 #define UNIT_HANGUP (1 << UNIT_V_HANGUP)
108 
109 /* VHCSR - 160440 - Control and Status Register */
110 
111 #define CSR_M_IND_ADDR      (017)
112 #define CSR_SKIP        (1 << 4)
113 #define CSR_MASTER_RESET    (1 << 5)
114 #define CSR_RXIE        (1 << 6)
115 #define CSR_RX_DATA_AVAIL   (1 << 7)
116 #define CSR_M_TX_LINE       (017)
117 #define CSR_V_TX_LINE       (8)
118 #define CSR_TX_DMA_ERR      (1 << 12)
119 #define CSR_DIAG_FAIL       (1 << 13)
120 #define CSR_TXIE        (1 << 14)
121 #define CSR_TX_ACTION       (1 << 15)
122 #define CSR_GETCHAN(x)  ((x) & CSR_M_IND_ADDR)
123 #define CSR_RW          \
124     (CSR_TXIE|CSR_RXIE|CSR_SKIP|CSR_M_IND_ADDR|CSR_MASTER_RESET)
125 #define RESET_ABORT     (052525)
126 
127 /* Receive Buffer (RBUF) */
128 
129 #define FIFO_SIZE       (256)
130 #define FIFO_ALARM      (191)
131 #define FIFO_HALF       (FIFO_SIZE / 2)
132 #define RBUF_M_RX_CHAR      (0377)
133 #define RBUF_M_RX_LINE      (07)
134 #define RBUF_V_RX_LINE      (8)
135 #define RBUF_PARITY_ERR     (1 << 12)
136 #define RBUF_FRAME_ERR      (1 << 13)
137 #define RBUF_OVERRUN_ERR    (1 << 14)
138 #define RBUF_DATA_VALID     (1 << 15)
139 #define RBUF_GETLINE(x)     (((x) >> RBUF_V_RX_LINE) & RBUF_M_RX_LINE)
140 #define RBUF_PUTLINE(x)     ((x) << RBUF_V_RX_LINE)
141 #define RBUF_DIAG       \
142     (RBUF_PARITY_ERR|RBUF_FRAME_ERR|RBUF_OVERRUN_ERR)
143 #define XON         (021)
144 #define XOFF            (023)
145 
146 /* Transmit Character Register (TXCHAR) */
147 
148 #define TXCHAR_M_CHAR       (0377)
149 #define TXCHAR_TX_DATA_VALID    (1 << 15)
150 
151 /* Receive Timer Register (RXTIMER) */
152 
153 #define RXTIMER_M_RX_TIMER  (0377)
154 
155 /* Line-Parameter Register (LPR) */
156 
157 #define LPR_DISAB_XRPT      (1 << 0)    /* not impl. in real DHU */
158 #define LPR_V_DIAG      (1)
159 #define LPR_M_DIAG      (03)
160 #define LPR_V_CHAR_LGTH     (3)
161 #define LPR_M_CHAR_LGTH     (03)
162 #define LPR_PARITY_ENAB     (1 << 5)
163 #define LPR_EVEN_PARITY     (1 << 6)
164 #define LPR_STOP_CODE       (1 << 7)
165 #define LPR_V_RX_SPEED      (8)
166 #define LPR_M_RX_SPEED      (017)
167 #define LPR_V_TX_SPEED      (12)
168 #define LPR_M_TX_SPEED      (017)
169 
170 #define RATE_50         (0)
171 #define RATE_75         (1)
172 #define RATE_110        (2)
173 #define RATE_134        (3)
174 #define RATE_150        (4)
175 #define RATE_300        (5)
176 #define RATE_600        (6)
177 #define RATE_1200       (7)
178 #define RATE_1800       (8)
179 #define RATE_2000       (9)
180 #define RATE_2400       (10)
181 #define RATE_4800       (11)
182 #define RATE_7200       (12)
183 #define RATE_9600       (13)
184 #define RATE_19200      (14)
185 #define RATE_38400      (15)
186 
187 /* Line-Status Register (STAT) */
188 
189 #define STAT_DHUID      (1 << 8)    /* mode: 0=DHV, 1=DHU */
190 #define STAT_MDL        (1 << 9)    /* always 0, has modem support */
191 #define STAT_CTS        (1 << 11)   /* CTS from modem */
192 #define STAT_DCD        (1 << 12)   /* DCD from modem */
193 #define STAT_RI         (1 << 13)   /* RI from modem */
194 #define STAT_DSR        (1 << 15)   /* DSR from modem */
195 
196 /* FIFO Size Register (FIFOSIZE) */
197 
198 #define FIFOSIZE_M_SIZE     (0377)
199 
200 /* FIFO Data Register (FIFODATA) */
201 
202 #define FIFODATA_W0     (0377)
203 #define FIFODATA_V_W1       (8)
204 #define FIFODATA_M_W1       (0377)
205 
206 /* Line-Control Register (LNCTRL) */
207 
208 #define LNCTRL_TX_ABORT     (1 << 0)
209 #define LNCTRL_IAUTO        (1 << 1)
210 #define LNCTRL_RX_ENA       (1 << 2)
211 #define LNCTRL_BREAK        (1 << 3)
212 #define LNCTRL_OAUTO        (1 << 4)
213 #define LNCTRL_FORCE_XOFF   (1 << 5)
214 #define LNCTRL_V_MAINT      (6)
215 #define LNCTRL_M_MAINT      (03)
216 #define LNCTRL_LINK_TYPE    (1 << 8)    /* 0=data leads only, 1=modem */
217 #define LNCTRL_DTR      (1 << 9)    /* DTR to modem */
218 #define LNCTRL_RTS      (1 << 12)   /* RTS to modem */
219 
220 /* Transmit Buffer Address Register Number 1 (TBUFFAD1) */
221 
222 /* Transmit Buffer Address Register Number 2 (TBUFFAD2) */
223 
224 #define TB2_M_TBUFFAD       (077)
225 #define TB2_TX_DMA_START    (1 << 7)
226 #define TB2_TX_ENA      (1 << 15)
227 
228 /* Transmit DMA Buffer Counter (TBUFFCT) */
229 
230 /* Self-Test Error Codes */
231 
232 #define SELF_NULL       (0201)
233 #define SELF_SKIP       (0203)
234 #define SELF_OCT        (0211)
235 #define SELF_RAM        (0225)
236 #define SELF_RCD        (0231)
237 #define SELF_DRD        (0235)
238 
239 #define BMP_OK          (0305)
240 #define BMP_BAD         (0307)
241 
242 /* Loopback types */
243 
244 #define LOOP_NONE       (0)
245 #define LOOP_H325       (1)
246 #define LOOP_H3101      (2) /* p.2-13 DHQ manual */
247 /* Local storage */
248 
249 static uint16   vh_csr[VH_MUXES]    = { 0 };    /* CSRs */
250 static uint16   vh_timer[VH_MUXES]  = { 1 };    /* controller timeout */
251 static uint16   vh_mcount[VH_MUXES] = { 0 };
252 static uint32   vh_timeo[VH_MUXES]  = { 0 };
253 static uint32   vh_ovrrun[VH_MUXES] = { 0 };    /* line overrun bits */
254 /* XOFF'd channels, one bit/channel */
255 static uint32   vh_stall[VH_MUXES]  = { 0 };
256 static uint16   vh_loop[VH_MUXES]   = { 0 };    /* loopback status */
257 
258 /* One bit per controller: */
259 static uint32   vh_rxi = 0; /* rcv interrupts */
260 static uint32   vh_txi = 0; /* xmt interrupts */
261 static uint32   vh_crit = 0;    /* FIFO.CRIT */
262 
263 static const int32 bitmask[4] = { 037, 077, 0177, 0377 };
264 
265 /* RX FIFO state */
266 
267 static int32    rbuf_idx[VH_MUXES]      = { 0 };/* index into vh_rbuf */
268 static uint32   vh_rbuf[VH_MUXES][FIFO_SIZE]    = { { 0 } };
269 
270 /* TXQ state */
271 
272 #define TXQ_SIZE    (16)
273 static int32    txq_idx[VH_MUXES]       = { 0 };
274 static uint32   vh_txq[VH_MUXES][TXQ_SIZE]  = { { 0 } };
275 
276 /* Need to extend the TMLN structure */
277 
278 typedef struct {
279     TMLN    *tmln;
280     uint16  lpr;        /* line parameters */
281     uint16  lnctrl;     /* line control */
282     uint16  lstat;      /* line modem status */
283     uint16  tbuffct;    /* remaining character count */
284     uint16  tbuf1;
285     uint16  tbuf2;
286     uint16  txchar;     /* single character I/O */
287 } TMLX;
288 
289 static TMLN vh_ldsc[VH_MUXES * VH_LINES] = { { 0 } };
290 static TMXR vh_desc = { VH_MUXES * VH_LINES, 0, 0, vh_ldsc };
291 static TMLX vh_parm[VH_MUXES * VH_LINES] = { { 0 } };
292 
293 /* debugging bitmaps */
294 #define DBG_REG  0x0001                                 /* trace read/write registers */
295 #define DBG_INT  0x0002                                 /* display transfer requests */
296 /* #define DBG_XMT  TMXR_DBG_XMT                           /* display Transmitted Data */
297 /* #define DBG_RCV  TMXR_DBG_RCV                           /* display Received Data */
298 
299 DEBTAB vh_debug[] = {
300   {"REG",    DBG_REG},
301   {"INT",    DBG_INT},
302 //  {"XMT",    DBG_XMT},
303 //  {"RCV",    DBG_RCV},
304   {0}
305 };
306 
307 /* Forward references */
308 static t_stat vh_rd (int32 *data, int32 PA, int32 access);
309 static t_stat vh_wr (int32 data, int32 PA, int32 access);
310 static t_stat vh_svc (UNIT *uptr);
311 static int32 vh_rxinta (void);
312 static int32 vh_txinta (void);
313 static t_stat vh_clear (int32 vh, t_bool flag);
314 static t_stat vh_reset (DEVICE *dptr);
315 static t_stat vh_attach (UNIT *uptr, char *cptr);
316 static t_stat vh_detach (UNIT *uptr);
317 static t_stat vh_show_detail (FILE *st, UNIT *uptr, int32 val, void *desc);
318 static t_stat vh_show_rbuf (FILE *st, UNIT *uptr, int32 val, void *desc);
319 static t_stat vh_show_txq (FILE *st, UNIT *uptr, int32 val, void *desc);
320 static t_stat vh_putc (int32 vh, TMLX *lp, int32 chan, int32 data);
321 static void doDMA (int32 vh, int32 chan);
322 static t_stat vh_setnl (UNIT *uptr, int32 val, char *cptr, void *desc);
323 static t_stat vh_set_log (UNIT *uptr, int32 val, char *cptr, void *desc);
324 static t_stat vh_set_nolog (UNIT *uptr, int32 val, char *cptr, void *desc);
325 static t_stat vh_show_log (FILE *st, UNIT *uptr, int32 val, void *desc);
326 
327 int32 tmxr_send_buffered_data (TMLN *lp);
328 
329 /* SIMH I/O Structures */
330 
331 static DIB vh_dib = {
332     IOBA_VH,
333     IOLN_VH * VH_MUXES,
334     &vh_rd,     /* read */
335     &vh_wr,     /* write */
336     2,          /* # of vectors */
337     IVCL (VHRX),
338     VEC_VHRX,
339     { &vh_rxinta, &vh_txinta }  /* int. ack. routines */
340 };
341 
342 static UNIT vh_unit[VH_MUXES] = {
343     { UDATA (&vh_svc, UNIT_IDLE|UNIT_ATTABLE, 0) },
344 };
345 
346 static const REG vh_reg[] = {
347     { BRDATA (CSR,     vh_csr, DEV_RDX, 16, VH_MUXES) },
348     { GRDATA (DEVADDR, vh_dib.ba, DEV_RDX, 32, 0), REG_HRO },
349     { GRDATA (DEVVEC,  vh_dib.vec, DEV_RDX, 16, 0), REG_HRO },
350     { NULL }
351 };
352 
353 static const MTAB vh_mod[] = {
354     { UNIT_MODEDHU, 0, "DHV mode", "DHV", NULL },
355     { UNIT_MODEDHU, UNIT_MODEDHU, "DHU mode", "DHU", NULL },
356     { UNIT_FASTDMA, 0, NULL, "NORMAL", NULL },
357     { UNIT_FASTDMA, UNIT_FASTDMA, "fast DMA", "FASTDMA", NULL },
358     { UNIT_MODEM, 0, NULL, "NOMODEM", NULL },
359     { UNIT_MODEM, UNIT_MODEM, "modem", "MODEM", NULL },
360     { UNIT_HANGUP, 0, NULL, "NOHANGUP", NULL },
361     { UNIT_HANGUP, UNIT_HANGUP, "hangup", "HANGUP", NULL },
362     { MTAB_XTD|MTAB_VDV, 020, "ADDRESS", "ADDRESS",
363         &set_addr, &show_addr, NULL },
364     { MTAB_XTD|MTAB_VDV, VH_LINES, "VECTOR", "VECTOR",
365         &set_vec, &show_vec_mux, (void *) &vh_desc },
366     { MTAB_XTD|MTAB_VDV, 0, NULL, "AUTOCONFIGURE",
367         &set_addr_flt, NULL, NULL },
368     { MTAB_XTD|MTAB_VDV, 0, "LINES", "LINES",
369         &vh_setnl, &tmxr_show_lines, (void *) &vh_desc },
370     { UNIT_ATT, UNIT_ATT, "summary", NULL,
371         NULL, &tmxr_show_summ, (void *) &vh_desc },
372     { MTAB_XTD|MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL,
373         NULL, &tmxr_show_cstat, (void *) &vh_desc },
374     { MTAB_XTD|MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL,
375         NULL, &tmxr_show_cstat, (void *) &vh_desc },
376     { MTAB_XTD|MTAB_VDV, 1, NULL, "DISCONNECT",
377         &tmxr_dscln, NULL, &vh_desc },
378     { MTAB_XTD|MTAB_VDV | MTAB_NMO, 0, "DETAIL", NULL,
379         NULL, &vh_show_detail, NULL },
380     { MTAB_XTD|MTAB_VDV | MTAB_NMO, 0, "RBUF", NULL,
381         NULL, &vh_show_rbuf, NULL },
382     { MTAB_XTD|MTAB_VDV | MTAB_NMO, 0, "TXQ", NULL,
383         NULL, &vh_show_txq, NULL },
384     { MTAB_XTD|MTAB_VDV | MTAB_NC, 0, NULL, "LOG",
385       &vh_set_log, NULL, &vh_desc },
386     { MTAB_XTD|MTAB_VDV | MTAB_NC, 0, NULL, "NOLOG",
387       &vh_set_nolog, NULL, &vh_desc },
388     { MTAB_XTD|MTAB_VDV | MTAB_NMO, 0, "LOG", NULL,
389       NULL, &vh_show_log, &vh_desc },
390     { 0 }
391 };
392 
393 DEVICE vh_dev = {
394     "VH",           /* name */
395     vh_unit,        /* units */
396     (REG *)vh_reg,  /* registers */
397     (MTAB *)vh_mod, /* modifiers */
398     VH_MUXES,       /* # units */
399     DEV_RDX,        /* address radix */
400     8,              /* address width */
401     1,              /* address increment */
402     DEV_RDX,        /* data radix */
403     8,              /* data width */
404     NULL,           /* examine routine */
405     NULL,           /* deposit routine */
406     &vh_reset,      /* reset routine */
407     NULL,           /* boot routine */
408     &vh_attach,     /* attach routine */
409     &vh_detach,     /* detach routine */
410     (void *)&vh_dib,/* context */
411     DEV_FLTA | DEV_DISABLE | DEV_DIS |DEV_NET | DEV_QBUS | DEV_UBUS | DEV_DEBUG,    /* flags */
412     0, vh_debug
413 };
414 
415 /* Register names for Debug tracing */
416 static char *vh_rd_dhv_regs[] =
417     {"CSR   ", "RBUF  ", "LPR   ", "STAT  ", "LNCTRL", "TBFAD1", "TBFAD2", "TBFCNT" };
418 static char *vh_wr_dhv_regs[] =
419     {"CSR   ", "TXCHAR", "LPR   ", "STAT  ", "LNCTRL", "TBFAD1", "TBFAD2", "TBFCNT" };
420 static char *vh_rd_dhu_regs[] =
421     {"CSR   ", "RBUF  ", "LPR   ", "FIFOSZ", "LNCTRL", "TBFAD1", "TBFAD2", "TBFCNT" };
422 static char *vh_wr_dhu_regs[] =
423     {"CSR   ", "RXTIMR", "LPR   ", "FIFODT", "LNCTRL", "TBFAD1", "TBFAD2", "TBFCNT" };
424 
425 /* Interrupt routines */
426 
vh_clr_rxint(int32 vh)427 static void vh_clr_rxint (  int32   vh  )
428 {
429     vh_rxi &= ~(1 << vh);
430     if (vh_rxi == 0)
431         CLR_INT (VHRX);
432     else
433         SET_INT (VHRX);
434 }
435 
vh_set_rxint(int32 vh)436 static void vh_set_rxint (  int32   vh  )
437 {
438     vh_rxi |= (1 << vh);
439     SET_INT (VHRX);
440 }
441 
442 /* RX interrupt ack. (bus cycle) */
443 
vh_rxinta(void)444 static int32 vh_rxinta (void)
445 {
446     int32   vh;
447 
448     for (vh = 0; vh < vh_desc.lines/VH_LINES; vh++) {
449         if (vh_rxi & (1 << vh)) {
450             sim_debug(DBG_INT, &vh_dev, "vh_rzinta(vh=%d)\n", vh);
451             vh_clr_rxint (vh);
452             return (vh_dib.vec + (vh * 010));
453         }
454     }
455     return (0);
456 }
457 
vh_clr_txint(int32 vh)458 static void vh_clr_txint (  int32   vh  )
459 {
460     vh_txi &= ~(1 << vh);
461     if (vh_txi == 0)
462         CLR_INT (VHTX);
463     else
464         SET_INT (VHTX);
465 }
466 
vh_set_txint(int32 vh)467 static void vh_set_txint (  int32   vh  )
468 {
469     vh_txi |= (1 << vh);
470     SET_INT (VHTX);
471 }
472 
473 /* TX interrupt ack. (bus cycle) */
474 
vh_txinta(void)475 static int32 vh_txinta (void)
476 {
477     int32   vh;
478 
479     for (vh = 0; vh < vh_desc.lines/VH_LINES; vh++) {
480         if (vh_txi & (1 << vh)) {
481             sim_debug(DBG_INT, &vh_dev, "vh_txinta(vh=%d)\n", vh);
482             vh_clr_txint (vh);
483             return (vh_dib.vec + 4 + (vh * 010));
484         }
485     }
486     return (0);
487 }
488 /* RX FIFO get/put routines */
489 
490 /* return 0 on success, -1 on FIFO overflow */
491 
fifo_put(int32 vh,TMLX * lp,int32 data)492 static int32 fifo_put ( int32   vh,
493             TMLX    *lp,
494             int32   data    )
495 {
496     int32   status = 0;
497 
498     if (lp == NULL)
499         goto override;
500     /* this might have to move to vh_getc() */
501     if ((lp->lnctrl & LNCTRL_OAUTO) && ((data & RBUF_DIAG) == 0)) {
502         TMLX    *l0p;
503         /* implement transmitted data flow control */
504         switch (data & 0377) {
505         case XON:
506             lp->tbuf2 |= TB2_TX_ENA;
507             goto common;
508         case XOFF:
509             lp->tbuf2 &= ~TB2_TX_ENA;
510         common:
511             /* find line 0 for this controller */
512             l0p = &vh_parm[vh * VH_LINES];
513             if (l0p->lpr & LPR_DISAB_XRPT)
514                 return (0);
515             break;
516         default:
517             break;
518         }
519     }
520 /* BUG: which of the following 2 is correct? */
521     /* if ((data & RBUF_DIAG) == RBUF_DIAG) */
522     if (data & RBUF_DIAG)
523         goto override;
524     if (((lp->lnctrl >> LNCTRL_V_MAINT) & LNCTRL_M_MAINT) == 2)
525         goto override;
526     if (!(lp->lnctrl & LNCTRL_RX_ENA))
527         return (0);
528 override:
529     vh_csr[vh] |= CSR_RX_DATA_AVAIL;
530     if (rbuf_idx[vh] < FIFO_SIZE) {
531         vh_rbuf[vh][rbuf_idx[vh]] = data;
532         rbuf_idx[vh] += 1;
533     } else {
534         vh_ovrrun[vh] |= (1 << RBUF_GETLINE (data));
535         status = -1;
536     }
537     if (vh_csr[vh] & CSR_RXIE) {
538         if (vh_unit[vh].flags & UNIT_MODEDHU) {
539             /* was it a modem status change? */
540             if ((data & RBUF_DIAG) == RBUF_DIAG)
541                 vh_set_rxint (vh);
542             /* look for FIFO alarm @ 3/4 full */
543             else if (rbuf_idx[vh] == FIFO_ALARM)
544                 vh_set_rxint (vh);
545             else if (vh_timer[vh] == 0)
546                 ; /* nothing, infinite timeout */
547             else if (vh_timer[vh] == 1)
548                 vh_set_rxint (vh);
549             else if (vh_timeo[vh] == 0)
550                 vh_timeo[vh] = MS2SIMH (vh_timer[vh]) + 1;
551         } else {
552             /* Interrupt on transition _from_ an empty FIFO */
553             if (rbuf_idx[vh] == 1)
554                 vh_set_rxint (vh);
555         }
556     }
557     if (rbuf_idx[vh] > FIFO_ALARM)
558         vh_crit |= (1 << vh);
559     /* Implement RX FIFO-level flow control */
560     if (lp != NULL) {
561         if ((lp->lnctrl & LNCTRL_FORCE_XOFF) ||
562               ((vh_crit & (1 << vh)) && (lp->lnctrl & LNCTRL_IAUTO))) {
563             int32   chan = RBUF_GETLINE(data);
564             vh_stall[vh] ^= (1 << chan);
565             /* send XOFF every other character received */
566             if (vh_stall[vh] & (1 << chan))
567                 vh_putc (vh, lp, chan, XOFF);
568         }
569     }
570     return (status);
571 }
572 
fifo_get(int32 vh)573 static int32 fifo_get ( int32   vh  )
574 {
575     int32   data, i;
576 
577     if (rbuf_idx[vh] == 0) {
578         vh_csr[vh] &= ~CSR_RX_DATA_AVAIL;
579         return (0);
580     }
581     /* pick off the first character, mark valid */
582     data = vh_rbuf[vh][0] | RBUF_DATA_VALID;
583     /* move the remainder up */
584     rbuf_idx[vh] -= 1;
585     for (i = 0; i < rbuf_idx[vh]; i++)
586         vh_rbuf[vh][i] = vh_rbuf[vh][i + 1];
587     /* rbuf_idx[vh] -= 1; */
588     /* look for any previous overruns */
589     if (vh_ovrrun[vh]) {
590         for (i = 0; i < VH_LINES; i++) {
591             if (vh_ovrrun[vh] & (1 << i)) {
592                 fifo_put (vh, NULL, RBUF_OVERRUN_ERR |
593                       RBUF_PUTLINE (i));
594                 vh_ovrrun[vh] &= ~(1 << i);
595                 break;
596             }
597         }
598     }
599     /* recompute FIFO alarm condition */
600     if ((rbuf_idx[vh] < FIFO_HALF) && (vh_crit & (1 << vh))) {
601         vh_crit &= ~(1 << vh);
602         /* send XON to all XOFF'd channels on this controller */
603         for (i = 0; i < VH_LINES; i++) {
604             TMLX    *lp = &vh_parm[(vh * VH_LINES) + i];
605             if (lp->lnctrl & LNCTRL_FORCE_XOFF)
606                 continue;
607             if (vh_stall[vh] & (1 << i)) {
608                 vh_putc (vh, NULL, i, XON);
609                 vh_stall[vh] &= ~(1 << i);
610             }
611         }
612     }
613     return (data & 0177777);
614 }
615 /* TX Q manipulation */
616 
dq_tx_report(int32 vh)617 static int32 dq_tx_report ( int32   vh  )
618 {
619     int32   data, i;
620 
621     if (txq_idx[vh] == 0)
622         return (0);
623     data = vh_txq[vh][0];
624     txq_idx[vh] -= 1;
625     for (i = 0; i < txq_idx[vh]; i++)
626         vh_txq[vh][i] = vh_txq[vh][i + 1];
627     /* txq_idx[vh] -= 1; */
628     return (data & 0177777);
629 }
630 
q_tx_report(int32 vh,int32 data)631 static void q_tx_report (   int32   vh,
632                 int32   data    )
633 {
634     if (vh_csr[vh] & CSR_TXIE)
635         vh_set_txint (vh);
636     if (txq_idx[vh] >= TXQ_SIZE) {
637 /* BUG: which of the following 2 is correct? */
638         dq_tx_report (vh);
639         /* return; */
640     }
641     vh_txq[vh][txq_idx[vh]] = CSR_TX_ACTION | data;
642     txq_idx[vh] += 1;
643 }
644 /* Channel get/put routines */
645 
HangupModem(int32 vh,TMLX * lp,int32 chan)646 static void HangupModem (   int32   vh,
647                 TMLX    *lp,
648                 int32   chan    )
649 {
650     if (vh_unit[vh].flags & UNIT_MODEM)
651         lp->lstat &= ~(STAT_DCD|STAT_DSR|STAT_CTS|STAT_RI);
652     if (lp->lnctrl & LNCTRL_LINK_TYPE)
653         /* RBUF<0> = 0 for modem status */
654         fifo_put (vh, lp, RBUF_DIAG |
655                   RBUF_PUTLINE (chan) |
656                   ((lp->lstat >> 8) & 0376));
657         /* BUG: check for overflow above */
658 }
659 
660 /* TX a character on a line, regardless of the TX enable state */
661 
vh_putc(int32 vh,TMLX * lp,int32 chan,int32 data)662 static t_stat vh_putc ( int32   vh,
663             TMLX    *lp,
664             int32   chan,
665             int32   data    )
666 {
667     int32   val;
668     t_stat  status = SCPE_OK;
669 
670     /* truncate to desired character length */
671     data &= bitmask[(lp->lpr >> LPR_V_CHAR_LGTH) & LPR_M_CHAR_LGTH];
672     switch ((lp->lnctrl >> LNCTRL_V_MAINT) & LNCTRL_M_MAINT) {
673     case 0:     /* normal */
674 #if 0
675         /* check for (external) loopback setting */
676         switch (vh_loop[vh]) {
677         default:
678         case LOOP_NONE:
679             break;
680         }
681 #endif
682         status = tmxr_putc_ln (lp->tmln, data);
683         if (status == SCPE_LOST) {
684             tmxr_reset_ln (lp->tmln);
685             HangupModem (vh, lp, chan);
686         } else if (status == SCPE_STALL) {
687             /* let's flush and try again */
688             tmxr_send_buffered_data (lp->tmln);
689             status = tmxr_putc_ln (lp->tmln, data);
690         }
691         break;
692     case 1:     /* auto echo */
693         break;
694     case 2:     /* local loopback */
695         if (lp->lnctrl & LNCTRL_BREAK)
696             val = fifo_put (vh, lp,
697                 RBUF_FRAME_ERR | RBUF_PUTLINE (chan));
698         else
699             val = fifo_put (vh, lp,
700                 RBUF_PUTLINE (chan) | data);
701         status = (val < 0) ? SCPE_TTMO : SCPE_OK;
702         break;
703     default:    /* remote loopback */
704         break;
705     }
706     return (status);
707 }
708 
709 /* Retrieve all stored input from TMXR and place in RX FIFO */
710 
vh_getc(int32 vh)711 static void vh_getc (   int32   vh  )
712 {
713     uint32  i, c;
714     TMLX    *lp;
715 
716     for (i = 0; i < VH_LINES; i++) {
717         lp = &vh_parm[(vh * VH_LINES) + i];
718         while ((c = tmxr_getc_ln (lp->tmln)) != 0) {
719             if (c & SCPE_BREAK) {
720                 fifo_put (vh, lp,
721                     RBUF_FRAME_ERR | RBUF_PUTLINE (i));
722                 /* BUG: check for overflow above */
723             } else {
724                 c &= bitmask[(lp->lpr >> LPR_V_CHAR_LGTH) &
725                     LPR_M_CHAR_LGTH];
726                 fifo_put (vh, lp, RBUF_PUTLINE (i) | c);
727                 /* BUG: check for overflow above */
728             }
729         }
730     }
731 }
732 
733 /* I/O dispatch routines */
734 
vh_rd(int32 * data,int32 PA,int32 access)735 static t_stat vh_rd (   int32   *data,
736             int32   PA,
737             int32   access  )
738 {
739     int32   vh = ((PA - vh_dib.ba) >> 4) & VH_MNOMASK, line;
740     TMLX    *lp;
741 
742     switch ((PA >> 1) & 7) {
743     case 0:     /* CSR */
744         *data = vh_csr[vh] | dq_tx_report (vh);
745         vh_csr[vh] &= ~0117400; /* clear the read-once bits */
746         break;
747     case 1:     /* RBUF */
748         *data = fifo_get (vh);
749         break;
750     case 2:     /* LPR */
751         if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES) {
752             *data = 0;
753             break;
754         }
755         line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]);
756         lp = &vh_parm[line];
757         *data = lp->lpr;
758         break;
759     case 3:     /* STAT/FIFOSIZE */
760         if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES) {
761             *data = 0;
762             break;
763         }
764         line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]);
765         lp = &vh_parm[line];
766         *data = (lp->lstat & ~0377) |       /* modem status */
767 #if 0
768             (64 - tmxr_tqln (lp->tmln));
769 fprintf (stderr, "\rtqln %d\n", 64 - tmxr_tqln (lp->tmln));
770 #else
771             64;
772 #endif
773         break;
774     case 4:     /* LNCTRL */
775         if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES) {
776             *data = 0;
777             break;
778         }
779         line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]);
780         lp = &vh_parm[line];
781         *data = lp->lnctrl;
782         break;
783     case 5:     /* TBUFFAD1 */
784         if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES) {
785             *data = 0;
786             break;
787         }
788         line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]);
789         lp = &vh_parm[line];
790         *data = lp->tbuf1;
791         break;
792     case 6:     /* TBUFFAD2 */
793         if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES) {
794             *data = 0;
795             break;
796         }
797         line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]);
798         lp = &vh_parm[line];
799         *data = lp->tbuf2;
800         break;
801     case 7:     /* TBUFFCT */
802         if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES) {
803             *data = 0;
804             break;
805         }
806         line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]);
807         lp = &vh_parm[line];
808         *data = lp->tbuffct;
809         break;
810     default:
811         /* can't happen */
812         break;
813     }
814 
815     sim_debug(DBG_REG, &vh_dev, "vh_rd(PA=0x%08X [%s], access=%d, data=0x%X)\n", PA,
816               ((vh_unit[vh].flags & UNIT_MODEDHU) ? vh_rd_dhu_regs : vh_rd_dhv_regs)[(PA >> 1) & 07], access, data);
817 
818     return (SCPE_OK);
819 }
820 
vh_wr(int32 data,int32 PA,int32 access)821 static t_stat vh_wr (   int32   data,
822             int32   PA,
823             int32   access  )
824 {
825     int32   vh = ((PA - vh_dib.ba) >> 4) & VH_MNOMASK, line;
826     TMLX    *lp;
827 
828     sim_debug(DBG_REG, &vh_dev, "vh_wr(PA=0x%08X [%s], access=%d, data=0x%X)\n", PA,
829               ((vh_unit[vh].flags & UNIT_MODEDHU) ? vh_wr_dhu_regs : vh_wr_dhv_regs)[(PA >> 1) & 07], access, data);
830 
831     switch ((PA >> 1) & 7) {
832     case 0:     /* CSR, but no read-modify-write */
833         if (access == WRITEB)
834             data = (PA & 1) ?
835                 (vh_csr[vh] & 0377) | (data << 8) :
836                 (vh_csr[vh] & ~0377) | (data & 0377);
837         if (data & CSR_MASTER_RESET) {
838             if ((vh_unit[vh].flags & UNIT_MODEDHU) && (data & CSR_SKIP))
839                 data &= ~CSR_MASTER_RESET;
840             if (vh == 0) /* Only start unit service on the first unit.  Units are polled there */
841                 sim_activate (&vh_unit[vh], clk_cosched (tmxr_poll));
842             /* vh_mcount[vh] = 72; */ /* 1.2 seconds */
843             vh_mcount[vh] = MS2SIMH (1200); /* 1.2 seconds */
844         }
845         if ((data & CSR_RXIE) == 0)
846             vh_clr_rxint (vh);
847         /* catch the RXIE transition if the FIFO is not empty */
848         else if (((vh_csr[vh] & CSR_RXIE) == 0) &&
849               (rbuf_idx[vh] != 0)) {
850             if (vh_unit[vh].flags & UNIT_MODEDHU) {
851                 if (rbuf_idx[vh] > FIFO_ALARM)
852                     vh_set_rxint (vh);
853                 else if (vh_timer[vh] == 0)
854                     ;
855                 else if (vh_timer[vh] == 1)
856                     vh_set_rxint (vh);
857                 else if (vh_timeo[vh] == 0)
858                     vh_timeo[vh] = MS2SIMH (vh_timer[vh]) + 1;
859             } else {
860                 vh_set_rxint (vh);
861             }
862         }
863         if ((data & CSR_TXIE) == 0)
864             vh_clr_txint (vh);
865         else if (((vh_csr[vh] & CSR_TXIE) == 0) &&
866               (txq_idx[vh] != 0))
867             vh_set_txint (vh);
868         vh_csr[vh] = (vh_csr[vh] & ~((uint16) CSR_RW)) | (data & (uint16) CSR_RW);
869         break;
870     case 1:     /* TXCHAR/RXTIMER */
871         if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES)
872             break;
873         if ((data == RESET_ABORT) && (vh_csr[vh] & CSR_MASTER_RESET)) {
874             vh_mcount[vh] = 1;
875             break;
876         }
877         if (vh_unit[vh].flags & UNIT_MODEDHU) {
878             if (CSR_GETCHAN (vh_csr[vh]) != 0)
879                 break;
880             if (access == WRITEB)
881                 data = (PA & 1) ?
882                     (vh_timer[vh] & 0377) | (data << 8) :
883                     (vh_timer[vh] & ~0377) | (data & 0377);
884             vh_timer[vh] = data & 0377;
885 #if 0
886             if (vh_csr[vh] & CSR_RXIE) {
887                 if (rbuf_idx[vh] > FIFO_ALARM)
888                     vh_set_rxint (vh);
889                 else if (vh_timer[vh] == 0)
890                     ;
891                 else if (vh_timer[vh] == 1)
892                     vh_set_rxint (vh);
893                 else if (vh_timeo[vh] == 0)
894                     vh_timeo[vh] = MS2SIMH (vh_timer[vh]) + 1;
895             }
896 #endif
897         } else {
898             line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]);
899             lp = &vh_parm[line];
900             if (access == WRITEB)
901                 data = (PA & 1) ?
902                     (lp->txchar & 0377) | (data << 8) :
903                     (lp->txchar & ~0377) | (data & 0377);
904             lp->txchar = data;  /* TXCHAR */
905             if (lp->txchar & TXCHAR_TX_DATA_VALID) {
906                 if (lp->tbuf2 & TB2_TX_ENA)
907                     vh_putc (vh, lp,
908                         CSR_GETCHAN (vh_csr[vh]),
909                         lp->txchar);
910                 q_tx_report (vh,
911                     CSR_GETCHAN (vh_csr[vh]) << CSR_V_TX_LINE);
912                 lp->txchar &= ~TXCHAR_TX_DATA_VALID;
913             }
914         }
915         break;
916     case 2:     /* LPR */
917         if ((data == RESET_ABORT) && (vh_csr[vh] & CSR_MASTER_RESET)) {
918             vh_mcount[vh] = 1;
919             break;
920         }
921         if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES)
922             break;
923         line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]);
924         lp = &vh_parm[line];
925         if (access == WRITEB)
926             data = (PA & 1) ?
927                 (lp->lpr & 0377) | (data << 8) :
928                 (lp->lpr & ~0377) | (data & 0377);
929         /* Modify only if CSR<3:0> == 0 */
930         if (CSR_GETCHAN (vh_csr[vh]) != 0)
931             data &= ~LPR_DISAB_XRPT;
932         lp->lpr = data;
933         if (((lp->lpr >> LPR_V_DIAG) & LPR_M_DIAG) == 1) {
934             fifo_put (vh, lp,
935                 RBUF_DIAG |
936                 RBUF_PUTLINE (CSR_GETCHAN (vh_csr[vh])) |
937                 BMP_OK);
938             /* BUG: check for overflow above */
939             lp->lpr &= ~(LPR_M_DIAG << LPR_V_DIAG);
940         }
941         break;
942     case 3:     /* STAT/FIFODATA */
943         if ((data == RESET_ABORT) && (vh_csr[vh] & CSR_MASTER_RESET)) {
944             vh_mcount[vh] = 1;
945             break;
946         }
947         if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES)
948             break;
949         line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]);
950         lp = &vh_parm[line];
951         if (vh_unit[vh].flags & UNIT_MODEDHU) {
952             /* high byte writes not allowed */
953             if (PA & 1)
954                 break;
955             /* transmit 1 or 2 characters */
956             if (!(lp->tbuf2 & TB2_TX_ENA))
957                 break;
958             vh_putc (vh, lp, CSR_GETCHAN (vh_csr[vh]), data);
959             q_tx_report (vh, CSR_GETCHAN (vh_csr[vh]) << CSR_V_TX_LINE);
960             if (access != WRITEB)
961                 vh_putc (vh, lp, CSR_GETCHAN (vh_csr[vh]),
962                     data >> 8);
963         }
964         break;
965     case 4:     /* LNCTRL */
966         if ((data == RESET_ABORT) && (vh_csr[vh] & CSR_MASTER_RESET)) {
967             vh_mcount[vh] = 1;
968             break;
969         }
970         if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES)
971             break;
972         line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]);
973         lp = &vh_parm[line];
974         if (access == WRITEB)
975             data = (PA & 1) ?
976                 (lp->lnctrl & 0377) | (data << 8) :
977                 (lp->lnctrl & ~0377) | (data & 0377);
978         /* catch the abort TX transition */
979         if (!(lp->lnctrl & LNCTRL_TX_ABORT) &&
980              (data & LNCTRL_TX_ABORT)) {
981             if ((lp->tbuf2 & TB2_TX_ENA) &&
982                 (lp->tbuf2 & TB2_TX_DMA_START)) {
983                 lp->tbuf2 &= ~TB2_TX_DMA_START;
984                 q_tx_report (vh, CSR_GETCHAN (vh_csr[vh]) << CSR_V_TX_LINE);
985             }
986         }
987         /* Implement program-initiated flow control */
988         if ( (data & LNCTRL_FORCE_XOFF) &&
989              !(lp->lnctrl & LNCTRL_FORCE_XOFF) ) {
990             if (!(lp->lnctrl & LNCTRL_IAUTO))
991                 vh_putc (vh, lp, CSR_GETCHAN (vh_csr[vh]), XOFF);
992         } else if ( !(data & LNCTRL_FORCE_XOFF) &&
993                 (lp->lnctrl & LNCTRL_FORCE_XOFF) ) {
994             if (!(lp->lnctrl & LNCTRL_IAUTO))
995                 vh_putc (vh, lp, CSR_GETCHAN (vh_csr[vh]), XON);
996             else if (!(vh_crit & (1 << vh)) &&
997                  (vh_stall[vh] & (1 << CSR_GETCHAN (vh_csr[vh]))))
998                 vh_putc (vh, lp, CSR_GETCHAN (vh_csr[vh]), XON);
999         }
1000         if ( (data & LNCTRL_IAUTO) &&       /* IAUTO 0->1 */
1001              !(lp->lnctrl & LNCTRL_IAUTO) ) {
1002             if (!(lp->lnctrl & LNCTRL_FORCE_XOFF)) {
1003                 if (vh_crit & (1 << vh)) {
1004                     vh_putc (vh, lp,
1005                         CSR_GETCHAN (vh_csr[vh]), XOFF);
1006                     vh_stall[vh] |= (1 << CSR_GETCHAN (vh_csr[vh]));
1007                 }
1008             } else {
1009                 /* vh_stall[vh] |= (1 << CSR_GETCHAN (vh_csr[vh])) */;
1010             }
1011         } else if ( !(data & LNCTRL_IAUTO) &&
1012                 (lp->lnctrl & LNCTRL_IAUTO) ) {
1013             if (!(lp->lnctrl & LNCTRL_FORCE_XOFF))
1014                 vh_putc (vh, lp, CSR_GETCHAN (vh_csr[vh]), XON);
1015         }
1016         /* check modem control bits */
1017         if ( !(data & LNCTRL_DTR) &&    /* DTR 1->0 */
1018               (lp->lnctrl & LNCTRL_DTR)) {
1019             if ((lp->tmln->conn) && (vh_unit[vh].flags & UNIT_HANGUP)) {
1020                 tmxr_linemsg (lp->tmln, "\r\nLine hangup\r\n");
1021                 tmxr_reset_ln (lp->tmln);
1022             }
1023             HangupModem (vh, lp, CSR_GETCHAN (vh_csr[vh]));
1024         }
1025         lp->lnctrl = data;
1026         lp->tmln->rcve = (data & LNCTRL_RX_ENA) ? 1 : 0;
1027         tmxr_poll_rx (&vh_desc);
1028         vh_getc (vh);
1029         if (lp->lnctrl & LNCTRL_BREAK)
1030             vh_putc (vh, lp, CSR_GETCHAN (vh_csr[vh]), 0);
1031         break;
1032     case 5:     /* TBUFFAD1 */
1033         if ((data == RESET_ABORT) && (vh_csr[vh] & CSR_MASTER_RESET)) {
1034             vh_mcount[vh] = 1;
1035             break;
1036         }
1037         if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES)
1038             break;
1039         line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]);
1040         lp = &vh_parm[line];
1041         if (access == WRITEB)
1042             data = (PA & 1) ?
1043                 (lp->tbuf1 & 0377) | (data << 8) :
1044                 (lp->tbuf1 & ~0377) | (data & 0377);
1045         lp->tbuf1 = data;
1046         break;
1047     case 6:     /* TBUFFAD2 */
1048         if ((data == RESET_ABORT) && (vh_csr[vh] & CSR_MASTER_RESET)) {
1049             vh_mcount[vh] = 1;
1050             break;
1051         }
1052         if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES)
1053             break;
1054         line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]);
1055         lp = &vh_parm[line];
1056         if (access == WRITEB)
1057             data = (PA & 1) ?
1058                 (lp->tbuf2 & 0377) | (data << 8) :
1059                 (lp->tbuf2 & ~0377) | (data & 0377);
1060         lp->tbuf2 = data;
1061         /* if starting a DMA, clear DMA_ERR */
1062         if (vh_unit[vh].flags & UNIT_FASTDMA) {
1063             doDMA (vh, CSR_GETCHAN (vh_csr[vh]));
1064             tmxr_send_buffered_data (lp->tmln);
1065         }
1066         break;
1067     case 7:     /* TBUFFCT */
1068         if ((data == RESET_ABORT) && (vh_csr[vh] & CSR_MASTER_RESET)) {
1069             vh_mcount[vh] = 1;
1070             break;
1071         }
1072         if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES)
1073             break;
1074         line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]);
1075         lp = &vh_parm[line];
1076         if (access == WRITEB)
1077             data = (PA & 1) ?
1078                 (lp->tbuffct & 0377) | (data << 8) :
1079                 (lp->tbuffct & ~0377) | (data & 0377);
1080         lp->tbuffct = data;
1081         break;
1082     default:
1083         /* can't happen */
1084         break;
1085     }
1086     return (SCPE_OK);
1087 }
1088 
doDMA(int32 vh,int32 chan)1089 static void doDMA ( int32   vh,
1090             int32   chan    )
1091 {
1092     int32   line, status;
1093     uint32  pa;
1094     TMLX    *lp;
1095 
1096     line = (vh * VH_LINES) + chan;
1097     lp = &vh_parm[line];
1098     if ((lp->tbuf2 & TB2_TX_ENA) && (lp->tbuf2 & TB2_TX_DMA_START)) {
1099 /* BUG: should compare against available xmit buffer space */
1100         pa = lp->tbuf1;
1101         pa |= (lp->tbuf2 & TB2_M_TBUFFAD) << 16;
1102         status = chan << CSR_V_TX_LINE;
1103         while (lp->tbuffct) {
1104             uint8   buf;
1105             if (Map_ReadB (pa, 1, &buf)) {
1106                 status |= CSR_TX_DMA_ERR;
1107                 lp->tbuffct = 0;
1108                 break;
1109             }
1110             if (vh_putc (vh, lp, chan, buf) != SCPE_OK)
1111                 break;
1112             /* pa = (pa + 1) & PAMASK; */
1113             pa = (pa + 1) & ((1 << 22) - 1);
1114             lp->tbuffct--;
1115         }
1116         lp->tbuf1 = pa & 0177777;
1117         lp->tbuf2 = (lp->tbuf2 & ~TB2_M_TBUFFAD) |
1118                 ((pa >> 16) & TB2_M_TBUFFAD);
1119         if (lp->tbuffct == 0) {
1120             lp->tbuf2 &= ~TB2_TX_DMA_START;
1121             q_tx_report (vh, status);
1122         }
1123     }
1124 }
1125 
1126 /* Perform many of the functions of PROC2 */
1127 
vh_svc(UNIT * uptr)1128 static t_stat vh_svc (  UNIT    *uptr   )
1129 {
1130     int32   vh, newln, i;
1131 
1132     /* scan all muxes for countdown reset */
1133     for (vh = 0; vh < vh_desc.lines/VH_LINES; vh++) {
1134         if (vh_csr[vh] & CSR_MASTER_RESET) {
1135             if (vh_mcount[vh] != 0)
1136                 vh_mcount[vh] -= 1;
1137             else
1138                 vh_clear (vh, FALSE);
1139         }
1140     }
1141     /* sample every 10ms for modem changes (new connections) */
1142     newln = tmxr_poll_conn (&vh_desc);
1143     if (newln >= 0) {
1144         TMLX    *lp;
1145         int32   line;
1146         vh = newln / VH_LINES;  /* determine which mux */
1147         line = newln - (vh * VH_LINES);
1148         lp = &vh_parm[newln];
1149         lp->lstat |= STAT_DSR | STAT_DCD | STAT_CTS;
1150         if (!(lp->lnctrl & LNCTRL_DTR))
1151             lp->lstat |= STAT_RI;
1152         if (lp->lnctrl & LNCTRL_LINK_TYPE)
1153             fifo_put (vh, lp, RBUF_DIAG |
1154                       RBUF_PUTLINE (line) |
1155                       ((lp->lstat >> 8) & 0376));
1156             /* BUG: should check for overflow above */
1157     }
1158     /* scan all muxes, lines for DMA to complete; start every 3.12ms */
1159     for (vh = 0; vh < vh_desc.lines/VH_LINES; vh++) {
1160         for (i = 0; i < VH_LINES; i++)
1161             doDMA (vh, i);
1162     }
1163     /* interrupt driven in a real DHQ */
1164     tmxr_poll_rx (&vh_desc);
1165     for (vh = 0; vh < vh_desc.lines/VH_LINES; vh++)
1166         vh_getc (vh);
1167     tmxr_poll_tx (&vh_desc);
1168     /* scan all DHU-mode muxes for RX FIFO timeout */
1169     for (vh = 0; vh < vh_desc.lines/VH_LINES; vh++) {
1170         if (vh_unit[vh].flags & UNIT_MODEDHU) {
1171             if (vh_timeo[vh] && (vh_csr[vh] & CSR_RXIE)) {
1172                 vh_timeo[vh] -= 1;
1173                 if ((vh_timeo[vh] == 0) && rbuf_idx[vh])
1174                     vh_set_rxint (vh);
1175             }
1176         }
1177     }
1178     sim_activate (uptr, tmxr_poll); /* requeue ourselves */
1179     return (SCPE_OK);
1180 }
1181 
1182 /* init a channel on a controller */
1183 
1184 /* set for:
1185 send/receive 9600
1186 8 data bits
1187 1 stop bit
1188 no parity
1189 parity odd
1190 auto-flow off
1191 RX disabled
1192 TX enabled
1193 no break on line
1194 no loopback
1195 link type set to data-leads only
1196 DTR & RTS off
1197 DMA character counter 0
1198 DMA start address registers 0
1199 TX_DMA_START 0
1200 TX_ABORT 0
1201 auto-flow reports enabled
1202 FIFO size set to 64
1203 */
1204 
vh_init_chan(int32 vh,int32 chan)1205 static void vh_init_chan (  int32   vh,
1206                 int32   chan    )
1207 {
1208     int32   line;
1209     TMLX    *lp;
1210 
1211     line = (vh * VH_LINES) + chan;
1212     lp = &vh_parm[line];
1213     lp->lpr = (RATE_9600 << LPR_V_TX_SPEED) |
1214           (RATE_9600 << LPR_V_RX_SPEED) |
1215           (03 << LPR_V_CHAR_LGTH);
1216     lp->lnctrl = 0;
1217     lp->lstat &= ~(STAT_MDL | STAT_DHUID | STAT_RI);
1218     if (vh_unit[vh].flags & UNIT_MODEDHU)
1219         lp->lstat |= STAT_DHUID | 64;
1220     if (!(vh_unit[vh].flags & UNIT_MODEM))
1221         lp->lstat |= STAT_DSR | STAT_DCD | STAT_CTS;
1222     lp->tmln->xmte = 1;
1223     lp->tmln->rcve = 0;
1224     lp->tbuffct = 0;
1225     lp->tbuf1 = 0;
1226     lp->tbuf2 = TB2_TX_ENA;
1227     lp->txchar = 0;
1228 }
1229 
1230 /* init a controller; flag true if BINIT, false if master.reset */
1231 
vh_clear(int32 vh,t_bool flag)1232 static t_stat vh_clear (    int32   vh,
1233                 t_bool  flag    )
1234 {
1235     int32   i;
1236 
1237     txq_idx[vh] = 0;
1238     rbuf_idx[vh] = 0;
1239     /* put 8 diag bytes in FIFO: 6 SELF_x, 2 circuit revision codes */
1240     if (vh_csr[vh] & CSR_SKIP) {
1241         fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(0) | SELF_SKIP);
1242         fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(1) | SELF_SKIP);
1243         fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(2) | SELF_SKIP);
1244         fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(3) | SELF_SKIP);
1245         fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(4) | SELF_SKIP);
1246         fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(5) | SELF_SKIP);
1247         fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(6) | 0107);
1248         fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(7) | 0105);
1249     } else {
1250         fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(0) | SELF_NULL);
1251         fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(1) | SELF_NULL);
1252         fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(2) | SELF_NULL);
1253         fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(3) | SELF_NULL);
1254         fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(4) | SELF_NULL);
1255         fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(5) | SELF_NULL);
1256         /* PROC2 ver. 1 */
1257         fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(6) | 0107);
1258         /* PROC1 ver. 1 */
1259         fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(7) | 0105);
1260     }
1261     vh_csr[vh] &= ~(CSR_TX_ACTION|CSR_DIAG_FAIL|CSR_MASTER_RESET);
1262     if (flag)
1263         vh_csr[vh] &= ~(CSR_TXIE|CSR_RXIE|CSR_SKIP);
1264     vh_csr[vh] |= CSR_TX_DMA_ERR | (CSR_M_TX_LINE << CSR_V_TX_LINE);
1265     vh_clr_rxint (vh);
1266     vh_clr_txint (vh);
1267     vh_timer[vh] = 1;
1268     vh_timeo[vh] = 0;
1269     vh_ovrrun[vh] = 0;
1270     for (i = 0; i < VH_LINES; i++)
1271         vh_init_chan (vh, i);
1272     vh_crit &= ~(1 << vh);
1273     vh_stall[vh] = 0;
1274     vh_loop[vh] = LOOP_NONE;
1275     return (SCPE_OK);
1276 }
1277 
1278 /* Reset all controllers.  Used by BINIT and RESET. */
1279 
vh_reset(DEVICE * dptr)1280 static t_stat vh_reset (    DEVICE  *dptr   )
1281 {
1282     int32   i;
1283 
1284     for (i = 0; i < vh_desc.lines; i++)
1285         vh_parm[i].tmln = &vh_ldsc[i];
1286     for (i = 0; i < vh_desc.lines/VH_LINES; i++) {
1287 #if     defined (VM_PDP11)
1288         /* if Unibus, force DHU mode */
1289         if (UNIBUS)
1290             vh_unit[i].flags |= UNIT_MODEDHU;
1291 #endif
1292         vh_clear (i, TRUE);
1293     }
1294     vh_rxi = vh_txi = 0;
1295     CLR_INT (VHRX);
1296     CLR_INT (VHTX);
1297     sim_cancel (&vh_unit[0]);
1298     return (auto_config (dptr->name, (dptr->flags & DEV_DIS) ? 0 : vh_desc.lines/VH_LINES));
1299 }
1300 
1301 
vh_attach(UNIT * uptr,char * cptr)1302 static t_stat vh_attach (   UNIT    *uptr,
1303                 char    *cptr   )
1304 {
1305     if (uptr == &vh_unit[0])
1306         return (tmxr_attach (&vh_desc, uptr, cptr));
1307     return (SCPE_NOATT);
1308 }
1309 
vh_detach(UNIT * uptr)1310 static t_stat vh_detach (   UNIT    *uptr   )
1311 {
1312     return (tmxr_detach (&vh_desc, uptr));
1313 }
1314 
vh_detail_line(FILE * st,int32 vh,int32 chan)1315 static void vh_detail_line (    FILE    *st,
1316                 int32   vh,
1317                 int32   chan    )
1318 {
1319     int32   line;
1320     TMLX    *lp;
1321 
1322     line = (vh * VH_LINES) + chan;
1323     lp = &vh_parm[line];
1324     fprintf (st, "\tline %d\tlpr %06o, lnctrl %06o, lstat %06o\n",
1325         chan, lp->lpr, lp->lnctrl, lp->lstat);
1326     fprintf (st, "\t\ttbuffct %06o, tbuf1 %06o, tbuf2 %06o, txchar %06o\n",
1327         lp->tbuffct, lp->tbuf1, lp->tbuf2, lp->txchar);
1328     fprintf (st, "\t\ttmln rcve %d xmte %d\n",
1329         lp->tmln->rcve, lp->tmln->xmte);
1330 }
1331 
vh_show_detail(FILE * st,UNIT * uptr,int32 val,void * desc)1332 static t_stat vh_show_detail (   FILE    *st,
1333                 UNIT    *uptr,
1334                 int32   val,
1335                 void    *desc   )
1336 {
1337     int32   i, j;
1338 
1339     fprintf (st, "VH:\trxi %d, txi %d\n", vh_rxi, vh_txi);
1340     for (i = 0; i < vh_desc.lines/VH_LINES; i++) {
1341         fprintf (st, "VH%d:\tmode %s, crit %d\n", i,
1342             vh_unit[i].flags & UNIT_MODEDHU ? "DHU" : "DHV",
1343             vh_crit & (1 << i));
1344         fprintf (st, "\tCSR %06o, mcount %d, rbuf_idx %d, txq_idx %d\n",
1345             vh_csr[i], vh_mcount[i], rbuf_idx[i], txq_idx[i]);
1346         for (j = 0; j < VH_LINES; j++)
1347             vh_detail_line (st, i, j);
1348     }
1349     return (SCPE_OK);
1350 }
1351 
vh_show_rbuf(FILE * st,UNIT * uptr,int32 val,void * desc)1352 static t_stat vh_show_rbuf (    FILE    *st,
1353                 UNIT    *uptr,
1354                 int32   val,
1355                 void    *desc   )
1356 {
1357     int32   i;
1358 
1359     for (i = 0; i < rbuf_idx[0]; i++)
1360         fprintf (st, "%03d: %06o\n", i, vh_rbuf[0][i]);
1361     return (SCPE_OK);
1362 }
1363 
vh_show_txq(FILE * st,UNIT * uptr,int32 val,void * desc)1364 static t_stat vh_show_txq ( FILE    *st,
1365                 UNIT    *uptr,
1366                 int32   val,
1367                 void    *desc   )
1368 {
1369     int32   i;
1370 
1371     for (i = 0; i < txq_idx[0]; i++)
1372         fprintf (st, "%02d: %06o\n\r", i, vh_txq[0][i]);
1373     return (SCPE_OK);
1374 }
1375 
1376 /* SET LINES processor */
1377 
vh_setnl(UNIT * uptr,int32 val,char * cptr,void * desc)1378 static t_stat vh_setnl (UNIT *uptr, int32 val, char *cptr, void *desc)
1379 {
1380 int32 newln, i, t, ndev;
1381 t_stat r;
1382 
1383 if (cptr == NULL)
1384     return SCPE_ARG;
1385 newln = (int32) get_uint (cptr, 10, (VH_MUXES * VH_LINES), &r);
1386 if ((r != SCPE_OK) || (newln == vh_desc.lines))
1387     return r;
1388 if ((newln == 0) || (newln % VH_LINES))
1389     return SCPE_ARG;
1390 if (newln < vh_desc.lines) {
1391     for (i = newln, t = 0; i < vh_desc.lines; i++)
1392         t = t | vh_ldsc[i].conn;
1393     if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE))
1394         return SCPE_OK;
1395     for (i = newln; i < vh_desc.lines; i++) {
1396         if (vh_ldsc[i].conn) {
1397             tmxr_linemsg (&vh_ldsc[i], "\r\nOperator disconnected line\r\n");
1398             tmxr_reset_ln (&vh_ldsc[i]);                /* reset line */
1399             }
1400         if ((i % VH_LINES) == (VH_LINES - 1))
1401             vh_clear (i / VH_LINES, TRUE);              /* reset mux */
1402         }
1403     }
1404 vh_dib.lnt = (newln / VH_LINES) * IOLN_VH;              /* set length */
1405 vh_desc.lines = newln;
1406 ndev = ((vh_dev.flags & DEV_DIS)? 0: (vh_desc.lines / VH_LINES));
1407 vh_dev.numunits = (newln / VH_LINES);
1408 return auto_config (vh_dev.name, ndev);                 /* auto config */
1409 }
1410 
1411 /* SET LOG processor */
1412 
vh_set_log(UNIT * uptr,int32 val,char * cptr,void * desc)1413 static t_stat vh_set_log (UNIT *uptr, int32 val, char *cptr, void *desc)
1414 {
1415 char *tptr;
1416 t_stat r;
1417 int32 ln;
1418 
1419 if (cptr == NULL)
1420     return SCPE_ARG;
1421 tptr = strchr (cptr, '=');
1422 if ((tptr == NULL) || (*tptr == 0))
1423     return SCPE_ARG;
1424 *tptr++ = 0;
1425 ln = (int32) get_uint (cptr, 10, (VH_MUXES * VH_LINES), &r);
1426 if ((r != SCPE_OK) || (ln >= vh_desc.lines))
1427     return SCPE_ARG;
1428 return tmxr_set_log (NULL, ln, tptr, desc);
1429 }
1430 
1431 /* SET NOLOG processor */
1432 
vh_set_nolog(UNIT * uptr,int32 val,char * cptr,void * desc)1433 static t_stat vh_set_nolog (UNIT *uptr, int32 val, char *cptr, void *desc)
1434 {
1435 t_stat r;
1436 int32 ln;
1437 
1438 if (cptr == NULL)
1439     return SCPE_ARG;
1440 ln = (int32) get_uint (cptr, 10, (VH_MUXES * VH_LINES), &r);
1441 if ((r != SCPE_OK) || (ln >= vh_desc.lines))
1442     return SCPE_ARG;
1443 return tmxr_set_nolog (NULL, ln, NULL, desc);
1444 }
1445 
1446 /* SHOW LOG processor */
1447 
vh_show_log(FILE * st,UNIT * uptr,int32 val,void * desc)1448 static t_stat vh_show_log (FILE *st, UNIT *uptr, int32 val, void *desc)
1449 {
1450 int32 i;
1451 
1452 for (i = 0; i < vh_desc.lines; i++) {
1453     fprintf (st, "line %d: ", i);
1454     tmxr_show_log (st, NULL, i, desc);
1455     fprintf (st, "\n");
1456     }
1457 return SCPE_OK;
1458 }
1459