Commit | Line | Data |
---|---|---|
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 | |
35 | extern int32 int_req, dev_busy, dev_done, dev_disable;\r | |
36 | t_stat pkb_svc (UNIT *uptr);\r | |
37 | t_stat pkb_reset (DEVICE *dptr);\r | |
38 | extern t_stat sim_poll_kbd (void);\r | |
39 | extern t_stat sim_putchar (int32 out);\r | |
40 | extern int32 IAR[], level;\r | |
41 | extern 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 | |
65 | int32 key_req = 0x01; /* Request key: ^A */\r | |
66 | int32 key_rtn = 0x12; /* Return key: ^R */\r | |
67 | int32 key_can = 0x1B; /* Cancel key: ESC */\r | |
68 | int32 key_end = 0x0d; /* End key - CR */\r | |
69 | \r | |
70 | UNIT pkb_unit = { UDATA (&pkb_svc, 0, 0), KBD_POLL_WAIT };\r | |
71 | \r | |
72 | REG 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 | |
85 | MTAB pkb_mod[] = {\r | |
86 | { 0 }\r | |
87 | };\r | |
88 | \r | |
89 | DEVICE 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 | |
100 | unsigned 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 | |
122 | unsigned 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 | |
145 | int32 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 | |
242 | t_stat pkb_svc (UNIT *uptr)\r | |
243 | {\r | |
244 | int32 temp, ac, ec;\r | |
245 | \r | |
246 | sim_activate (&pkb_unit, pkb_unit.wait); /* continue poll */\r | |
247 | \r | |
248 | if (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 | |
255 | if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */\r | |
256 | \r | |
257 | ac = temp & 0x7f; /* placed type ASCII char in ac */\r | |
258 | if (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 | |
265 | if (islower(ac))\r | |
266 | ac = toupper(ac); \r | |
267 | ec = ascii_to_ebcdic[ac]; /* Translate */\r | |
268 | pkb_unit.buf = ec; /* put in buf */\r | |
269 | pkb_unit.pos = pkb_unit.pos + 1;\r | |
270 | if (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 | |
278 | if (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 | |
286 | if (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 | |
294 | if (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 | |
298 | return SCPE_OK;\r | |
299 | }\r | |
300 | \r | |
301 | /* Reset routine */\r | |
302 | \r | |
303 | t_stat pkb_reset (DEVICE *dptr)\r | |
304 | {\r | |
305 | pkb_unit.buf = 0;\r | |
306 | int_req = int_req & ~0x02; /* reset interrupt */ \r | |
307 | sim_activate (&pkb_unit, pkb_unit.wait); /* activate unit */\r | |
308 | return SCPE_OK;\r | |
309 | }\r | |
310 | \r | |
311 | t_stat pkb_setmod (UNIT *uptr, int32 value)\r | |
312 | {\r | |
313 | return SCPE_OK;\r | |
314 | }\r | |
315 | \r |