First Commit of my working state
[simh.git] / PDP18B / pdp18b_tt1.c
CommitLineData
196ba1fc
PH
1/* pdp15_ttx.c: PDP-15 additional terminals simulator\r
2\r
3 Copyright (c) 1993-2007, Robert M Supnik\r
4\r
5 Permission is hereby granted, free of charge, to any person obtaining a\r
6 copy of this software and associated documentation files (the "Software"),\r
7 to deal in the Software without restriction, including without limitation\r
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
9 and/or sell copies of the Software, and to permit persons to whom the\r
10 Software is furnished to do so, subject to the following conditions:\r
11\r
12 The above copyright notice and this permission notice shall be included in\r
13 all copies or substantial portions of the Software.\r
14\r
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21\r
22 Except as contained in this notice, the name of Robert M Supnik shall not be\r
23 used in advertising or otherwise to promote the sale, use or other dealings\r
24 in this Software without prior written authorization from Robert M Supnik.\r
25\r
26 ttix,ttox LT15/LT19 terminal input/output\r
27\r
28 18-Jun-07 RMS Added UNIT_IDLE flag\r
29 30-Sep-06 RMS Fixed handling of non-printable characters in KSR mode\r
30 22-Nov-05 RMS Revised for new terminal processing routines\r
31 29-Jun-05 RMS Added SET TTOXn DISCONNECT\r
32 21-Jun-05 RMS Fixed bug in SHOW CONN/STATS\r
33 14-Jan-04 RMS Cloned from pdp8_ttx.c\r
34\r
35 This module implements 16 individual serial interfaces similar in function\r
36 to the console. These interfaces are mapped to Telnet based connections as\r
37 though they were the four lines of a terminal multiplexor. The connection\r
38 polling mechanism is superimposed onto the keyboard of the first interface.\r
39*/\r
40\r
41#include "pdp18b_defs.h"\r
42#include "sim_sock.h"\r
43#include "sim_tmxr.h"\r
44#include <ctype.h>\r
45\r
46#if defined (PDP15)\r
47#define TTX_MAXL 16 /* max number of lines */\r
48#elif defined (PDP9)\r
49#define TTX_MAXL 4\r
50#else\r
51#define TTX_MAXL 1\r
52#endif\r
53\r
54uint32 ttix_done = 0; /* input flags */\r
55uint32 ttox_done = 0; /* output flags */\r
56uint8 ttix_buf[TTX_MAXL] = { 0 }; /* input buffers */\r
57uint8 ttox_buf[TTX_MAXL] = { 0 }; /* output buffers */\r
58TMLN ttx_ldsc[TTX_MAXL] = { 0 }; /* line descriptors */\r
59TMXR ttx_desc = { 1, 0, 0, ttx_ldsc }; /* mux descriptor */\r
60#define ttx_lines ttx_desc.lines /* current number of lines */\r
61\r
62extern int32 int_hwre[API_HLVL+1];\r
63extern int32 tmxr_poll;\r
64extern int32 stop_inst;\r
65\r
66DEVICE ttix_dev, ttox_dev;\r
67int32 ttix (int32 dev, int32 pulse, int32 dat);\r
68int32 ttox (int32 dev, int32 pulse, int32 dat);\r
69t_stat ttix_svc (UNIT *uptr);\r
70t_bool ttix_test_done (int32 ln);\r
71void ttix_set_done (int32 ln);\r
72void ttix_clr_done (int32 ln);\r
73t_stat ttox_svc (UNIT *uptr);\r
74t_bool ttox_test_done (int32 ln);\r
75void ttox_set_done (int32 ln);\r
76void ttox_clr_done (int32 ln);\r
77int32 ttx_getln (int32 dev, int32 pulse);\r
78t_stat ttx_attach (UNIT *uptr, char *cptr);\r
79t_stat ttx_detach (UNIT *uptr);\r
80t_stat ttx_reset (DEVICE *dptr);\r
81void ttx_reset_ln (int32 i);\r
82t_stat ttx_summ (FILE *st, UNIT *uptr, int32 val, void *desc);\r
83t_stat ttx_show (FILE *st, UNIT *uptr, int32 val, void *desc);\r
84t_stat ttx_vlines (UNIT *uptr, int32 val, char *cptr, void *desc);\r
85\r
86/* TTIx data structures\r
87\r
88 ttix_dev TTIx device descriptor\r
89 ttix_unit TTIx unit descriptor\r
90 ttix_reg TTIx register list\r
91 ttix_mod TTIx modifiers list\r
92*/\r
93\r
94DIB ttix_dib = { \r
95 DEV_TTO1, 8, NULL,\r
96 { &ttox, &ttix, &ttox, &ttix, &ttox, &ttix, &ttox, &ttix }\r
97 };\r
98\r
99UNIT ttix_unit = { UDATA (&ttix_svc, UNIT_IDLE|UNIT_ATTABLE, 0), KBD_POLL_WAIT };\r
100\r
101REG ttx_nlreg = { DRDATA (NLINES, ttx_lines, 4), PV_LEFT };\r
102\r
103REG ttix_reg[] = {\r
104 { BRDATA (BUF, ttix_buf, 8, 8, TTX_MAXL) },\r
105 { ORDATA (DONE, ttix_done, TTX_MAXL) },\r
106 { FLDATA (INT, int_hwre[API_TTI1], INT_V_TTI1) },\r
107 { DRDATA (TIME, ttix_unit.wait, 24), REG_NZ + PV_LEFT },\r
108 { ORDATA (DEVNUM, ttix_dib.dev, 6), REG_HRO },\r
109 { NULL }\r
110 };\r
111\r
112MTAB ttix_mod[] = {\r
113 { MTAB_XTD | MTAB_VDV | MTAB_VAL, 0, "lines", "LINES",\r
114 &ttx_vlines, NULL, &ttx_nlreg },\r
115 { UNIT_ATT, UNIT_ATT, "summary", NULL, NULL, &ttx_summ },\r
116 { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT",\r
117 &tmxr_dscln, NULL, &ttx_desc },\r
118 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL,\r
119 NULL, &ttx_show, NULL },\r
120 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL,\r
121 NULL, &ttx_show, NULL },\r
122 { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",\r
123 &set_devno, &show_devno, NULL },\r
124 { 0 }\r
125 };\r
126\r
127DEVICE tti1_dev = {\r
128 "TTIX", &ttix_unit, ttix_reg, ttix_mod,\r
129 1, 10, 31, 1, 8, 8,\r
130 &tmxr_ex, &tmxr_dep, &ttx_reset,\r
131 NULL, &ttx_attach, &ttx_detach,\r
132 &ttix_dib, DEV_NET | DEV_DISABLE\r
133 };\r
134\r
135/* TTOx data structures\r
136\r
137 ttox_dev TTOx device descriptor\r
138 ttox_unit TTOx unit descriptor\r
139 ttox_reg TTOx register list\r
140*/\r
141\r
142UNIT ttox_unit[] = {\r
143 { UDATA (&ttox_svc, TT_MODE_KSR, 0), SERIAL_OUT_WAIT },\r
144 { UDATA (&ttox_svc, TT_MODE_KSR+UNIT_DIS, 0), SERIAL_OUT_WAIT },\r
145 { UDATA (&ttox_svc, TT_MODE_KSR+UNIT_DIS, 0), SERIAL_OUT_WAIT },\r
146 { UDATA (&ttox_svc, TT_MODE_KSR+UNIT_DIS, 0), SERIAL_OUT_WAIT },\r
147 { UDATA (&ttox_svc, TT_MODE_KSR+UNIT_DIS, 0), SERIAL_OUT_WAIT },\r
148 { UDATA (&ttox_svc, TT_MODE_KSR+UNIT_DIS, 0), SERIAL_OUT_WAIT },\r
149 { UDATA (&ttox_svc, TT_MODE_KSR+UNIT_DIS, 0), SERIAL_OUT_WAIT },\r
150 { UDATA (&ttox_svc, TT_MODE_KSR+UNIT_DIS, 0), SERIAL_OUT_WAIT },\r
151 { UDATA (&ttox_svc, TT_MODE_KSR+UNIT_DIS, 0), SERIAL_OUT_WAIT },\r
152 { UDATA (&ttox_svc, TT_MODE_KSR+UNIT_DIS, 0), SERIAL_OUT_WAIT },\r
153 { UDATA (&ttox_svc, TT_MODE_KSR+UNIT_DIS, 0), SERIAL_OUT_WAIT },\r
154 { UDATA (&ttox_svc, TT_MODE_KSR+UNIT_DIS, 0), SERIAL_OUT_WAIT },\r
155 { UDATA (&ttox_svc, TT_MODE_KSR+UNIT_DIS, 0), SERIAL_OUT_WAIT },\r
156 { UDATA (&ttox_svc, TT_MODE_KSR+UNIT_DIS, 0), SERIAL_OUT_WAIT },\r
157 { UDATA (&ttox_svc, TT_MODE_KSR+UNIT_DIS, 0), SERIAL_OUT_WAIT },\r
158 { UDATA (&ttox_svc, TT_MODE_KSR+UNIT_DIS, 0), SERIAL_OUT_WAIT }\r
159 };\r
160\r
161REG ttox_reg[] = {\r
162 { BRDATA (BUF, ttox_buf, 8, 8, TTX_MAXL) },\r
163 { ORDATA (DONE, ttox_done, TTX_MAXL) },\r
164 { FLDATA (INT, int_hwre[API_TTO1], INT_V_TTO1) },\r
165 { URDATA (TIME, ttox_unit[0].wait, 10, 24, 0,\r
166 TTX_MAXL, PV_LEFT) },\r
167 { NULL }\r
168 };\r
169\r
170MTAB ttox_mod[] = {\r
171 { TT_MODE, TT_MODE_KSR, "KSR", "KSR", NULL },\r
172 { TT_MODE, TT_MODE_7B, "7b", "7B", NULL },\r
173 { TT_MODE, TT_MODE_8B, "8b", "8B", NULL },\r
174 { TT_MODE, TT_MODE_7P, "7p", "7P", NULL },\r
175 { MTAB_XTD|MTAB_VUN, 0, NULL, "DISCONNECT",\r
176 &tmxr_dscln, NULL, &ttx_desc },\r
177 { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG",\r
178 &tmxr_set_log, &tmxr_show_log, &ttx_desc },\r
179 { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG",\r
180 &tmxr_set_nolog, NULL, &ttx_desc },\r
181 { 0 }\r
182 };\r
183\r
184DEVICE tto1_dev = {\r
185 "TTOX", ttox_unit, ttox_reg, ttox_mod,\r
186 TTX_MAXL, 10, 31, 1, 8, 8,\r
187 NULL, NULL, &ttx_reset, \r
188 NULL, NULL, NULL,\r
189 NULL, DEV_DISABLE\r
190 };\r
191\r
192/* Terminal input: IOT routine */\r
193\r
194int32 ttix (int32 dev, int32 pulse, int32 dat)\r
195{\r
196int32 ln = ttx_getln (dev, pulse); /* line # */\r
197\r
198if (ln > ttx_lines) return dat;\r
199if (pulse & 001) { /* KSF1 */\r
200 if (ttix_test_done (ln)) dat = dat | IOT_SKP;\r
201 }\r
202if (pulse & 002) { /* KRB1 */\r
203 ttix_clr_done (ln); /* clear flag */\r
204 dat = dat | ttix_buf[ln]; /* return buffer */\r
205 }\r
206return dat;\r
207}\r
208\r
209/* Unit service */\r
210\r
211t_stat ttix_svc (UNIT *uptr)\r
212{\r
213int32 ln, c, temp;\r
214\r
215if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */\r
216sim_activate (uptr, tmxr_poll); /* continue poll */\r
217ln = tmxr_poll_conn (&ttx_desc); /* look for connect */\r
218if (ln >= 0) ttx_ldsc[ln].rcve = 1; /* got one? rcv enab */\r
219tmxr_poll_rx (&ttx_desc); /* poll for input */\r
220for (ln = 0; ln < TTX_MAXL; ln++) { /* loop thru lines */\r
221 if (ttx_ldsc[ln].conn) { /* connected? */\r
222 if (temp = tmxr_getc_ln (&ttx_ldsc[ln])) { /* get char */\r
223 if (temp & SCPE_BREAK) c = 0; /* break? */\r
224 else c = sim_tt_inpcvt (temp, TT_GET_MODE (ttox_unit[ln].flags) | TTUF_KSR);\r
225 ttix_buf[ln] = c;\r
226 ttix_set_done (ln);\r
227 }\r
228 }\r
229 }\r
230return SCPE_OK;\r
231}\r
232\r
233/* Interrupt handling routines */\r
234\r
235t_bool ttix_test_done (int32 ln)\r
236{\r
237if (ttix_done & (1 << ln)) return TRUE;\r
238return FALSE;\r
239}\r
240\r
241void ttix_set_done (int32 ln)\r
242{\r
243ttix_done = ttix_done | (1 << ln);\r
244SET_INT (TTI1);\r
245return;\r
246}\r
247\r
248void ttix_clr_done (int32 ln)\r
249{\r
250ttix_done = ttix_done & ~(1 << ln);\r
251if (ttix_done) { SET_INT (TTI1); }\r
252else {\r
253 CLR_INT (TTI1);\r
254 }\r
255return;\r
256}\r
257\r
258/* Terminal output: IOT routine */\r
259\r
260int32 ttox (int32 dev, int32 pulse, int32 dat)\r
261{\r
262int32 ln = ttx_getln (dev, pulse); /* line # */\r
263\r
264if (ln > ttx_lines) return dat;\r
265if (pulse & 001) { /* TSF */\r
266 if (ttox_test_done (ln)) dat = dat | IOT_SKP;\r
267 }\r
268if (pulse & 002) ttox_clr_done (ln); /* clear flag */\r
269if (pulse & 004) { /* load buffer */\r
270 sim_activate (&ttox_unit[ln], ttox_unit[ln].wait); /* activate unit */\r
271 ttox_buf[ln] = dat & 0377; /* load buffer */\r
272 }\r
273return dat;\r
274}\r
275\r
276/* Unit service */\r
277\r
278t_stat ttox_svc (UNIT *uptr)\r
279{\r
280int32 c, ln = uptr - ttox_unit; /* line # */\r
281\r
282if (ttx_ldsc[ln].conn) { /* connected? */\r
283 if (ttx_ldsc[ln].xmte) { /* tx enabled? */\r
284 TMLN *lp = &ttx_ldsc[ln]; /* get line */\r
285 c = sim_tt_outcvt (ttox_buf[ln], TT_GET_MODE (ttox_unit[ln].flags) | TTUF_KSR);\r
286 if (c >= 0) tmxr_putc_ln (lp, c); /* output char */\r
287 tmxr_poll_tx (&ttx_desc); /* poll xmt */\r
288 }\r
289 else {\r
290 tmxr_poll_tx (&ttx_desc); /* poll xmt */\r
291 sim_activate (uptr, ttox_unit[ln].wait); /* wait */\r
292 return SCPE_OK;\r
293 }\r
294 }\r
295ttox_set_done (ln); /* set done */\r
296return SCPE_OK;\r
297}\r
298\r
299/* Interrupt handling routines */\r
300\r
301t_bool ttox_test_done (int32 ln)\r
302{\r
303if (ttox_done & (1 << ln)) return TRUE;\r
304return FALSE;\r
305}\r
306\r
307void ttox_set_done (int32 ln)\r
308{\r
309ttox_done = ttox_done | (1 << ln);\r
310SET_INT (TTO1);\r
311return;\r
312}\r
313\r
314void ttox_clr_done (int32 ln)\r
315{\r
316ttox_done = ttox_done & ~(1 << ln);\r
317if (ttox_done) { SET_INT (TTO1); }\r
318else { CLR_INT (TTO1); }\r
319return;\r
320}\r
321\r
322/* Compute relative line number\r
323\r
324 This algorithm does not assign contiguous line numbers of ascending\r
325 LT19's. Rather, line numbers follow a simple progression based on\r
326 the relative IOT number and the subdevice select */\r
327\r
328int32 ttx_getln (int32 dev, int32 pulse)\r
329{\r
330int32 rdno = ((dev - ttix_dib.dev) >> 1) & 3;\r
331\r
332#if defined (PDP15) /* PDP-15? */\r
333int32 sub = (pulse >> 4) & 3;\r
334return (rdno * 4) + sub; /* use dev, subdev */\r
335#else /* others */ \r
336return rdno; /* use dev only */\r
337#endif\r
338}\r
339\r
340/* Reset routine */\r
341\r
342t_stat ttx_reset (DEVICE *dptr)\r
343{\r
344int32 ln;\r
345\r
346if (dptr->flags & DEV_DIS) { /* sync enables */\r
347 ttix_dev.flags = ttox_dev.flags | DEV_DIS;\r
348 ttox_dev.flags = ttox_dev.flags | DEV_DIS;\r
349 }\r
350else {\r
351 ttix_dev.flags = ttix_dev.flags & ~DEV_DIS;\r
352 ttox_dev.flags = ttox_dev.flags & ~DEV_DIS;\r
353 }\r
354if (ttix_unit.flags & UNIT_ATT) /* if attached, */\r
355 sim_activate (&ttix_unit, tmxr_poll); /* activate */\r
356else sim_cancel (&ttix_unit); /* else stop */\r
357for (ln = 0; ln < TTX_MAXL; ln++) ttx_reset_ln (ln); /* for all lines */\r
358return SCPE_OK;\r
359}\r
360\r
361/* Reset line n */\r
362\r
363void ttx_reset_ln (int32 ln)\r
364{\r
365ttix_buf[ln] = 0; /* clear buf, */\r
366ttox_buf[ln] = 0;\r
367ttix_clr_done (ln); /* clear done */\r
368ttox_clr_done (ln);\r
369sim_cancel (&ttox_unit[ln]); /* stop poll */\r
370return;\r
371}\r
372\r
373/* Attach master unit */\r
374\r
375t_stat ttx_attach (UNIT *uptr, char *cptr)\r
376{\r
377t_stat r;\r
378\r
379r = tmxr_attach (&ttx_desc, uptr, cptr); /* attach */\r
380if (r != SCPE_OK) return r; /* error */\r
381sim_activate (uptr, tmxr_poll); /* start poll */\r
382return SCPE_OK;\r
383}\r
384\r
385/* Detach master unit */\r
386\r
387t_stat ttx_detach (UNIT *uptr)\r
388{\r
389int32 i;\r
390t_stat r;\r
391\r
392r = tmxr_detach (&ttx_desc, uptr); /* detach */\r
393sim_cancel (uptr); /* stop poll */\r
394for (i = 0; i < TTX_MAXL; i++) ttx_ldsc[i].rcve = 0; /* disable rcv */\r
395return r;\r
396}\r
397\r
398/* Show summary processor */\r
399\r
400t_stat ttx_summ (FILE *st, UNIT *uptr, int32 val, void *desc)\r
401{\r
402int32 i, t;\r
403\r
404for (i = t = 0; i < TTX_MAXL; i++) t = t + (ttx_ldsc[i].conn != 0);\r
405if (t == 1) fprintf (st, "1 connection");\r
406else fprintf (st, "%d connections", t);\r
407return SCPE_OK;\r
408}\r
409\r
410/* SHOW CONN/STAT processor */\r
411\r
412t_stat ttx_show (FILE *st, UNIT *uptr, int32 val, void *desc)\r
413{\r
414int32 i, t;\r
415\r
416for (i = t = 0; i < TTX_MAXL; i++) t = t + (ttx_ldsc[i].conn != 0);\r
417if (t) {\r
418 for (i = 0; i < ttx_lines; i++) {\r
419 if (ttx_ldsc[i].conn) {\r
420 if (val) tmxr_fconns (st, &ttx_ldsc[i], i);\r
421 else tmxr_fstats (st, &ttx_ldsc[i], i);\r
422 }\r
423 }\r
424 }\r
425else fprintf (st, "all disconnected\n");\r
426return SCPE_OK;\r
427}\r
428\r
429/* Change number of lines */\r
430\r
431t_stat ttx_vlines (UNIT *uptr, int32 val, char *cptr, void *desc)\r
432{\r
433int32 newln, i, t;\r
434t_stat r;\r
435\r
436if (cptr == NULL) return SCPE_ARG;\r
437newln = get_uint (cptr, 10, TTX_MAXL, &r);\r
438if ((r != SCPE_OK) || (newln == ttx_lines)) return r;\r
439if (newln == 0) return SCPE_ARG;\r
440if (newln < ttx_lines) {\r
441 for (i = newln, t = 0; i < ttx_lines; i++) t = t | ttx_ldsc[i].conn;\r
442 if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE))\r
443 return SCPE_OK;\r
444 for (i = newln; i < ttx_lines; i++) {\r
445 if (ttx_ldsc[i].conn) {\r
446 tmxr_linemsg (&ttx_ldsc[i], "\r\nOperator disconnected line\r\n");\r
447 tmxr_reset_ln (&ttx_ldsc[i]); /* reset line */\r
448 }\r
449 ttox_unit[i].flags = ttox_unit[i].flags | UNIT_DIS;\r
450 ttx_reset_ln (i);\r
451 }\r
452 }\r
453else {\r
454 for (i = ttx_lines; i < newln; i++) {\r
455 ttox_unit[i].flags = ttox_unit[i].flags & ~UNIT_DIS;\r
456 ttx_reset_ln (i);\r
457 }\r
458 }\r
459ttx_lines = newln;\r
460return SCPE_OK;\r
461}\r
462\r
463\r