1 /* h316_stddev.c: Honeywell 316/516 standard devices
2 
3    Copyright (c) 1999-2008, 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          316/516-50 paper tape reader
27    ptp          316/516-52 paper tape punch
28    tty          316/516-33 teleprinter
29    clk/options  316/516-12 real time clocks/internal options
30 
31    09-Jun-07    RMS     Fixed bug in clock increment (Theo Engel)
32    30-Sep-06    RMS     Fixed handling of non-printable characters in KSR mode
33    03-Apr-06    RMS     Fixed bugs in punch state handling (Theo Engel)
34    22-Nov-05    RMS     Revised for new terminal processing routines
35    05-Feb-05    RMS     Fixed bug in OCP '0001 (Philipp Hachtmann)
36    31-Jan-05    RMS     Fixed bug in TTY print (Philipp Hachtmann)
37    01-Dec-04    RMS     Fixed problem in SKS '104 (Philipp Hachtmann)
38                         Fixed bug in SKS '504
39                         Added PTR detach routine, stops motion
40                         Added PTR/PTP ASCII file support
41                         Added TTR/TTP support
42    24-Oct-03    RMS     Added DMA/DMC support
43    25-Apr-03    RMS     Revised for extended file support
44    01-Mar-03    RMS     Added SET/SHOW CLK FREQ support
45    22-Dec-02    RMS     Added break support
46    01-Nov-02    RMS     Added 7b/8b support to terminal
47    30-May-02    RMS     Widened POS to 32b
48    03-Nov-01    RMS     Implemented upper case for console output
49    29-Nov-01    RMS     Added read only unit support
50    07-Sep-01    RMS     Moved function prototypes
51 
52    The ASR-33/35 reader/punch logic, and the ASCII file support for all paper tape
53    devices, logic is taken, with grateful thanks, from Adrian Wise's H316 emulator.
54 
55    Teletype reader transitions:
56 
57    - SET TTY2 START puts the reader in RUN
58    - XOFF from keyboard/reader stops the reader after 1-2 more characters are read
59    - XON from program starts the reader
60    - Detach, SET TTY2 STOP, or end of file stops the reader
61 
62    Teletype punch transitions:
63 
64    - SET TTY3 START puts the punch in RUN
65    - XOFF from program stops the punch after 1 more character is punched
66    - TAPE from program starts the punch after 1 character delay
67    - Detach or SET TTY3 STOP stops the punch
68 */
69 
70 #include "h316_defs.h"
71 #include <ctype.h>
72 
73 #define UNIT_V_ASC      (TTUF_V_UF + 0)                 /* ASCII */
74 #define UNIT_V_UASC     (TTUF_V_UF + 1)                 /* Unix ASCII */
75 #define UNIT_ASC        (1 << UNIT_V_ASC)
76 #define UNIT_UASC       (1 << UNIT_V_UASC)
77 #define STA             u3                              /* state bits */
78 #define LF_PEND         01                              /* lf pending */
79 #define RUNNING         02                              /* tape running */
80 
81 #define XON             0021
82 #define TAPE            0022
83 #define XOFF            0023
84 #define RUBOUT          0377
85 
86 extern uint16 M[];
87 extern int32 PC;
88 extern int32 stop_inst;
89 extern int32 C, dp, ext, extoff_pending, sc;
90 extern int32 dev_int, dev_enb;
91 extern int32 sim_switches;
92 extern UNIT cpu_unit;
93 
94 uint32 ptr_motion = 0;                                  /* read motion */
95 uint32 ptr_stopioe = 0;                                 /* stop on error */
96 uint32 ptp_stopioe = 0;
97 uint32 ptp_power = 0;                                   /* punch power, time */
98 int32 ptp_ptime;
99 uint32 ttr_stopioe = 0;
100 uint32 tty_mode = 0;                                    /* input (0), output (1) */
101 uint32 tty_buf = 0;                                     /* tty buffer */
102 uint32 ttr_xoff_read = 0;
103 uint32 ttp_tape_rcvd = 0;
104 uint32 ttp_xoff_rcvd = 0;
105 int32 clk_tps = 60;                                     /* ticks per second */
106 
107 int32 ptrio (int32 inst, int32 fnc, int32 dat, int32 dev);
108 t_stat ptr_svc (UNIT *uptr);
109 t_stat ptr_reset (DEVICE *dptr);
110 t_stat ptr_boot (int32 unitno, DEVICE *dptr);
111 int32 ptpio (int32 inst, int32 fnc, int32 dat, int32 dev);
112 t_stat ptp_svc (UNIT *uptr);
113 t_stat ptp_reset (DEVICE *dptr);
114 int32 ttyio (int32 inst, int32 fnc, int32 dat, int32 dev);
115 t_stat tti_svc (UNIT *uptr);
116 t_stat tto_svc (UNIT *uptr);
117 t_stat tty_reset (DEVICE *dptr);
118 t_stat ttio_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc);
119 t_stat ttrp_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc);
120 t_stat ttrp_set_start_stop (UNIT *uptr, int32 val, char *cptr, void *desc);
121 int32 clkio (int32 inst, int32 fnc, int32 dat, int32 dev);
122 t_stat clk_svc (UNIT *uptr);
123 t_stat clk_reset (DEVICE *dptr);
124 t_stat clk_set_freq (UNIT *uptr, int32 val, char *cptr, void *desc);
125 t_stat clk_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc);
126 t_stat pt_attach (UNIT *uptr, char *cptr);
127 t_stat pt_detach (UNIT *uptr);
128 t_stat tto_write (int32 c);
129 t_stat ttp_write (int32 c);
130 
131 /* PTR data structures
132 
133    ptr_dev      PTR device descriptor
134    ptr_unit     PTR unit descriptor
135    ptr_mod      PTR modifiers
136    ptr_reg      PTR register list
137 */
138 
139 DIB ptr_dib = { PTR, IOBUS, 1, &ptrio };
140 
141 UNIT ptr_unit = {
142     UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0),
143            SERIAL_IN_WAIT
144     };
145 
146 REG ptr_reg[] = {
147     { ORDATA (BUF, ptr_unit.buf, 8) },
148     { FLDATA (READY, dev_int, INT_V_PTR) },
149     { FLDATA (ENABLE, dev_enb, INT_V_PTR) },
150     { FLDATA (MOTION, ptr_motion, 0) },
151     { DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT },
152     { DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT },
153     { ORDATA (RSTATE, ptr_unit.STA, 2), REG_HIDDEN },
154     { FLDATA (STOP_IOE, ptr_stopioe, 0) },
155     { NULL }
156     };
157 
158 MTAB pt_mod[] = {
159     { UNIT_ATT+UNIT_ASC+UNIT_UASC, UNIT_ATT+UNIT_ASC, "ASCII", NULL },
160     { UNIT_ATT+UNIT_ASC+UNIT_UASC, UNIT_ATT+UNIT_ASC+UNIT_UASC, "Unix ASCII", NULL },
161     { 0 }
162     };
163 
164 DEVICE ptr_dev = {
165     "PTR", &ptr_unit, ptr_reg, pt_mod,
166     1, 10, 31, 1, 8, 8,
167     NULL, NULL, &ptr_reset,
168     &ptr_boot, &pt_attach, &pt_detach,
169     &ptr_dib, 0
170     };
171 
172 /* PTP data structures
173 
174    ptp_dev      PTP device descriptor
175    ptp_unit     PTP unit descriptor
176    ptp_mod      PTP modifiers
177    ptp_reg      PTP register list
178 */
179 
180 DIB ptp_dib = { PTP, IOBUS, 1, &ptpio };
181 
182 UNIT ptp_unit = {
183     UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT
184     };
185 
186 REG ptp_reg[] = {
187     { ORDATA (BUF, ptp_unit.buf, 8) },
188     { FLDATA (READY, dev_int, INT_V_PTP) },
189     { FLDATA (ENABLE, dev_enb, INT_V_PTP) },
190     { FLDATA (POWER, ptp_power, 0) },
191     { DRDATA (POS, ptp_unit.pos, T_ADDR_W), PV_LEFT },
192     { ORDATA (PSTATE, ptp_unit.STA, 2), REG_HIDDEN },
193     { DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT },
194     { DRDATA (PWRTIME, ptp_ptime, 24), PV_LEFT },
195     { FLDATA (STOP_IOE, ptp_stopioe, 0) },
196     { NULL }
197     };
198 
199 DEVICE ptp_dev = {
200     "PTP", &ptp_unit, ptp_reg, pt_mod,
201     1, 10, 31, 1, 8, 8,
202     NULL, NULL, &ptp_reset,
203     NULL, &pt_attach, NULL,
204     &ptp_dib, 0
205     };
206 
207 /* TTY data structures
208 
209    tty_dev      TTY device descriptor
210    tty_unit     TTY unit descriptor
211    tty_reg      TTY register list
212    tty_mod      TTy modifiers list
213 */
214 
215 #define TTI     0
216 #define TTO     1
217 #define TTR     2
218 #define TTP     3
219 
220 DIB tty_dib = { TTY, IOBUS, 1, &ttyio };
221 
222 UNIT tty_unit[] = {
223     { UDATA (&tti_svc, TT_MODE_KSR, 0), KBD_POLL_WAIT },
224     { UDATA (&tto_svc, TT_MODE_KSR, 0), SERIAL_OUT_WAIT },
225     { UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0) },
226     { UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) }
227     };
228 
229 REG tty_reg[] = {
230     { ORDATA (BUF, tty_buf, 8) },
231     { FLDATA (MODE, tty_mode, 0) },
232     { FLDATA (READY, dev_int, INT_V_TTY) },
233     { FLDATA (ENABLE, dev_enb, INT_V_TTY) },
234     { DRDATA (KPOS, tty_unit[TTI].pos, T_ADDR_W), PV_LEFT },
235     { DRDATA (KTIME, tty_unit[TTI].wait, 24), REG_NZ + PV_LEFT },
236     { DRDATA (TPOS, tty_unit[TTO].pos, T_ADDR_W), PV_LEFT },
237     { DRDATA (TTIME, tty_unit[TTO].wait, 24), REG_NZ + PV_LEFT },
238     { ORDATA (RXOFF, ttr_xoff_read, 2), REG_HIDDEN },
239     { ORDATA (RSTATE, tty_unit[TTR].STA, 2), REG_HIDDEN },
240     { DRDATA (RPOS, tty_unit[TTR].pos, T_ADDR_W), PV_LEFT },
241     { ORDATA (PTAPE, ttp_tape_rcvd, 2), REG_HIDDEN },
242     { ORDATA (PXOFF, ttp_xoff_rcvd, 2), REG_HIDDEN },
243     { ORDATA (PSTATE, tty_unit[TTP].STA, 2), REG_HIDDEN },
244     { DRDATA (PPOS, tty_unit[TTP].pos, T_ADDR_W), PV_LEFT },
245     { FLDATA (STOP_IOE, ttr_stopioe, 0) },
246     { NULL }
247     };
248 
249 MTAB tty_mod[] = {
250     { TT_MODE, TT_MODE_KSR, "KSR", "KSR", &ttio_set_mode },
251     { TT_MODE, TT_MODE_7B,  "7b",  "7B",  &ttio_set_mode },
252     { TT_MODE, TT_MODE_8B,  "8b",  "8B",  &ttio_set_mode },
253     { TT_MODE, TT_MODE_7P,  "7p",  "7P",  &ttio_set_mode },
254     { UNIT_ATTABLE+UNIT_ASC+UNIT_UASC, UNIT_ATTABLE, NULL, "BINARY",
255       &ttrp_set_mode },
256     { UNIT_ATTABLE+UNIT_ASC+UNIT_UASC, UNIT_ATTABLE+UNIT_ASC, "ASCII", "ASCII",
257       &ttrp_set_mode },
258     { UNIT_ATTABLE+UNIT_ASC+UNIT_UASC, UNIT_ATTABLE+UNIT_ASC+UNIT_UASC, "Unix ASCII", "UASCII",
259       &ttrp_set_mode },
260     { MTAB_XTD|MTAB_VUN|MTAB_NMO, 1, NULL, "START", &ttrp_set_start_stop },
261     { MTAB_XTD|MTAB_VUN|MTAB_NMO, 0, NULL, "STOP", &ttrp_set_start_stop },
262     { 0 }
263     };
264 
265 DEVICE tty_dev = {
266     "TTY", tty_unit, tty_reg, tty_mod,
267     4, 10, 31, 1, 8, 8,
268     NULL, NULL, &tty_reset,
269     NULL, &pt_attach, &pt_detach,
270     &tty_dib, 0
271     };
272 
273 /* CLK data structures
274 
275    clk_dev      CLK device descriptor
276    clk_unit     CLK unit descriptor
277    clk_mod      CLK modifiers
278    clk_reg      CLK register list
279 */
280 
281 DIB clk_dib = { CLK_KEYS, IOBUS, 1, &clkio };
282 
283 UNIT clk_unit = { UDATA (&clk_svc, 0, 0), 16000 };
284 
285 REG clk_reg[] = {
286     { FLDATA (READY, dev_int, INT_V_CLK) },
287     { FLDATA (ENABLE, dev_enb, INT_V_CLK) },
288     { DRDATA (TIME, clk_unit.wait, 24), REG_NZ + PV_LEFT },
289     { DRDATA (TPS, clk_tps, 8), PV_LEFT + REG_HRO },
290     { NULL }
291     };
292 
293 MTAB clk_mod[] = {
294     { MTAB_XTD|MTAB_VDV, 50, NULL, "50HZ",
295       &clk_set_freq, NULL, NULL },
296     { MTAB_XTD|MTAB_VDV, 60, NULL, "60HZ",
297       &clk_set_freq, NULL, NULL },
298     { MTAB_XTD|MTAB_VDV, 0, "FREQUENCY", NULL,
299       NULL, &clk_show_freq, NULL },
300     { 0 }
301     };
302 
303 DEVICE clk_dev = {
304     "CLK", &clk_unit, clk_reg, clk_mod,
305     1, 0, 0, 0, 0, 0,
306     NULL, NULL, &clk_reset,
307     NULL, NULL, NULL,
308     &clk_dib, 0
309     };
310 
311 /* Paper tape reader: IO routine */
312 
ptrio(int32 inst,int32 fnc,int32 dat,int32 dev)313 int32 ptrio (int32 inst, int32 fnc, int32 dat, int32 dev)
314 {
315 switch (inst) {                                         /* case on opcode */
316 
317     case ioOCP:                                         /* OCP */
318         if (fnc & 016)                                  /* only fnc 0,1 */
319             return IOBADFNC (dat);
320         ptr_motion = fnc ^ 1;
321         if (fnc)                                        /* fnc 1? stop */
322             sim_cancel (&ptr_unit);
323         else sim_activate (&ptr_unit, ptr_unit.wait);   /* fnc 0? start */
324         break;
325 
326     case ioSKS:                                         /* SKS */
327         if (fnc & 013)                                  /* only fnc 0,4 */
328             return IOBADFNC (dat);
329         if (((fnc == 000) && TST_INT (INT_PTR)) ||      /* fnc 0? skip rdy */
330             ((fnc == 004) && !TST_INTREQ (INT_PTR)))    /* fnc 4? skip !int */
331             return IOSKIP (dat);
332         break;
333 
334     case ioINA:                                         /* INA */
335         if (fnc)                                        /* only fnc 0 */
336             return IOBADFNC (dat);
337         if (TST_INT (INT_PTR)) {                        /* ready? */
338             CLR_INT (INT_PTR);                          /* clear ready */
339             if (ptr_motion)                             /* if motion, restart */
340                 sim_activate (&ptr_unit, ptr_unit.wait);
341             return IOSKIP (ptr_unit.buf | dat);         /* ret buf, skip */
342             }
343         break;
344         }                                               /* end case op */
345 
346 return dat;
347 }
348 
349 /* Unit service */
350 
ptr_svc(UNIT * uptr)351 t_stat ptr_svc (UNIT *uptr)
352 {
353 int32 c;
354 
355 if ((uptr->flags & UNIT_ATT) == 0)                      /* attached? */
356     return IORETURN (ptr_stopioe, SCPE_UNATT);
357 if (uptr->STA & LF_PEND) {                              /* lf pending? */
358     uptr->STA &= ~LF_PEND;                              /* clear flag */
359     c = 0212;                                           /* insert LF */
360     }
361 else {
362     if ((c = getc (uptr->fileref)) == EOF) {            /* read byte */
363         if (feof (uptr->fileref)) {
364             if (ptr_stopioe)
365                 printf ("PTR end of file\n");
366             else return SCPE_OK;
367             }
368         else perror ("PTR I/O error");
369         clearerr (uptr->fileref);
370         return SCPE_IOERR;
371         }
372     if ((uptr->flags & UNIT_UASC) && (c == '\n')) {     /* Unix newline? */
373         c = 0215;                                       /* insert CR */
374         uptr->STA |= LF_PEND;                           /* lf pending */
375 		}
376     else if ((uptr->flags & UNIT_ASC) && (c != 0))      /* ASCII? */
377         c = c | 0200;
378     uptr->pos = ftell (uptr->fileref);                  /* update pos */
379     }
380 SET_INT (INT_PTR);                                      /* set ready flag */
381 uptr->buf = c & 0377;                                   /* get byte */
382 return SCPE_OK;
383 }
384 
385 /* Paper tape attach routine - set or clear ASC/UASC flags if specified */
386 
pt_attach(UNIT * uptr,char * cptr)387 t_stat pt_attach (UNIT *uptr, char *cptr)
388 {
389 t_stat r;
390 
391 if (!(uptr->flags & UNIT_ATTABLE))
392     return SCPE_NOFNC;
393 if ((r = attach_unit (uptr, cptr)))
394     return r;
395 if (sim_switches & SWMASK ('A'))                        /* -a? ASCII */
396     uptr->flags |= UNIT_ASC;
397 else if (sim_switches & SWMASK ('U'))                   /* -u? Unix ASCII */
398     uptr->flags |= (UNIT_ASC|UNIT_UASC);
399 else if (sim_switches & SWMASK ('B'))                   /* -b? binary */
400     uptr->flags &= ~(UNIT_ASC|UNIT_UASC);
401 uptr->STA = 0;
402 return r;
403 }
404 
405 /* Detach routine - stop motion if not restore */
406 
pt_detach(UNIT * uptr)407 t_stat pt_detach (UNIT *uptr)
408 {
409 if (!(sim_switches & SIM_SW_REST)) sim_cancel (uptr);   /* stop motion */
410 uptr->STA = 0;
411 return detach_unit (uptr);
412 }
413 
414 /* Reset routine */
415 
ptr_reset(DEVICE * dptr)416 t_stat ptr_reset (DEVICE *dptr)
417 {
418 CLR_INT (INT_PTR);                                      /* clear ready, enb */
419 CLR_ENB (INT_PTR);
420 ptr_unit.buf = 0;                                       /* clear buffer */
421 ptr_unit.STA = 0;
422 ptr_motion = 0;                                         /* unit stopped */
423 sim_cancel (&ptr_unit);                                 /* deactivate unit */
424 return SCPE_OK;
425 }
426 
427 /* Paper tape reader bootstrap routine */
428 
429 #define PBOOT_START     1
430 #define PBOOT_SIZE      (sizeof (pboot) / sizeof (int32))
431 
432 static const int32 pboot[] = {
433     0010057,                                            /*        STA 57 */
434     0030001,                                            /*        OCP 1 */
435     0131001,                                            /* READ,  INA 1001 */
436     0002003,                                            /*        JMP READ */
437     0101040,                                            /*        SNZ */
438     0002003,                                            /*        JMP READ */
439     0010000,                                            /*        STA 0 */
440     0131001,                                            /* READ1, INA 1001 */
441     0002010,                                            /*        JMP READ1 */
442     0041470,                                            /*        LGL 8 */
443     0130001,                                            /* READ2, INA 1 */
444     0002013,                                            /*        JMP READ2 */
445     0110000,                                            /*        STA* 0 */
446     0024000,                                            /*        IRS 0 */
447     0100040                                             /*        SZE */
448     };
449 
ptr_boot(int32 unitno,DEVICE * dptr)450 t_stat ptr_boot (int32 unitno, DEVICE *dptr)
451 {
452 int32 i;
453 
454 for (i = 0; i < PBOOT_SIZE; i++)                        /* copy bootstrap */
455     M[PBOOT_START + i] = pboot[i];
456 PC = PBOOT_START;
457 return SCPE_OK;
458 }
459 
460 /* Paper tape punch: IO routine */
461 
ptpio(int32 inst,int32 fnc,int32 dat,int32 dev)462 int32 ptpio (int32 inst, int32 fnc, int32 dat, int32 dev)
463 {
464 switch (inst) {                                         /* case on opcode */
465 
466     case ioOCP:                                         /* OCP */
467         if (fnc & 016)                                  /* only fnc 0,1 */
468             return IOBADFNC (dat);
469         if (fnc) {                                      /* fnc 1? pwr off */
470             CLR_INT (INT_PTP);                          /* not ready */
471             ptp_power = 0;                              /* turn off power */
472             sim_cancel (&ptp_unit);                     /* stop punch */
473             }
474         else if (ptp_power == 0)                        /* fnc 0? start */
475             sim_activate (&ptp_unit, ptp_ptime);
476         break;
477 
478     case ioSKS:                                         /* SKS */
479         if ((fnc & 012) || (fnc == 005))                /* only 0, 1, 4 */
480             return IOBADFNC (dat);
481         if (((fnc == 000) && TST_INT (INT_PTP)) ||      /* fnc 0? skip rdy */
482             ((fnc == 001) &&                            /* fnc 1? skip ptp on */
483                 (ptp_power || sim_is_active (&ptp_unit))) ||
484             ((fnc == 004) && !TST_INTREQ (INT_PTP)))    /* fnc 4? skip !int */
485             return IOSKIP (dat);
486         break;
487 
488     case ioOTA:                                         /* OTA */
489         if (fnc)                                        /* only fnc 0 */
490             return IOBADFNC (dat);
491         if (TST_INT (INT_PTP)) {                        /* if ptp ready */
492             CLR_INT (INT_PTP);                          /* clear ready */
493             ptp_unit.buf = dat & 0377;                  /* store byte */
494             sim_activate (&ptp_unit, ptp_unit.wait);
495             return IOSKIP (dat);                        /* skip return */
496             }
497         break;
498         }
499 
500 return dat;
501 }
502 
503 /* Unit service */
504 
ptp_svc(UNIT * uptr)505 t_stat ptp_svc (UNIT *uptr)
506 {
507 int32 c;
508 
509 SET_INT (INT_PTP);                                      /* set flag */
510 if (ptp_power == 0) {                                   /* power on? */
511     ptp_power = 1;                                      /* ptp is ready */
512     return SCPE_OK;
513     }
514 if ((uptr->flags & UNIT_ATT) == 0)                      /* attached? */
515     return IORETURN (ptp_stopioe, SCPE_UNATT);
516 if (uptr->flags & UNIT_ASC) {                           /* ASCII? */
517     c = uptr->buf & 0177;                               /* mask to 7b */
518     if ((uptr->flags & UNIT_UASC) && (c == 015))        /* cr? drop if Unix */
519         return SCPE_OK;
520     else if (c == 012)                                  /* lf? cvt to nl */
521         c = '\n';
522     }
523 else c = uptr->buf & 0377;                              /* no, binary */
524 if (putc (c, uptr->fileref) == EOF) {                   /* output byte */
525     perror ("PTP I/O error");
526     clearerr (uptr->fileref);
527     return SCPE_IOERR;
528     }
529 uptr->pos = ftell (uptr->fileref);                      /* update pos */
530 return SCPE_OK;
531 }
532 
533 /* Reset routine */
534 
ptp_reset(DEVICE * dptr)535 t_stat ptp_reset (DEVICE *dptr)
536 {
537 CLR_INT (INT_PTP);                                      /* clear ready, enb */
538 CLR_ENB (INT_PTP);
539 ptp_power = 0;                                          /* power off */
540 ptp_unit.buf = 0;                                       /* clear buffer */
541 ptp_unit.STA = 0;
542 sim_cancel (&ptp_unit);                                 /* deactivate unit */
543 return SCPE_OK;
544 }
545 
546 /* Terminal: IO routine */
547 
ttyio(int32 inst,int32 fnc,int32 dat,int32 dev)548 int32 ttyio (int32 inst, int32 fnc, int32 dat, int32 dev)
549 {
550 switch (inst) {                                         /* case on opcode */
551 
552     case ioOCP:                                         /* OCP */
553         if (fnc & 016)                                  /* only fnc 0,1 */
554             return IOBADFNC (dat);
555         if (fnc && (tty_mode == 0)) {                   /* input to output? */
556             if (!sim_is_active (&tty_unit[TTO]))        /* set ready */
557                 SET_INT (INT_TTY);
558             tty_mode = 1;                               /* mode is output */
559             }
560         else if ((fnc == 0) && tty_mode) {              /* output to input? */
561             CLR_INT (INT_TTY);                          /* clear ready */
562             tty_mode = 0;                               /* mode is input */
563             }
564         break;
565 
566     case ioSKS:                                         /* SKS */
567         if (fnc & 012)                                  /* fnc 0,1,4,5 */
568             return IOBADFNC (dat);
569         if (((fnc == 000) && TST_INT (INT_TTY)) ||      /* fnc 0? skip rdy */
570             ((fnc == 001) &&                            /* fnc 1? skip !busy */
571                 (!tty_mode || !sim_is_active (&tty_unit[TTO]))) ||
572             ((fnc == 004) && !TST_INTREQ (INT_TTY)) ||  /* fnc 4? skip !int */
573             ((fnc == 005) && (tty_mode ||               /* fnc 5? skip !xoff */
574                 ((tty_buf & 0177) != XOFF))))           /* input & XOFF char */
575             return IOSKIP (dat);
576         break;
577 
578     case ioINA:                                         /* INA */
579         if (fnc & 005)                                  /* only 0,2 */
580             return IOBADFNC (dat);
581         if (TST_INT (INT_TTY)) {                        /* ready? */
582             if (tty_mode == 0)                          /* inp? clear rdy */
583                 CLR_INT (INT_TTY);
584             return IOSKIP (dat |
585                 (tty_buf & ((fnc & 002)? 077: 0377)));
586             }
587         break;
588 
589     case ioOTA:
590         if (fnc & 015)                                  /* only 0,2 */
591             return IOBADFNC (dat);
592         if (TST_INT (INT_TTY)) {                        /* ready? */
593             tty_buf = dat & 0377;                       /* store char */
594             if (fnc & 002) {                            /* binary mode? */
595                 tty_buf = tty_buf | 0100;               /* set ch 7 */
596                 if (tty_buf & 040)
597                     tty_buf = tty_buf & 0277;
598                 }
599             if (tty_mode) {
600                 sim_activate (&tty_unit[TTO], tty_unit[TTO].wait);
601                 CLR_INT (INT_TTY);
602                 }
603             return IOSKIP (dat);
604             }
605         break;
606         }                                               /* end case op */
607 
608 return dat;
609 }
610 
611 /* Input service - keyboard and reader */
612 
tti_svc(UNIT * uptr)613 t_stat tti_svc (UNIT *uptr)
614 {
615 int32 out, c;
616 UNIT *ruptr = &tty_unit[TTR];
617 
618 sim_activate (uptr, uptr->wait);                        /* continue poll */
619 if ((c = sim_poll_kbd ()) >= SCPE_KFLAG) {              /* character? */
620     out = c & 0177;                                     /* mask echo to 7b */
621     if (c & SCPE_BREAK)                                 /* break? */
622         c = 0;
623     else c = sim_tt_inpcvt (c, TT_GET_MODE (uptr->flags) | TTUF_KSR);
624     uptr->pos = uptr->pos + 1;
625     }
626 else if (c != SCPE_OK)                                  /* error? */
627     return c;
628 else if ((ruptr->flags & UNIT_ATT) &&                   /* TTR attached */
629     (ruptr->STA & RUNNING)) {                           /* and running? */
630     if (ruptr->STA & LF_PEND) {                         /* lf pending? */
631         c = 0212;                                       /* char is lf */
632         ruptr->STA &= ~LF_PEND;                         /* clear flag */
633         }
634     else {                                              /* normal read */
635         if ((c = getc (ruptr->fileref)) == EOF) {       /* read byte */
636             if (feof (ruptr->fileref)) {                /* EOF? */
637                 ruptr->STA &= ~RUNNING;                 /* stop reader */
638                 if (ttr_stopioe)
639                     printf ("TTR end of file\n");
640                 else return SCPE_OK;
641                 }
642             else perror ("TTR I/O error");
643             clearerr (ruptr->fileref);
644             return SCPE_IOERR;
645             }
646         if ((ruptr->flags & UNIT_UASC) && (c == '\n')) {
647             c = 0215;                                   /* Unix ASCII NL? */
648             ruptr->STA |= LF_PEND;                      /* LF pending */
649             }
650         else if ((ruptr->flags & UNIT_ASC) && (c != 0))
651             c = c | 0200;                               /* ASCII nz? cvt */
652         ruptr->pos = ftell (ruptr->fileref);
653         }
654     if (ttr_xoff_read != 0) {                           /* reader stopping? */
655         if (c == RUBOUT)                                /* rubout? stop */
656             ttr_xoff_read = 0;
657         else ttr_xoff_read--;                           /* else decr state */
658         if (ttr_xoff_read == 0)                         /* delay done? */
659             ruptr->STA &= ~RUNNING;                     /* stop reader */
660         }
661     else if ((c & 0177) == XOFF)                        /* XOFF read? */
662         ttr_xoff_read = 2;
663     out = c;                                            /* echo char */
664     }
665 else return SCPE_OK;                                    /* no char */
666 if (tty_mode == 0) {                                    /* input mode? */
667     tty_buf = c & 0377;                                 /* put char in buf */
668     SET_INT (INT_TTY);                                  /* set flag */
669     }
670 tto_write (out);                                        /* echo to printer */
671 return ttp_write (out);                                 /* and punch */
672 }
673 
674 /* Output service - printer and punch */
675 
tto_svc(UNIT * uptr)676 t_stat tto_svc (UNIT *uptr)
677 {
678 uint32 c7b;
679 UNIT *ruptr = &tty_unit[TTR];
680 UNIT *puptr = &tty_unit[TTP];
681 t_stat r;
682 
683 c7b = tty_buf & 0177;
684 if (ttp_tape_rcvd != 0) {                               /* prev = tape? */
685     ttp_tape_rcvd--;                                    /* decrement state */
686     if ((ttp_tape_rcvd == 0) && (puptr->flags & UNIT_ATT))
687         puptr->STA |= RUNNING;                          /* start after delay */
688     }
689 else if (c7b == TAPE)                                   /* char = TAPE? */
690     ttp_tape_rcvd = 2;
691 if (ttp_xoff_rcvd != 0) {                               /* prev = XOFF? */
692     ttp_xoff_rcvd--;                                    /* decrement state */
693     if (ttp_xoff_rcvd == 0)                             /* stop after delay */
694         puptr->STA &= ~RUNNING;
695     }
696 else if (c7b == XOFF)                                   /* char = XOFF? */
697     ttp_xoff_rcvd = 2;
698 if ((c7b == XON) && (ruptr->flags & UNIT_ATT)) {        /* char = XON? */
699     ruptr->STA |= RUNNING;                              /* start reader */
700     ttr_xoff_read = 0;                                  /* cancel stop */
701     }
702 if ((r = tto_write (tty_buf)) != SCPE_OK) {             /* print; error? */
703     sim_activate (uptr, uptr->wait);                    /* try again */
704     return ((r == SCPE_STALL)? SCPE_OK: r);             /* !stall? report */
705     }
706 if ((r = ttp_write (tty_buf)) != SCPE_OK)               /* punch; error? */
707     return r;
708 SET_INT (INT_TTY);                                      /* set done flag */
709 return SCPE_OK;
710 }
711 
712 /* Output to printer */
713 
tto_write(int32 c)714 t_stat tto_write (int32 c)
715 {
716 UNIT *tuptr = &tty_unit[TTO];
717 
718 c = sim_tt_outcvt (c, TT_GET_MODE (tuptr->flags) | TTUF_KSR);
719 tuptr->pos = tuptr->pos + 1;
720 if (c >= 0)
721     return sim_putchar_s (c);
722 else return SCPE_OK;
723 }
724 
725 /* Output to punch */
726 
ttp_write(int32 c)727 t_stat ttp_write (int32 c)
728 {
729 uint32 p, c7b;
730 UNIT *puptr = &tty_unit[TTP];
731 
732 if ((puptr->flags & UNIT_ATT) &&                        /* TTP attached */
733     (puptr->STA & RUNNING)) {                           /* and running? */
734     c7b = c & 0177;
735     if (!(puptr->flags & UNIT_UASC) || (c7b != 015)) {
736         if (puptr->flags & UNIT_ASC) {                  /* ASCII? */
737             if (c7b == 012) p = '\n';                   /* cvt LF */
738             else p = c7b;                               /* else 7b */
739             }
740         else p = c;                                     /* untouched */
741         if (putc (p, puptr->fileref) == EOF) {          /* output byte */
742             perror ("TTP I/O error");
743             clearerr (puptr->fileref);
744             return SCPE_IOERR;
745             }
746         puptr->pos = ftell (puptr->fileref);            /* update pos */
747         }
748     }
749 return SCPE_OK;
750 }
751 
752 /* Reset routine */
753 
tty_reset(DEVICE * dptr)754 t_stat tty_reset (DEVICE *dptr)
755 {
756 CLR_INT (INT_TTY);                                      /* clear ready, enb */
757 CLR_ENB (INT_TTY);
758 tty_mode = 0;                                           /* mode = input */
759 tty_buf = 0;
760 ttr_xoff_read = 0;                                      /* clr TTR, TTP flags */
761 ttp_tape_rcvd = 0;
762 ttp_xoff_rcvd = 0;
763 tty_unit[TTR].STA = 0;
764 tty_unit[TTP].STA = 0;
765 sim_activate (&tty_unit[TTI], tty_unit[TTI].wait);      /* activate poll */
766 sim_cancel (&tty_unit[TTO]);                            /* cancel output */
767 return SCPE_OK;
768 }
769 
770 /* Set keyboard/printer mode - make sure flags agree */
771 
ttio_set_mode(UNIT * uptr,int32 val,char * cptr,void * desc)772 t_stat ttio_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc)
773 {
774 if (uptr->flags & UNIT_ATTABLE)                         /* not TTR, TTP */
775     return SCPE_NOFNC;
776 tty_unit[TTO].flags = (tty_unit[TTO].flags & ~TT_MODE) | val;
777 if (val == TT_MODE_7P)
778     val = TT_MODE_7B;
779 tty_unit[TTI].flags = (tty_unit[TTI].flags & ~TT_MODE) | val;
780 return SCPE_OK;
781 }
782 
783 /* Set reader/punch mode */
784 
ttrp_set_mode(UNIT * uptr,int32 val,char * cptr,void * desc)785 t_stat ttrp_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc)
786 {
787 if (!(uptr->flags & UNIT_ATTABLE))                      /* TTR, TTP only */
788     return SCPE_NOFNC;
789 if (!(val & UNIT_UASC))
790     uptr->STA &= ~LF_PEND;
791 return SCPE_OK;
792 }
793 
794 /* Set reader/punch start/stop */
795 
ttrp_set_start_stop(UNIT * uptr,int32 val,char * cptr,void * desc)796 t_stat ttrp_set_start_stop (UNIT *uptr, int32 val, char *cptr, void *desc)
797 {
798 if (!(uptr->flags & UNIT_ATTABLE))                      /* TTR, TTP only */
799     return SCPE_NOFNC;
800 if (!(uptr->flags & UNIT_ATT))                          /* must be attached */
801     return SCPE_UNATT;
802 if (val)                                                /* start? set running */
803     uptr->STA |= RUNNING;
804 else uptr->STA &= ~RUNNING;                             /* stop? clr running */
805 if (uptr->flags & UNIT_ROABLE)                          /* TTR? cancel stop */
806     ttr_xoff_read = 0;
807 else ttp_tape_rcvd = ttp_xoff_rcvd = 0;                 /* TTP? cancel all */
808 return SCPE_OK;
809 }
810 
811 /* Clock/options: IO routine */
812 
clkio(int32 inst,int32 fnc,int32 dat,int32 dev)813 int32 clkio (int32 inst, int32 fnc, int32 dat, int32 dev)
814 {
815 switch (inst) {                                         /* case on opcode */
816 
817     case ioOCP:                                         /* OCP */
818         if (fnc & 015)                                  /* only fnc 0,2 */
819             return IOBADFNC (dat);
820         CLR_INT (INT_CLK);                              /* reset ready */
821         if (fnc)                                        /* fnc = 2? stop */
822             sim_cancel (&clk_unit);
823         else {                                          /* fnc = 0? */
824             if (!sim_is_active (&clk_unit))
825                 sim_activate (&clk_unit,                /* activate */
826             sim_rtc_init (clk_unit.wait));              /* init calibr */
827             }
828         break;
829 
830     case ioSKS:                                         /* SKS */
831         if (fnc == 000) {                               /* clock skip !int */
832             if (!TST_INTREQ (INT_CLK))
833                 return IOSKIP (dat);
834 			}
835         else if ((fnc & 007) == 002) {                  /* mem parity? */
836             if (((fnc == 002) && !TST_INT (INT_MPE)) ||
837                 ((fnc == 012) && TST_INT (INT_MPE)))
838                 return IOSKIP (dat);
839             }
840         else return IOBADFNC (dat);                     /* invalid fnc */
841         break;
842 
843     case ioOTA:                                         /* OTA */
844         if (fnc == 000)                                 /* SMK */
845             dev_enb = dat;
846         else if (fnc == 010) {                          /* OTK */
847             C = (dat >> 15) & 1;                        /* set C */
848             if (cpu_unit.flags & UNIT_HSA)              /* HSA included? */
849                 dp = (dat >> 14) & 1;                   /* set dp */
850             if (cpu_unit.flags & UNIT_EXT) {            /* ext opt? */
851                 if (dat & 020000) {                     /* ext set? */
852                     ext = 1;                            /* yes, set */
853                     extoff_pending = 0;
854                     }
855                 else extoff_pending = 1;                /* no, clr later */
856                 }
857             sc = dat & 037;                             /* set sc */
858             }
859         else return IOBADFNC (dat);
860         break;
861         }
862 
863 return dat;
864 }
865 
866 /* Unit service */
867 
clk_svc(UNIT * uptr)868 t_stat clk_svc (UNIT *uptr)
869 {
870 
871 M[M_CLK] = (M[M_CLK] + 1) & DMASK;                      /* increment mem ctr */
872 if (M[M_CLK] == 0)                                      /* = 0? set flag */
873     SET_INT (INT_CLK);
874 sim_activate (&clk_unit, sim_rtc_calb (clk_tps));       /* reactivate */
875 return SCPE_OK;
876 }
877 
878 /* Reset routine */
879 
clk_reset(DEVICE * dptr)880 t_stat clk_reset (DEVICE *dptr)
881 {
882 CLR_INT (INT_CLK);                                      /* clear ready, enb */
883 CLR_ENB (INT_CLK);
884 sim_cancel (&clk_unit);                                 /* deactivate unit */
885 return SCPE_OK;
886 }
887 
888 /* Set frequency */
889 
clk_set_freq(UNIT * uptr,int32 val,char * cptr,void * desc)890 t_stat clk_set_freq (UNIT *uptr, int32 val, char *cptr, void *desc)
891 {
892 if (cptr)
893     return SCPE_ARG;
894 if ((val != 50) && (val != 60))
895     return SCPE_IERR;
896 clk_tps = val;
897 return SCPE_OK;
898 }
899 
900 /* Show frequency */
901 
clk_show_freq(FILE * st,UNIT * uptr,int32 val,void * desc)902 t_stat clk_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc)
903 {
904 fprintf (st, (clk_tps == 50)? "50Hz": "60Hz");
905 return SCPE_OK;
906 }
907