1 /* pdp8_tt.c: PDP-8 console terminal simulator
2
3 Copyright (c) 1993-2012, 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 tti,tto KL8E terminal input/output
27
28 18-Apr-12 RMS Revised to use clock coscheduling
29 18-Jun-07 RMS Added UNIT_IDLE flag to console input
30 18-Oct-06 RMS Synced keyboard to clock
31 30-Sep-06 RMS Fixed handling of non-printable characters in KSR mode
32 22-Nov-05 RMS Revised for new terminal processing routines
33 28-May-04 RMS Removed SET TTI CTRL-C
34 29-Dec-03 RMS Added console output backpressure support
35 25-Apr-03 RMS Revised for extended file support
36 02-Mar-02 RMS Added SET TTI CTRL-C
37 22-Dec-02 RMS Added break support
38 01-Nov-02 RMS Added 7B/8B support
39 04-Oct-02 RMS Added DIBs, device number support
40 30-May-02 RMS Widened POS to 32b
41 07-Sep-01 RMS Moved function prototypes
42 */
43
44 #include "pdp8_defs.h"
45 #include <ctype.h>
46
47 extern int32 int_req, int_enable, dev_done, stop_inst;
48 extern int32 tmxr_poll, sim_is_running;
49
50 int32 tti (int32 IR, int32 AC);
51 int32 tto (int32 IR, int32 AC);
52 t_stat tti_svc (UNIT *uptr);
53 t_stat tto_svc (UNIT *uptr);
54 t_stat tti_reset (DEVICE *dptr);
55 t_stat tto_reset (DEVICE *dptr);
56 t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc);
57
58 /* TTI data structures
59
60 tti_dev TTI device descriptor
61 tti_unit TTI unit descriptor
62 tti_reg TTI register list
63 tti_mod TTI modifiers list
64 */
65
66 DIB tti_dib = { DEV_TTI, 1, { &tti } };
67
68 UNIT tti_unit = { UDATA (&tti_svc, UNIT_IDLE|TT_MODE_KSR, 0), 0 };
69
70 REG tti_reg[] = {
71 { ORDATA (BUF, tti_unit.buf, 8) },
72 { FLDATA (DONE, dev_done, INT_V_TTI) },
73 { FLDATA (ENABLE, int_enable, INT_V_TTI) },
74 { FLDATA (INT, int_req, INT_V_TTI) },
75 { DRDATA (POS, tti_unit.pos, T_ADDR_W), PV_LEFT },
76 { DRDATA (TIME, tti_unit.wait, 24), PV_LEFT },
77 { NULL }
78 };
79
80 MTAB tti_mod[] = {
81 { TT_MODE, TT_MODE_KSR, "KSR", "KSR", &tty_set_mode },
82 { TT_MODE, TT_MODE_7B, "7b", "7B", &tty_set_mode },
83 { TT_MODE, TT_MODE_8B, "8b", "8B", &tty_set_mode },
84 { TT_MODE, TT_MODE_7P, "7b", NULL, NULL },
85 { MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_dev, NULL },
86 { 0 }
87 };
88
89 DEVICE tti_dev = {
90 "TTI", &tti_unit, tti_reg, tti_mod,
91 1, 10, 31, 1, 8, 8,
92 NULL, NULL, &tti_reset,
93 NULL, NULL, NULL,
94 &tti_dib, 0
95 };
96
97 /* TTO data structures
98
99 tto_dev TTO device descriptor
100 tto_unit TTO unit descriptor
101 tto_reg TTO register list
102 */
103
104 DIB tto_dib = { DEV_TTO, 1, { &tto } };
105
106 UNIT tto_unit = { UDATA (&tto_svc, TT_MODE_KSR, 0), SERIAL_OUT_WAIT };
107
108 REG tto_reg[] = {
109 { ORDATA (BUF, tto_unit.buf, 8) },
110 { FLDATA (DONE, dev_done, INT_V_TTO) },
111 { FLDATA (ENABLE, int_enable, INT_V_TTO) },
112 { FLDATA (INT, int_req, INT_V_TTO) },
113 { DRDATA (POS, tto_unit.pos, T_ADDR_W), PV_LEFT },
114 { DRDATA (TIME, tto_unit.wait, 24), PV_LEFT },
115 { NULL }
116 };
117
118 MTAB tto_mod[] = {
119 { TT_MODE, TT_MODE_KSR, "KSR", "KSR", &tty_set_mode },
120 { TT_MODE, TT_MODE_7B, "7b", "7B", &tty_set_mode },
121 { TT_MODE, TT_MODE_8B, "8b", "8B", &tty_set_mode },
122 { TT_MODE, TT_MODE_7P, "7p", "7P", &tty_set_mode },
123 { MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_dev },
124 { 0 }
125 };
126
127 DEVICE tto_dev = {
128 "TTO", &tto_unit, tto_reg, tto_mod,
129 1, 10, 31, 1, 8, 8,
130 NULL, NULL, &tto_reset,
131 NULL, NULL, NULL,
132 &tto_dib, 0
133 };
134
135 /* Terminal input: IOT routine */
136
tti(int32 IR,int32 AC)137 int32 tti (int32 IR, int32 AC)
138 {
139 switch (IR & 07) { /* decode IR<9:11> */
140 case 0: /* KCF */
141 dev_done = dev_done & ~INT_TTI; /* clear flag */
142 int_req = int_req & ~INT_TTI;
143 return AC;
144
145 case 1: /* KSF */
146 return (dev_done & INT_TTI)? IOT_SKP + AC: AC;
147
148 case 2: /* KCC */
149 dev_done = dev_done & ~INT_TTI; /* clear flag */
150 int_req = int_req & ~INT_TTI;
151 return 0; /* clear AC */
152
153 case 4: /* KRS */
154 return (AC | tti_unit.buf); /* return buffer */
155
156 case 5: /* KIE */
157 if (AC & 1)
158 int_enable = int_enable | (INT_TTI+INT_TTO);
159 else int_enable = int_enable & ~(INT_TTI+INT_TTO);
160 int_req = INT_UPDATE; /* update interrupts */
161 return AC;
162
163 case 6: /* KRB */
164 dev_done = dev_done & ~INT_TTI; /* clear flag */
165 int_req = int_req & ~INT_TTI;
166 return (tti_unit.buf); /* return buffer */
167
168 default:
169 return (stop_inst << IOT_V_REASON) + AC;
170 } /* end switch */
171 }
172
173 /* Unit service */
174
tti_svc(UNIT * uptr)175 t_stat tti_svc (UNIT *uptr)
176 {
177 int32 c;
178
179 sim_activate (uptr, KBD_WAIT (uptr->wait, clk_cosched (tmxr_poll)));
180 /* continue poll */
181 if ((c = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or error? */
182 return c;
183 if (c & SCPE_BREAK) /* break? */
184 uptr->buf = 0;
185 else uptr->buf = sim_tt_inpcvt (c, TT_GET_MODE (uptr->flags) | TTUF_KSR);
186 uptr->pos = uptr->pos + 1;
187 dev_done = dev_done | INT_TTI; /* set done */
188 int_req = INT_UPDATE; /* update interrupts */
189 return SCPE_OK;
190 }
191
192 /* Reset routine */
193
tti_reset(DEVICE * dptr)194 t_stat tti_reset (DEVICE *dptr)
195 {
196 tti_unit.buf = 0;
197 dev_done = dev_done & ~INT_TTI; /* clear done, int */
198 int_req = int_req & ~INT_TTI;
199 int_enable = int_enable | INT_TTI; /* set enable */
200 if (!sim_is_running) /* RESET (not CAF)? */
201 sim_activate (&tti_unit, KBD_WAIT (tti_unit.wait, tmxr_poll));
202 return SCPE_OK;
203 }
204
205 /* Terminal output: IOT routine */
206
tto(int32 IR,int32 AC)207 int32 tto (int32 IR, int32 AC)
208 {
209 switch (IR & 07) { /* decode IR<9:11> */
210
211 case 0: /* TLF */
212 dev_done = dev_done | INT_TTO; /* set flag */
213 int_req = INT_UPDATE; /* update interrupts */
214 return AC;
215
216 case 1: /* TSF */
217 return (dev_done & INT_TTO)? IOT_SKP + AC: AC;
218
219 case 2: /* TCF */
220 dev_done = dev_done & ~INT_TTO; /* clear flag */
221 int_req = int_req & ~INT_TTO; /* clear int req */
222 return AC;
223
224 case 5: /* SPI */
225 return (int_req & (INT_TTI+INT_TTO))? IOT_SKP + AC: AC;
226
227 case 6: /* TLS */
228 dev_done = dev_done & ~INT_TTO; /* clear flag */
229 int_req = int_req & ~INT_TTO; /* clear int req */
230 case 4: /* TPC */
231 sim_activate (&tto_unit, tto_unit.wait); /* activate unit */
232 tto_unit.buf = AC; /* load buffer */
233 return AC;
234
235 default:
236 return (stop_inst << IOT_V_REASON) + AC;
237 } /* end switch */
238 }
239
240 /* Unit service */
241
tto_svc(UNIT * uptr)242 t_stat tto_svc (UNIT *uptr)
243 {
244 int32 c;
245 t_stat r;
246
247 c = sim_tt_outcvt (uptr->buf, TT_GET_MODE (uptr->flags) | TTUF_KSR);
248 if (c >= 0) {
249 if ((r = sim_putchar_s (c)) != SCPE_OK) { /* output char; error? */
250 sim_activate (uptr, uptr->wait); /* try again */
251 return ((r == SCPE_STALL)? SCPE_OK: r); /* if !stall, report */
252 }
253 }
254 dev_done = dev_done | INT_TTO; /* set done */
255 int_req = INT_UPDATE; /* update interrupts */
256 uptr->pos = uptr->pos + 1;
257 return SCPE_OK;
258 }
259
260 /* Reset routine */
261
tto_reset(DEVICE * dptr)262 t_stat tto_reset (DEVICE *dptr)
263 {
264 tto_unit.buf = 0;
265 dev_done = dev_done & ~INT_TTO; /* clear done, int */
266 int_req = int_req & ~INT_TTO;
267 int_enable = int_enable | INT_TTO; /* set enable */
268 sim_cancel (&tto_unit); /* deactivate unit */
269 return SCPE_OK;
270 }
271
tty_set_mode(UNIT * uptr,int32 val,char * cptr,void * desc)272 t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc)
273 {
274 tti_unit.flags = (tti_unit.flags & ~TT_MODE) | val;
275 tto_unit.flags = (tto_unit.flags & ~TT_MODE) | val;
276 return SCPE_OK;
277 }
278