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