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