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