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