| 1 | /* pdp1_stddev.c: PDP-1 standard devices\r |
| 2 | \r |
| 3 | Copyright (c) 1993-2006, Robert M. Supnik\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 Robert M Supnik 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 Robert M Supnik.\r |
| 25 | \r |
| 26 | ptr paper tape reader\r |
| 27 | ptp paper tape punch\r |
| 28 | tti keyboard\r |
| 29 | tto teleprinter\r |
| 30 | \r |
| 31 | 21-Dec-06 RMS Added 16-channel sequence break support\r |
| 32 | 29-Oct-03 RMS Added PTR FIODEC-to-ASCII translation (from Phil Budne)\r |
| 33 | 07-Sep-03 RMS Changed ioc to ios\r |
| 34 | 30-Aug-03 RMS Revised PTR to conform to Maintenance Manual;\r |
| 35 | added deadlock prevention on errors\r |
| 36 | 23-Jul-03 RMS Revised to detect I/O wait hang\r |
| 37 | 25-Apr-03 RMS Revised for extended file support\r |
| 38 | 22-Dec-02 RMS Added break support\r |
| 39 | 29-Nov-02 RMS Fixed output flag initialization (found by Derek Peschel)\r |
| 40 | 21-Nov-02 RMS Changed typewriter to half duplex (found by Derek Peschel)\r |
| 41 | 06-Oct-02 RMS Revised for V2.10\r |
| 42 | 30-May-02 RMS Widened POS to 32b\r |
| 43 | 29-Nov-01 RMS Added read only unit support\r |
| 44 | 07-Sep-01 RMS Moved function prototypes\r |
| 45 | 10-Jun-01 RMS Fixed comment\r |
| 46 | 30-Oct-00 RMS Standardized device naming\r |
| 47 | \r |
| 48 | Note: PTP timeout must be >10X faster that TTY output timeout for Macro\r |
| 49 | to work correctly!\r |
| 50 | */\r |
| 51 | \r |
| 52 | #include "pdp1_defs.h"\r |
| 53 | \r |
| 54 | #define FIODEC_STOP 013 /* stop code */\r |
| 55 | #define FIODEC_UC 074\r |
| 56 | #define FIODEC_LC 072\r |
| 57 | #define UC_V 6 /* upper case */\r |
| 58 | #define UC (1 << UC_V)\r |
| 59 | #define BOTH (1 << (UC_V + 1)) /* both cases */\r |
| 60 | #define CW (1 << (UC_V + 2)) /* char waiting */\r |
| 61 | #define TT_WIDTH 077\r |
| 62 | #define UNIT_V_ASCII (UNIT_V_UF + 0) /* ASCII/binary mode */\r |
| 63 | #define UNIT_ASCII (1 << UNIT_V_ASCII)\r |
| 64 | #define PTR_LEADER 20 /* ASCII leader chars */\r |
| 65 | \r |
| 66 | int32 ptr_state = 0;\r |
| 67 | int32 ptr_wait = 0;\r |
| 68 | int32 ptr_stopioe = 0;\r |
| 69 | int32 ptr_uc = 0; /* upper/lower case */\r |
| 70 | int32 ptr_hold = 0; /* holding buffer */\r |
| 71 | int32 ptr_leader = PTR_LEADER; /* leader count */\r |
| 72 | int32 ptr_sbs = 0; /* SBS level */\r |
| 73 | int32 ptp_stopioe = 0;\r |
| 74 | int32 ptp_sbs = 0; /* SBS level */\r |
| 75 | int32 tti_hold = 0; /* tti hold buf */\r |
| 76 | int32 tti_sbs = 0; /* SBS level */\r |
| 77 | int32 tty_buf = 0; /* tty buffer */\r |
| 78 | int32 tty_uc = 0; /* tty uc/lc */\r |
| 79 | int32 tto_sbs = 0;\r |
| 80 | \r |
| 81 | extern int32 ios, ioh, cpls, iosta;\r |
| 82 | extern int32 PF, IO, PC, TA;\r |
| 83 | extern int32 M[];\r |
| 84 | \r |
| 85 | int ptr_get_ascii (UNIT *uptr);\r |
| 86 | t_stat ptr_svc (UNIT *uptr);\r |
| 87 | t_stat ptp_svc (UNIT *uptr);\r |
| 88 | t_stat tti_svc (UNIT *uptr);\r |
| 89 | t_stat tto_svc (UNIT *uptr);\r |
| 90 | t_stat ptr_reset (DEVICE *dptr);\r |
| 91 | t_stat ptp_reset (DEVICE *dptr);\r |
| 92 | t_stat tty_reset (DEVICE *dptr);\r |
| 93 | t_stat ptr_boot (int32 unitno, DEVICE *dptr);\r |
| 94 | t_stat ptr_attach (UNIT *uptr, char *cptr);\r |
| 95 | \r |
| 96 | /* Character translation tables */\r |
| 97 | \r |
| 98 | int32 fiodec_to_ascii[128] = {\r |
| 99 | ' ', '1', '2', '3', '4', '5', '6', '7', /* lower case */\r |
| 100 | '8', '9', 0, 0, 0, 0, 0, 0,\r |
| 101 | '0', '/', 's', 't', 'u', 'v', 'w', 'x',\r |
| 102 | 'y', 'z', 0, ',', 0, 0, '\t', 0,\r |
| 103 | '@', 'j', 'k', 'l', 'm', 'n', 'o', 'p',\r |
| 104 | 'q', 'r', 0, 0, '-', ')', '\\', '(',\r |
| 105 | 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g',\r |
| 106 | 'h', 'i', '{', '.', '}', '\b', 0, '\r',\r |
| 107 | ' ', '"', '\'', '~', '#', '!', '&', '<', /* upper case */\r |
| 108 | '>', '^', 0, 0, 0, 0, 0, 0,\r |
| 109 | '`', '?', 'S', 'T', 'U', 'V', 'W', 'X',\r |
| 110 | 'Y', 'Z', 0, '=', 0, 0, '\t', 0,\r |
| 111 | '_', 'J', 'K', 'L', 'M', 'N', 'O', 'P',\r |
| 112 | 'Q', 'R', 0, 0, '+', ']', '|', '[',\r |
| 113 | 0, 'A', 'B', 'C', 'D', 'E', 'F', 'G',\r |
| 114 | 'H', 'I', '{', '*', '}', '\b', 0, '\r'\r |
| 115 | };\r |
| 116 | \r |
| 117 | int32 ascii_to_fiodec[128] = {\r |
| 118 | 0, 0, 0, 0, 0, 0, 0, 0,\r |
| 119 | BOTH+075, BOTH+036, 0, 0, 0, BOTH+077, 0, 0,\r |
| 120 | 0, 0, 0, 0, 0, 0, 0, 0,\r |
| 121 | 0, 0, 0, 0, 0, 0, 0, 0,\r |
| 122 | BOTH+0, UC+005, UC+001, UC+004, 0, 0, UC+006, UC+002,\r |
| 123 | 057, 055, UC+073, UC+054, 033, 054, 073, 021,\r |
| 124 | 020, 001, 002, 003, 004, 005, 006, 007,\r |
| 125 | 010, 011, 0, 0, UC+007, UC+033, UC+010, UC+021,\r |
| 126 | 040, UC+061, UC+062, UC+063, UC+064, UC+065, UC+066, UC+067,\r |
| 127 | UC+070, UC+071, UC+041, UC+042, UC+043, UC+044, UC+045, UC+046,\r |
| 128 | UC+047, UC+050, UC+051, UC+022, UC+023, UC+024, UC+025, UC+026,\r |
| 129 | UC+027, UC+030, UC+031, UC+057, 056, UC+055, UC+011, UC+040,\r |
| 130 | UC+020, 061, 062, 063, 064, 065, 066, 067,\r |
| 131 | 070, 071, 041, 042, 043, 044, 045, 046,\r |
| 132 | 047, 050, 051, 022, 023, 024, 025, 026,\r |
| 133 | 027, 030, 031, 0, UC+056, 0, UC+003, BOTH+075\r |
| 134 | };\r |
| 135 | \r |
| 136 | /* PTR data structures\r |
| 137 | \r |
| 138 | ptr_dev PTR device descriptor\r |
| 139 | ptr_unit PTR unit\r |
| 140 | ptr_reg PTR register list\r |
| 141 | */\r |
| 142 | \r |
| 143 | UNIT ptr_unit = {\r |
| 144 | UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0),\r |
| 145 | SERIAL_IN_WAIT\r |
| 146 | };\r |
| 147 | \r |
| 148 | REG ptr_reg[] = {\r |
| 149 | { ORDATA (BUF, ptr_unit.buf, 18) },\r |
| 150 | { FLDATA (UC, ptr_uc, UC_V) },\r |
| 151 | { FLDATA (DONE, iosta, IOS_V_PTR) },\r |
| 152 | { FLDATA (RPLS, cpls, CPLS_V_PTR) },\r |
| 153 | { ORDATA (HOLD, ptr_hold, 9), REG_HRO },\r |
| 154 | { ORDATA (STATE, ptr_state, 5), REG_HRO },\r |
| 155 | { FLDATA (WAIT, ptr_wait, 0), REG_HRO },\r |
| 156 | { DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT },\r |
| 157 | { DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT },\r |
| 158 | { DRDATA (LEADER, ptr_leader, 6), REG_HRO },\r |
| 159 | { FLDATA (STOP_IOE, ptr_stopioe, 0) },\r |
| 160 | { DRDATA (SBSLVL, ptr_sbs, 4), REG_HRO },\r |
| 161 | { NULL }\r |
| 162 | };\r |
| 163 | \r |
| 164 | MTAB ptr_mod[] = {\r |
| 165 | { MTAB_XTD|MTAB_VDV, 0, "SBSLVL", "SBSLVL",\r |
| 166 | &dev_set_sbs, &dev_show_sbs, (void *) &ptr_sbs },\r |
| 167 | { UNIT_ASCII, UNIT_ASCII, "ASCII", "ASCII", NULL },\r |
| 168 | { UNIT_ASCII, 0, "FIODEC", "FIODEC", NULL },\r |
| 169 | { 0 }\r |
| 170 | };\r |
| 171 | \r |
| 172 | DEVICE ptr_dev = {\r |
| 173 | "PTR", &ptr_unit, ptr_reg, ptr_mod,\r |
| 174 | 1, 10, 31, 1, 8, 8,\r |
| 175 | NULL, NULL, &ptr_reset,\r |
| 176 | &ptr_boot, &ptr_attach, NULL,\r |
| 177 | NULL, 0\r |
| 178 | };\r |
| 179 | \r |
| 180 | /* PTP data structures\r |
| 181 | \r |
| 182 | ptp_dev PTP device descriptor\r |
| 183 | ptp_unit PTP unit\r |
| 184 | ptp_reg PTP register list\r |
| 185 | */\r |
| 186 | \r |
| 187 | UNIT ptp_unit = {\r |
| 188 | UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT\r |
| 189 | };\r |
| 190 | \r |
| 191 | REG ptp_reg[] = {\r |
| 192 | { ORDATA (BUF, ptp_unit.buf, 8) },\r |
| 193 | { FLDATA (DONE, iosta, IOS_V_PTP) },\r |
| 194 | { FLDATA (RPLS, cpls, CPLS_V_PTP) },\r |
| 195 | { DRDATA (POS, ptp_unit.pos, T_ADDR_W), PV_LEFT },\r |
| 196 | { DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT },\r |
| 197 | { FLDATA (STOP_IOE, ptp_stopioe, 0) },\r |
| 198 | { DRDATA (SBSLVL, ptp_sbs, 4), REG_HRO },\r |
| 199 | { NULL }\r |
| 200 | };\r |
| 201 | \r |
| 202 | MTAB ptp_mod[] = {\r |
| 203 | { MTAB_XTD|MTAB_VDV, 0, "SBSLVL", "SBSLVL",\r |
| 204 | &dev_set_sbs, &dev_show_sbs, (void *) &ptp_sbs },\r |
| 205 | { 0 }\r |
| 206 | };\r |
| 207 | \r |
| 208 | DEVICE ptp_dev = {\r |
| 209 | "PTP", &ptp_unit, ptp_reg, ptp_mod,\r |
| 210 | 1, 10, 31, 1, 8, 8,\r |
| 211 | NULL, NULL, &ptp_reset,\r |
| 212 | NULL, NULL, NULL,\r |
| 213 | NULL, 0\r |
| 214 | };\r |
| 215 | \r |
| 216 | /* TTI data structures\r |
| 217 | \r |
| 218 | tti_dev TTI device descriptor\r |
| 219 | tti_unit TTI unit\r |
| 220 | tti_reg TTI register list\r |
| 221 | */\r |
| 222 | \r |
| 223 | UNIT tti_unit = { UDATA (&tti_svc, 0, 0), KBD_POLL_WAIT };\r |
| 224 | \r |
| 225 | REG tti_reg[] = {\r |
| 226 | { ORDATA (BUF, tty_buf, 6) },\r |
| 227 | { FLDATA (UC, tty_uc, UC_V) },\r |
| 228 | { ORDATA (HOLD, tti_hold, 9), REG_HRO },\r |
| 229 | { FLDATA (DONE, iosta, IOS_V_TTI) },\r |
| 230 | { DRDATA (POS, tti_unit.pos, T_ADDR_W), PV_LEFT },\r |
| 231 | { DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT },\r |
| 232 | { DRDATA (SBSLVL, tti_sbs, 4), REG_HRO },\r |
| 233 | { NULL }\r |
| 234 | };\r |
| 235 | \r |
| 236 | MTAB tti_mod[] = {\r |
| 237 | { MTAB_XTD|MTAB_VDV, 0, "SBSLVL", "SBSLVL",\r |
| 238 | &dev_set_sbs, &dev_show_sbs, (void *) &tti_sbs },\r |
| 239 | { 0 }\r |
| 240 | };\r |
| 241 | \r |
| 242 | DEVICE tti_dev = {\r |
| 243 | "TTI", &tti_unit, tti_reg, tti_mod,\r |
| 244 | 1, 10, 31, 1, 8, 8,\r |
| 245 | NULL, NULL, &tty_reset,\r |
| 246 | NULL, NULL, NULL,\r |
| 247 | NULL, 0\r |
| 248 | };\r |
| 249 | \r |
| 250 | /* TTO data structures\r |
| 251 | \r |
| 252 | tto_dev TTO device descriptor\r |
| 253 | tto_unit TTO unit\r |
| 254 | tto_reg TTO register list\r |
| 255 | */\r |
| 256 | \r |
| 257 | UNIT tto_unit = { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT * 10 };\r |
| 258 | \r |
| 259 | REG tto_reg[] = {\r |
| 260 | { ORDATA (BUF, tty_buf, 6) },\r |
| 261 | { FLDATA (UC, tty_uc, UC_V) },\r |
| 262 | { FLDATA (RPLS, cpls, CPLS_V_TTO) },\r |
| 263 | { FLDATA (DONE, iosta, IOS_V_TTO) },\r |
| 264 | { DRDATA (POS, tto_unit.pos, T_ADDR_W), PV_LEFT },\r |
| 265 | { DRDATA (TIME, tto_unit.wait, 24), PV_LEFT },\r |
| 266 | { DRDATA (SBSLVL, tto_sbs, 4), REG_HRO },\r |
| 267 | { NULL }\r |
| 268 | };\r |
| 269 | \r |
| 270 | MTAB tto_mod[] = {\r |
| 271 | { MTAB_XTD|MTAB_VDV, 0, "SBSLVL", "SBSLVL",\r |
| 272 | &dev_set_sbs, &dev_show_sbs, (void *) &tto_sbs },\r |
| 273 | { 0 }\r |
| 274 | };\r |
| 275 | \r |
| 276 | DEVICE tto_dev = {\r |
| 277 | "TTO", &tto_unit, tto_reg, tto_mod,\r |
| 278 | 1, 10, 31, 1, 8, 8,\r |
| 279 | NULL, NULL, &tty_reset,\r |
| 280 | NULL, NULL, NULL,\r |
| 281 | NULL, 0\r |
| 282 | };\r |
| 283 | \r |
| 284 | /* Paper tape reader: IOT routine. Points to note:\r |
| 285 | \r |
| 286 | - RPA (but not RPB) complements the reader clutch control. Thus,\r |
| 287 | if the reader is running, RPA will stop it.\r |
| 288 | - The status bit indicates data in the reader buffer that has not\r |
| 289 | been transfered to IO. It is cleared by any RB->IO operation,\r |
| 290 | including RRB and the completion pulse.\r |
| 291 | - A reader error on a wait mode operation could hang the simulator.\r |
| 292 | IOH is set; any retry (without RESET) will be NOP'd. Accordingly,\r |
| 293 | the PTR service routine clears IOH on any error during a rpa/rpb i.\r |
| 294 | */\r |
| 295 | \r |
| 296 | int32 ptr (int32 inst, int32 dev, int32 dat)\r |
| 297 | {\r |
| 298 | if (dev == 0030) { /* RRB */\r |
| 299 | iosta = iosta & ~IOS_PTR; /* clear status */\r |
| 300 | return ptr_unit.buf; /* return data */\r |
| 301 | }\r |
| 302 | if (dev == 0002) ptr_state = 18; /* RPB, mode = binary */\r |
| 303 | else if (sim_is_active (&ptr_unit)) { /* RPA, running? */\r |
| 304 | sim_cancel (&ptr_unit); /* stop reader */\r |
| 305 | return dat;\r |
| 306 | }\r |
| 307 | else ptr_state = 0; /* mode = alpha */\r |
| 308 | ptr_unit.buf = 0; /* clear buffer */\r |
| 309 | if (inst & IO_WAIT) ptr_wait = 1; /* set ptr wait */\r |
| 310 | else ptr_wait = 0; /* from IR<5> */\r |
| 311 | if (GEN_CPLS (inst)) { /* comp pulse? */\r |
| 312 | ios = 0;\r |
| 313 | cpls = cpls | CPLS_PTR;\r |
| 314 | }\r |
| 315 | else cpls = cpls & ~CPLS_PTR;\r |
| 316 | sim_activate (&ptr_unit, ptr_unit.wait); /* start reader */\r |
| 317 | return dat;\r |
| 318 | }\r |
| 319 | \r |
| 320 | /* Unit service */\r |
| 321 | \r |
| 322 | t_stat ptr_svc (UNIT *uptr)\r |
| 323 | {\r |
| 324 | int32 temp;\r |
| 325 | \r |
| 326 | if ((uptr->flags & UNIT_ATT) == 0) { /* attached? */\r |
| 327 | if (ptr_wait) ptr_wait = ioh = 0; /* if wait, clr ioh */\r |
| 328 | if ((cpls & CPLS_PTR) || ptr_stopioe) return SCPE_UNATT;\r |
| 329 | return SCPE_OK;\r |
| 330 | }\r |
| 331 | if ((uptr->flags & UNIT_ASCII) && (ptr_state == 0)) /* ASCII mode, alpha read? */\r |
| 332 | temp = ptr_get_ascii (uptr); /* get processed char */\r |
| 333 | else if ((temp = getc (uptr->fileref)) != EOF) /* no, get raw char */\r |
| 334 | uptr->pos = uptr->pos + 1; /* if not eof, count */\r |
| 335 | if (temp == EOF) { /* end of file? */\r |
| 336 | if (ptr_wait) ptr_wait = ioh = 0; /* if wait, clr ioh */\r |
| 337 | if (feof (uptr->fileref)) {\r |
| 338 | if ((cpls & CPLS_PTR) || ptr_stopioe) printf ("PTR end of file\n");\r |
| 339 | else return SCPE_OK;\r |
| 340 | }\r |
| 341 | else perror ("PTR I/O error");\r |
| 342 | clearerr (uptr->fileref);\r |
| 343 | return SCPE_IOERR;\r |
| 344 | }\r |
| 345 | if (ptr_state == 0) uptr->buf = temp & 0377; /* alpha */\r |
| 346 | else if (temp & 0200) { /* binary */\r |
| 347 | ptr_state = ptr_state - 6;\r |
| 348 | uptr->buf = uptr->buf | ((temp & 077) << ptr_state);\r |
| 349 | }\r |
| 350 | if (ptr_state == 0) { /* done? */\r |
| 351 | if (cpls & CPLS_PTR) { /* completion pulse? */\r |
| 352 | iosta = iosta & ~IOS_PTR; /* clear flag */\r |
| 353 | IO = uptr->buf; /* fill IO */\r |
| 354 | ios = 1; /* restart */\r |
| 355 | cpls = cpls & ~CPLS_PTR;\r |
| 356 | }\r |
| 357 | else { /* no, interrupt */\r |
| 358 | iosta = iosta | IOS_PTR; /* set flag */\r |
| 359 | dev_req_int (ptr_sbs); /* req interrupt */\r |
| 360 | }\r |
| 361 | }\r |
| 362 | else sim_activate (uptr, uptr->wait); /* get next char */\r |
| 363 | return SCPE_OK;\r |
| 364 | }\r |
| 365 | \r |
| 366 | /* Read next ASCII character */\r |
| 367 | \r |
| 368 | int ptr_get_ascii (UNIT *uptr)\r |
| 369 | {\r |
| 370 | int c;\r |
| 371 | int32 in;\r |
| 372 | \r |
| 373 | if (ptr_leader > 0) { /* leader? */\r |
| 374 | ptr_leader = ptr_leader - 1; /* count down */\r |
| 375 | return 0;\r |
| 376 | }\r |
| 377 | if (ptr_hold & CW) { /* char waiting? */\r |
| 378 | in = ptr_hold & TT_WIDTH; /* return char */\r |
| 379 | ptr_hold = 0; /* not waiting */\r |
| 380 | }\r |
| 381 | else {\r |
| 382 | for (;;) { /* until valid char */\r |
| 383 | if ((c = getc (uptr->fileref)) == EOF) /* get next char, EOF? */\r |
| 384 | return FIODEC_STOP; /* return STOP */\r |
| 385 | uptr->pos = uptr->pos + 1; /* count char */\r |
| 386 | c = c & 0177; /* cut to 7b */\r |
| 387 | if (c == '\n') c = '\r'; /* NL -> CR */\r |
| 388 | else if (c == '\r') continue; /* ignore CR */\r |
| 389 | in = ascii_to_fiodec[c]; /* convert char */\r |
| 390 | if ((in == 0) && (c != ' ')) continue; /* ignore unknowns */ \r |
| 391 | if ((in & BOTH) || ((in & UC) == ptr_uc)) /* case match? */\r |
| 392 | in = in & TT_WIDTH; /* cut to 6b */\r |
| 393 | else { /* no, case shift */\r |
| 394 | ptr_hold = in | CW; /* set char waiting */\r |
| 395 | ptr_uc = in & UC; /* set case */\r |
| 396 | in = ptr_uc? FIODEC_UC: FIODEC_LC; /* return case */\r |
| 397 | } /* end else */\r |
| 398 | break;\r |
| 399 | } /* end for */\r |
| 400 | } /* end else */\r |
| 401 | in = in * 010040201; /* even parity from */\r |
| 402 | in = in | 027555555400; /* HACKMEM 167 */\r |
| 403 | in = in % (9 << 7);\r |
| 404 | return in & 0377;\r |
| 405 | }\r |
| 406 | \r |
| 407 | /* Reset routine */\r |
| 408 | \r |
| 409 | t_stat ptr_reset (DEVICE *dptr)\r |
| 410 | {\r |
| 411 | ptr_state = 0; /* clear state */\r |
| 412 | ptr_wait = 0;\r |
| 413 | ptr_hold = 0;\r |
| 414 | ptr_uc = 0;\r |
| 415 | ptr_unit.buf = 0;\r |
| 416 | cpls = cpls & ~CPLS_PTR;\r |
| 417 | iosta = iosta & ~IOS_PTR; /* clear flag */\r |
| 418 | sim_cancel (&ptr_unit); /* deactivate unit */\r |
| 419 | return SCPE_OK;\r |
| 420 | }\r |
| 421 | \r |
| 422 | /* Attach routine */\r |
| 423 | \r |
| 424 | t_stat ptr_attach (UNIT *uptr, char *cptr)\r |
| 425 | {\r |
| 426 | ptr_leader = PTR_LEADER; /* set up leader */\r |
| 427 | return attach_unit (uptr, cptr);\r |
| 428 | }\r |
| 429 | \r |
| 430 | /* Bootstrap routine */\r |
| 431 | \r |
| 432 | int32 ptr_getw (UNIT *uptr)\r |
| 433 | {\r |
| 434 | int32 i, tmp, word;\r |
| 435 | \r |
| 436 | for (i = word = 0; i < 3;) {\r |
| 437 | if ((tmp = getc (uptr->fileref)) == EOF) return -1;\r |
| 438 | uptr->pos = uptr->pos + 1;\r |
| 439 | if (tmp & 0200) {\r |
| 440 | word = (word << 6) | (tmp & 077);\r |
| 441 | i++;\r |
| 442 | }\r |
| 443 | }\r |
| 444 | return word;\r |
| 445 | }\r |
| 446 | \r |
| 447 | t_stat ptr_boot (int32 unitno, DEVICE *dptr)\r |
| 448 | {\r |
| 449 | int32 origin, val;\r |
| 450 | int32 fld = TA & EPCMASK;\r |
| 451 | \r |
| 452 | for (;;) {\r |
| 453 | if ((val = ptr_getw (&ptr_unit)) < 0) return SCPE_FMT;\r |
| 454 | if (((val & 0760000) == OP_DIO) || /* DIO? */\r |
| 455 | ((val & 0760000) == OP_DAC)) { /* hack - Macro1 err */\r |
| 456 | origin = val & DAMASK;\r |
| 457 | if ((val = ptr_getw (&ptr_unit)) < 0) return SCPE_FMT;\r |
| 458 | M[fld | origin] = val;\r |
| 459 | }\r |
| 460 | else if ((val & 0760000) == OP_JMP) { /* JMP? */\r |
| 461 | PC = fld | (val & DAMASK);\r |
| 462 | break;\r |
| 463 | }\r |
| 464 | else return SCPE_FMT; /* bad instr */\r |
| 465 | }\r |
| 466 | return SCPE_OK; /* done */\r |
| 467 | }\r |
| 468 | \r |
| 469 | /* Paper tape punch: IOT routine */\r |
| 470 | \r |
| 471 | int32 ptp (int32 inst, int32 dev, int32 dat)\r |
| 472 | {\r |
| 473 | iosta = iosta & ~IOS_PTP; /* clear flag */\r |
| 474 | ptp_unit.buf = (dev == 0006)? ((dat >> 12) | 0200): (dat & 0377);\r |
| 475 | if (GEN_CPLS (inst)) { /* comp pulse? */\r |
| 476 | ios = 0;\r |
| 477 | cpls = cpls | CPLS_PTP;\r |
| 478 | }\r |
| 479 | else cpls = cpls & ~CPLS_PTP;\r |
| 480 | sim_activate (&ptp_unit, ptp_unit.wait); /* start unit */\r |
| 481 | return dat;\r |
| 482 | }\r |
| 483 | \r |
| 484 | /* Unit service */\r |
| 485 | \r |
| 486 | t_stat ptp_svc (UNIT *uptr)\r |
| 487 | {\r |
| 488 | if (cpls & CPLS_PTP) { /* completion pulse? */\r |
| 489 | ios = 1; /* restart */\r |
| 490 | cpls = cpls & ~CPLS_PTP;\r |
| 491 | }\r |
| 492 | iosta = iosta | IOS_PTP; /* set flag */\r |
| 493 | dev_req_int (ptp_sbs); /* req interrupt */\r |
| 494 | if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */\r |
| 495 | return IORETURN (ptp_stopioe, SCPE_UNATT);\r |
| 496 | if (putc (uptr->buf, uptr->fileref) == EOF) { /* I/O error? */\r |
| 497 | perror ("PTP I/O error");\r |
| 498 | clearerr (uptr->fileref);\r |
| 499 | return SCPE_IOERR;\r |
| 500 | }\r |
| 501 | uptr->pos = uptr->pos + 1;\r |
| 502 | return SCPE_OK;\r |
| 503 | }\r |
| 504 | \r |
| 505 | /* Reset routine */\r |
| 506 | \r |
| 507 | t_stat ptp_reset (DEVICE *dptr)\r |
| 508 | {\r |
| 509 | ptp_unit.buf = 0; /* clear state */\r |
| 510 | cpls = cpls & ~CPLS_PTP;\r |
| 511 | iosta = iosta & ~IOS_PTP; /* clear flag */\r |
| 512 | sim_cancel (&ptp_unit); /* deactivate unit */\r |
| 513 | return SCPE_OK;\r |
| 514 | }\r |
| 515 | \r |
| 516 | /* Typewriter IOT routines */\r |
| 517 | \r |
| 518 | int32 tti (int32 inst, int32 dev, int32 dat)\r |
| 519 | {\r |
| 520 | iosta = iosta & ~IOS_TTI; /* clear flag */\r |
| 521 | if (inst & (IO_WAIT | IO_CPLS)) /* wait or sync? */\r |
| 522 | return (STOP_RSRV << IOT_V_REASON) | (tty_buf & 077);\r |
| 523 | return tty_buf & 077;\r |
| 524 | }\r |
| 525 | \r |
| 526 | int32 tto (int32 inst, int32 dev, int32 dat)\r |
| 527 | {\r |
| 528 | iosta = iosta & ~IOS_TTO; /* clear flag */\r |
| 529 | tty_buf = dat & TT_WIDTH; /* load buffer */\r |
| 530 | if (GEN_CPLS (inst)) { /* comp pulse? */\r |
| 531 | ios = 0;\r |
| 532 | cpls = cpls | CPLS_TTO;\r |
| 533 | }\r |
| 534 | else cpls = cpls & ~CPLS_TTO;\r |
| 535 | sim_activate (&tto_unit, tto_unit.wait); /* activate unit */\r |
| 536 | return dat;\r |
| 537 | }\r |
| 538 | \r |
| 539 | /* Unit service routines */\r |
| 540 | \r |
| 541 | t_stat tti_svc (UNIT *uptr)\r |
| 542 | {\r |
| 543 | int32 in, temp;\r |
| 544 | \r |
| 545 | sim_activate (uptr, uptr->wait); /* continue poll */\r |
| 546 | if (tti_hold & CW) { /* char waiting? */\r |
| 547 | tty_buf = tti_hold & TT_WIDTH; /* return char */\r |
| 548 | tti_hold = 0; /* not waiting */\r |
| 549 | }\r |
| 550 | else {\r |
| 551 | if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp;\r |
| 552 | if (temp & SCPE_BREAK) return SCPE_OK; /* ignore break */\r |
| 553 | temp = temp & 0177;\r |
| 554 | if (temp == 0177) temp = '\b'; /* rubout? bs */\r |
| 555 | sim_putchar (temp); /* echo */\r |
| 556 | if (temp == '\r') sim_putchar ('\n'); /* cr? add nl */\r |
| 557 | in = ascii_to_fiodec[temp]; /* translate char */\r |
| 558 | if (in == 0) return SCPE_OK; /* no xlation? */\r |
| 559 | if ((in & BOTH) || ((in & UC) == (tty_uc & UC)))\r |
| 560 | tty_buf = in & TT_WIDTH;\r |
| 561 | else { /* must shift */\r |
| 562 | tty_uc = in & UC; /* new case */\r |
| 563 | tty_buf = tty_uc? FIODEC_UC: FIODEC_LC;\r |
| 564 | tti_hold = in | CW; /* set 2nd waiting */\r |
| 565 | }\r |
| 566 | }\r |
| 567 | iosta = iosta | IOS_TTI; /* set flag */\r |
| 568 | dev_req_int (tti_sbs); /* req interrupt */\r |
| 569 | PF = PF | PF_SS_1; /* set prog flag 1 */\r |
| 570 | uptr->pos = uptr->pos + 1;\r |
| 571 | return SCPE_OK;\r |
| 572 | }\r |
| 573 | \r |
| 574 | t_stat tto_svc (UNIT *uptr)\r |
| 575 | {\r |
| 576 | int32 c;\r |
| 577 | t_stat r;\r |
| 578 | \r |
| 579 | if (tty_buf == FIODEC_UC) tty_uc = UC; /* upper case? */\r |
| 580 | else if (tty_buf == FIODEC_LC) tty_uc = 0; /* lower case? */\r |
| 581 | else {\r |
| 582 | c = fiodec_to_ascii[tty_buf | tty_uc]; /* translate */\r |
| 583 | if (c && ((r = sim_putchar_s (c)) != SCPE_OK)) { /* output; error? */\r |
| 584 | sim_activate (uptr, uptr->wait); /* retry */\r |
| 585 | return ((r == SCPE_STALL)? SCPE_OK: r);\r |
| 586 | }\r |
| 587 | }\r |
| 588 | if (cpls & CPLS_TTO) { /* completion pulse? */\r |
| 589 | ios = 1; /* restart */\r |
| 590 | cpls = cpls & ~CPLS_TTO;\r |
| 591 | }\r |
| 592 | iosta = iosta | IOS_TTO; /* set flag */\r |
| 593 | dev_req_int (tto_sbs); /* req interrupt */\r |
| 594 | uptr->pos = uptr->pos + 1;\r |
| 595 | if (c == '\r') { /* cr? add lf */\r |
| 596 | sim_putchar ('\n');\r |
| 597 | uptr->pos = uptr->pos + 1;\r |
| 598 | }\r |
| 599 | return SCPE_OK;\r |
| 600 | }\r |
| 601 | \r |
| 602 | /* Reset routine */\r |
| 603 | \r |
| 604 | t_stat tty_reset (DEVICE *dptr)\r |
| 605 | {\r |
| 606 | tty_buf = 0; /* clear buffer */\r |
| 607 | tty_uc = 0; /* clear case */\r |
| 608 | tti_hold = 0; /* clear hold buf */\r |
| 609 | cpls = cpls & ~CPLS_TTO;\r |
| 610 | iosta = (iosta & ~IOS_TTI) | IOS_TTO; /* clear flag */\r |
| 611 | sim_activate (&tti_unit, tti_unit.wait); /* activate keyboard */\r |
| 612 | sim_cancel (&tto_unit); /* stop printer */\r |
| 613 | return SCPE_OK;\r |
| 614 | }\r |