| 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 |