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