1 /* pdp1_dcs.c: PDP-1D terminal multiplexor simulator
3 Copyright (c) 2006, Robert M Supnik
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:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
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.
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.
26 dcs Type 630 data communications subsystem
28 This module implements up to 32 individual serial interfaces.
31 #include "pdp1_defs.h"
35 #define DCS_LINES 32 /* lines */
36 #define DCS_LINE_MASK (DCS_LINES - 1)
37 #define DCSL_WAIT 1000 /* output wait */
38 #define DCS_NUMLIN dcs_desc.lines
40 int32 dcs_sbs
= 0; /* SBS level */
41 uint32 dcs_send
= 0; /* line for send */
42 uint32 dcs_scan
= 0; /* line for scanner */
43 uint8 dcs_flg
[DCS_LINES
]; /* line flags */
44 uint8 dcs_buf
[DCS_LINES
]; /* line bufffers */
46 extern int32 iosta
, stop_inst
;
47 extern int32 tmxr_poll
;
49 TMLN dcs_ldsc
[DCS_LINES
] = { 0 }; /* line descriptors */
50 TMXR dcs_desc
= { DCS_LINES
, 0, 0, dcs_ldsc
}; /* mux descriptor */
52 t_stat
dcsi_svc (UNIT
*uptr
);
53 t_stat
dcso_svc (UNIT
*uptr
);
54 t_stat
dcs_reset (DEVICE
*dptr
);
55 t_stat
dcs_attach (UNIT
*uptr
, char *cptr
);
56 t_stat
dcs_detach (UNIT
*uptr
);
57 t_stat
dcs_summ (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
);
58 t_stat
dcs_show (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
);
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
);
63 /* DCS data structures
65 dcs_dev DCS device descriptor
66 dcs_unit DCS unit descriptor
67 dcs_reg DCS register list
68 dcs_mod DCS modifiers list
71 REG dcs_nlreg
= { DRDATA (NLINES
, DCS_NUMLIN
, 6), PV_LEFT
};
73 UNIT dcs_unit
= { UDATA (&dcsi_svc
, UNIT_ATTABLE
, 0) };
76 { BRDATA (BUF
, dcs_buf
, 8, 8, DCS_LINES
) },
77 { BRDATA (FLAGS
, dcs_flg
, 8, 1, DCS_LINES
) },
78 { FLDATA (SCNF
, iosta
, IOS_V_DCS
) },
79 { ORDATA (SCAN
, dcs_scan
, 5) },
80 { ORDATA (SEND
, dcs_send
, 5) },
81 { DRDATA (SBSLVL
, dcs_sbs
, 4), REG_HRO
},
86 { MTAB_XTD
|MTAB_VDV
, 0, "SBSLVL", "SBSLVL",
87 &dev_set_sbs
, &dev_show_sbs
, (void *) &dcs_sbs
},
88 { MTAB_XTD
| MTAB_VDV
| MTAB_VAL
, 0, "lines", "LINES",
89 &dcs_vlines
, NULL
, &dcs_nlreg
},
90 { MTAB_XTD
| MTAB_VDV
, 1, NULL
, "DISCONNECT",
91 &tmxr_dscln
, NULL
, &dcs_desc
},
92 { UNIT_ATT
, UNIT_ATT
, "connections", NULL
, NULL
, &dcs_summ
},
93 { MTAB_XTD
| MTAB_VDV
| MTAB_NMO
, 1, "CONNECTIONS", NULL
,
94 NULL
, &dcs_show
, NULL
},
95 { MTAB_XTD
| MTAB_VDV
| MTAB_NMO
, 0, "STATISTICS", NULL
,
96 NULL
, &dcs_show
, NULL
},
101 "DCS", &dcs_unit
, dcs_reg
, dcs_mod
,
103 &tmxr_ex
, &tmxr_dep
, &dcs_reset
,
104 NULL
, &dcs_attach
, &dcs_detach
,
105 NULL
, DEV_NET
| DEV_DISABLE
| DEV_DIS
108 /* DCSL data structures
110 dcsl_dev DCSL device descriptor
111 dcsl_unit DCSL unit descriptor
112 dcsl_reg DCSL register list
113 dcsl_mod DCSL modifiers list
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 { UDATA (&dcso_svc
, TT_MODE_UC
, 0), DCSL_WAIT
}
152 { TT_MODE
, TT_MODE_UC
, "UC", "UC", NULL
},
153 { TT_MODE
, TT_MODE_7B
, "7b", "7B", NULL
},
154 { TT_MODE
, TT_MODE_8B
, "8b", "8B", NULL
},
155 { TT_MODE
, TT_MODE_7P
, "7p", "7P", NULL
},
156 { MTAB_XTD
|MTAB_VUN
, 0, NULL
, "DISCONNECT",
157 &tmxr_dscln
, NULL
, &dcs_desc
},
158 { MTAB_XTD
|MTAB_VUN
|MTAB_NC
, 0, "LOG", "LOG",
159 &tmxr_set_log
, &tmxr_show_log
, &dcs_desc
},
160 { MTAB_XTD
|MTAB_VUN
|MTAB_NC
, 0, NULL
, "NOLOG",
161 &tmxr_set_nolog
, NULL
, &dcs_desc
},
166 { URDATA (TIME
, dcsl_unit
[0].wait
, 10, 24, 0,
167 DCS_LINES
, REG_NZ
+ PV_LEFT
) },
172 "DCSL", dcsl_unit
, dcsl_reg
, dcsl_mod
,
173 DCS_LINES
, 10, 31, 1, 8, 8,
174 NULL
, NULL
, &dcs_reset
,
179 /* DCS IOT routine */
181 int32
dcs (int32 inst
, int32 dev
, int32 dat
)
183 int32 pls
= (inst
>> 6) & 077;
185 if (dcs_dev
.flags
& DEV_DIS
) /* disabled? */
186 return (stop_inst
<< IOT_V_REASON
) | dat
; /* illegal inst */
187 if (pls
& 020) dat
= 0; /* pulse 20? clr IO */
189 switch (pls
& 057) { /* case IR<6,8:11> */
192 dat
|= dcs_buf
[dcs_scan
]; /* return line buf */
193 dcs_flg
[dcs_scan
] = 0; /* clr line flag */
197 dat
|= dcs_scan
; /* return line num */
201 dat
|= dcs_buf
[dcs_scan
]; /* return line buf */
202 dcs_flg
[dcs_scan
] = 0; /* clr line flag */
205 dcs_scan_next (TRUE
); /* unlock scanner */
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
);
215 dcs_send
= dat
& DCS_LINE_MASK
; /* load line num */
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 */
226 return (stop_inst
<< IOT_V_REASON
) | dat
; /* illegal inst */
232 /* Unit service - receive side
234 Poll all active lines for input
235 Poll for new connections
238 t_stat
dcsi_svc (UNIT
*uptr
)
242 if ((uptr
->flags
& UNIT_ATT
) == 0) return SCPE_OK
; /* attached? */
243 if (dcs_dev
.flags
& DEV_DIS
) return SCPE_OK
;
244 sim_activate (uptr
, tmxr_poll
); /* continue poll */
245 ln
= tmxr_poll_conn (&dcs_desc
); /* look for connect */
246 if (ln
>= 0) { /* got one? */
247 dcs_ldsc
[ln
].rcve
= 1; /* set rcv enable */
249 tmxr_poll_rx (&dcs_desc
); /* poll for input */
250 for (ln
= 0; ln
< DCS_NUMLIN
; ln
++) { /* loop thru lines */
251 if (dcs_ldsc
[ln
].conn
) { /* connected? */
252 if (c
= tmxr_getc_ln (&dcs_ldsc
[ln
])) { /* get char */
253 if (c
& SCPE_BREAK
) c
= 0; /* break? */
254 else c
= sim_tt_inpcvt (c
, TT_GET_MODE (dcsl_unit
[ln
].flags
)|TTUF_KSR
);
255 dcs_buf
[ln
] = c
; /* save char */
256 dcs_flg
[ln
] = 1; /* set line flag */
257 dcs_scan_next (FALSE
); /* kick scanner */
258 out
= sim_tt_outcvt (c
& 0177, TT_GET_MODE (dcsl_unit
[ln
].flags
));
260 tmxr_putc_ln (&dcs_ldsc
[ln
], out
); /* echo char */
261 tmxr_poll_tx (&dcs_desc
); /* poll xmt */
265 else dcs_ldsc
[ln
].rcve
= 0; /* disconnected */
270 /* Unit service - transmit side */
272 t_stat
dcso_svc (UNIT
*uptr
)
275 uint32 ln
= uptr
- dcsl_unit
; /* line # */
277 if (dcs_dev
.flags
& DEV_DIS
) return SCPE_OK
;
278 if (dcs_ldsc
[ln
].conn
) { /* connected? */
279 if (dcs_ldsc
[ln
].xmte
) { /* xmt enabled? */
280 c
= sim_tt_outcvt (dcs_buf
[ln
] & 0177, TT_GET_MODE (uptr
->flags
));
281 if (c
>= 0) tmxr_putc_ln (&dcs_ldsc
[ln
], c
); /* output char */
282 tmxr_poll_tx (&dcs_desc
); /* poll xmt */
284 else { /* buf full */
285 tmxr_poll_tx (&dcs_desc
); /* poll xmt */
286 sim_activate (uptr
, uptr
->wait
); /* reschedule */
290 dcs_flg
[ln
] = 1; /* set line flag */
291 dcs_scan_next (FALSE
); /* kick scanner */
297 void dcs_scan_next (t_bool unlk
)
301 if (unlk
) iosta
&= ~IOS_DCS
; /* unlock? */
302 else if (iosta
& IOS_DCS
) return; /* no, locked? */
303 for (i
= 0; i
< DCS_LINES
; i
++) { /* scan flags */
304 dcs_scan
= (dcs_scan
+ 1) & DCS_LINE_MASK
; /* next flag */
305 if (dcs_flg
[dcs_scan
] != 0) { /* flag set? */
306 iosta
|= IOS_DCS
; /* lock scanner */
307 dev_req_int (dcs_sbs
); /* request intr */
316 t_stat
dcs_reset (DEVICE
*dptr
)
320 if (dcs_dev
.flags
& DEV_DIS
) /* master disabled? */
321 dcsl_dev
.flags
= dcsl_dev
.flags
| DEV_DIS
; /* disable lines */
322 else dcsl_dev
.flags
= dcsl_dev
.flags
& ~DEV_DIS
;
323 if (dcs_unit
.flags
& UNIT_ATT
) /* master att? */
324 sim_activate_abs (&dcs_unit
, tmxr_poll
); /* activate */
325 else sim_cancel (&dcs_unit
); /* else stop */
326 for (i
= 0; i
< DCS_LINES
; i
++) dcs_reset_ln (i
); /* reset lines */
329 iosta
&= ~IOS_DCS
; /* clr intr req */
333 /* Attach master unit */
335 t_stat
dcs_attach (UNIT
*uptr
, char *cptr
)
339 r
= tmxr_attach (&dcs_desc
, uptr
, cptr
); /* attach */
340 if (r
!= SCPE_OK
) return r
; /* error */
341 sim_activate_abs (uptr
, tmxr_poll
); /* start poll */
345 /* Detach master unit */
347 t_stat
dcs_detach (UNIT
*uptr
)
352 r
= tmxr_detach (&dcs_desc
, uptr
); /* detach */
353 for (i
= 0; i
< DCS_LINES
; i
++) dcs_ldsc
[i
].rcve
= 0; /* disable rcv */
354 sim_cancel (uptr
); /* stop poll */
358 /* Show summary processor */
360 t_stat
dcs_summ (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
364 for (i
= t
= 0; i
< DCS_LINES
; i
++) t
= t
+ (dcs_ldsc
[i
].conn
!= 0);
365 if (t
== 1) fprintf (st
, "1 connection");
366 else fprintf (st
, "%d connections", t
);
370 /* SHOW CONN/STAT processor */
372 t_stat
dcs_show (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
376 for (i
= t
= 0; i
< DCS_LINES
; i
++) t
= t
+ (dcs_ldsc
[i
].conn
!= 0);
378 for (i
= 0; i
< DCS_LINES
; i
++) {
379 if (dcs_ldsc
[i
].conn
) {
380 if (val
) tmxr_fconns (st
, &dcs_ldsc
[i
], i
);
381 else tmxr_fstats (st
, &dcs_ldsc
[i
], i
);
385 else fprintf (st
, "all disconnected\n");
389 /* Change number of lines */
391 t_stat
dcs_vlines (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
396 if (cptr
== NULL
) return SCPE_ARG
;
397 newln
= get_uint (cptr
, 10, DCS_LINES
, &r
);
398 if ((r
!= SCPE_OK
) || (newln
== DCS_NUMLIN
)) return r
;
399 if (newln
== 0) return SCPE_ARG
;
400 if (newln
< DCS_LINES
) {
401 for (i
= newln
, t
= 0; i
< DCS_NUMLIN
; i
++) t
= t
| dcs_ldsc
[i
].conn
;
402 if (t
&& !get_yn ("This will disconnect users; proceed [N]?", FALSE
))
404 for (i
= newln
; i
< DCS_NUMLIN
; i
++) {
405 if (dcs_ldsc
[i
].conn
) {
406 tmxr_linemsg (&dcs_ldsc
[i
], "\r\nOperator disconnected line\r\n");
407 tmxr_reset_ln (&dcs_ldsc
[i
]); /* reset line */
409 dcsl_unit
[i
].flags
= dcsl_unit
[i
].flags
| UNIT_DIS
;
414 for (i
= DCS_NUMLIN
; i
< newln
; i
++) {
415 dcsl_unit
[i
].flags
= dcsl_unit
[i
].flags
& ~UNIT_DIS
;
423 /* Reset an individual line */
425 void dcs_reset_ln (int32 ln
)
427 sim_cancel (&dcsl_unit
[ln
]);