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