First Commit of my working state
[simh.git] / PDP11 / pdp11_dz.c
1 /* pdp11_dz.c: DZ11 terminal multiplexor simulator
2
3 Copyright (c) 2001-2007, 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 dz DZ11 terminal multiplexor
27
28 18-Jun-07 RMS Added UNIT_IDLE flag
29 29-Oct-06 RMS Synced poll and clock
30 22-Nov-05 RMS Revised for new terminal processing routines
31 07-Jul-05 RMS Removed extraneous externs
32 15-Jun-05 RMS Revised for new autoconfigure interface
33 04-Apr-04 RMS Added per-line logging
34 05-Jan-04 RMS Revised for tmxr library changes
35 19-May-03 RMS Revised for new conditional compilation scheme
36 09-May-03 RMS Added network device flag
37 22-Dec-02 RMS Added break (framing error) support
38 31-Oct-02 RMS Added 8b support
39 12-Oct-02 RMS Added autoconfigure support
40 29-Sep-02 RMS Fixed bug in set number of lines routine
41 Added variable vector support
42 New data structures
43 22-Apr-02 RMS Updated for changes in sim_tmxr
44 28-Apr-02 RMS Fixed interrupt acknowledge, fixed SHOW DZ ADDRESS
45 14-Jan-02 RMS Added multiboard support
46 30-Dec-01 RMS Added show statistics, set disconnect
47 Removed statistics registers
48 03-Dec-01 RMS Modified for extended SET/SHOW
49 09-Nov-01 RMS Added VAX support
50 20-Oct-01 RMS Moved getchar from sim_tmxr, changed interrupt
51 logic to use tmxr_rqln
52 06-Oct-01 RMS Fixed bug in carrier detect logic
53 03-Oct-01 RMS Added support for BSD-style "ringless" modems
54 27-Sep-01 RMS Fixed bug in xmte initialization
55 17-Sep-01 RMS Added separate autodisconnect switch
56 16-Sep-01 RMS Fixed modem control bit offsets
57 */
58
59 #if defined (VM_PDP10) /* PDP10 version */
60 #include "pdp10_defs.h"
61 #define RANK_DZ 0 /* no autoconfig */
62 #define DZ_8B_DFLT 0
63 extern int32 int_req;
64
65 #elif defined (VM_VAX) /* VAX version */
66 #include "vax_defs.h"
67 #define DZ_8B_DFLT TT_MODE_8B
68 extern int32 int_req[IPL_HLVL];
69
70 #else /* PDP-11 version */
71 #include "pdp11_defs.h"
72 #define DZ_8B_DFLT TT_MODE_8B
73 extern int32 int_req[IPL_HLVL];
74 #endif
75
76 #include "sim_sock.h"
77 #include "sim_tmxr.h"
78
79 #if !defined (DZ_MUXES)
80 #define DZ_MUXES 1
81 #endif
82 #if !defined (DZ_LINES)
83 #define DZ_LINES 8
84 #endif
85
86 #define DZ_MNOMASK (DZ_MUXES - 1) /* mask for mux no */
87 #define DZ_LNOMASK (DZ_LINES - 1) /* mask for lineno */
88 #define DZ_LMASK ((1 << DZ_LINES) - 1) /* mask of lines */
89 #define DZ_SILO_ALM 16 /* silo alarm level */
90
91 /* DZCSR - 160100 - control/status register */
92
93 #define CSR_MAINT 0000010 /* maint - NI */
94 #define CSR_CLR 0000020 /* clear */
95 #define CSR_MSE 0000040 /* master scan enb */
96 #define CSR_RIE 0000100 /* rcv int enb */
97 #define CSR_RDONE 0000200 /* rcv done - RO */
98 #define CSR_V_TLINE 8 /* xmit line - RO */
99 #define CSR_TLINE (DZ_LNOMASK << CSR_V_TLINE)
100 #define CSR_SAE 0010000 /* silo alm enb */
101 #define CSR_SA 0020000 /* silo alm - RO */
102 #define CSR_TIE 0040000 /* xmit int enb */
103 #define CSR_TRDY 0100000 /* xmit rdy - RO */
104 #define CSR_RW (CSR_MSE | CSR_RIE | CSR_SAE | CSR_TIE)
105 #define CSR_MBZ (0004003 | CSR_CLR | CSR_MAINT)
106
107 #define CSR_GETTL(x) (((x) >> CSR_V_TLINE) & DZ_LNOMASK)
108 #define CSR_PUTTL(x,y) x = ((x) & ~CSR_TLINE) | (((y) & DZ_LNOMASK) << CSR_V_TLINE)
109
110 /* DZRBUF - 160102 - receive buffer, read only */
111
112 #define RBUF_CHAR 0000377 /* rcv char */
113 #define RBUF_V_RLINE 8 /* rcv line */
114 #define RBUF_PARE 0010000 /* parity err - NI */
115 #define RBUF_FRME 0020000 /* frame err */
116 #define RBUF_OVRE 0040000 /* overrun err - NI */
117 #define RBUF_VALID 0100000 /* rcv valid */
118 #define RBUF_MBZ 0004000
119
120 /* DZLPR - 160102 - line parameter register, write only, word access only */
121
122 #define LPR_V_LINE 0 /* line */
123 #define LPR_LPAR 0007770 /* line pars - NI */
124 #define LPR_RCVE 0010000 /* receive enb */
125 #define LPR_GETLN(x) (((x) >> LPR_V_LINE) & DZ_LNOMASK)
126
127 /* DZTCR - 160104 - transmission control register */
128
129 #define TCR_V_XMTE 0 /* xmit enables */
130 #define TCR_V_DTR 8 /* DTRs */
131
132 /* DZMSR - 160106 - modem status register, read only */
133
134 #define MSR_V_RI 0 /* ring indicators */
135 #define MSR_V_CD 8 /* carrier detect */
136
137 /* DZTDR - 160106 - transmit data, write only */
138
139 #define TDR_CHAR 0000377 /* xmit char */
140 #define TDR_V_TBR 8 /* xmit break - NI */
141
142 extern int32 IREQ (HLVL);
143 extern int32 sim_switches;
144 extern FILE *sim_log;
145 extern int32 tmxr_poll; /* calibrated delay */
146
147 uint16 dz_csr[DZ_MUXES] = { 0 }; /* csr */
148 uint16 dz_rbuf[DZ_MUXES] = { 0 }; /* rcv buffer */
149 uint16 dz_lpr[DZ_MUXES] = { 0 }; /* line param */
150 uint16 dz_tcr[DZ_MUXES] = { 0 }; /* xmit control */
151 uint16 dz_msr[DZ_MUXES] = { 0 }; /* modem status */
152 uint16 dz_tdr[DZ_MUXES] = { 0 }; /* xmit data */
153 uint8 dz_sae[DZ_MUXES] = { 0 }; /* silo alarm enabled */
154 uint32 dz_rxi = 0; /* rcv interrupts */
155 uint32 dz_txi = 0; /* xmt interrupts */
156 int32 dz_mctl = 0; /* modem ctrl enabled */
157 int32 dz_auto = 0; /* autodiscon enabled */
158 TMLN dz_ldsc[DZ_MUXES * DZ_LINES] = { 0 }; /* line descriptors */
159 TMXR dz_desc = { DZ_MUXES * DZ_LINES, 0, 0, dz_ldsc }; /* mux descriptor */
160
161 DEVICE dz_dev;
162 t_stat dz_rd (int32 *data, int32 PA, int32 access);
163 t_stat dz_wr (int32 data, int32 PA, int32 access);
164 int32 dz_rxinta (void);
165 int32 dz_txinta (void);
166 t_stat dz_svc (UNIT *uptr);
167 t_stat dz_reset (DEVICE *dptr);
168 t_stat dz_attach (UNIT *uptr, char *cptr);
169 t_stat dz_detach (UNIT *uptr);
170 t_stat dz_clear (int32 dz, t_bool flag);
171 int32 dz_getc (int32 dz);
172 void dz_update_rcvi (void);
173 void dz_update_xmti (void);
174 void dz_clr_rxint (int32 dz);
175 void dz_set_rxint (int32 dz);
176 void dz_clr_txint (int32 dz);
177 void dz_set_txint (int32 dz);
178 t_stat dz_summ (FILE *st, UNIT *uptr, int32 val, void *desc);
179 t_stat dz_show (FILE *st, UNIT *uptr, int32 val, void *desc);
180 t_stat dz_show_vec (FILE *st, UNIT *uptr, int32 val, void *desc);
181 t_stat dz_setnl (UNIT *uptr, int32 val, char *cptr, void *desc);
182 t_stat dz_set_log (UNIT *uptr, int32 val, char *cptr, void *desc);
183 t_stat dz_set_nolog (UNIT *uptr, int32 val, char *cptr, void *desc);
184 t_stat dz_show_log (FILE *st, UNIT *uptr, int32 val, void *desc);
185
186 /* DZ data structures
187
188 dz_dev DZ device descriptor
189 dz_unit DZ unit list
190 dz_reg DZ register list
191 */
192
193 DIB dz_dib = {
194 IOBA_DZ, IOLN_DZ * DZ_MUXES, &dz_rd, &dz_wr,
195 2, IVCL (DZRX), VEC_DZRX, { &dz_rxinta, &dz_txinta }
196 };
197
198 UNIT dz_unit = { UDATA (&dz_svc, UNIT_IDLE|UNIT_ATTABLE|DZ_8B_DFLT, 0) };
199
200 REG dz_nlreg = { DRDATA (NLINES, dz_desc.lines, 6), PV_LEFT };
201
202 REG dz_reg[] = {
203 { BRDATA (CSR, dz_csr, DEV_RDX, 16, DZ_MUXES) },
204 { BRDATA (RBUF, dz_rbuf, DEV_RDX, 16, DZ_MUXES) },
205 { BRDATA (LPR, dz_lpr, DEV_RDX, 16, DZ_MUXES) },
206 { BRDATA (TCR, dz_tcr, DEV_RDX, 16, DZ_MUXES) },
207 { BRDATA (MSR, dz_msr, DEV_RDX, 16, DZ_MUXES) },
208 { BRDATA (TDR, dz_tdr, DEV_RDX, 16, DZ_MUXES) },
209 { BRDATA (SAENB, dz_sae, DEV_RDX, 1, DZ_MUXES) },
210 { GRDATA (RXINT, dz_rxi, DEV_RDX, DZ_MUXES, 0) },
211 { GRDATA (TXINT, dz_txi, DEV_RDX, DZ_MUXES, 0) },
212 { FLDATA (MDMCTL, dz_mctl, 0) },
213 { FLDATA (AUTODS, dz_auto, 0) },
214 { GRDATA (DEVADDR, dz_dib.ba, DEV_RDX, 32, 0), REG_HRO },
215 { GRDATA (DEVVEC, dz_dib.vec, DEV_RDX, 16, 0), REG_HRO },
216 { NULL }
217 };
218
219 MTAB dz_mod[] = {
220 { TT_MODE, TT_MODE_7B, "7b", "7B", NULL },
221 { TT_MODE, TT_MODE_8B, "8b", "8B", NULL },
222 { TT_MODE, TT_MODE_7P, "7p", "7P", NULL },
223 { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT",
224 &tmxr_dscln, NULL, &dz_desc },
225 { UNIT_ATT, UNIT_ATT, "connections", NULL, NULL, &dz_summ },
226 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL,
227 NULL, &dz_show, NULL },
228 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL,
229 NULL, &dz_show, NULL },
230 { MTAB_XTD|MTAB_VDV, 010, "ADDRESS", "ADDRESS",
231 &set_addr, &show_addr, NULL },
232 { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR",
233 &set_vec, &dz_show_vec, NULL },
234 #if !defined (VM_PDP10)
235 { MTAB_XTD | MTAB_VDV, 0, NULL, "AUTOCONFIGURE",
236 &set_addr_flt, NULL, NULL },
237 #endif
238 { MTAB_XTD | MTAB_VDV | MTAB_VAL, 0, "lines", "LINES",
239 &dz_setnl, NULL, &dz_nlreg },
240 { MTAB_XTD | MTAB_VDV, 0, NULL, "LOG",
241 &dz_set_log, NULL, &dz_desc },
242 { MTAB_XTD | MTAB_VDV, 0, NULL, "NOLOG",
243 &dz_set_nolog, NULL, &dz_desc },
244 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "LOG", NULL,
245 NULL, &dz_show_log, &dz_desc },
246 { 0 }
247 };
248
249 DEVICE dz_dev = {
250 "DZ", &dz_unit, dz_reg, dz_mod,
251 1, DEV_RDX, 8, 1, DEV_RDX, 8,
252 &tmxr_ex, &tmxr_dep, &dz_reset,
253 NULL, &dz_attach, &dz_detach,
254 &dz_dib, DEV_FLTA | DEV_DISABLE | DEV_NET | DEV_UBUS | DEV_QBUS
255 };
256
257 /* IO dispatch routines, I/O addresses 177601x0 - 177601x7 */
258
259 t_stat dz_rd (int32 *data, int32 PA, int32 access)
260 {
261 int32 dz = ((PA - dz_dib.ba) >> 3) & DZ_MNOMASK; /* get mux num */
262
263 switch ((PA >> 1) & 03) { /* case on PA<2:1> */
264
265 case 00: /* CSR */
266 *data = dz_csr[dz] = dz_csr[dz] & ~CSR_MBZ;
267 break;
268
269 case 01: /* RBUF */
270 dz_csr[dz] = dz_csr[dz] & ~CSR_SA; /* clr silo alarm */
271 if (dz_csr[dz] & CSR_MSE) { /* scanner on? */
272 dz_rbuf[dz] = dz_getc (dz); /* get top of silo */
273 if (!dz_rbuf[dz]) dz_sae[dz] = 1; /* empty? re-enable */
274 tmxr_poll_rx (&dz_desc); /* poll input */
275 dz_update_rcvi (); /* update rx intr */
276 }
277 else {
278 dz_rbuf[dz] = 0; /* no data */
279 dz_update_rcvi (); /* no rx intr */
280 }
281 *data = dz_rbuf[dz];
282 break;
283
284 case 02: /* TCR */
285 *data = dz_tcr[dz];
286 break;
287
288 case 03: /* MSR */
289 *data = dz_msr[dz];
290 break;
291 }
292
293 return SCPE_OK;
294 }
295
296 t_stat dz_wr (int32 data, int32 PA, int32 access)
297 {
298 int32 dz = ((PA - dz_dib.ba) >> 3) & DZ_MNOMASK; /* get mux num */
299 int32 i, c, line;
300 TMLN *lp;
301
302 switch ((PA >> 1) & 03) { /* case on PA<2:1> */
303
304 case 00: /* CSR */
305 if (access == WRITEB) data = (PA & 1)? /* byte? merge */
306 (dz_csr[dz] & 0377) | (data << 8):
307 (dz_csr[dz] & ~0377) | data;
308 if (data & CSR_CLR) dz_clear (dz, FALSE); /* clr? reset */
309 if (data & CSR_MSE) /* MSE? start poll */
310 sim_activate (&dz_unit, clk_cosched (tmxr_poll));
311 else dz_csr[dz] &= ~(CSR_SA | CSR_RDONE | CSR_TRDY);
312 if ((data & CSR_RIE) == 0) dz_clr_rxint (dz); /* RIE = 0? */
313 else if (((dz_csr[dz] & CSR_IE) == 0) && /* RIE 0->1? */
314 ((dz_csr[dz] & CSR_SAE)?
315 (dz_csr[dz] & CSR_SA): (dz_csr[dz] & CSR_RDONE)))
316 dz_set_rxint (dz);
317 if ((data & CSR_TIE) == 0) dz_clr_txint (dz); /* TIE = 0? */
318 else if (((dz_csr[dz] & CSR_TIE) == 0) && (dz_csr[dz] & CSR_TRDY))
319 dz_set_txint (dz);
320 dz_csr[dz] = (dz_csr[dz] & ~CSR_RW) | (data & CSR_RW);
321 break;
322
323 case 01: /* LPR */
324 dz_lpr[dz] = data;
325 line = (dz * DZ_LINES) + LPR_GETLN (data); /* get line num */
326 lp = &dz_ldsc[line]; /* get line desc */
327 if (dz_lpr[dz] & LPR_RCVE) lp->rcve = 1; /* rcv enb? on */
328 else lp->rcve = 0; /* else line off */
329 tmxr_poll_rx (&dz_desc); /* poll input */
330 dz_update_rcvi (); /* update rx intr */
331 break;
332
333 case 02: /* TCR */
334 if (access == WRITEB) data = (PA & 1)? /* byte? merge */
335 (dz_tcr[dz] & 0377) | (data << 8):
336 (dz_tcr[dz] & ~0377) | data;
337 if (dz_mctl) { /* modem ctl? */
338 dz_msr[dz] |= ((data & 0177400) & /* dcd |= dtr & ring */
339 ((dz_msr[dz] & DZ_LMASK) << MSR_V_CD));
340 dz_msr[dz] &= ~(data >> TCR_V_DTR); /* ring &= ~dtr */
341 if (dz_auto) { /* auto disconnect? */
342 int32 drop;
343 drop = (dz_tcr[dz] & ~data) >> TCR_V_DTR; /* drop = dtr & ~data */
344 for (i = 0; i < DZ_LINES; i++) { /* drop hangups */
345 line = (dz * DZ_LINES) + i; /* get line num */
346 lp = &dz_ldsc[line]; /* get line desc */
347 if (lp->conn && (drop & (1 << i))) {
348 tmxr_linemsg (lp, "\r\nLine hangup\r\n");
349 tmxr_reset_ln (lp); /* reset line, cdet */
350 dz_msr[dz] &= ~(1 << (i + MSR_V_CD));
351 } /* end if drop */
352 } /* end for */
353 } /* end if auto */
354 } /* end if modem */
355 dz_tcr[dz] = data;
356 tmxr_poll_tx (&dz_desc); /* poll output */
357 dz_update_xmti (); /* update int */
358 break;
359
360 case 03: /* TDR */
361 if (PA & 1) { /* odd byte? */
362 dz_tdr[dz] = (dz_tdr[dz] & 0377) | (data << 8); /* just save */
363 break;
364 }
365 dz_tdr[dz] = data;
366 if (dz_csr[dz] & CSR_MSE) { /* enabled? */
367 line = (dz * DZ_LINES) + CSR_GETTL (dz_csr[dz]);
368 lp = &dz_ldsc[line]; /* get line desc */
369 c = sim_tt_outcvt (dz_tdr[dz], TT_GET_MODE (dz_unit.flags));
370 if (c >= 0) tmxr_putc_ln (lp, c); /* store char */
371 tmxr_poll_tx (&dz_desc); /* poll output */
372 dz_update_xmti (); /* update int */
373 }
374 break;
375 }
376
377 return SCPE_OK;
378 }
379
380 /* Unit service routine
381
382 The DZ11 polls to see if asynchronous activity has occurred and now
383 needs to be processed. The polling interval is controlled by the clock
384 simulator, so for most environments, it is calibrated to real time.
385 Typical polling intervals are 50-60 times per second.
386
387 The simulator assumes that software enables all of the multiplexors,
388 or none of them.
389 */
390
391 t_stat dz_svc (UNIT *uptr)
392 {
393 int32 dz, t, newln;
394
395 for (dz = t = 0; dz < DZ_MUXES; dz++) /* check enabled */
396 t = t | (dz_csr[dz] & CSR_MSE);
397 if (t) { /* any enabled? */
398 newln = tmxr_poll_conn (&dz_desc); /* poll connect */
399 if ((newln >= 0) && dz_mctl) { /* got a live one? */
400 dz = newln / DZ_LINES; /* get mux num */
401 if (dz_tcr[dz] & (1 << (newln + TCR_V_DTR))) /* DTR set? */
402 dz_msr[dz] |= (1 << (newln + MSR_V_CD)); /* set cdet */
403 else dz_msr[dz] |= (1 << newln); /* set ring */
404 }
405 tmxr_poll_rx (&dz_desc); /* poll input */
406 dz_update_rcvi (); /* upd rcv intr */
407 tmxr_poll_tx (&dz_desc); /* poll output */
408 dz_update_xmti (); /* upd xmt intr */
409 sim_activate (uptr, tmxr_poll); /* reactivate */
410 }
411 return SCPE_OK;
412 }
413
414 /* Get first available character for mux, if any */
415
416 int32 dz_getc (int32 dz)
417 {
418 uint32 i, line, c;
419
420 for (i = c = 0; (i < DZ_LINES) && (c == 0); i++) { /* loop thru lines */
421 line = (dz * DZ_LINES) + i; /* get line num */
422 c = tmxr_getc_ln (&dz_ldsc[line]); /* test for input */
423 if (c & SCPE_BREAK) c = RBUF_VALID | RBUF_FRME; /* break? frame err */
424 if (c) c = c | (i << RBUF_V_RLINE); /* or in line # */
425 } /* end for */
426 return c;
427 }
428
429 /* Update receive interrupts */
430
431 void dz_update_rcvi (void)
432 {
433 int32 i, dz, line, scnt[DZ_MUXES];
434 TMLN *lp;
435
436 for (dz = 0; dz < DZ_MUXES; dz++) { /* loop thru muxes */
437 scnt[dz] = 0; /* clr input count */
438 for (i = 0; i < DZ_LINES; i++) { /* poll lines */
439 line = (dz * DZ_LINES) + i; /* get line num */
440 lp = &dz_ldsc[line]; /* get line desc */
441 scnt[dz] = scnt[dz] + tmxr_rqln (lp); /* sum buffers */
442 if (dz_mctl && !lp->conn) /* if disconn */
443 dz_msr[dz] &= ~(1 << (i + MSR_V_CD)); /* reset car det */
444 }
445 }
446 for (dz = 0; dz < DZ_MUXES; dz++) { /* loop thru muxes */
447 if (scnt[dz] && (dz_csr[dz] & CSR_MSE)) { /* input & enabled? */
448 dz_csr[dz] |= CSR_RDONE; /* set done */
449 if (dz_sae[dz] && (scnt[dz] >= DZ_SILO_ALM)) { /* alm enb & cnt hi? */
450 dz_csr[dz] |= CSR_SA; /* set status */
451 dz_sae[dz] = 0; /* disable alarm */
452 }
453 }
454 else dz_csr[dz] &= ~CSR_RDONE; /* no, clear done */
455 if ((dz_csr[dz] & CSR_RIE) && /* int enable */
456 ((dz_csr[dz] & CSR_SAE)?
457 (dz_csr[dz] & CSR_SA): (dz_csr[dz] & CSR_RDONE)))
458 dz_set_rxint (dz); /* and alm/done? */
459 else dz_clr_rxint (dz); /* no, clear int */
460 }
461 return;
462 }
463
464 /* Update transmit interrupts */
465
466 void dz_update_xmti (void)
467 {
468 int32 dz, linemask, i, j, line;
469
470 for (dz = 0; dz < DZ_MUXES; dz++) { /* loop thru muxes */
471 linemask = dz_tcr[dz] & DZ_LMASK; /* enabled lines */
472 dz_csr[dz] &= ~CSR_TRDY; /* assume not rdy */
473 j = CSR_GETTL (dz_csr[dz]); /* start at current */
474 for (i = 0; i < DZ_LINES; i++) { /* loop thru lines */
475 j = (j + 1) & DZ_LNOMASK; /* next line */
476 line = (dz * DZ_LINES) + j; /* get line num */
477 if ((linemask & (1 << j)) && dz_ldsc[line].xmte) {
478 CSR_PUTTL (dz_csr[dz], j); /* put ln in csr */
479 dz_csr[dz] |= CSR_TRDY; /* set xmt rdy */
480 break;
481 }
482 }
483 if ((dz_csr[dz] & CSR_TIE) && (dz_csr[dz] & CSR_TRDY)) /* ready plus int? */
484 dz_set_txint (dz);
485 else dz_clr_txint (dz); /* no int req */
486 }
487 return;
488 }
489
490 /* Interrupt routines */
491
492 void dz_clr_rxint (int32 dz)
493 {
494 dz_rxi = dz_rxi & ~(1 << dz); /* clr mux rcv int */
495 if (dz_rxi == 0) CLR_INT (DZRX); /* all clr? */
496 else SET_INT (DZRX); /* no, set intr */
497 return;
498 }
499
500 void dz_set_rxint (int32 dz)
501 {
502 dz_rxi = dz_rxi | (1 << dz); /* set mux rcv int */
503 SET_INT (DZRX); /* set master intr */
504 return;
505 }
506
507 int32 dz_rxinta (void)
508 {
509 int32 dz;
510
511 for (dz = 0; dz < DZ_MUXES; dz++) { /* find 1st mux */
512 if (dz_rxi & (1 << dz)) {
513 dz_clr_rxint (dz); /* clear intr */
514 return (dz_dib.vec + (dz * 010)); /* return vector */
515 }
516 }
517 return 0;
518 }
519
520 void dz_clr_txint (int32 dz)
521 {
522 dz_txi = dz_txi & ~(1 << dz); /* clr mux xmt int */
523 if (dz_txi == 0) CLR_INT (DZTX); /* all clr? */
524 else SET_INT (DZTX); /* no, set intr */
525 return;
526 }
527
528 void dz_set_txint (int32 dz)
529 {
530 dz_txi = dz_txi | (1 << dz); /* set mux xmt int */
531 SET_INT (DZTX); /* set master intr */
532 return;
533 }
534
535 int32 dz_txinta (void)
536 {
537 int32 dz;
538
539 for (dz = 0; dz < DZ_MUXES; dz++) { /* find 1st mux */
540 if (dz_txi & (1 << dz)) {
541 dz_clr_txint (dz); /* clear intr */
542 return (dz_dib.vec + 4 + (dz * 010)); /* return vector */
543 }
544 }
545 return 0;
546 }
547
548 /* Device reset */
549
550 t_stat dz_clear (int32 dz, t_bool flag)
551 {
552 int32 i, line;
553
554 dz_csr[dz] = 0; /* clear CSR */
555 dz_rbuf[dz] = 0; /* silo empty */
556 dz_lpr[dz] = 0; /* no params */
557 if (flag) dz_tcr[dz] = 0; /* INIT? clr all */
558 else dz_tcr[dz] &= ~0377; /* else save dtr */
559 dz_tdr[dz] = 0;
560 dz_sae[dz] = 1; /* alarm on */
561 dz_clr_rxint (dz); /* clear int */
562 dz_clr_txint (dz);
563 for (i = 0; i < DZ_LINES; i++) { /* loop thru lines */
564 line = (dz * DZ_LINES) + i;
565 if (!dz_ldsc[line].conn) dz_ldsc[line].xmte = 1; /* set xmt enb */
566 dz_ldsc[line].rcve = 0; /* clr rcv enb */
567 }
568 return SCPE_OK;
569 }
570
571 t_stat dz_reset (DEVICE *dptr)
572 {
573 int32 i, ndev;
574
575 for (i = 0; i < DZ_MUXES; i++) dz_clear (i, TRUE); /* init muxes */
576 dz_rxi = dz_txi = 0; /* clr master int */
577 CLR_INT (DZRX);
578 CLR_INT (DZTX);
579 sim_cancel (&dz_unit); /* stop poll */
580 ndev = ((dptr->flags & DEV_DIS)? 0: (dz_desc.lines / DZ_LINES));
581 return auto_config (dptr->name, ndev); /* auto config */
582 }
583
584 /* Attach */
585
586 t_stat dz_attach (UNIT *uptr, char *cptr)
587 {
588 t_stat r;
589 extern int32 sim_switches;
590
591 dz_mctl = dz_auto = 0; /* modem ctl off */
592 r = tmxr_attach (&dz_desc, uptr, cptr); /* attach mux */
593 if (r != SCPE_OK) return r; /* error? */
594 if (sim_switches & SWMASK ('M')) { /* modem control? */
595 dz_mctl = 1;
596 printf ("Modem control activated\n");
597 if (sim_log) fprintf (sim_log, "Modem control activated\n");
598 if (sim_switches & SWMASK ('A')) { /* autodisconnect? */
599 dz_auto = 1;
600 printf ("Auto disconnect activated\n");
601 if (sim_log) fprintf (sim_log, "Auto disconnect activated\n");
602 }
603 }
604 return SCPE_OK;
605 }
606
607 /* Detach */
608
609 t_stat dz_detach (UNIT *uptr)
610 {
611 return tmxr_detach (&dz_desc, uptr);
612 }
613
614 /* Show summary processor */
615
616 t_stat dz_summ (FILE *st, UNIT *uptr, int32 val, void *desc)
617 {
618 int32 i, t;
619
620 for (i = t = 0; i < dz_desc.lines; i++) { /* get num conn */
621 if (dz_ldsc[i].conn) t = t + 1;
622 }
623 if (t == 1) fprintf (st, "1 connection");
624 else fprintf (st, "%d connections", t);
625 return SCPE_OK;
626 }
627
628 /* SHOW CONN/STAT processor */
629
630 t_stat dz_show (FILE *st, UNIT *uptr, int32 val, void *desc)
631 {
632 int32 i, t;
633
634 for (i = t = 0; i < dz_desc.lines; i++) { /* loop thru conn */
635 if (dz_ldsc[i].conn) {
636 t = 1;
637 if (val) tmxr_fconns (st, &dz_ldsc[i], i);
638 else tmxr_fstats (st, &dz_ldsc[i], i);
639 }
640 }
641 if (t == 0) fprintf (st, "all disconnected\n");
642 return SCPE_OK;
643 }
644
645 /* SET LINES processor */
646
647 t_stat dz_setnl (UNIT *uptr, int32 val, char *cptr, void *desc)
648 {
649 int32 newln, i, t, ndev;
650 t_stat r;
651
652 if (cptr == NULL) return SCPE_ARG;
653 newln = (int32) get_uint (cptr, 10, (DZ_MUXES * DZ_LINES), &r);
654 if ((r != SCPE_OK) || (newln == dz_desc.lines)) return r;
655 if ((newln == 0) || (newln % DZ_LINES)) return SCPE_ARG;
656 if (newln < dz_desc.lines) {
657 for (i = newln, t = 0; i < dz_desc.lines; i++) t = t | dz_ldsc[i].conn;
658 if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE))
659 return SCPE_OK;
660 for (i = newln; i < dz_desc.lines; i++) {
661 if (dz_ldsc[i].conn) {
662 tmxr_linemsg (&dz_ldsc[i], "\r\nOperator disconnected line\r\n");
663 tmxr_reset_ln (&dz_ldsc[i]); /* reset line */
664 }
665 if ((i % DZ_LINES) == (DZ_LINES - 1))
666 dz_clear (i / DZ_LINES, TRUE); /* reset mux */
667 }
668 }
669 dz_dib.lnt = (newln / DZ_LINES) * IOLN_DZ; /* set length */
670 dz_desc.lines = newln;
671 ndev = ((dz_dev.flags & DEV_DIS)? 0: (dz_desc.lines / DZ_LINES));
672 return auto_config (dz_dev.name, ndev); /* auto config */
673 }
674
675 /* SHOW VECTOR processor */
676
677 t_stat dz_show_vec (FILE *st, UNIT *uptr, int32 val, void *desc)
678 {
679 return show_vec (st, uptr, ((dz_desc.lines * 2) / DZ_LINES), desc);
680 }
681
682 /* SET LOG processor */
683
684 t_stat dz_set_log (UNIT *uptr, int32 val, char *cptr, void *desc)
685 {
686 char *tptr;
687 t_stat r;
688 int32 ln;
689
690 if (cptr == NULL) return SCPE_ARG;
691 tptr = strchr (cptr, '=');
692 if ((tptr == NULL) || (*tptr == 0)) return SCPE_ARG;
693 *tptr++ = 0;
694 ln = (int32) get_uint (cptr, 10, (DZ_MUXES * DZ_LINES), &r);
695 if ((r != SCPE_OK) || (ln >= dz_desc.lines)) return SCPE_ARG;
696 return tmxr_set_log (NULL, ln, tptr, desc);
697 }
698
699 /* SET NOLOG processor */
700
701 t_stat dz_set_nolog (UNIT *uptr, int32 val, char *cptr, void *desc)
702 {
703 t_stat r;
704 int32 ln;
705
706 if (cptr == NULL) return SCPE_ARG;
707 ln = (int32) get_uint (cptr, 10, (DZ_MUXES * DZ_LINES), &r);
708 if ((r != SCPE_OK) || (ln >= dz_desc.lines)) return SCPE_ARG;
709 return tmxr_set_nolog (NULL, ln, NULL, desc);
710 }
711
712 /* SHOW LOG processor */
713
714 t_stat dz_show_log (FILE *st, UNIT *uptr, int32 val, void *desc)
715 {
716 int32 i;
717
718 for (i = 0; i < dz_desc.lines; i++) {
719 fprintf (st, "line %d: ", i);
720 tmxr_show_log (st, NULL, i, desc);
721 fprintf (st, "\n");
722 }
723 return SCPE_OK;
724 }
725
726
727