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