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 
pkb(int32 op,int32 m,int32 n,int32 data)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 
pkb_svc(UNIT * uptr)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 
pkb_reset(DEVICE * dptr)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 
pkb_setmod(UNIT * uptr,int32 value)311 t_stat pkb_setmod (UNIT *uptr, int32 value)
312 {
313 return SCPE_OK;
314 }
315 
316