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