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