1 /* pdp1_dcs.c: PDP-1D terminal multiplexor simulator
2 
3    Copyright (c) 2006-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    dcs          Type 630 data communications subsystem
27 
28    19-Nov-2008  RMS     Revised for common TMXR show routines
29 
30    This module implements up to 32 individual serial interfaces.
31 */
32 
33 #include "pdp1_defs.h"
34 #include "sim_sock.h"
35 #include "sim_tmxr.h"
36 
37 #define DCS_LINES       32                              /* lines */
38 #define DCS_LINE_MASK   (DCS_LINES - 1)
39 #define DCSL_WAIT       1000                            /* output wait */
40 #define DCS_NUMLIN      dcs_desc.lines
41 
42 int32 dcs_sbs = 0;                                      /* SBS level */
43 uint32 dcs_send = 0;                                    /* line for send */
44 uint32 dcs_scan = 0;                                    /* line for scanner */
45 uint8 dcs_flg[DCS_LINES];                               /* line flags */
46 uint8 dcs_buf[DCS_LINES];                               /* line bufffers */
47 
48 extern int32 iosta, stop_inst;
49 extern int32 tmxr_poll;
50 
51 TMLN dcs_ldsc[DCS_LINES] = { 0 };                       /* line descriptors */
52 TMXR dcs_desc = { DCS_LINES, 0, 0, dcs_ldsc };          /* mux descriptor */
53 
54 t_stat dcsi_svc (UNIT *uptr);
55 t_stat dcso_svc (UNIT *uptr);
56 t_stat dcs_reset (DEVICE *dptr);
57 t_stat dcs_attach (UNIT *uptr, char *cptr);
58 t_stat dcs_detach (UNIT *uptr);
59 t_stat dcs_vlines (UNIT *uptr, int32 val, char *cptr, void *desc);
60 void dcs_reset_ln (int32 ln);
61 void dcs_scan_next (t_bool unlk);
62 
63 /* DCS data structures
64 
65    dcs_dev      DCS device descriptor
66    dcs_unit     DCS unit descriptor
67    dcs_reg      DCS register list
68    dcs_mod      DCS modifiers list
69 */
70 
71 UNIT dcs_unit = { UDATA (&dcsi_svc, UNIT_ATTABLE, 0) };
72 
73 REG dcs_reg[] = {
74     { BRDATA (BUF, dcs_buf, 8, 8, DCS_LINES) },
75     { BRDATA (FLAGS, dcs_flg, 8, 1, DCS_LINES) },
76     { FLDATA (SCNF, iosta, IOS_V_DCS) },
77     { ORDATA (SCAN, dcs_scan, 5) },
78     { ORDATA (SEND, dcs_send, 5) },
79     { DRDATA (SBSLVL, dcs_sbs, 4), REG_HRO },
80     { NULL }
81     };
82 
83 MTAB dcs_mod[] = {
84     { MTAB_XTD|MTAB_VDV, 0, "SBSLVL", "SBSLVL",
85       &dev_set_sbs, &dev_show_sbs, (void *) &dcs_sbs },
86     { MTAB_XTD | MTAB_VDV, 0, "LINES", "LINES",
87       &dcs_vlines, &tmxr_show_lines, (void *) &dcs_desc },
88     { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT",
89       &tmxr_dscln, NULL, (void *) &dcs_desc },
90     { UNIT_ATT, UNIT_ATT, "summary", NULL,
91       NULL, &tmxr_show_summ, (void *) &dcs_desc },
92     { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL,
93       NULL, &tmxr_show_cstat, (void *) &dcs_desc },
94     { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL,
95       NULL, &tmxr_show_cstat, (void *) &dcs_desc },
96     { 0 }
97     };
98 
99 DEVICE dcs_dev = {
100     "DCS", &dcs_unit, dcs_reg, dcs_mod,
101     1, 10, 31, 1, 8, 8,
102     &tmxr_ex, &tmxr_dep, &dcs_reset,
103     NULL, &dcs_attach, &dcs_detach,
104     NULL, DEV_NET | DEV_DISABLE | DEV_DIS
105     };
106 
107 /* DCSL data structures
108 
109    dcsl_dev     DCSL device descriptor
110    dcsl_unit    DCSL unit descriptor
111    dcsl_reg     DCSL register list
112    dcsl_mod     DCSL modifiers list
113 */
114 
115 UNIT dcsl_unit[] = {
116     { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
117     { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
118     { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
119     { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
120     { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
121     { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
122     { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
123     { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
124     { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
125     { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
126     { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
127     { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
128     { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
129     { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
130     { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
131     { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
132     { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
133     { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
134     { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
135     { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
136     { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
137     { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
138     { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
139     { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
140     { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
141     { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
142     { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
143     { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
144     { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
145     { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
146     { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
147     { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }
148     };
149 
150 MTAB dcsl_mod[] = {
151     { TT_MODE, TT_MODE_UC, "UC", "UC", NULL },
152     { TT_MODE, TT_MODE_7B, "7b", "7B", NULL },
153     { TT_MODE, TT_MODE_8B, "8b", "8B", NULL },
154     { TT_MODE, TT_MODE_7P, "7p", "7P", NULL },
155     { MTAB_XTD|MTAB_VUN, 0, NULL, "DISCONNECT",
156       &tmxr_dscln, NULL, &dcs_desc },
157     { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG",
158       &tmxr_set_log, &tmxr_show_log, &dcs_desc },
159     { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG",
160       &tmxr_set_nolog, NULL, &dcs_desc },
161     { 0 }
162     };
163 
164 REG dcsl_reg[] = {
165     { URDATA (TIME, dcsl_unit[0].wait, 10, 24, 0,
166               DCS_LINES, REG_NZ + PV_LEFT) },
167     { NULL }
168     };
169 
170 DEVICE dcsl_dev = {
171     "DCSL", dcsl_unit, dcsl_reg, dcsl_mod,
172     DCS_LINES, 10, 31, 1, 8, 8,
173     NULL, NULL, &dcs_reset,
174     NULL, NULL, NULL,
175     NULL, DEV_DIS
176     };
177 
178 /* DCS IOT routine */
179 
dcs(int32 inst,int32 dev,int32 dat)180 int32 dcs (int32 inst, int32 dev, int32 dat)
181 {
182 int32 pls = (inst >> 6) & 077;
183 
184 if (dcs_dev.flags & DEV_DIS)                            /* disabled? */
185     return (stop_inst << IOT_V_REASON) | dat;           /* illegal inst */
186 if (pls & 020)                                          /* pulse 20? clr IO */
187     dat = 0;
188 
189 switch (pls & 057) {                                    /* case IR<6,8:11> */
190 
191     case 000:                                           /* RCH */
192         dat |= dcs_buf[dcs_scan];                       /* return line buf */
193         dcs_flg[dcs_scan] = 0;                          /* clr line flag */
194         break;
195 
196     case 001:                                           /* RRC */
197         dat |= dcs_scan;                                /* return line num */
198         break;
199 
200     case 010:                                           /* RCC */
201         dat |= dcs_buf[dcs_scan];                       /* return line buf */
202         dcs_flg[dcs_scan] = 0;                          /* clr line flag */
203                                                         /* fall through */
204     case 011:                                           /* RSC */
205         dcs_scan_next (TRUE);                           /* unlock scanner */
206         break;
207 
208     case 040:                                           /* TCB */
209         dcs_buf[dcs_send] = dat & 0377;                 /* load buffer */
210         dcs_flg[dcs_send] = 0;                          /* clr line flag */
211         sim_activate (&dcsl_unit[dcs_send], dcsl_unit[dcs_send].wait);
212         break;
213 
214     case 041:                                           /* SSB */
215         dcs_send = dat & DCS_LINE_MASK;                 /* load line num */
216         break;
217 
218     case 050:                                           /* TCC */
219         dcs_buf[dcs_scan] = dat & 0377;                 /* load buffer */
220         dcs_flg[dcs_scan] = 0;                          /* clr line flag */
221         sim_activate (&dcsl_unit[dcs_scan], dcsl_unit[dcs_scan].wait);
222         dcs_scan_next (TRUE);                           /* unlock scanner */
223         break;
224 
225     default:
226         return (stop_inst << IOT_V_REASON) | dat;       /* illegal inst */
227         }                                               /* end case */
228 
229 return dat;
230 }
231 
232 /* Unit service - receive side
233 
234    Poll all active lines for input
235    Poll for new connections
236 */
237 
dcsi_svc(UNIT * uptr)238 t_stat dcsi_svc (UNIT *uptr)
239 {
240 int32 ln, c, out;
241 
242 if ((uptr->flags & UNIT_ATT) == 0)                      /* attached? */
243     return SCPE_OK;
244 if (dcs_dev.flags & DEV_DIS)
245     return SCPE_OK;
246 sim_activate (uptr, tmxr_poll);                         /* continue poll */
247 ln = tmxr_poll_conn (&dcs_desc);                        /* look for connect */
248 if (ln >= 0) {                                          /* got one? */
249     dcs_ldsc[ln].rcve = 1;                              /* set rcv enable */
250     }
251 tmxr_poll_rx (&dcs_desc);                               /* poll for input */
252 for (ln = 0; ln < DCS_NUMLIN; ln++) {                   /* loop thru lines */
253     if (dcs_ldsc[ln].conn) {                            /* connected? */
254         if ((c = tmxr_getc_ln (&dcs_ldsc[ln]))) {       /* get char */
255             if (c & SCPE_BREAK)                         /* break? */
256                 c = 0;
257             else c = sim_tt_inpcvt (c, TT_GET_MODE (dcsl_unit[ln].flags)|TTUF_KSR);
258             dcs_buf[ln] = c;                            /* save char */
259             dcs_flg[ln] = 1;                            /* set line flag */
260             dcs_scan_next (FALSE);                      /* kick scanner */
261             out = sim_tt_outcvt (c & 0177, TT_GET_MODE (dcsl_unit[ln].flags));
262             if (out >= 0) {
263                 tmxr_putc_ln (&dcs_ldsc[ln], out);      /* echo char */
264                 tmxr_poll_tx (&dcs_desc);               /* poll xmt */
265                 }
266             }
267         }
268     else dcs_ldsc[ln].rcve = 0;                         /* disconnected */
269     }                                                   /* end for */
270 return SCPE_OK;
271 }
272 
273 /* Unit service - transmit side */
274 
dcso_svc(UNIT * uptr)275 t_stat dcso_svc (UNIT *uptr)
276 {
277 int32 c;
278 uint32 ln = uptr - dcsl_unit;                           /* line # */
279 
280 if (dcs_dev.flags & DEV_DIS)
281     return SCPE_OK;
282 if (dcs_ldsc[ln].conn) {                                /* connected? */
283     if (dcs_ldsc[ln].xmte) {                            /* xmt enabled? */
284         c = sim_tt_outcvt (dcs_buf[ln] & 0177, TT_GET_MODE (uptr->flags));
285         if (c >= 0)                                     /* output char */
286             tmxr_putc_ln (&dcs_ldsc[ln], c);
287         tmxr_poll_tx (&dcs_desc);                       /* poll xmt */
288         }
289     else {                                              /* buf full */
290         tmxr_poll_tx (&dcs_desc);                       /* poll xmt */
291         sim_activate (uptr, uptr->wait);                /* reschedule */
292         return SCPE_OK;
293         }
294     }
295 dcs_flg[ln] = 1;                                        /* set line flag */
296 dcs_scan_next (FALSE);                                  /* kick scanner */
297 return SCPE_OK;
298 }
299 
300 /* Kick scanner */
301 
dcs_scan_next(t_bool unlk)302 void dcs_scan_next (t_bool unlk)
303 {
304 int32 i;
305 
306 if (unlk)                                               /* unlock? */
307     iosta &= ~IOS_DCS;
308 else if (iosta & IOS_DCS)                               /* no, locked? */
309     return;
310 for (i = 0; i < DCS_LINES; i++) {                       /* scan flags */
311     dcs_scan = (dcs_scan + 1) & DCS_LINE_MASK;          /* next flag */
312     if (dcs_flg[dcs_scan] != 0) {                       /* flag set? */
313         iosta |= IOS_DCS;                               /* lock scanner */
314         dev_req_int (dcs_sbs);                          /* request intr */
315         return;
316         }
317     }
318 return;
319 }
320 
321 /* Reset routine */
322 
dcs_reset(DEVICE * dptr)323 t_stat dcs_reset (DEVICE *dptr)
324 {
325 int32 i;
326 
327 if (dcs_dev.flags & DEV_DIS)                            /* master disabled? */
328     dcsl_dev.flags = dcsl_dev.flags | DEV_DIS;          /* disable lines */
329 else dcsl_dev.flags = dcsl_dev.flags & ~DEV_DIS;
330 if (dcs_unit.flags & UNIT_ATT)                          /* master att? */
331     sim_activate_abs (&dcs_unit, tmxr_poll);            /* activate */
332 else sim_cancel (&dcs_unit);                            /* else stop */
333 for (i = 0; i < DCS_LINES; i++)                         /* reset lines */
334     dcs_reset_ln (i);
335 dcs_send = 0;
336 dcs_scan = 0;
337 iosta &= ~IOS_DCS;                                      /* clr intr req */
338 return SCPE_OK;
339 }
340 
341 /* Attach master unit */
342 
dcs_attach(UNIT * uptr,char * cptr)343 t_stat dcs_attach (UNIT *uptr, char *cptr)
344 {
345 t_stat r;
346 
347 r = tmxr_attach (&dcs_desc, uptr, cptr);                /* attach */
348 if (r != SCPE_OK)                                       /* error */
349     return r;
350 sim_activate_abs (uptr, tmxr_poll);                     /* start poll */
351 return SCPE_OK;
352 }
353 
354 /* Detach master unit */
355 
dcs_detach(UNIT * uptr)356 t_stat dcs_detach (UNIT *uptr)
357 {
358 int32 i;
359 t_stat r;
360 
361 r = tmxr_detach (&dcs_desc, uptr);                      /* detach */
362 for (i = 0; i < DCS_LINES; i++)                         /* disable rcv */
363     dcs_ldsc[i].rcve = 0;
364 sim_cancel (uptr);                                      /* stop poll */
365 return r;
366 }
367 
368 /* Change number of lines */
369 
dcs_vlines(UNIT * uptr,int32 val,char * cptr,void * desc)370 t_stat dcs_vlines (UNIT *uptr, int32 val, char *cptr, void *desc)
371 {
372 int32 newln, i, t;
373 t_stat r;
374 
375 if (cptr == NULL)
376     return SCPE_ARG;
377 newln = get_uint (cptr, 10, DCS_LINES, &r);
378 if ((r != SCPE_OK) || (newln == DCS_NUMLIN))
379     return r;
380 if (newln == 0)
381     return SCPE_ARG;
382 if (newln < DCS_LINES) {
383     for (i = newln, t = 0; i < DCS_NUMLIN; i++)
384         t = t | dcs_ldsc[i].conn;
385     if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE))
386             return SCPE_OK;
387     for (i = newln; i < DCS_NUMLIN; i++) {
388         if (dcs_ldsc[i].conn) {
389             tmxr_linemsg (&dcs_ldsc[i], "\r\nOperator disconnected line\r\n");
390             tmxr_reset_ln (&dcs_ldsc[i]);               /* reset line */
391             }
392         dcsl_unit[i].flags = dcsl_unit[i].flags | UNIT_DIS;
393         dcs_reset_ln (i);
394         }
395     }
396 else {
397     for (i = DCS_NUMLIN; i < newln; i++) {
398         dcsl_unit[i].flags = dcsl_unit[i].flags & ~UNIT_DIS;
399         dcs_reset_ln (i);
400         }
401     }
402 DCS_NUMLIN = newln;
403 return SCPE_OK;
404 }
405 
406 /* Reset an individual line */
407 
dcs_reset_ln(int32 ln)408 void dcs_reset_ln (int32 ln)
409 {
410 sim_cancel (&dcsl_unit[ln]);
411 dcs_buf[ln] = 0;
412 dcs_flg[ln] = 0;
413 return;
414 }
415