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