1 /* pdp11_dl.c: PDP-11 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    dli,dlo      DL11 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    20-May-2008  RMS     Added modem control support
33 */
34 
35 #if defined (VM_PDP10)                                  /* PDP10 version */
36 #error "DL11 is not supported on the PDP-10!"
37 
38 #elif defined (VM_VAX)                                  /* VAX version */
39 #error "DL11 is not supported on the VAX!"
40 
41 #else                                                   /* PDP-11 version */
42 #include "pdp11_defs.h"
43 #endif
44 #include "sim_sock.h"
45 #include "sim_tmxr.h"
46 
47 #define DLX_MASK        (DLX_LINES - 1)
48 #define DLI_RCI         0                               /* rcv ints */
49 #define DLI_DSI         1                               /* dset ints */
50 
51 /* Modem control */
52 
53 #define DLX_V_MDM       (TTUF_V_UF + 0)
54 #define DLX_MDM         (1u << DLX_V_MDM)
55 
56 /* registers */
57 
58 #define DLICSR_DSI      0100000                         /* dataset int, RO */
59 #define DLICSR_RNG      0040000                         /* ring, RO */
60 #define DLICSR_CTS      0020000                         /* CTS, RO */
61 #define DLICSR_CDT      0010000                         /* CDT, RO */
62 #define DLICSR_SEC      0002000                         /* sec rcv, RONI */
63 #define DLICSR_DSIE     0000040                         /* DSI ie, RW */
64 #define DLICSR_SECX     0000010                         /* sec xmt, RWNI */
65 #define DLICSR_RTS      0000004                         /* RTS, RW */
66 #define DLICSR_DTR      0000002                         /* DTR, RW */
67 #define DLICSR_RD       (CSR_DONE|CSR_IE)               /* DL11C */
68 #define DLICSR_WR       (CSR_IE)
69 #define DLICSR_RD_M     (DLICSR_DSI|DLICSR_RNG|DLICSR_CTS|DLICSR_CDT|DLICSR_SEC| \
70                          CSR_DONE|CSR_IE|DLICSR_DSIE|DLICSR_SECX|DLICSR_RTS|DLICSR_DTR)
71 #define DLICSR_WR_M     (CSR_IE|DLICSR_DSIE|DLICSR_SECX|DLICSR_RTS|DLICSR_DTR)
72 #define DLIBUF_ERR      0100000
73 #define DLIBUF_OVR      0040000
74 #define DLIBUF_RBRK     0020000
75 #define DLIBUF_RD       (DLIBUF_ERR|DLIBUF_OVR|DLIBUF_RBRK|0377)
76 #define DLOCSR_MNT      0000004                         /* maint, RWNI */
77 #define DLOCSR_XBR      0000001                         /* xmit brk, RWNI */
78 #define DLOCSR_RD       (CSR_DONE|CSR_IE|DLOCSR_MNT|DLOCSR_XBR)
79 #define DLOCSR_WR       (CSR_IE|DLOCSR_MNT|DLOCSR_XBR)
80 
81 extern int32 int_req[IPL_HLVL];
82 extern int32 tmxr_poll;
83 
84 uint16 dli_csr[DLX_LINES] = { 0 };                      /* control/status */
85 uint16 dli_buf[DLX_LINES] = { 0 };
86 uint32 dli_ireq[2] = { 0, 0};
87 uint16 dlo_csr[DLX_LINES] = { 0 };                      /* control/status */
88 uint8 dlo_buf[DLX_LINES] = { 0 };
89 uint32 dlo_ireq = 0;
90 TMLN dlx_ldsc[DLX_LINES] = { 0 };                       /* line descriptors */
91 TMXR dlx_desc = { DLX_LINES, 0, 0, dlx_ldsc };          /* mux descriptor */
92 
93 t_stat dlx_rd (int32 *data, int32 PA, int32 access);
94 t_stat dlx_wr (int32 data, int32 PA, int32 access);
95 t_stat dlx_reset (DEVICE *dptr);
96 t_stat dli_svc (UNIT *uptr);
97 t_stat dlo_svc (UNIT *uptr);
98 t_stat dlx_attach (UNIT *uptr, char *cptr);
99 t_stat dlx_detach (UNIT *uptr);
100 t_stat dlx_set_lines (UNIT *uptr, int32 val, char *cptr, void *desc);
101 void dlx_enbdis (int32 dis);
102 void dli_clr_int (int32 ln, uint32 wd);
103 void dli_set_int (int32 ln, uint32 wd);
104 int32 dli_iack (void);
105 void dlo_clr_int (int32 ln);
106 void dlo_set_int (int32 ln);
107 int32 dlo_iack (void);
108 void dlx_reset_ln (int32 ln);
109 
110 /* DLI data structures
111 
112    dli_dev      DLI device descriptor
113    dli_unit     DLI unit descriptor
114    dli_reg      DLI register list
115 */
116 
117 DIB dli_dib = {
118     IOBA_DL, IOLN_DL, &dlx_rd, &dlx_wr,
119     2, IVCL (DLI), VEC_DLI, { &dli_iack, &dlo_iack }
120     };
121 
122 UNIT dli_unit = { UDATA (&dli_svc, 0, 0), KBD_POLL_WAIT };
123 
124 REG dli_reg[] = {
125     { BRDATA (BUF, dli_buf, DEV_RDX, 16, DLX_LINES) },
126     { BRDATA (CSR, dli_csr, DEV_RDX, 16, DLX_LINES) },
127     { GRDATA (IREQ, dli_ireq[DLI_RCI], DEV_RDX, DLX_LINES, 0) },
128     { GRDATA (DSI, dli_ireq[DLI_DSI], DEV_RDX, DLX_LINES, 0) },
129     { DRDATA (LINES, dlx_desc.lines, 6), REG_HRO },
130     { GRDATA (DEVADDR, dli_dib.ba, DEV_RDX, 32, 0), REG_HRO },
131     { GRDATA (DEVIOLN, dli_dib.lnt, DEV_RDX, 32, 0), REG_HRO },
132     { GRDATA (DEVVEC, dli_dib.vec, DEV_RDX, 16, 0), REG_HRO },
133     { NULL }
134     };
135 
136 MTAB dli_mod[] = {
137     { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT",
138       &tmxr_dscln, NULL, &dlx_desc },
139     { UNIT_ATT, UNIT_ATT, "summary", NULL,
140       NULL, &tmxr_show_summ, (void *) &dlx_desc },
141     { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL,
142       NULL, &tmxr_show_cstat, (void *) &dlx_desc },
143     { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL,
144       NULL, &tmxr_show_cstat, (void *) &dlx_desc },
145     { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL,
146       &set_addr, &show_addr, NULL },
147     { MTAB_XTD | MTAB_VDV, 0, NULL, "AUTOCONFIGURE",
148       &set_addr_flt, NULL, NULL },
149     { MTAB_XTD|MTAB_VDV, 1, "VECTOR", NULL,
150       &set_vec, &show_vec_mux, (void *) &dlx_desc },
151     { MTAB_XTD | MTAB_VDV, 0, "LINES", "LINES",
152       &dlx_set_lines, &tmxr_show_lines, (void *) &dlx_desc },
153     { 0 }
154     };
155 
156 DEVICE dli_dev = {
157     "DLI", &dli_unit, dli_reg, dli_mod,
158     1, 10, 31, 1, 8, 8,
159     NULL, NULL, &dlx_reset,
160     NULL, &dlx_attach, &dlx_detach,
161     &dli_dib, DEV_FLTA | DEV_UBUS | DEV_QBUS | DEV_DISABLE | DEV_DIS
162     };
163 
164 /* DLO data structures
165 
166    dlo_dev      DLO device descriptor
167    dlo_unit     DLO unit descriptor
168    dlo_reg      DLO register list
169 */
170 
171 UNIT dlo_unit[] = {
172     { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
173     { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
174     { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
175     { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
176     { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
177     { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
178     { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
179     { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
180     { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
181     { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
182     { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
183     { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
184     { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
185     { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
186     { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
187     { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }
188     };
189 
190 REG dlo_reg[] = {
191     { BRDATA (BUF, dlo_buf, DEV_RDX, 8, DLX_LINES) },
192     { BRDATA (CSR, dlo_csr, DEV_RDX, 16, DLX_LINES) },
193     { GRDATA (IREQ, dlo_ireq, DEV_RDX, DLX_LINES, 0) },
194     { URDATA (TIME, dlo_unit[0].wait, 10, 31, 0,
195               DLX_LINES, PV_LEFT) },
196     { NULL }
197     };
198 
199 MTAB dlo_mod[] = {
200     { TT_MODE, TT_MODE_UC, "UC", "UC", NULL },
201     { TT_MODE, TT_MODE_7B, "7b", "7B", NULL },
202     { TT_MODE, TT_MODE_8B, "8b", "8B", NULL },
203     { TT_MODE, TT_MODE_7P, "7p", "7P", NULL },
204     { DLX_MDM, 0,       "no dataset", "NODATASET", NULL },
205     { DLX_MDM, DLX_MDM, "dataset",    "DATASET",   NULL },
206     { MTAB_XTD|MTAB_VUN, 0, NULL, "DISCONNECT",
207       &tmxr_dscln, NULL, &dlx_desc },
208     { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG",
209       &tmxr_set_log, &tmxr_show_log, &dlx_desc },
210     { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG",
211       &tmxr_set_nolog, NULL, &dlx_desc },
212     { 0 }
213     };
214 
215 DEVICE dlo_dev = {
216     "DLO", dlo_unit, dlo_reg, dlo_mod,
217     DLX_LINES, 10, 31, 1, 8, 8,
218     NULL, NULL, &dlx_reset,
219     NULL, NULL, NULL,
220     NULL, DEV_UBUS | DEV_QBUS | DEV_DISABLE | DEV_DIS
221     };
222 
223 /* Terminal input routines */
224 
dlx_rd(int32 * data,int32 PA,int32 access)225 t_stat dlx_rd (int32 *data, int32 PA, int32 access)
226 {
227 int32 ln = ((PA - dli_dib.ba) >> 3) & DLX_MASK;
228 
229 switch ((PA >> 1) & 03) {                               /* decode PA<2:1> */
230 
231     case 00:                                            /* tti csr */
232         *data = dli_csr[ln] &
233             ((dlo_unit[ln].flags & DLX_MDM)? DLICSR_RD_M: DLICSR_RD);
234         dli_csr[ln] &= ~DLICSR_DSI;                     /* clr DSI flag */
235         dli_clr_int (ln, DLI_DSI);                      /* clr dset int req */
236         return SCPE_OK;
237 
238     case 01:                                            /* tti buf */
239         *data = dli_buf[ln] & DLIBUF_RD;
240         dli_csr[ln] &= ~CSR_DONE;                       /* clr rcv done */
241         dli_clr_int (ln, DLI_RCI);                      /* clr rcv int req */
242         return SCPE_OK;
243 
244     case 02:                                            /* tto csr */
245         *data = dlo_csr[ln] & DLOCSR_RD;
246         return SCPE_OK;
247 
248     case 03:                                            /* tto buf */
249         *data = dlo_buf[ln];
250         return SCPE_OK;
251         }                                               /* end switch PA */
252 
253 return SCPE_NXM;
254 }
255 
dlx_wr(int32 data,int32 PA,int32 access)256 t_stat dlx_wr (int32 data, int32 PA, int32 access)
257 {
258 int32 ln = ((PA - dli_dib.ba) >> 3) & DLX_MASK;
259 TMLN *lp = &dlx_ldsc[ln];
260 
261 switch ((PA >> 1) & 03) {                               /* decode PA<2:1> */
262 
263     case 00:                                            /* tti csr */
264         if (PA & 1)                                     /* odd byte RO */
265             return SCPE_OK;
266         if ((data & CSR_IE) == 0)
267             dli_clr_int (ln, DLI_RCI);
268         else if ((dli_csr[ln] & (CSR_DONE + CSR_IE)) == CSR_DONE)
269             dli_set_int (ln, DLI_RCI);
270         if (dlo_unit[ln].flags & DLX_MDM) {             /* modem control */
271             if ((data & DLICSR_DSIE) == 0)
272                 dli_clr_int (ln, DLI_DSI);
273             else if ((dli_csr[ln] & (DLICSR_DSI|DLICSR_DSIE)) == DLICSR_DSI)
274                 dli_set_int (ln, DLI_DSI);
275             if ((data ^ dli_csr[ln]) & DLICSR_DTR) {    /* DTR change? */
276                 if ((data & DLICSR_DTR) && lp->conn) {  /* setting DTR? */
277                     dli_csr[ln] = (dli_csr[ln] & ~DLICSR_RNG) |
278                         (DLICSR_CDT|DLICSR_CTS|DLICSR_DSI);
279                     if (data & DLICSR_DSIE)             /* if ie, req int */
280                         dli_set_int (ln, DLI_DSI);
281                     }                                   /* end DTR 0->1 + ring */
282                 else {                                  /* clearing DTR */
283                     if (lp->conn) {                     /* connected? */
284                         tmxr_linemsg (lp, "\r\nLine hangup\r\n");
285                         tmxr_reset_ln (lp);             /* reset line */
286                         if (dli_csr[ln] & DLICSR_CDT) { /* carrier det? */
287                             dli_csr[ln] |= DLICSR_DSI;
288                             if (data & DLICSR_DSIE)     /* if ie, req int */
289                                 dli_set_int (ln, DLI_DSI);
290                             }
291                         }
292                     dli_csr[ln] &= ~(DLICSR_CDT|DLICSR_RNG|DLICSR_CTS);
293                                                         /* clr CDT,RNG,CTS */
294                     }                                   /* end DTR 1->0 */
295                 }                                       /* end DTR chg */
296             dli_csr[ln] = (uint16) ((dli_csr[ln] & ~DLICSR_WR_M) | (data & DLICSR_WR_M));
297             }                                           /* end modem */
298         dli_csr[ln] = (uint16) ((dli_csr[ln] & ~DLICSR_WR) | (data & DLICSR_WR));
299         return SCPE_OK;
300 
301     case 01:                                            /* tti buf */
302         return SCPE_OK;
303 
304     case 02:                                            /* tto csr */
305         if (PA & 1)
306             return SCPE_OK;
307         if ((data & CSR_IE) == 0)
308             dlo_clr_int (ln);
309         else if ((dlo_csr[ln] & (CSR_DONE + CSR_IE)) == CSR_DONE)
310             dlo_set_int (ln);
311         dlo_csr[ln] = (uint16) ((dlo_csr[ln] & ~DLOCSR_WR) | (data & DLOCSR_WR));
312         return SCPE_OK;
313 
314     case 03:                                            /* tto buf */
315         if ((PA & 1) == 0)
316             dlo_buf[ln] = data & 0377;
317         dlo_csr[ln] &= ~CSR_DONE;
318         dlo_clr_int (ln);
319         sim_activate (&dlo_unit[ln], dlo_unit[ln].wait);
320         return SCPE_OK;
321         }                                               /* end switch PA */
322 
323 return SCPE_NXM;
324 }
325 
326 /* Terminal input service */
327 
dli_svc(UNIT * uptr)328 t_stat dli_svc (UNIT *uptr)
329 {
330 int32 ln, c, temp;
331 
332 if ((uptr->flags & UNIT_ATT) == 0)                      /* attached? */
333     return SCPE_OK;
334 sim_activate (uptr, clk_cosched (tmxr_poll));           /* continue poll */
335 ln = tmxr_poll_conn (&dlx_desc);                        /* look for connect */
336 if (ln >= 0) {                                          /* got one? rcv enb */
337     dlx_ldsc[ln].rcve = 1;
338     if (dlo_unit[ln].flags & DLX_MDM) {                 /* modem control? */
339         if (dli_csr[ln] & DLICSR_DTR)                   /* DTR already set? */
340             dli_csr[ln] |= (DLICSR_CDT|DLICSR_CTS|DLICSR_DSI);
341         else dli_csr[ln] |= (DLICSR_RNG|DLICSR_DSI);    /* no, ring */
342         if (dli_csr[ln] & DLICSR_DSIE)                  /* if ie, */
343             dli_set_int (ln, DLI_DSI);                  /* req int */
344         }                                               /* end modem */
345     }                                                   /* end new conn */
346 tmxr_poll_rx (&dlx_desc);                               /* poll for input */
347 for (ln = 0; ln < DLX_LINES; ln++) {                    /* loop thru lines */
348     if (dlx_ldsc[ln].conn) {                            /* connected? */
349         if ((temp = tmxr_getc_ln (&dlx_ldsc[ln]))) {    /* get char */
350             if (temp & SCPE_BREAK)                      /* break? */
351                 c = DLIBUF_ERR|DLIBUF_RBRK;
352             else c = sim_tt_inpcvt (temp, TT_GET_MODE (dlo_unit[ln].flags));
353             if (dli_csr[ln] & CSR_DONE)
354                 c |= DLIBUF_ERR|DLIBUF_OVR;
355             else dli_csr[ln] |= CSR_DONE;
356             if (dli_csr[ln] & CSR_IE)
357                 dli_set_int (ln, DLI_RCI);
358             dli_buf[ln] = c;
359             }
360         }
361     else if (dlo_unit[ln].flags & DLX_MDM) {            /* discpnn & modem? */
362         if (dli_csr[ln] & DLICSR_CDT) {                 /* carrier detect? */
363             dli_csr[ln] |= DLICSR_DSI;                  /* dataset change */
364             if (dli_csr[ln] & DLICSR_DSIE)              /* if ie, */
365                 dli_set_int (ln, DLI_DSI);              /* req int */
366             }
367         dli_csr[ln] &= ~(DLICSR_CDT|DLICSR_RNG|DLICSR_CTS);
368                                                         /* clr CDT,RNG,CTS */
369         }
370     }
371 return SCPE_OK;
372 }
373 
374 /* Terminal output service */
375 
dlo_svc(UNIT * uptr)376 t_stat dlo_svc (UNIT *uptr)
377 {
378 int32 c;
379 int32 ln = uptr - dlo_unit;                             /* line # */
380 
381 if (dlx_ldsc[ln].conn) {                                /* connected? */
382     if (dlx_ldsc[ln].xmte) {                            /* tx enabled? */
383         TMLN *lp = &dlx_ldsc[ln];                       /* get line */
384         c = sim_tt_outcvt (dlo_buf[ln], TT_GET_MODE (dlo_unit[ln].flags));
385         if (c >= 0)                                     /* output char */
386             tmxr_putc_ln (lp, c);
387         tmxr_poll_tx (&dlx_desc);                       /* poll xmt */
388         }
389     else {
390         tmxr_poll_tx (&dlx_desc);                       /* poll xmt */
391         sim_activate (uptr, dlo_unit[ln].wait);         /* wait */
392         return SCPE_OK;
393         }
394     }
395 dlo_csr[ln] |= CSR_DONE;                                /* set done */
396 if (dlo_csr[ln] & CSR_IE)
397     dlo_set_int (ln);
398 return SCPE_OK;
399 }
400 
401 /* Interrupt routines */
402 
dli_clr_int(int32 ln,uint32 wd)403 void dli_clr_int (int32 ln, uint32 wd)
404 {
405 dli_ireq[wd] &= ~(1 << ln);                             /* clr rcv/dset int */
406 if ((dli_ireq[DLI_RCI] | dli_ireq[DLI_DSI]) == 0)       /* all clr? */
407     CLR_INT (DLI);                                      /* all clr? */
408 else SET_INT (DLI);                                     /* no, set intr */
409 return;
410 }
411 
dli_set_int(int32 ln,uint32 wd)412 void dli_set_int (int32 ln, uint32 wd)
413 {
414 dli_ireq[wd] |= (1 << ln);                              /* set rcv/dset int */
415 SET_INT (DLI);                                          /* set master intr */
416 return;
417 }
418 
dli_iack(void)419 int32 dli_iack (void)
420 {
421 int32 ln;
422 
423 for (ln = 0; ln < DLX_LINES; ln++) {                    /* find 1st line */
424     if ((dli_ireq[DLI_RCI] | dli_ireq[DLI_DSI]) & (1 << ln)) {
425         dli_clr_int (ln, DLI_RCI);                      /* clr both req */
426         dli_clr_int (ln, DLI_DSI);
427         return (dli_dib.vec + (ln * 010));              /* return vector */
428         }
429     }
430 return 0;
431 }
432 
dlo_clr_int(int32 ln)433 void dlo_clr_int (int32 ln)
434 {
435 dlo_ireq &= ~(1 << ln);                                 /* clr xmit int */
436 if (dlo_ireq == 0)                                      /* all clr? */
437     CLR_INT (DLO);
438 else SET_INT (DLO);                                     /* no, set intr */
439 return;
440 }
441 
dlo_set_int(int32 ln)442 void dlo_set_int (int32 ln)
443 {
444 dlo_ireq |= (1 << ln);                                  /* set xmit int */
445 SET_INT (DLO);                                          /* set master intr */
446 return;
447 }
448 
dlo_iack(void)449 int32 dlo_iack (void)
450 {
451 int32 ln;
452 
453 for (ln = 0; ln < DLX_LINES; ln++) {                    /* find 1st line */
454     if (dlo_ireq & (1 << ln)) {
455         dlo_clr_int (ln);                               /* clear intr */
456         return (dli_dib.vec + (ln * 010) + 4);          /* return vector */
457         }
458     }
459 return 0;
460 }
461 
462 /* Reset */
463 
dlx_reset(DEVICE * dptr)464 t_stat dlx_reset (DEVICE *dptr)
465 {
466 int32 ln;
467 
468 dlx_enbdis (dptr->flags & DEV_DIS);                     /* sync enables */
469 sim_cancel (&dli_unit);                                 /* assume stop */
470 if (dli_unit.flags & UNIT_ATT)                          /* if attached, */
471     sim_activate (&dli_unit, tmxr_poll);                /* activate */
472 for (ln = 0; ln < DLX_LINES; ln++)                      /* for all lines */
473     dlx_reset_ln (ln);
474 return auto_config (dli_dev.name, dlx_desc.lines);      /* auto config */
475 }
476 
477 /* Reset individual line */
478 
dlx_reset_ln(int32 ln)479 void dlx_reset_ln (int32 ln)
480 {
481 dli_buf[ln] = 0;                                        /* clear buf */
482 if (dlo_unit[ln].flags & DLX_MDM)                       /* modem */
483     dli_csr[ln] &= DLICSR_DTR;                          /* dont clr DTR */
484 else dli_csr[ln] = 0;
485 dlo_buf[ln] = 0;                                        /* clear buf */
486 dlo_csr[ln] = CSR_DONE;
487 sim_cancel (&dlo_unit[ln]);                             /* deactivate */
488 dli_clr_int (ln, DLI_RCI);
489 dli_clr_int (ln, DLI_DSI);
490 dlo_clr_int (ln);
491 return;
492 }
493 
494 /* Attach master unit */
495 
dlx_attach(UNIT * uptr,char * cptr)496 t_stat dlx_attach (UNIT *uptr, char *cptr)
497 {
498 t_stat r;
499 
500 r = tmxr_attach (&dlx_desc, uptr, cptr);                /* attach */
501 if (r != SCPE_OK)                                       /* error */
502     return r;
503 sim_activate (uptr, tmxr_poll);                         /* start poll */
504 return SCPE_OK;
505 }
506 
507 /* Detach master unit */
508 
dlx_detach(UNIT * uptr)509 t_stat dlx_detach (UNIT *uptr)
510 {
511 int32 i;
512 t_stat r;
513 
514 r = tmxr_detach (&dlx_desc, uptr);                      /* detach */
515 for (i = 0; i < DLX_LINES; i++)                         /* all lines, */
516     dlx_ldsc[i].rcve = 0;                               /* disable rcv */
517 sim_cancel (uptr);                                      /* stop poll */
518 return r;
519 }
520 
521 /* Enable/disable device */
522 
dlx_enbdis(int32 dis)523 void dlx_enbdis (int32 dis)
524 {
525 if (dis) {
526     dli_dev.flags = dli_dev.flags | DEV_DIS;
527     dlo_dev.flags = dlo_dev.flags | DEV_DIS;
528     }
529 else {
530     dli_dev.flags = dli_dev.flags & ~DEV_DIS;
531     dlo_dev.flags = dlo_dev.flags & ~DEV_DIS;
532     }
533 return;
534 }
535 
536 /* Change number of lines */
537 
dlx_set_lines(UNIT * uptr,int32 val,char * cptr,void * desc)538 t_stat dlx_set_lines (UNIT *uptr, int32 val, char *cptr, void *desc)
539 {
540 int32 newln, i, t;
541 t_stat r;
542 
543 if (cptr == NULL)
544     return SCPE_ARG;
545 newln = get_uint (cptr, 10, DLX_LINES, &r);
546 if ((r != SCPE_OK) || (newln == dlx_desc.lines))
547     return r;
548 if (newln == 0)
549     return SCPE_ARG;
550 if (newln < dlx_desc.lines) {
551     for (i = newln, t = 0; i < dlx_desc.lines; i++)
552         t = t | dlx_ldsc[i].conn;
553     if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE))
554         return SCPE_OK;
555     for (i = newln; i < dlx_desc.lines; i++) {
556         if (dlx_ldsc[i].conn) {
557             tmxr_linemsg (&dlx_ldsc[i], "\r\nOperator disconnected line\r\n");
558             tmxr_reset_ln (&dlx_ldsc[i]);               /* reset line */
559             }
560         dlo_unit[i].flags |= UNIT_DIS;
561         dlx_reset_ln (i);
562         }
563     }
564 else {
565     for (i = dlx_desc.lines; i < newln; i++) {
566         dlo_unit[i].flags &= ~UNIT_DIS;
567         dlx_reset_ln (i);
568         }
569     }
570 dlx_desc.lines = newln;
571 dli_dib.lnt = newln * 010;                             /* upd IO page lnt */
572 return auto_config (dli_dev.name, newln);              /* auto config */
573 }
574