First Commit of my working state
[simh.git] / S3 / s3_pkb.c
1 /* s3_pkb.c: System/3 5471 console terminal simulator
2
3 Copyright (c) 2001-2005, Charles E. Owen
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 Charles E. Owen 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 Charles E. Owen.
25
26 pkb 5471 printer/keyboard
27
28 25-Apr-03 RMS Revised for extended file support
29 08-Oct-02 RMS Added impossible function catcher
30 */
31
32 #include "s3_defs.h"
33 #include <ctype.h>
34
35 extern int32 int_req, dev_busy, dev_done, dev_disable;
36 t_stat pkb_svc (UNIT *uptr);
37 t_stat pkb_reset (DEVICE *dptr);
38 extern t_stat sim_poll_kbd (void);
39 extern t_stat sim_putchar (int32 out);
40 extern int32 IAR[], level;
41 extern int32 debug_reg;
42
43 /* 5471 data structures
44
45 pkb_dev TTI device descriptor
46 pkb_unit TTI unit descriptor
47 pkb_reg TTI register list
48 pkb_mod TTI/TTO modifiers list
49 */
50
51 /* Flag bits : (kept in pkb_unit.u3) */
52
53 #define PRT_INTREQ 0x800 /* Printer interrupt pending */
54 #define KBD_INTREQ 0x400 /* Request key interrupt pending */
55 #define KBD_INTEND 0x200 /* End or cancel key interrupt pending */
56 #define KBD_INTKEY 0x100 /* Return or other key interrupt pending */
57 #define KBD_REQLIGHT 0x20 /* Request Pending Indicator (light on/off) */
58 #define KBD_PROLIGHT 0x10 /* Proceed indicator (light on/off) */
59 #define KBD_REQINT 0x04 /* Req key interrupts enabled */
60 #define KBD_KEYINT 0x02 /* Other key interrupts enabled */
61 #define PRT_PRTINT 0x01 /* Printer interrupts enabled */
62
63 /* Keys mapped to 5471 functions */
64
65 int32 key_req = 0x01; /* Request key: ^A */
66 int32 key_rtn = 0x12; /* Return key: ^R */
67 int32 key_can = 0x1B; /* Cancel key: ESC */
68 int32 key_end = 0x0d; /* End key - CR */
69
70 UNIT pkb_unit = { UDATA (&pkb_svc, 0, 0), KBD_POLL_WAIT };
71
72 REG pkb_reg[] = {
73 { HRDATA (FLAG, pkb_unit.u3, 16) },
74 { HRDATA (IBUF, pkb_unit.buf, 8) },
75 { HRDATA (OBUF, pkb_unit.u4, 8) },
76 { HRDATA (REQKEY, key_req, 8) },
77 { HRDATA (RTNKEY, key_rtn, 8) },
78 { HRDATA (CANKEY, key_can, 8) },
79 { HRDATA (ENDKEY, key_end, 8) },
80 { DRDATA (POS, pkb_unit.pos, T_ADDR_W), PV_LEFT },
81 { DRDATA (TIME, pkb_unit.wait, 24), REG_NZ + PV_LEFT },
82 { NULL }
83 };
84
85 MTAB pkb_mod[] = {
86 { 0 }
87 };
88
89 DEVICE pkb_dev = {
90 "PKB", &pkb_unit, pkb_reg, pkb_mod,
91 1, 10, 31, 1, 8, 8,
92 NULL, NULL, &pkb_reset,
93 NULL, NULL, NULL
94 };
95
96
97 /*-------------------------------------------------------------------*/
98 /* EBCDIC to ASCII translate table */
99 /*-------------------------------------------------------------------*/
100 unsigned char ebcdic_to_ascii[] = {
101 "\x00\x01\x02\x03\xA6\x09\xA7\x7F\xA9\xB0\xB1\x0B\x0C\x0D\x0E\x0F"
102 "\x10\x11\x12\x13\xB2\xB4\x08\xB7\x18\x19\x1A\xB8\xBA\x1D\xBB\x1F"
103 "\xBD\xC0\x1C\xC1\xC2\x0A\x17\x1B\xC3\xC4\xC5\xC6\xC7\x05\x06\x07"
104 "\xC8\xC9\x16\xCB\xCC\x1E\xCD\x04\xCE\xD0\xD1\xD2\x14\x15\xD3\xFC"
105 "\x20\xD4\x83\x84\x85\xA0\xD5\x86\x87\xA4\xD6\x2E\x3C\x28\x2B\xD7"
106 "\x26\x82\x88\x89\x8A\xA1\x8C\x8B\x8D\xD8\x21\x24\x2A\x29\x3B\x5E"
107 "\x2D\x2F\xD9\x8E\xDB\xDC\xDD\x8F\x80\xA5\x7C\x2C\x25\x5F\x3E\x3F"
108 "\xDE\x90\xDF\xE0\xE2\xE3\xE4\xE5\xE6\x60\x3A\x23\x40\x27\x3D\x22"
109 "\xE7\x61\x62\x63\x64\x65\x66\x67\x68\x69\xAE\xAF\xE8\xE9\xEA\xEC"
110 "\xF0\x6A\x6B\x6C\x6D\x6E\x6F\x70\x71\x72\xF1\xF2\x91\xF3\x92\xF4"
111 "\xF5\x7E\x73\x74\x75\x76\x77\x78\x79\x7A\xAD\xA8\xF6\x5B\xF7\xF8"
112 "\x9B\x9C\x9D\x9E\x9F\xB5\xB6\xAC\xAB\xB9\xAA\xB3\xBC\x5D\xBE\xBF"
113 "\x7B\x41\x42\x43\x44\x45\x46\x47\x48\x49\xCA\x93\x94\x95\xA2\xCF"
114 "\x7D\x4A\x4B\x4C\x4D\x4E\x4F\x50\x51\x52\xDA\x96\x81\x97\xA3\x98"
115 "\x5C\xE1\x53\x54\x55\x56\x57\x58\x59\x5A\xFD\xEB\x99\xED\xEE\xEF"
116 "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\xFE\xFB\x9A\xF9\xFA\xFF"
117 };
118
119 /*-------------------------------------------------------------------*/
120 /* ASCII to EBCDIC translate table */
121 /*-------------------------------------------------------------------*/
122 unsigned char ascii_to_ebcdic[] = {
123 "\x00\x01\x02\x03\x37\x2D\x2E\x2F\x16\x05\x25\x0B\x0C\x0D\x0E\x0F"
124 "\x10\x11\x12\x13\x3C\x3D\x32\x26\x18\x19\x1A\x27\x22\x1D\x35\x1F"
125 "\x40\x5A\x7F\x7B\x5B\x6C\x50\x7D\x4D\x5D\x5C\x4E\x6B\x60\x4B\x61"
126 "\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\x7A\x5E\x4C\x7E\x6E\x6F"
127 "\x7C\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xD1\xD2\xD3\xD4\xD5\xD6"
128 "\xD7\xD8\xD9\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xAD\xE0\xBD\x5F\x6D"
129 "\x79\x81\x82\x83\x84\x85\x86\x87\x88\x89\x91\x92\x93\x94\x95\x96"
130 "\x97\x98\x99\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xC0\x6A\xD0\xA1\x07"
131 "\x68\xDC\x51\x42\x43\x44\x47\x48\x52\x53\x54\x57\x56\x58\x63\x67"
132 "\x71\x9C\x9E\xCB\xCC\xCD\xDB\xDD\xDF\xEC\xFC\xB0\xB1\xB2\xB3\xB4"
133 "\x45\x55\xCE\xDE\x49\x69\x04\x06\xAB\x08\xBA\xB8\xB7\xAA\x8A\x8B"
134 "\x09\x0A\x14\xBB\x15\xB5\xB6\x17\x1B\xB9\x1C\x1E\xBC\x20\xBE\xBF"
135 "\x21\x23\x24\x28\x29\x2A\x2B\x2C\x30\x31\xCA\x33\x34\x36\x38\xCF"
136 "\x39\x3A\x3B\x3E\x41\x46\x4A\x4F\x59\x62\xDA\x64\x65\x66\x70\x72"
137 "\x73\xE1\x74\x75\x76\x77\x78\x80\x8C\x8D\x8E\xEB\x8F\xED\xEE\xEF"
138 "\x90\x9A\x9B\x9D\x9F\xA0\xAC\xAE\xAF\xFD\xFE\xFB\x3F\xEA\xFA\xFF"
139 };
140
141 /* -------------------------------------------------------------------- */
142
143 /* Console Input: master routine */
144
145 int32 pkb (int32 op, int32 m, int32 n, int32 data)
146 {
147 int32 iodata= 0, ec, ac;
148 switch (op) {
149 case 0: /* SIO 5471 */
150 if (n != 0)
151 return STOP_INVDEV;
152 /*printf("%04X SIO %d,%d,%02X\n\r", IAR[level]-4, m, n, data);*/
153 if (m == 0) { /* Keyboard */
154 pkb_unit.u3 &= 0xFC1;
155 pkb_unit.u3 |= data;
156 if (data & 0x01) {
157 pkb_unit.u3 &= ~KBD_INTREQ;
158 pkb_unit.u3 &= ~KBD_INTKEY;
159 pkb_unit.u3 &= ~KBD_INTEND;
160 return RESET_INTERRUPT;
161 }
162 } else { /* Printer */
163 if (data & 0x80) { /* start print bit */
164 if (debug_reg & 0x80)
165 return STOP_IBKPT;
166 ec = pkb_unit.u4 & 0xff;
167 ac = ebcdic_to_ascii[ec];
168 sim_putchar(ac);
169 pkb_unit.u3 |= PRT_INTREQ;
170 }
171 if (data & 0x40) { /* Carr. Return */
172 sim_putchar('\n');
173 sim_putchar('\r');
174 pkb_unit.u3 |= PRT_INTREQ;
175 }
176 pkb_unit.u3 &= 0xFFe;
177 if (data & 0x04) /* Print interrupt flag */
178 pkb_unit.u3 |= PRT_PRTINT;
179 if (data & 0x01) { /* Reset Interrupt */
180 if (level < 8) {
181 if (!(data & 0x80))
182 pkb_unit.u3 &= ~PRT_INTREQ;
183 return RESET_INTERRUPT;
184 }
185 }
186 }
187 return SCPE_OK;
188 case 1: /* LIO 5471 */
189 if (n != 0)
190 return STOP_INVDEV;
191 if (m != 1)
192 return STOP_INVDEV;
193 pkb_unit.u4 = (data >> 8) & 0xff;
194 return SCPE_OK;
195 break;
196 case 2: /* TIO 5471 */
197 return STOP_INVDEV;
198 case 3: /* SNS 5471 */
199 if (n != 1 && n != 3)
200 return (STOP_INVDEV << 16);
201 if (m == 0) { /* Keyboard data */
202 if (n == 1) { /* Sense bytes 0 & 1 */
203 iodata = (pkb_unit.buf << 8) & 0xff00;
204 if (pkb_unit.u3 & KBD_INTREQ)
205 iodata |= 0x80;
206 if (pkb_unit.u3 & KBD_INTEND)
207 iodata |= 0x40;
208 if (pkb_unit.u3 & KBD_INTKEY)
209 iodata |= 0x08;
210 if (pkb_unit.buf == 0x12) /* Return key */
211 iodata |= 0x04;
212 if (pkb_unit.buf == 0x03) /* Cancel key */
213 iodata |= 0x20;
214 if (pkb_unit.buf == 0x0d) /* End key */
215 iodata |= 0x10;
216 iodata |= ((SCPE_OK << 16) & 0xffff0000);
217 } else { /* Sense bytes 2 & 3 */
218 iodata = 0; /* Manual says CE use only */
219 }
220 } else { /* Printer Data */
221 if (n == 1) { /* Sense bytes 0 & 1 */
222 iodata = 0;
223 if (pkb_unit.u3 & PRT_INTREQ)
224 iodata |= 0x80;
225 } else {
226 iodata = 0; /* CE use only */
227 }
228 }
229 iodata |= ((SCPE_OK << 16) & 0xffff0000);
230 return (iodata);
231 case 4: /* APL 5471 */
232 return STOP_INVDEV;
233 default:
234 break;
235 }
236 printf (">>PKB non-existent function %d\n", op);
237 return SCPE_OK;
238 }
239
240 /* Unit service */
241
242 t_stat pkb_svc (UNIT *uptr)
243 {
244 int32 temp, ac, ec;
245
246 sim_activate (&pkb_unit, pkb_unit.wait); /* continue poll */
247
248 if (pkb_unit.u3 & PRT_INTREQ) { /* Printer Interrupt */
249 int_req |= 2;
250 return SCPE_OK;
251 }
252
253 /* Keyboard : handle input */
254
255 if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */
256
257 ac = temp & 0x7f; /* placed type ASCII char in ac */
258 if (pkb_unit.u3 & KBD_REQINT) {
259 if (ac == key_req) { /* Request Key */
260 pkb_unit.u3 |= KBD_INTREQ;
261 int_req |= 2;
262 return SCPE_OK;
263 }
264 }
265 if (islower(ac))
266 ac = toupper(ac);
267 ec = ascii_to_ebcdic[ac]; /* Translate */
268 pkb_unit.buf = ec; /* put in buf */
269 pkb_unit.pos = pkb_unit.pos + 1;
270 if (ac == key_end) { /* End key */
271 if (pkb_unit.u3 & KBD_KEYINT) {
272 pkb_unit.u3 |= KBD_INTEND;
273 pkb_unit.buf = 0x0d;
274 int_req |= 2;
275 }
276 return SCPE_OK;
277 }
278 if (ac == key_can) { /* Cancel key */
279 if (pkb_unit.u3 & KBD_KEYINT) {
280 pkb_unit.u3 |= KBD_INTEND;
281 pkb_unit.buf = 0x03;
282 int_req |= 2;
283 }
284 return SCPE_OK;
285 }
286 if (ac == key_rtn) { /* Return key */
287 if (pkb_unit.u3 & KBD_KEYINT) {
288 pkb_unit.u3 |= KBD_INTKEY;
289 pkb_unit.buf = 0x12;
290 int_req |= 2;
291 }
292 return SCPE_OK;
293 }
294 if (pkb_unit.u3 & KBD_KEYINT) { /* Key interupts enabled ? */
295 int_req |= 2; /* Device 1 Interrupt! */
296 pkb_unit.u3 |= KBD_INTKEY; /* Set pending flag */
297 }
298 return SCPE_OK;
299 }
300
301 /* Reset routine */
302
303 t_stat pkb_reset (DEVICE *dptr)
304 {
305 pkb_unit.buf = 0;
306 int_req = int_req & ~0x02; /* reset interrupt */
307 sim_activate (&pkb_unit, pkb_unit.wait); /* activate unit */
308 return SCPE_OK;
309 }
310
311 t_stat pkb_setmod (UNIT *uptr, int32 value)
312 {
313 return SCPE_OK;
314 }
315