| 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 |