Commit | Line | Data |
---|---|---|
196ba1fc PH |
1 | /* pdp8_ttx.c: PDP-8 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 PT08/KL8JA terminal input/output\r | |
27 | \r | |
28 | 07-Jun-06 RMS Added UNIT_IDLE flag\r | |
29 | 06-Jul-06 RMS Fixed bug in DETACH routine\r | |
30 | 22-Nov-05 RMS Revised for new terminal processing routines\r | |
31 | 29-Jun-05 RMS Added SET TTOXn DISCONNECT\r | |
32 | Fixed bug in SET LOG/NOLOG\r | |
33 | 21-Jun-05 RMS Fixed bug in SHOW CONN/STATS\r | |
34 | 05-Jan-04 RMS Revised for tmxr library changes\r | |
35 | 09-May-03 RMS Added network device flag\r | |
36 | 25-Apr-03 RMS Revised for extended file support\r | |
37 | 22-Dec-02 RMS Added break support\r | |
38 | 02-Nov-02 RMS Added 7B/8B support\r | |
39 | 04-Oct-02 RMS Added DIB, device number support\r | |
40 | 22-Aug-02 RMS Updated for changes to sim_tmxr.c\r | |
41 | 06-Jan-02 RMS Added device enable/disable support\r | |
42 | 30-Dec-01 RMS Complete rebuild\r | |
43 | 30-Nov-01 RMS Added extended SET/SHOW support\r | |
44 | \r | |
45 | This module implements four individual serial interfaces similar in function\r | |
46 | to the console. These interfaces are mapped to Telnet based connections as\r | |
47 | though they were the four lines of a terminal multiplexor. The connection\r | |
48 | polling mechanism is superimposed onto the keyboard of the first interface.\r | |
49 | */\r | |
50 | \r | |
51 | #include "pdp8_defs.h"\r | |
52 | #include "sim_sock.h"\r | |
53 | #include "sim_tmxr.h"\r | |
54 | #include <ctype.h>\r | |
55 | \r | |
56 | #define TTX_LINES 4\r | |
57 | #define TTX_MASK (TTX_LINES - 1)\r | |
58 | \r | |
59 | #define TTX_GETLN(x) (((x) >> 4) & TTX_MASK)\r | |
60 | \r | |
61 | extern int32 int_req, int_enable, dev_done, stop_inst;\r | |
62 | \r | |
63 | uint8 ttix_buf[TTX_LINES] = { 0 }; /* input buffers */\r | |
64 | uint8 ttox_buf[TTX_LINES] = { 0 }; /* output buffers */\r | |
65 | int32 ttx_tps = 100; /* polls per second */\r | |
66 | TMLN ttx_ldsc[TTX_LINES] = { 0 }; /* line descriptors */\r | |
67 | TMXR ttx_desc = { TTX_LINES, 0, 0, ttx_ldsc }; /* mux descriptor */\r | |
68 | \r | |
69 | DEVICE ttix_dev, ttox_dev;\r | |
70 | int32 ttix (int32 IR, int32 AC);\r | |
71 | int32 ttox (int32 IR, int32 AC);\r | |
72 | t_stat ttix_svc (UNIT *uptr);\r | |
73 | t_stat ttix_reset (DEVICE *dptr);\r | |
74 | t_stat ttox_svc (UNIT *uptr);\r | |
75 | t_stat ttox_reset (DEVICE *dptr);\r | |
76 | t_stat ttx_attach (UNIT *uptr, char *cptr);\r | |
77 | t_stat ttx_detach (UNIT *uptr);\r | |
78 | t_stat ttx_summ (FILE *st, UNIT *uptr, int32 val, void *desc);\r | |
79 | t_stat ttx_show (FILE *st, UNIT *uptr, int32 val, void *desc);\r | |
80 | void ttx_enbdis (int32 dis);\r | |
81 | \r | |
82 | /* TTIx data structures\r | |
83 | \r | |
84 | ttix_dev TTIx device descriptor\r | |
85 | ttix_unit TTIx unit descriptor\r | |
86 | ttix_reg TTIx register list\r | |
87 | ttix_mod TTIx modifiers list\r | |
88 | */\r | |
89 | \r | |
90 | DIB ttix_dib = { DEV_KJ8, 8,\r | |
91 | { &ttix, &ttox, &ttix, &ttox, &ttix, &ttox, &ttix, &ttox } };\r | |
92 | \r | |
93 | UNIT ttix_unit = { UDATA (&ttix_svc, UNIT_IDLE|UNIT_ATTABLE, 0), KBD_POLL_WAIT };\r | |
94 | \r | |
95 | REG ttix_reg[] = {\r | |
96 | { BRDATA (BUF, ttix_buf, 8, 8, TTX_LINES) },\r | |
97 | { GRDATA (DONE, dev_done, 8, TTX_LINES, INT_V_TTI1) },\r | |
98 | { GRDATA (ENABLE, int_enable, 8, TTX_LINES, INT_V_TTI1) },\r | |
99 | { GRDATA (INT, int_req, 8, TTX_LINES, INT_V_TTI1) },\r | |
100 | { DRDATA (TIME, ttix_unit.wait, 24), REG_NZ + PV_LEFT },\r | |
101 | { DRDATA (TPS, ttx_tps, 10), REG_NZ + PV_LEFT },\r | |
102 | { ORDATA (DEVNUM, ttix_dib.dev, 6), REG_HRO },\r | |
103 | { NULL }\r | |
104 | };\r | |
105 | \r | |
106 | MTAB ttix_mod[] = {\r | |
107 | { UNIT_ATT, UNIT_ATT, "summary", NULL, NULL, &ttx_summ },\r | |
108 | { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT",\r | |
109 | &tmxr_dscln, NULL, &ttx_desc },\r | |
110 | { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL,\r | |
111 | NULL, &ttx_show, NULL },\r | |
112 | { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL,\r | |
113 | NULL, &ttx_show, NULL },\r | |
114 | { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",\r | |
115 | &set_dev, &show_dev, NULL },\r | |
116 | { 0 }\r | |
117 | };\r | |
118 | \r | |
119 | DEVICE ttix_dev = {\r | |
120 | "TTIX", &ttix_unit, ttix_reg, ttix_mod,\r | |
121 | 1, 10, 31, 1, 8, 8,\r | |
122 | &tmxr_ex, &tmxr_dep, &ttix_reset,\r | |
123 | NULL, &ttx_attach, &ttx_detach,\r | |
124 | &ttix_dib, DEV_NET | DEV_DISABLE\r | |
125 | };\r | |
126 | \r | |
127 | /* TTOx data structures\r | |
128 | \r | |
129 | ttox_dev TTOx device descriptor\r | |
130 | ttox_unit TTOx unit descriptor\r | |
131 | ttox_reg TTOx register list\r | |
132 | */\r | |
133 | \r | |
134 | UNIT ttox_unit[] = {\r | |
135 | { UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },\r | |
136 | { UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },\r | |
137 | { UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },\r | |
138 | { UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }\r | |
139 | };\r | |
140 | \r | |
141 | REG ttox_reg[] = {\r | |
142 | { BRDATA (BUF, ttox_buf, 8, 8, TTX_LINES) },\r | |
143 | { GRDATA (DONE, dev_done, 8, TTX_LINES, INT_V_TTO1) },\r | |
144 | { GRDATA (ENABLE, int_enable, 8, TTX_LINES, INT_V_TTO1) },\r | |
145 | { GRDATA (INT, int_req, 8, TTX_LINES, INT_V_TTO1) },\r | |
146 | { URDATA (TIME, ttox_unit[0].wait, 10, 24, 0,\r | |
147 | TTX_LINES, PV_LEFT) },\r | |
148 | { NULL }\r | |
149 | };\r | |
150 | \r | |
151 | MTAB ttox_mod[] = {\r | |
152 | { TT_MODE, TT_MODE_UC, "UC", "UC", NULL },\r | |
153 | { TT_MODE, TT_MODE_7B, "7b", "7B", NULL },\r | |
154 | { TT_MODE, TT_MODE_8B, "8b", "8B", NULL },\r | |
155 | { TT_MODE, TT_MODE_7P, "7p", "7P", NULL },\r | |
156 | { MTAB_XTD|MTAB_VUN, 0, NULL, "DISCONNECT",\r | |
157 | &tmxr_dscln, NULL, &ttx_desc },\r | |
158 | { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG",\r | |
159 | &tmxr_set_log, &tmxr_show_log, &ttx_desc },\r | |
160 | { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG",\r | |
161 | &tmxr_set_nolog, NULL, &ttx_desc },\r | |
162 | { 0 }\r | |
163 | };\r | |
164 | \r | |
165 | DEVICE ttox_dev = {\r | |
166 | "TTOX", ttox_unit, ttox_reg, ttox_mod,\r | |
167 | 4, 10, 31, 1, 8, 8,\r | |
168 | NULL, NULL, &ttox_reset, \r | |
169 | NULL, NULL, NULL,\r | |
170 | NULL, DEV_DISABLE\r | |
171 | };\r | |
172 | \r | |
173 | /* Terminal input: IOT routine */\r | |
174 | \r | |
175 | int32 ttix (int32 inst, int32 AC)\r | |
176 | {\r | |
177 | int32 pulse = inst & 07; /* IOT pulse */\r | |
178 | int32 ln = TTX_GETLN (inst); /* line # */\r | |
179 | int32 itti = (INT_TTI1 << ln); /* rx intr */\r | |
180 | int32 itto = (INT_TTO1 << ln); /* tx intr */\r | |
181 | \r | |
182 | switch (pulse) { /* case IR<9:11> */\r | |
183 | \r | |
184 | case 0: /* KCF */\r | |
185 | dev_done = dev_done & ~itti; /* clear flag */\r | |
186 | int_req = int_req & ~itti;\r | |
187 | break;\r | |
188 | \r | |
189 | case 1: /* KSF */\r | |
190 | return (dev_done & itti)? IOT_SKP + AC: AC;\r | |
191 | \r | |
192 | case 2: /* KCC */\r | |
193 | dev_done = dev_done & ~itti; /* clear flag */\r | |
194 | int_req = int_req & ~itti;\r | |
195 | return 0; /* clear AC */\r | |
196 | \r | |
197 | case 4: /* KRS */\r | |
198 | return (AC | ttix_buf[ln]); /* return buf */\r | |
199 | \r | |
200 | case 5: /* KIE */\r | |
201 | if (AC & 1) int_enable = int_enable | (itti + itto);\r | |
202 | else int_enable = int_enable & ~(itti + itto);\r | |
203 | int_req = INT_UPDATE; /* update intr */\r | |
204 | break;\r | |
205 | \r | |
206 | case 6: /* KRB */\r | |
207 | dev_done = dev_done & ~itti; /* clear flag */\r | |
208 | int_req = int_req & ~itti;\r | |
209 | return ttix_buf[ln]; /* return buf */\r | |
210 | \r | |
211 | default:\r | |
212 | return (stop_inst << IOT_V_REASON) + AC;\r | |
213 | } /* end switch */\r | |
214 | \r | |
215 | return AC;\r | |
216 | }\r | |
217 | \r | |
218 | /* Unit service */\r | |
219 | \r | |
220 | t_stat ttix_svc (UNIT *uptr)\r | |
221 | {\r | |
222 | int32 ln, c, temp;\r | |
223 | \r | |
224 | if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */\r | |
225 | temp = sim_rtcn_calb (ttx_tps, TMR_TTX); /* calibrate */\r | |
226 | sim_activate (uptr, temp); /* continue poll */\r | |
227 | ln = tmxr_poll_conn (&ttx_desc); /* look for connect */\r | |
228 | if (ln >= 0) ttx_ldsc[ln].rcve = 1; /* got one? rcv enb*/\r | |
229 | tmxr_poll_rx (&ttx_desc); /* poll for input */\r | |
230 | for (ln = 0; ln < TTX_LINES; ln++) { /* loop thru lines */\r | |
231 | if (ttx_ldsc[ln].conn) { /* connected? */\r | |
232 | if (temp = tmxr_getc_ln (&ttx_ldsc[ln])) { /* get char */\r | |
233 | if (temp & SCPE_BREAK) c = 0; /* break? */\r | |
234 | else c = sim_tt_inpcvt (temp, TT_GET_MODE (ttox_unit[ln].flags));\r | |
235 | ttix_buf[ln] = c;\r | |
236 | dev_done = dev_done | (INT_TTI1 << ln);\r | |
237 | int_req = INT_UPDATE;\r | |
238 | }\r | |
239 | }\r | |
240 | }\r | |
241 | return SCPE_OK;\r | |
242 | }\r | |
243 | \r | |
244 | /* Reset routine */\r | |
245 | \r | |
246 | t_stat ttix_reset (DEVICE *dptr)\r | |
247 | {\r | |
248 | int32 t, ln, itto;\r | |
249 | \r | |
250 | ttx_enbdis (dptr->flags & DEV_DIS); /* sync enables */\r | |
251 | if (ttix_unit.flags & UNIT_ATT) { /* if attached, */\r | |
252 | if (!sim_is_active (&ttix_unit)) {\r | |
253 | t = sim_rtcn_init (ttix_unit.wait, TMR_TTX);\r | |
254 | sim_activate (&ttix_unit, t); /* activate */\r | |
255 | }\r | |
256 | }\r | |
257 | else sim_cancel (&ttix_unit); /* else stop */\r | |
258 | for (ln = 0; ln < TTX_LINES; ln++) { /* for all lines */\r | |
259 | ttix_buf[ln] = 0; /* clear buf, */\r | |
260 | itto = (INT_TTI1 << ln); /* interrupt */\r | |
261 | dev_done = dev_done & ~itto; /* clr done, int */\r | |
262 | int_req = int_req & ~itto;\r | |
263 | int_enable = int_enable | itto; /* set enable */\r | |
264 | }\r | |
265 | return SCPE_OK;\r | |
266 | }\r | |
267 | \r | |
268 | /* Terminal output: IOT routine */\r | |
269 | \r | |
270 | int32 ttox (int32 inst, int32 AC)\r | |
271 | {\r | |
272 | int32 pulse = inst & 07; /* pulse */\r | |
273 | int32 ln = TTX_GETLN (inst); /* line # */\r | |
274 | int32 itti = (INT_TTI1 << ln); /* rx intr */\r | |
275 | int32 itto = (INT_TTO1 << ln); /* tx intr */\r | |
276 | \r | |
277 | switch (pulse) { /* case IR<9:11> */\r | |
278 | \r | |
279 | case 0: /* TLF */\r | |
280 | dev_done = dev_done | itto; /* set flag */\r | |
281 | int_req = INT_UPDATE; /* update intr */\r | |
282 | break;\r | |
283 | \r | |
284 | case 1: /* TSF */\r | |
285 | return (dev_done & itto)? IOT_SKP + AC: AC;\r | |
286 | \r | |
287 | case 2: /* TCF */\r | |
288 | dev_done = dev_done & ~itto; /* clear flag */\r | |
289 | int_req = int_req & ~itto; /* clear intr */\r | |
290 | break;\r | |
291 | \r | |
292 | case 5: /* SPI */\r | |
293 | return (int_req & (itti | itto))? IOT_SKP + AC: AC;\r | |
294 | \r | |
295 | case 6: /* TLS */\r | |
296 | dev_done = dev_done & ~itto; /* clear flag */\r | |
297 | int_req = int_req & ~itto; /* clear int req */\r | |
298 | case 4: /* TPC */\r | |
299 | sim_activate (&ttox_unit[ln], ttox_unit[ln].wait); /* activate */\r | |
300 | ttox_buf[ln] = AC & 0377; /* load buffer */\r | |
301 | break;\r | |
302 | \r | |
303 | default:\r | |
304 | return (stop_inst << IOT_V_REASON) + AC;\r | |
305 | } /* end switch */\r | |
306 | \r | |
307 | return AC;\r | |
308 | }\r | |
309 | \r | |
310 | /* Unit service */\r | |
311 | \r | |
312 | t_stat ttox_svc (UNIT *uptr)\r | |
313 | {\r | |
314 | int32 c, ln = uptr - ttox_unit; /* line # */\r | |
315 | \r | |
316 | if (ttx_ldsc[ln].conn) { /* connected? */\r | |
317 | if (ttx_ldsc[ln].xmte) { /* tx enabled? */\r | |
318 | TMLN *lp = &ttx_ldsc[ln]; /* get line */\r | |
319 | c = sim_tt_outcvt (ttox_buf[ln], TT_GET_MODE (ttox_unit[ln].flags));\r | |
320 | if (c >= 0) tmxr_putc_ln (lp, c); /* output char */\r | |
321 | tmxr_poll_tx (&ttx_desc); /* poll xmt */\r | |
322 | }\r | |
323 | else {\r | |
324 | tmxr_poll_tx (&ttx_desc); /* poll xmt */\r | |
325 | sim_activate (uptr, ttox_unit[ln].wait); /* wait */\r | |
326 | return SCPE_OK;\r | |
327 | }\r | |
328 | }\r | |
329 | dev_done = dev_done | (INT_TTO1 << ln); /* set done */\r | |
330 | int_req = INT_UPDATE; /* update intr */\r | |
331 | return SCPE_OK;\r | |
332 | }\r | |
333 | \r | |
334 | /* Reset routine */\r | |
335 | \r | |
336 | t_stat ttox_reset (DEVICE *dptr)\r | |
337 | {\r | |
338 | int32 ln, itto;\r | |
339 | \r | |
340 | ttx_enbdis (dptr->flags & DEV_DIS); /* sync enables */\r | |
341 | for (ln = 0; ln < TTX_LINES; ln++) { /* for all lines */\r | |
342 | ttox_buf[ln] = 0; /* clear buf */\r | |
343 | itto = (INT_TTO1 << ln); /* interrupt */\r | |
344 | dev_done = dev_done & ~itto; /* clr done, int */\r | |
345 | int_req = int_req & ~itto;\r | |
346 | int_enable = int_enable | itto; /* set enable */\r | |
347 | sim_cancel (&ttox_unit[ln]); /* deactivate */\r | |
348 | }\r | |
349 | return SCPE_OK;\r | |
350 | }\r | |
351 | \r | |
352 | /* Attach master unit */\r | |
353 | \r | |
354 | t_stat ttx_attach (UNIT *uptr, char *cptr)\r | |
355 | {\r | |
356 | int32 t;\r | |
357 | t_stat r;\r | |
358 | \r | |
359 | r = tmxr_attach (&ttx_desc, uptr, cptr); /* attach */\r | |
360 | if (r != SCPE_OK) return r; /* error */\r | |
361 | t = sim_rtcn_init (ttix_unit.wait, TMR_TTX); /* init calib */\r | |
362 | sim_activate (uptr, t); /* start poll */\r | |
363 | return SCPE_OK;\r | |
364 | }\r | |
365 | \r | |
366 | /* Detach master unit */\r | |
367 | \r | |
368 | t_stat ttx_detach (UNIT *uptr)\r | |
369 | {\r | |
370 | int32 i;\r | |
371 | t_stat r;\r | |
372 | \r | |
373 | r = tmxr_detach (&ttx_desc, uptr); /* detach */\r | |
374 | for (i = 0; i < TTX_LINES; i++) /* all lines, */\r | |
375 | ttx_ldsc[i].rcve = 0; /* disable rcv */\r | |
376 | sim_cancel (uptr); /* stop poll */\r | |
377 | return r;\r | |
378 | }\r | |
379 | \r | |
380 | /* Show summary processor */\r | |
381 | \r | |
382 | t_stat ttx_summ (FILE *st, UNIT *uptr, int32 val, void *desc)\r | |
383 | {\r | |
384 | int32 i, t;\r | |
385 | \r | |
386 | for (i = t = 0; i < TTX_LINES; i++) t = t + (ttx_ldsc[i].conn != 0);\r | |
387 | if (t == 1) fprintf (st, "1 connection");\r | |
388 | else fprintf (st, "%d connections", t);\r | |
389 | return SCPE_OK;\r | |
390 | }\r | |
391 | \r | |
392 | /* SHOW CONN/STAT processor */\r | |
393 | \r | |
394 | t_stat ttx_show (FILE *st, UNIT *uptr, int32 val, void *desc)\r | |
395 | {\r | |
396 | int32 i, t;\r | |
397 | \r | |
398 | for (i = t = 0; i < TTX_LINES; i++) t = t + (ttx_ldsc[i].conn != 0);\r | |
399 | if (t) {\r | |
400 | for (i = 0; i < TTX_LINES; i++) {\r | |
401 | if (ttx_ldsc[i].conn) { \r | |
402 | if (val) tmxr_fconns (st, &ttx_ldsc[i], i);\r | |
403 | else tmxr_fstats (st, &ttx_ldsc[i], i);\r | |
404 | }\r | |
405 | }\r | |
406 | }\r | |
407 | else fprintf (st, "all disconnected\n");\r | |
408 | return SCPE_OK;\r | |
409 | }\r | |
410 | \r | |
411 | /* Enable/disable device */\r | |
412 | \r | |
413 | void ttx_enbdis (int32 dis)\r | |
414 | {\r | |
415 | if (dis) {\r | |
416 | ttix_dev.flags = ttox_dev.flags | DEV_DIS;\r | |
417 | ttox_dev.flags = ttox_dev.flags | DEV_DIS;\r | |
418 | }\r | |
419 | else {\r | |
420 | ttix_dev.flags = ttix_dev.flags & ~DEV_DIS;\r | |
421 | ttox_dev.flags = ttox_dev.flags & ~DEV_DIS;\r | |
422 | }\r | |
423 | return;\r | |
424 | }\r |