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