First Commit of my working state
[simh.git] / I1620 / i1620_tty.c
1 /* i1620_tty.c: IBM 1620 typewriter
2
3 Copyright (c) 2002-2005, 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 tty console typewriter
27
28 21-Sep-05 RMS Revised translation tables for 7094/1401 compatibility
29 22-Dec-02 RMS Added break test
30 */
31
32 #include "i1620_defs.h"
33
34 #define TTO_COLMAX 80
35
36 int32 tto_col = 0;
37
38 extern uint8 M[MAXMEMSIZE];
39 extern uint8 ind[NUM_IND];
40 extern UNIT cpu_unit;
41 extern uint32 io_stop;
42
43 void tti_unlock (void);
44 t_stat tti_rnum (int8 *c);
45 t_stat tti_ralp (int8 *c);
46 t_stat tti_read (int8 *c);
47 t_stat tto_num (uint32 pa, uint32 len);
48 t_stat tto_write (uint32 c);
49 t_stat tty_svc (UNIT *uptr);
50 t_stat tty_reset (DEVICE *dptr);
51
52 /* TTY data structures
53
54 tty_dev TTY device descriptor
55 tty_unit TTY unit descriptor
56 tty_reg TTY register list
57 */
58
59 UNIT tty_unit = { UDATA (&tty_svc, 0, 0), KBD_POLL_WAIT };
60
61 REG tty_reg[] = {
62 { DRDATA (COL, tto_col, 7) },
63 { DRDATA (TIME, tty_unit.wait, 24), REG_NZ + PV_LEFT },
64 { NULL }
65 };
66
67 DEVICE tty_dev = {
68 "TTY", &tty_unit, tty_reg, NULL,
69 1, 10, 31, 1, 8, 7,
70 NULL, NULL, &tty_reset,
71 NULL, NULL, NULL
72 };
73
74 /* Data tables */
75
76 /* Keyboard to numeric */
77
78 const char *tti_to_num = "0123456789|=@:;}";
79
80 /* Keyboard to alphameric (digit pair) - translates LC to UC */
81
82 const int8 tti_to_alp[128] = {
83 -1, -1, -1, -1, -1, -1, -1, -1, /* 00 */
84 -1, -1, -1, -1, -1, -1, -1, -1,
85 -1, -1, -1, -1, -1, -1, -1, -1, /* 10 */
86 -1, -1, -1, -1, -1, -1, -1, -1,
87 0x00, 0x02, -1, 0x33, 0x13, 0x24, 0x10, 0x34, /* !"#$%&' */
88 0x24, 0x04, 0x14, 0x10, 0x23, 0x20, 0x03, 0x21, /* ()*+,-./ */
89 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 01234567 */
90 0x78, 0x79, -1, -1, -1, 0x33, -1, -1, /* 89:;<=>? */
91 0x34, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* @ABCDEFG */
92 0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, /* HIJKLMNO */
93 0x57, 0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, /* PQRSTUVW */
94 0x67, 0x68, 0x69, -1, -1, -1, -1, -1, /* XYZ[\]^_ */
95 -1, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* `abcdefg */
96 0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, /* hijklmno */
97 0x57, 0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, /* pqrstuvw */
98 0x67, 0x68, 0x69, -1, -1, 0x0F, -1, -1 /* xyz{|}~ */
99 };
100
101 /* Numeric (digit) to typewriter */
102
103 const char num_to_tto[16] = {
104 '0', '1', '2', '3', '4', '5', '6', '7',
105 '8', '9', '|', '=', '@', ':', ';', '}'
106 };
107
108 /* Alphameric (digit pair) to typewriter */
109
110 const char alp_to_tto[256] = {
111 ' ', -1, '?', '.', ')', -1, -1, -1, /* 00 */
112 -1, -1, -1, -1, -1, -1, -1, -1,
113 '+', -1, '!', '$', '*', ' ', -1, -1, /* 10 */
114 -1, -1, -1, -1, -1, -1, -1, -1,
115 '-', '/', '|', ',', '(', -1, -1, -1, /* 20 */
116 -1, -1, -1, -1, -1, -1, -1, -1,
117 -1, -1, '0', '=', '@', ':', -1, -1, /* 30 */
118 -1, -1, -1, -1, -1, -1, -1, -1,
119 -1, 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 40 */
120 'H', 'I', -1, -1, -1, -1, -1, -1,
121 '-', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* 50 */
122 'Q', 'R', -1, -1, -1, -1, -1, -1,
123 -1, '/', 'S', 'T', 'U', 'V', 'W', 'X', /* 60 */
124 'Y', 'Z', -1, -1, -1, -1, -1, -1,
125 '0', '1', '2', '3', '4', '5', '6', '7', /* 70 */
126 '8', '9', -1, -1, -1, -1, -1, -1,
127 -1, -1, -1, -1, -1, -1, -1, -1, /* 80 */
128 -1, -1, -1, -1, -1, -1, -1, -1,
129 -1, -1, -1, -1, -1, -1, -1, -1, /* 90 */
130 -1, -1, -1, -1, -1, -1, -1, -1,
131 -1, -1, -1, -1, -1, -1, -1, -1, /* A0 */
132 -1, -1, -1, -1, -1, -1, -1, -1,
133 -1, -1, -1, -1, -1, -1, -1, -1, /* B0 */
134 -1, -1, -1, -1, -1, -1, -1, -1,
135 -1, -1, -1, -1, -1, -1, -1, -1, /* C0 */
136 -1, -1, -1, -1, -1, -1, -1, -1,
137 -1, -1, -1, -1, -1, -1, -1, -1, /* D0 */
138 -1, -1, -1, -1, -1, -1, -1, -1,
139 -1, -1, -1, -1, -1, -1, -1, -1, /* E0 */
140 -1, -1, -1, -1, -1, -1, -1, -1,
141 -1, -1, -1, -1, -1, -1, -1, -1, /* F0 */
142 -1, -1, -1, -1, -1, -1, -1, -1
143 };
144
145 /* Terminal IO
146
147 - On input, parity errors cannot occur.
148 - On input, release-start does NOT cause a record mark to be stored.
149 - On output, invalid characters type an invalid character and set WRCHK.
150 If IO stop is set, the system halts at the end of the operation.
151 */
152
153 t_stat tty (uint32 op, uint32 pa, uint32 f0, uint32 f1)
154 {
155 t_addr i;
156 uint8 d;
157 int8 ttc;
158 t_stat r, sta;
159
160 sta = SCPE_OK;
161 switch (op) { /* case on op */
162
163 case OP_K: /* control */
164 switch (f1) { /* case on control */
165 case 1: /* space */
166 tto_write (' ');
167 break;
168 case 2: /* return */
169 tto_write ('\r');
170 break;
171 case 3: /* backspace */
172 if ((cpu_unit.flags & IF_MII) == 0) return STOP_INVFNC;
173 tto_write ('\b');
174 break;
175 case 4: /* index */
176 if ((cpu_unit.flags & IF_MII) == 0) return STOP_INVFNC;
177 tto_write ('\n');
178 break;
179 case 8: /* tab */
180 tto_write ('\t');
181 break;
182 default:
183 return STOP_INVFNC;
184 }
185 return SCPE_OK;
186
187 case OP_RN: /* read numeric */
188 tti_unlock (); /* unlock keyboard */
189 for (i = 0; i < MEMSIZE; i++) { /* (stop runaway) */
190 r = tti_rnum (&ttc); /* read char */
191 if (r != SCPE_OK) return r; /* error? */
192 if (ttc == 0x7F) return SCPE_OK; /* end record? */
193 M[pa] = ttc & (FLAG | DIGIT); /* store char */
194 PP (pa); /* incr mem addr */
195 }
196 break;
197
198 case OP_RA: /* read alphameric */
199 tti_unlock ();
200 for (i = 0; i < MEMSIZE; i = i + 2) { /* (stop runaway) */
201 r = tti_ralp (&ttc); /* read char */
202 if (r != SCPE_OK) return r; /* error? */
203 if (ttc == 0x7F) return SCPE_OK; /* end record? */
204 M[pa] = (M[pa] & FLAG) | (ttc & DIGIT); /* store 2 digits */
205 M[pa - 1] = (M[pa - 1] & FLAG) | ((ttc >> 4) & DIGIT);
206 pa = ADDR_A (pa, 2); /* incr mem addr */
207 }
208 break;
209
210 case OP_DN:
211 return tto_num (pa, 20000 - (pa % 20000)); /* dump numeric */
212
213 case OP_WN:
214 return tto_num (pa, 0); /* type numeric */
215
216 case OP_WA:
217 for (i = 0; i < MEMSIZE; i = i + 2) { /* stop runaway */
218 d = M[pa] & DIGIT; /* get digit */
219 if ((d & 0xA) == REC_MARK) return sta; /* 8-2 char? done */
220 d = ((M[pa - 1] & DIGIT) << 4) | d; /* get digit pair */
221 ttc = alp_to_tto[d]; /* translate */
222 if (ttc < 0) { /* bad char? */
223 ind[IN_WRCHK] = 1; /* set write check */
224 if (io_stop) sta = STOP_INVCHR; /* set return status */
225 }
226 tto_write (ttc & 0x7F); /* write */
227 pa = ADDR_A (pa, 2); /* incr mem addr */
228 }
229 break;
230
231 default: /* invalid function */
232 return STOP_INVFNC;
233 }
234
235 return STOP_RWRAP;
236 }
237
238 /* Read numerically - cannot generate parity errors */
239
240 t_stat tti_rnum (int8 *c)
241 {
242 int8 raw, flg = 0;
243 char *cp;
244 t_stat r;
245
246 *c = -1; /* no char yet */
247 do {
248 r = tti_read (&raw); /* get char */
249 if (r != SCPE_OK) return r; /* error? */
250 if (raw == '\r') *c = 0x7F; /* return? mark */
251 else if ((raw == '~') || (raw == '`')) flg = FLAG; /* flag? mark */
252 else if (cp = strchr (tti_to_num, raw)) /* legal? */
253 *c = ((int8) (cp - tti_to_num)) | flg; /* assemble char */
254 else raw = 007; /* beep! */
255 tto_write (raw); /* echo */
256 } while (*c == -1);
257 return SCPE_OK;
258 }
259
260 /* Read alphamerically - cannot generate parity errors */
261
262 t_stat tti_ralp (int8 *c)
263 {
264 int8 raw;
265 t_stat r;
266
267 *c = -1; /* no char yet */
268 do {
269 r = tti_read (&raw); /* get char */
270 if (r != SCPE_OK) return r; /* error? */
271 if (raw == '\r') *c = 0x7F; /* return? mark */
272 else if (tti_to_alp[raw] >= 0) /* legal char? */
273 *c = tti_to_alp[raw]; /* xlate */
274 else raw = 007; /* beep! */
275 tto_write (raw); /* echo */
276 } while (*c == -1);
277 return SCPE_OK;
278 }
279
280 /* Read from keyboard */
281
282 t_stat tti_read (int8 *c)
283 {
284 int32 t;
285
286 do {
287 t = sim_poll_kbd (); /* get character */
288 } while ((t == SCPE_OK) || (t & SCPE_BREAK)); /* ignore break */
289 if (t < SCPE_KFLAG) return t; /* error? */
290 *c = t & 0177; /* store character */
291 return SCPE_OK;
292 }
293
294 /* Write numerically - cannot generate parity errors */
295
296 t_stat tto_num (uint32 pa, uint32 len)
297 {
298 t_stat r;
299 uint8 d;
300 uint32 i, end;
301
302 end = pa + len;
303 for (i = 0; i < MEMSIZE; i++) { /* (stop runaway) */
304 d = M[pa]; /* get char */
305 if (len? (pa >= end): /* dump: end reached? */
306 ((d & REC_MARK) == REC_MARK)) /* write: rec mark? */
307 return SCPE_OK; /* end operation */
308 if (d & FLAG) tto_write ('`'); /* flag? */
309 r = tto_write (num_to_tto[d & DIGIT]); /* write */
310 if (r != SCPE_OK) return r; /* error? */
311 PP (pa); /* incr mem addr */
312 }
313 return STOP_RWRAP;
314 }
315
316 /* Write, maintaining position */
317
318 t_stat tto_write (uint32 c)
319 {
320 int32 rpt;
321
322 if (c == '\t') { /* tab? */
323 rpt = 8 - (tto_col % 8); /* distance to next */
324 tto_col = tto_col + rpt; /* tab over */
325 while (rpt-- > 0) sim_putchar (' '); /* use spaces */
326 return SCPE_OK;
327 }
328 if (c == '\r') { /* return? */
329 sim_putchar ('\r'); /* crlf */
330 sim_putchar ('\n');
331 tto_col = 0; /* clear colcnt */
332 return SCPE_OK;
333 }
334 if ((c == '\n') || (c == 007)) { /* non-spacing? */
335 sim_putchar (c);
336 return SCPE_OK;
337 }
338 if (c == '\b') tto_col = tto_col? tto_col - 1: 0; /* backspace? */
339 else tto_col++; /* normal */
340 if (tto_col > TTO_COLMAX) { /* line wrap? */
341 sim_putchar ('\r');
342 sim_putchar ('\n');
343 tto_col = 0;
344 }
345 sim_putchar (c);
346 return SCPE_OK;
347 }
348
349 /* Unit service - polls for WRU */
350
351 t_stat tty_svc (UNIT *uptr)
352 {
353 int32 temp;
354
355 sim_activate (&tty_unit, tty_unit.wait); /* continue poll */
356 if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */
357 return SCPE_OK;
358 }
359
360 /* Reset routine */
361
362 t_stat tty_reset (DEVICE *dptr)
363 {
364 sim_activate (&tty_unit, tty_unit.wait); /* activate poll */
365 tto_col = 0;
366 return SCPE_OK;
367 }
368
369 /* TTI unlock - signals that we are ready for keyboard input */
370
371 void tti_unlock (void)
372 {
373 tto_write ('>');
374 return;
375 }