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