First Commit of my working state
[simh.git] / PDP11 / pdp11_dc.c
1 /* pdp11_dc.c: PDP-11 DC11 multiple terminal interface simulator
2
3 Copyright (c) 1993-2008, Robert M Supnik
4
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22 Except as contained in this notice, the name of Robert M Supnik shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from Robert M Supnik.
25
26 dci,dco DC11 terminal input/output
27
28 The simulator supports both hardwired and modem-like behavior. If modem
29 control is not enabled, carrier detect, ring, and carrier change are
30 never set.
31 */
32
33 #if defined (VM_PDP10) /* PDP10 version */
34 #error "DC11 is not supported on the PDP-10!"
35
36 #elif defined (VM_VAX) /* VAX version */
37 #error "DC11 is not supported on the VAX!"
38
39 #else /* PDP-11 version */
40 #include "pdp11_defs.h"
41 #endif
42 #include "sim_sock.h"
43 #include "sim_tmxr.h"
44
45 #define DCX_MASK (DCX_LINES - 1)
46
47 /* Parity and modem control */
48
49 #define DCX_V_OPAR (TTUF_V_UF + 0)
50 #define DCX_V_EPAR (TTUF_V_UF + 1)
51 #define DCX_V_MDM (TTUF_V_UF + 2)
52 #define DCX_OPAR (1u << DCX_V_OPAR)
53 #define DCX_EPAR (1u << DCX_V_EPAR)
54 #define DCX_MDM (1u << DCX_V_MDM)
55
56 /* registers */
57
58 #define DCICSR_RD 0173777
59 #define DCICSR_WR 0003533
60 #define DCICSR_DTR 0000001 /* DTR (RW) */
61 #define DCICSR_XBR 0000002 /* xmit brk (RWNI) */
62 #define DCICSR_CDT 0000004 /* car det (RO) */
63 #define DCICSR_PAR 0000040 /* odd par (RO) */
64 #define DCICSR_OVR 0010000 /* overrun (RO) */
65 #define DCICSR_RNG 0020000 /* ring (RO) */
66 #define DCICSR_CCH 0040000 /* car change (RO) */
67 #define DCICSR_ALLERR (DCICSR_OVR|DCICSR_RNG|DCICSR_CCH)
68 #define DCICSR_ERR 0100000 /* error */
69 #define DCOCSR_RD 0100737
70 #define DCOCSR_WR 0000535
71 #define DCOCSR_RTS 0000001 /* req to send (RW) */
72 #define DCOCSR_CTS 0000002 /* clr to send (RO) */
73 #define DCOCSR_MNT 0000004 /* maint (RWNI) */
74
75 extern int32 int_req[IPL_HLVL];
76 extern int32 tmxr_poll;
77
78 uint16 dci_csr[DCX_LINES] = { 0 }; /* control/status */
79 uint8 dci_buf[DCX_LINES] = { 0 };
80 uint32 dci_ireq = 0;
81 uint16 dco_csr[DCX_LINES] = { 0 }; /* control/status */
82 uint8 dco_buf[DCX_LINES] = { 0 };
83 uint32 dco_ireq = 0;
84 TMLN dcx_ldsc[DCX_LINES] = { 0 }; /* line descriptors */
85 TMXR dcx_desc = { DCX_LINES, 0, 0, dcx_ldsc }; /* mux descriptor */
86
87 static const uint8 odd_par[] = {
88 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 00 */
89 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80,
90 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 10 */
91 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
92 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 20 */
93 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
94 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 30 */
95 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80,
96 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 40 */
97 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
98 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 50 */
99 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80,
100 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 60 */
101 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80,
102 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 70 */
103 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
104 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 80 */
105 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
106 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 90 */
107 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80,
108 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* A0 */
109 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80,
110 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* B0 */
111 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
112 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* C0 */
113 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80,
114 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* D0 */
115 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
116 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* E0 */
117 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
118 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* F0 */
119 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80
120 };
121
122 t_stat dcx_rd (int32 *data, int32 PA, int32 access);
123 t_stat dcx_wr (int32 data, int32 PA, int32 access);
124 t_stat dcx_reset (DEVICE *dptr);
125 t_stat dci_svc (UNIT *uptr);
126 t_stat dco_svc (UNIT *uptr);
127 t_stat dcx_attach (UNIT *uptr, char *cptr);
128 t_stat dcx_detach (UNIT *uptr);
129 t_stat dcx_summ (FILE *st, UNIT *uptr, int32 val, void *desc);
130 t_stat dcx_show (FILE *st, UNIT *uptr, int32 val, void *desc);
131 t_stat dcx_show_vec (FILE *st, UNIT *uptr, int32 val, void *desc);
132 t_stat dcx_set_lines (UNIT *uptr, int32 val, char *cptr, void *desc);
133 t_stat dcx_show_lines (FILE *st, UNIT *uptr, int32 val, void *desc);
134 void dcx_enbdis (int32 dis);
135 void dci_clr_int (int32 ln);
136 void dci_set_int (int32 ln);
137 int32 dci_iack (void);
138 void dco_clr_int (int32 ln);
139 void dco_set_int (int32 ln);
140 int32 dco_iack (void);
141 void dcx_reset_ln (int32 ln);
142
143 /* DCI data structures
144
145 dci_dev DCI device descriptor
146 dci_unit DCI unit descriptor
147 dci_reg DCI register list
148 */
149
150 DIB dci_dib = {
151 IOBA_DC, IOLN_DC, &dcx_rd, &dcx_wr,
152 2, IVCL (DCI), VEC_DCI, { &dci_iack, &dco_iack }
153 };
154
155 UNIT dci_unit = { UDATA (&dci_svc, 0, 0), KBD_POLL_WAIT };
156
157 REG dci_reg[] = {
158 { BRDATA (BUF, dci_buf, DEV_RDX, 8, DCX_LINES) },
159 { BRDATA (CSR, dci_csr, DEV_RDX, 16, DCX_LINES) },
160 { GRDATA (IREQ, dci_ireq, DEV_RDX, DCX_LINES, 0) },
161 { DRDATA (LINES, dcx_desc.lines, 6), REG_HRO },
162 { GRDATA (DEVADDR, dci_dib.ba, DEV_RDX, 32, 0), REG_HRO },
163 { GRDATA (DEVIOLN, dci_dib.lnt, DEV_RDX, 32, 0), REG_HRO },
164 { GRDATA (DEVVEC, dci_dib.vec, DEV_RDX, 16, 0), REG_HRO },
165 { NULL }
166 };
167
168 MTAB dci_mod[] = {
169 { UNIT_ATT, UNIT_ATT, "summary", NULL, NULL, &dcx_summ },
170 { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT",
171 &tmxr_dscln, NULL, &dcx_desc },
172 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL,
173 NULL, &dcx_show, NULL },
174 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL,
175 NULL, &dcx_show, NULL },
176 { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL,
177 &set_addr, &show_addr, NULL },
178 { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL,
179 &set_vec, &dcx_show_vec, NULL },
180 { MTAB_XTD | MTAB_VDV, 0, "lines", "LINES",
181 &dcx_set_lines, &dcx_show_lines },
182 { 0 }
183 };
184
185 DEVICE dci_dev = {
186 "DCI", &dci_unit, dci_reg, dci_mod,
187 1, 10, 31, 1, 8, 8,
188 NULL, NULL, &dcx_reset,
189 NULL, &dcx_attach, &dcx_detach,
190 &dci_dib, DEV_UBUS | DEV_QBUS | DEV_DISABLE | DEV_DIS
191 };
192
193 /* DCO data structures
194
195 dco_dev DCO device descriptor
196 dco_unit DCO unit descriptor
197 dco_reg DCO register list
198 */
199
200 UNIT dco_unit[] = {
201 { UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT },
202 { UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT },
203 { UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT },
204 { UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT },
205 { UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT },
206 { UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT },
207 { UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT },
208 { UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT },
209 { UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT },
210 { UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT },
211 { UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT },
212 { UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT },
213 { UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT },
214 { UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT },
215 { UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT },
216 { UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT }
217 };
218
219 REG dco_reg[] = {
220 { BRDATA (BUF, dco_buf, DEV_RDX, 8, DCX_LINES) },
221 { BRDATA (CSR, dco_csr, DEV_RDX, 16, DCX_LINES) },
222 { GRDATA (IREQ, dco_ireq, DEV_RDX, DCX_LINES, 0) },
223 { URDATA (TIME, dco_unit[0].wait, 10, 31, 0,
224 DCX_LINES, PV_LEFT) },
225 { NULL }
226 };
227
228 MTAB dco_mod[] = {
229 { TT_MODE, TT_MODE_UC, "UC", "UC", NULL },
230 { TT_MODE, TT_MODE_7B, "7b", "7B", NULL },
231 { TT_MODE, TT_MODE_8B, "8b", "8B", NULL },
232 { TT_MODE, TT_MODE_7P, "7p", "7P", NULL },
233 { DCX_OPAR+DCX_EPAR, 0, "no parity", "NOPARITY", NULL },
234 { DCX_OPAR+DCX_EPAR, DCX_OPAR, "odd parity", "ODDPARITY", NULL },
235 { DCX_OPAR+DCX_EPAR, DCX_EPAR, "even parity", "EVENPARITY", NULL },
236 { DCX_MDM, 0, "no dataset", "NODATASET", NULL },
237 { DCX_MDM, DCX_MDM, "dataset", "DATASET", NULL },
238 { MTAB_XTD|MTAB_VUN, 0, NULL, "DISCONNECT",
239 &tmxr_dscln, NULL, &dcx_desc },
240 { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG",
241 &tmxr_set_log, &tmxr_show_log, &dcx_desc },
242 { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG",
243 &tmxr_set_nolog, NULL, &dcx_desc },
244 { 0 }
245 };
246
247 DEVICE dco_dev = {
248 "DCO", dco_unit, dco_reg, dco_mod,
249 DCX_LINES, 10, 31, 1, 8, 8,
250 NULL, NULL, &dcx_reset,
251 NULL, NULL, NULL,
252 NULL, DEV_UBUS | DEV_DISABLE | DEV_DIS
253 };
254
255 /* Terminal input routines */
256
257 t_stat dcx_rd (int32 *data, int32 PA, int32 access)
258 {
259 int32 ln = ((PA - dci_dib.ba) >> 3) & DCX_MASK;
260
261 switch ((PA >> 1) & 03) { /* decode PA<2:1> */
262
263 case 00: /* dci csr */
264 if (dci_csr[ln] & DCICSR_ALLERR)
265 dci_csr[ln] |= DCICSR_ERR;
266 else dci_csr[ln] &= ~DCICSR_ERR;
267 *data = dci_csr[ln] & DCICSR_RD;
268 dci_csr[ln] &= ~(CSR_DONE|DCICSR_ALLERR|DCICSR_ERR);
269 return SCPE_OK;
270
271 case 01: /* dci buf */
272 dci_clr_int (ln);
273 *data = dci_buf[ln];
274 return SCPE_OK;
275
276 case 02: /* dco csr */
277 *data = dco_csr[ln] & DCOCSR_RD;
278 return SCPE_OK;
279
280 case 03: /* dco buf */
281 *data = dco_buf[ln];
282 return SCPE_OK;
283 } /* end switch PA */
284
285 return SCPE_NXM;
286 }
287
288 t_stat dcx_wr (int32 data, int32 PA, int32 access)
289 {
290 int32 ln = ((PA - dci_dib.ba) >> 3) & DCX_MASK;
291 TMLN *lp = &dcx_ldsc[ln];
292
293 switch ((PA >> 1) & 03) { /* decode PA<2:1> */
294
295 case 00: /* dci csr */
296 if (access == WRITEB) /* byte write? */
297 data = (PA & 1)?
298 (dci_csr[ln] & 0377) | (data << 8):
299 (dci_csr[ln] & ~0377) | data;
300 if ((data & CSR_IE) == 0) /* clr ie? */
301 dci_clr_int (ln); /* clr int req */
302 else if ((dci_csr[ln] & (CSR_DONE + CSR_IE)) == CSR_DONE)
303 dci_set_int (ln);
304 if (((data ^ dci_csr[ln]) & DCICSR_DTR) && /* DTR change? */
305 (dco_unit[ln].flags & DCX_MDM)) { /* modem ctl? */
306 if (data & DCICSR_DTR) { /* setting DTR? */
307 if (lp->conn) { /* ringing? */
308 dci_csr[ln] = (dci_csr[ln] & ~DCICSR_RNG) |
309 (DCICSR_CDT|DCICSR_CCH|DCICSR_ERR);
310 dco_csr[ln] |= DCOCSR_CTS; /* set CDT,CCH,CTS */
311 if (data & CSR_IE) /* if ie, req int */
312 dci_set_int (ln);
313 }
314 } /* end DTR 0->1 */
315 else { /* clearing DTR */
316 if (lp->conn) { /* connected? */
317 tmxr_linemsg (lp, "\r\nLine hangup\r\n");
318 tmxr_reset_ln (lp); /* reset line */
319 if (dci_csr[ln] & DCICSR_CDT) { /* carrier det? */
320 dci_csr[ln] |= (DCICSR_CCH|DCICSR_ERR);
321 if (data & CSR_IE) /* if ie, req int */
322 dci_set_int (ln);
323 }
324 }
325 dci_csr[ln] &= ~(DCICSR_CDT|DCICSR_RNG);
326 dco_csr[ln] &= ~DCOCSR_CTS; /* clr CDT,RNG,CTS */
327 } /* end DTR 1->0 */
328 } /* end DTR chg+modem */
329 dci_csr[ln] = (uint16) ((dci_csr[ln] & ~DCICSR_WR) | (data & DCICSR_WR));
330 return SCPE_OK;
331
332 case 01: /* dci buf */
333 return SCPE_OK;
334
335 case 02: /* dco csr */
336 if (access == WRITEB) /* byte write? */
337 data = (PA & 1)?
338 (dco_csr[ln] & 0377) | (data << 8):
339 (dco_csr[ln] & ~0377) | data;
340 if ((data & CSR_IE) == 0) /* clr ie? */
341 dco_clr_int (ln); /* clr int req */
342 else if ((dco_csr[ln] & (CSR_DONE + CSR_IE)) == CSR_DONE)
343 dco_set_int (ln);
344 dco_csr[ln] = (uint16) ((dco_csr[ln] & ~DCOCSR_WR) | (data & DCOCSR_WR));
345 return SCPE_OK;
346
347 case 03: /* dco buf */
348 if ((PA & 1) == 0)
349 dco_buf[ln] = data & 0377;
350 dco_csr[ln] &= ~CSR_DONE; /* clr done */
351 dco_clr_int (ln); /* clr int req */
352 sim_activate (&dco_unit[ln], dco_unit[ln].wait);
353 return SCPE_OK;
354 } /* end switch PA */
355
356 return SCPE_NXM;
357 }
358
359 /* Terminal input service */
360
361 t_stat dci_svc (UNIT *uptr)
362 {
363 int32 ln, c, temp;
364
365 if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
366 return SCPE_OK;
367 sim_activate (uptr, tmxr_poll); /* continue poll */
368 ln = tmxr_poll_conn (&dcx_desc); /* look for connect */
369 if (ln >= 0) { /* got one? */
370 dcx_ldsc[ln].rcve = 1; /* set rcv enb */
371 if (dco_unit[ln].flags & DCX_MDM) { /* modem control? */
372 if (dci_csr[ln] & DCICSR_DTR) /* DTR already set? */
373 dci_csr[ln] |= (DCICSR_CDT|DCICSR_CCH|DCICSR_ERR);
374 else dci_csr[ln] |= (DCICSR_RNG|DCICSR_ERR); /* no, ring */
375 if (dci_csr[ln] & CSR_IE) /* if ie, */
376 dci_set_int (ln); /* req int */
377 }
378 else dco_csr[ln] |= DCOCSR_CTS; /* just connect */
379 }
380 tmxr_poll_rx (&dcx_desc); /* poll for input */
381 for (ln = 0; ln < DCX_LINES; ln++) { /* loop thru lines */
382 if (dcx_ldsc[ln].conn) { /* connected? */
383 if ((temp = tmxr_getc_ln (&dcx_ldsc[ln])) && /* get char */
384 !(temp & SCPE_BREAK)) { /* not break? */
385 c = sim_tt_inpcvt (temp, TT_GET_MODE (dco_unit[ln].flags));
386 if (dci_csr[ln] & CSR_DONE) /* overrun? */
387 dci_csr[ln] |= DCICSR_OVR;
388 else dci_csr[ln] |= CSR_DONE; /* set done */
389 if (dci_csr[ln] & CSR_IE) /* if ie, */
390 dci_set_int (ln); /* req int */
391 if (dco_unit[ln].flags & DCX_OPAR) /* odd parity */
392 c = (c & 0177) | odd_par[c & 0177];
393 else if (dco_unit[ln].flags & DCX_EPAR) /* even parity */
394 c = (c & 0177) | (odd_par[c & 0177] ^ 0200);
395 dci_buf[ln] = c;
396 if ((c & 0200) == odd_par[c & 0177]) /* odd par? */
397 dci_csr[ln] |= DCICSR_PAR;
398 else dci_csr[ln] &= ~DCICSR_PAR;
399 }
400 }
401 else { /* disconnected */
402 if ((dco_unit[ln].flags & DCX_MDM) && /* modem control? */
403 (dci_csr[ln] & DCICSR_CDT)) { /* carrier detect? */
404 dci_csr[ln] |= (DCICSR_CCH|DCICSR_ERR); /* carrier change */
405 if (dci_csr[ln] & CSR_IE) /* if ie, */
406 dci_set_int (ln); /* req int */
407 }
408 dci_csr[ln] &= ~(DCICSR_CDT|DCICSR_RNG); /* clr CDT,RNG,CTS */
409 dco_csr[ln] &= ~DCOCSR_CTS;
410 }
411 }
412 return SCPE_OK;
413 }
414
415 /* Terminal output service */
416
417 t_stat dco_svc (UNIT *uptr)
418 {
419 int32 c;
420 int32 ln = uptr - dco_unit; /* line # */
421
422 if (dcx_ldsc[ln].conn) { /* connected? */
423 if (dcx_ldsc[ln].xmte) { /* tx enabled? */
424 TMLN *lp = &dcx_ldsc[ln]; /* get line */
425 c = sim_tt_outcvt (dco_buf[ln], TT_GET_MODE (dco_unit[ln].flags));
426 if (c >= 0) tmxr_putc_ln (lp, c); /* output char */
427 tmxr_poll_tx (&dcx_desc); /* poll xmt */
428 }
429 else {
430 tmxr_poll_tx (&dcx_desc); /* poll xmt */
431 sim_activate (uptr, dco_unit[ln].wait); /* wait */
432 return SCPE_OK;
433 }
434 }
435 dco_csr[ln] |= CSR_DONE; /* set done */
436 if (dco_csr[ln] & CSR_IE) /* ie set? */
437 dco_set_int (ln); /* req int */
438 return SCPE_OK;
439 }
440
441 /* Interrupt routines */
442
443 void dci_clr_int (int32 ln)
444 {
445 dci_ireq &= ~(1 << ln); /* clr mux rcv int */
446 if (dci_ireq == 0) /* all clr? */
447 CLR_INT (DCI);
448 else SET_INT (DCI); /* no, set intr */
449 return;
450 }
451
452 void dci_set_int (int32 ln)
453 {
454 dci_ireq |= (1 << ln); /* clr mux rcv int */
455 SET_INT (DCI); /* set master intr */
456 return;
457 }
458
459 int32 dci_iack (void)
460 {
461 int32 ln;
462
463 for (ln = 0; ln < DCX_LINES; ln++) { /* find 1st line */
464 if (dci_ireq & (1 << ln)) {
465 dci_clr_int (ln); /* clear intr */
466 return (dci_dib.vec + (ln * 010)); /* return vector */
467 }
468 }
469 return 0;
470 }
471
472 void dco_clr_int (int32 ln)
473 {
474 dco_ireq &= ~(1 << ln); /* clr mux rcv int */
475 if (dco_ireq == 0) /* all clr? */
476 CLR_INT (DCO);
477 else SET_INT (DCO); /* no, set intr */
478 return;
479 }
480
481 void dco_set_int (int32 ln)
482 {
483 dco_ireq |= (1 << ln); /* clr mux rcv int */
484 SET_INT (DCO); /* set master intr */
485 return;
486 }
487
488 int32 dco_iack (void)
489 {
490 int32 ln;
491
492 for (ln = 0; ln < DCX_LINES; ln++) { /* find 1st line */
493 if (dco_ireq & (1 << ln)) {
494 dco_clr_int (ln); /* clear intr */
495 return (dci_dib.vec + (ln * 010) + 4); /* return vector */
496 }
497 }
498 return 0;
499 }
500
501 /* Reset */
502
503 t_stat dcx_reset (DEVICE *dptr)
504 {
505 int32 ln;
506
507 dcx_enbdis (dptr->flags & DEV_DIS); /* sync enables */
508 sim_cancel (&dci_unit); /* assume stop */
509 if (dci_unit.flags & UNIT_ATT) /* if attached, */
510 sim_activate (&dci_unit, tmxr_poll); /* activate */
511 for (ln = 0; ln < DCX_LINES; ln++) /* for all lines */
512 dcx_reset_ln (ln);
513 return auto_config (dci_dev.name, dcx_desc.lines); /* auto config */
514 }
515
516 /* Reset individual line */
517
518 void dcx_reset_ln (int32 ln)
519 {
520 dci_buf[ln] = 0; /* clear buf */
521 dci_csr[ln] = 0;
522 dco_buf[ln] = 0; /* clear buf */
523 dco_csr[ln] = CSR_DONE;
524 sim_cancel (&dco_unit[ln]); /* deactivate */
525 dci_clr_int (ln);
526 dco_clr_int (ln);
527 return;
528 }
529
530 /* Attach master unit */
531
532 t_stat dcx_attach (UNIT *uptr, char *cptr)
533 {
534 t_stat r;
535
536 r = tmxr_attach (&dcx_desc, uptr, cptr); /* attach */
537 if (r != SCPE_OK) /* error? */
538 return r;
539 sim_activate (uptr, tmxr_poll); /* start poll */
540 return SCPE_OK;
541 }
542
543 /* Detach master unit */
544
545 t_stat dcx_detach (UNIT *uptr)
546 {
547 int32 i;
548 t_stat r;
549
550 r = tmxr_detach (&dcx_desc, uptr); /* detach */
551 for (i = 0; i < DCX_LINES; i++) /* all lines, */
552 dcx_ldsc[i].rcve = 0; /* disable rcv */
553 sim_cancel (uptr); /* stop poll */
554 return r;
555 }
556
557 /* Show summary processor */
558
559 t_stat dcx_summ (FILE *st, UNIT *uptr, int32 val, void *desc)
560 {
561 int32 i, t;
562
563 for (i = t = 0; i < DCX_LINES; i++) t = t + (dcx_ldsc[i].conn != 0);
564 if (t == 1) fprintf (st, "1 connection");
565 else fprintf (st, "%d connections", t);
566 return SCPE_OK;
567 }
568
569 /* SHOW CONN/STAT processor */
570
571 t_stat dcx_show (FILE *st, UNIT *uptr, int32 val, void *desc)
572 {
573 int32 i, t;
574
575 for (i = t = 0; i < DCX_LINES; i++) t = t + (dcx_ldsc[i].conn != 0);
576 if (t) {
577 for (i = 0; i < DCX_LINES; i++) {
578 if (dcx_ldsc[i].conn) {
579 if (val) tmxr_fconns (st, &dcx_ldsc[i], i);
580 else tmxr_fstats (st, &dcx_ldsc[i], i);
581 }
582 }
583 }
584 else fprintf (st, "all disconnected\n");
585 return SCPE_OK;
586 }
587
588 /* Enable/disable device */
589
590 void dcx_enbdis (int32 dis)
591 {
592 if (dis) {
593 dci_dev.flags = dco_dev.flags | DEV_DIS;
594 dco_dev.flags = dco_dev.flags | DEV_DIS;
595 }
596 else {
597 dci_dev.flags = dci_dev.flags & ~DEV_DIS;
598 dco_dev.flags = dco_dev.flags & ~DEV_DIS;
599 }
600 return;
601 }
602
603 /* SHOW VECTOR processor */
604
605 t_stat dcx_show_vec (FILE *st, UNIT *uptr, int32 val, void *desc)
606 {
607 return show_vec (st, uptr, dcx_desc.lines * 2, desc);
608 }
609
610 /* Change number of lines */
611
612 t_stat dcx_set_lines (UNIT *uptr, int32 val, char *cptr, void *desc)
613 {
614 int32 newln, i, t;
615 t_stat r;
616
617 if (cptr == NULL) return SCPE_ARG;
618 newln = get_uint (cptr, 10, DCX_LINES, &r);
619 if ((r != SCPE_OK) || (newln == dcx_desc.lines)) return r;
620 if (newln == 0) return SCPE_ARG;
621 if (newln < dcx_desc.lines) {
622 for (i = newln, t = 0; i < dcx_desc.lines; i++) t = t | dcx_ldsc[i].conn;
623 if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE))
624 return SCPE_OK;
625 for (i = newln; i < dcx_desc.lines; i++) {
626 if (dcx_ldsc[i].conn) {
627 tmxr_linemsg (&dcx_ldsc[i], "\r\nOperator disconnected line\r\n");
628 tmxr_reset_ln (&dcx_ldsc[i]); /* reset line */
629 }
630 dco_unit[i].flags |= UNIT_DIS;
631 dcx_reset_ln (i);
632 }
633 }
634 else {
635 for (i = dcx_desc.lines; i < newln; i++) {
636 dco_unit[i].flags &= ~UNIT_DIS;
637 dcx_reset_ln (i);
638 }
639 }
640 dcx_desc.lines = newln;
641 dci_dib.lnt = newln * 010; /* upd IO page lnt */
642 return auto_config (dci_dev.name, newln); /* auto config */
643 }
644
645 /* Show number of lines */
646
647 t_stat dcx_show_lines (FILE *st, UNIT *uptr, int32 val, void *desc)
648 {
649 fprintf (st, "lines=%d", dcx_desc.lines);
650 return SCPE_OK;
651 }