1 /* lgp_stddev.c: LGP-30 standard devices
2 
3    Copyright (c) 2004-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    tti          typewriter input (keyboard and reader)
27    tto          typewriter output (printer and punch)
28    ptr          high speed reader
29    ptpp         high speed punch
30 
31    26-Nov-2008  RMS     Changed encode character from # to !
32 */
33 
34 #include "lgp_defs.h"
35 #include <ctype.h>
36 
37 uint32 tt_wait = WPS / 10;
38 uint32 tti_buf = 0;
39 uint32 tti_rdy = 0;
40 uint32 tto_uc = 0;
41 uint32 tto_buf = 0;
42 uint32 ttr_stopioe = 1;
43 uint32 ptr_rdy = 0;
44 uint32 ptr_stopioe = 1;
45 uint32 ptp_stopioe = 1;
46 
47 extern uint32 A;
48 extern uint32 inp_strt, inp_done;
49 extern uint32 out_strt, out_done;
50 extern UNIT cpu_unit;
51 extern int32 sim_switches;
52 
53 t_stat tti_svc (UNIT *uptr);
54 t_stat ttr_svc (UNIT *uptr);
55 t_stat tto_svc (UNIT *uptr);
56 t_stat tti_reset (DEVICE *uptr);
57 t_stat tto_reset (DEVICE *uptr);
58 t_stat ptr_svc (UNIT *uptr);
59 t_stat ptp_svc (UNIT *uptr);
60 t_stat ptr_reset (DEVICE *uptr);
61 t_stat ptp_reset (DEVICE *uptr);
62 t_stat tap_attach (UNIT *uptr, char *cptr);
63 t_stat tap_attable (UNIT *uptr, int32 val, char *cptr, void *desc);
64 t_stat read_reader (UNIT *uptr, int32 stop, int32 *c);
65 t_stat write_tto (int32 flex);
66 t_stat write_punch (UNIT *uptr, int32 flex);
67 t_stat tti_rdrss (UNIT *uptr, int32 val, char *cptr, void *desc);
68 t_stat punch_feed (UNIT *uptr, int32 val, char *cptr, void *desc);
69 t_stat send_start (UNIT *uptr, int32 val, char *cptr, void *desc);
70 
71 extern uint32 shift_in (uint32 a, uint32 dat, uint32 sh4);
72 
73 /* Conversion tables */
74 
75 const int32 flex_to_ascii[128] = {
76     -1  , 'z', '0', ' ', '>', 'b', '1', '-',
77     '<' , 'y', '2', '+', '|', 'r', '3', ';',
78     '\r', 'i', '4', '/','\\', 'd', '5', '.',
79     '\t', 'n', '6', ',', -1 , 'm', '7', 'v',
80     '\'', 'p', '8', 'o', -1 , 'e', '9', 'x',
81     -1  , 'u', 'f', -1 , -1 , 't', 'g', -1 ,
82     -1  , 'h', 'j', -1 , -1 , 'c', 'k', -1 ,
83     -1  , 'a', 'q', -1 , -1 , 's', 'w', 0  ,
84 
85     -1  , 'Z', ')', ' ', -1 , 'B', 'L', '_',
86     -1  , 'Y', '*', '=', '|', 'R', '"', ':',
87     '\r', 'I', '^', '?','\\', 'D', '%', ']',
88     '\t', 'N', '$', '[', -1 , 'M', '~', 'V',
89     '\'', 'P', '#', 'O', -1 , 'E', '(', 'X',
90     -1  , 'U', 'F', -1 , -1 , 'T', 'G', -1 ,
91     -1  , 'H', 'J', -1 , -1 , 'C', 'K', -1 ,
92     -1  , 'A', 'Q', -1 , -1 , 'S', 'W', 0
93     };
94 
95 const int32 ascii_to_flex[128] = {
96     -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 ,
97     024, 030, -1 , -1 , -1 , 020, -1 , -1 ,
98     -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 ,
99     -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 ,
100     003, -1 , 016, 042, 032, 026, -1 , 040,
101     046, 001, 012, 013, 033, 007, 027, 023,
102     002, 006, 012, 016, 022, 026, 032, 036,
103     042, 046, 017, 017, 004, 013, 010, 023,
104     -1 , 071, 005, 065, 025, 045, 052, 056,
105     061, 021, 062, 066, 006, 035, 031, 043,
106     041, 072, 015, 075, 055, 051, 037, 076,
107     047, 011, 001, 033, -1 , 027, 022, 007,
108     -1,  071, 005, 065, 025, 045, 052, 056,
109     061, 021, 062, 066, 006, 035, 031, 043,
110     041, 072, 015, 075, 055, 051, 037, 076,
111     047, 011, 001, -1 , 014, -1 , 036, 077
112     };
113 
114 static const uint8 flex_inp_valid[64] = {
115     1, 1, 1, 1, 0, 1, 1, 1,
116     0, 1, 1, 1, 0, 1, 1, 1,
117     0, 1, 1, 1, 0, 1, 1, 1,
118     0, 1, 1, 1, 0, 1, 1, 1,
119     1, 1, 1, 1, 0, 1, 1, 1,
120     0, 1, 1, 1, 0, 1, 1, 1,
121     0, 1, 1, 1, 0, 1, 1, 1,
122     0, 1, 1, 1, 0, 1, 1, 1
123     };
124 
125 /* TTI data structures
126 
127    tti_dev      TTI device descriptor
128    tti_unit     TTI unit descriptor
129    tti_mod      TTI modifier list
130    tti_reg      TTI register list
131 */
132 
133 UNIT tti_unit[] = {
134     { UDATA (&tti_svc, 0, 0) },
135     { UDATA (&ttr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0) }
136     };
137 
138 REG tti_reg[] = {
139     { HRDATA (BUF, tti_buf, 6) },
140     { FLDATA (RDY, tti_rdy, 0) },
141     { DRDATA (KPOS, tti_unit[0].pos, T_ADDR_W), PV_LEFT },
142     { DRDATA (RPOS, tti_unit[1].pos, T_ADDR_W), PV_LEFT },
143     { DRDATA (TIME, tt_wait, 24), REG_NZ + PV_LEFT },
144     { FLDATA (STOP_IOE, ttr_stopioe, 0) },
145     { NULL }
146     };
147 
148 MTAB tti_mod[] = {
149     { UNIT_FLEX_D, UNIT_FLEX_D, NULL, "FLEX", &tap_attable },
150     { UNIT_FLEX_D, 0,           NULL, "ASCII", &tap_attable },
151     { UNIT_ATT+UNIT_FLEX, UNIT_ATT+UNIT_FLEX,
152       "file is Flex", NULL },
153     { UNIT_ATT+UNIT_FLEX, UNIT_ATT,
154       "file is ASCII", NULL },
155     { UNIT_ATTABLE+UNIT_ATT+UNIT_FLEX, UNIT_ATTABLE+UNIT_FLEX,
156       "default is Flex", NULL },
157     { UNIT_ATTABLE+UNIT_ATT+UNIT_FLEX, UNIT_ATTABLE,
158       "default is ASCII", NULL },
159     { UNIT_ATTABLE+UNIT_NOCS, UNIT_ATTABLE+UNIT_NOCS,
160       "ignore conditional stop", "NOCSTOP", &tap_attable },
161     { UNIT_ATTABLE+UNIT_NOCS, UNIT_ATTABLE          ,
162       NULL, "CSTOP", &tap_attable },
163     { MTAB_XTD|MTAB_VDV, 0, NULL, "START", &send_start },
164     { MTAB_XTD|MTAB_VDV, 1, NULL, "RSTART", &tti_rdrss },
165     { MTAB_XTD|MTAB_VDV, 0, NULL, "RSTOP", &tti_rdrss },
166     { 0 }
167     };
168 
169 DEVICE tti_dev = {
170     "TTI", tti_unit, tti_reg, tti_mod,
171     2, 10, 31, 1, 16, 7,
172     NULL, NULL, &tti_reset,
173     NULL, &tap_attach, NULL
174     };
175 
176 /* TTO data structures
177 
178    tto_dev      TTO device descriptor
179    tto_unit     TTO unit descriptor
180    tto_mod      TTO modifier list
181    tto_reg      TTO register list
182 */
183 
184 UNIT tto_unit[] = {
185     { UDATA (&tto_svc, 0, 0) },
186     { UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) }
187     };
188 
189 REG tto_reg[] = {
190     { HRDATA (BUF, tto_buf, 6) },
191     { FLDATA (UC, tto_uc, 0) },
192     { DRDATA (TPOS, tto_unit[0].pos, T_ADDR_W), PV_LEFT },
193     { DRDATA (PPOS, tto_unit[1].pos, T_ADDR_W), PV_LEFT },
194     { DRDATA (TIME, tt_wait, 24), PV_LEFT },
195     { NULL }
196     };
197 
198 MTAB tto_mod[] = {
199     { UNIT_FLEX_D, UNIT_FLEX_D, NULL, "FLEX", &tap_attable },
200     { UNIT_FLEX_D, 0,           NULL, "ASCII", &tap_attable },
201     { UNIT_ATT+UNIT_FLEX, UNIT_ATT+UNIT_FLEX,
202       "file is Flex", NULL },
203     { UNIT_ATT+UNIT_FLEX, UNIT_ATT,
204       "file is ASCII", NULL },
205     { UNIT_ATTABLE+UNIT_ATT+UNIT_FLEX, UNIT_ATTABLE+UNIT_FLEX,
206       "default is Flex", NULL },
207     { UNIT_ATTABLE+UNIT_ATT+UNIT_FLEX, UNIT_ATTABLE,
208       "default is ASCII", NULL },
209     { MTAB_XTD|MTAB_VUN, 0, NULL, "FEED", &punch_feed },
210     { 0 }
211     };
212 
213 DEVICE tto_dev = {
214     "TTO", tto_unit, tto_reg, tto_mod,
215     2, 10, 31, 1, 16, 7,
216     NULL, NULL, &tto_reset,
217     NULL, &tap_attach, NULL
218     };
219 
220 /* PTR data structures
221 
222    ptr_dev      PTR device descriptor
223    ptr_unit     PTR unit descriptor
224    ptr_mod      PTR modifier list
225    ptr_reg      PTR register list
226 */
227 
228 UNIT ptr_unit = {
229     UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), WPS / 200
230     };
231 
232 REG ptr_reg[] = {
233     { HRDATA (BUF, ptr_unit.buf, 6) },
234     { FLDATA (RDY, ptr_rdy, 0) },
235     { DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT },
236     { DRDATA (TIME, ptr_unit.wait, 24), REG_NZ + PV_LEFT },
237     { FLDATA (STOP_IOE, ptr_stopioe, 0) },
238     { NULL }
239     };
240 
241 MTAB ptr_mod[] = {
242     { UNIT_FLEX_D, UNIT_FLEX_D, NULL, "FLEX", &tap_attable },
243     { UNIT_FLEX_D, 0,           NULL, "ASCII", &tap_attable },
244     { UNIT_ATT+UNIT_FLEX, UNIT_ATT+UNIT_FLEX,
245       "file is Flex", NULL },
246     { UNIT_ATT+UNIT_FLEX, UNIT_ATT,
247       "file is ASCII", NULL },
248     { UNIT_ATTABLE+UNIT_ATT+UNIT_FLEX, UNIT_ATTABLE+UNIT_FLEX,
249       "default is Flex", NULL },
250     { UNIT_ATTABLE+UNIT_ATT+UNIT_FLEX, UNIT_ATTABLE,
251       "default is ASCII", NULL },
252     { 0 }
253     };
254 
255 DEVICE ptr_dev = {
256     "PTR", &ptr_unit, ptr_reg, ptr_mod,
257     1, 10, 31, 1, 16, 7,
258     NULL, NULL, &ptr_reset,
259     NULL, &tap_attach, NULL
260     };
261 
262 /* PTP data structures
263 
264    ptp_dev      PTP device descriptor
265    ptp_unit     PTP unit descriptor
266    ptp_mod      PTP modifier list
267    ptp_reg      PTP register list
268 */
269 
270 UNIT ptp_unit = {
271     UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), WPS / 20
272     };
273 
274 REG ptp_reg[] = {
275     { ORDATA (BUF, ptp_unit.buf, 8) },
276     { DRDATA (POS, ptp_unit.pos, T_ADDR_W), PV_LEFT },
277     { DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT },
278     { FLDATA (STOP_IOE, ptp_stopioe, 0) },
279     { NULL }
280     };
281 
282 MTAB ptp_mod[] = {
283     { UNIT_FLEX_D, UNIT_FLEX_D, NULL, "FLEX", &tap_attable },
284     { UNIT_FLEX_D, 0,           NULL, "ASCII", &tap_attable },
285     { UNIT_ATT+UNIT_FLEX, UNIT_ATT+UNIT_FLEX,
286       "file is Flex", NULL },
287     { UNIT_ATT+UNIT_FLEX, UNIT_ATT,
288       "file is ASCII", NULL },
289     { UNIT_ATTABLE+UNIT_ATT+UNIT_FLEX, UNIT_ATTABLE+UNIT_FLEX,
290       "default is Flex", NULL },
291     { UNIT_ATTABLE+UNIT_ATT+UNIT_FLEX, UNIT_ATTABLE,
292       "default is ASCII", NULL },
293     { 0 }
294     };
295 
296 DEVICE ptp_dev = {
297     "PTP", &ptp_unit, ptp_reg, ptp_mod,
298     1, 10, 31, 1, 16, 7,
299     NULL, NULL, &ptp_reset,
300     NULL, &tap_attach, NULL
301     };
302 
303 /* Input instruction */
304 
op_i_strt(uint32 dev)305 void op_i_strt (uint32 dev)
306 {
307 switch (dev) {                                          /* case on device */
308 
309     case DEV_PT:                                        /* ptr */
310         sim_activate (&ptr_unit, ptr_unit.wait);        /* activate */
311         break;
312 
313     case DEV_TT:                                        /* tti/ttr */
314         if (Q_MANI)                                     /* manual input? */
315             sim_putchar ('`');
316         else sim_activate (&tti_unit[1], tt_wait);      /* no, must be ttr */
317         break;
318         }
319 return;
320 }
321 
op_i(uint32 dev,uint32 ch,uint32 sh4)322 t_stat op_i (uint32 dev, uint32 ch, uint32 sh4)
323 {
324 if (Q_LGP21 && out_strt)                                /* LGP-21? must be idle */
325     return STOP_STALL;
326 if (!inp_strt) {                                        /* input started? */
327     inp_strt = 1;                                       /* no, set start */
328     inp_done = 0;                                       /* clear done */
329     A = shift_in (A, ch, sh4);
330     tti_rdy = ptr_rdy = 0;                              /* no input */
331     if (Q_LGP21 || Q_INPT)                              /* LGP-21 or PTR? start */
332         op_i_strt (dev);
333     }
334 switch (dev) {                                          /* case on device */
335 
336     case DEV_PT:                                        /* ptr */
337         if (ptr_rdy) {                                  /* char ready? */
338             ptr_rdy = 0;                                /* reset ready */
339             if ((ptr_unit.buf != FLEX_DEL) &&           /* ignore delete and */
340                 (!Q_LGP21 || ((ptr_unit.buf & 3) == 2))) /* LGP-21 4b? zone != 2 */
341                 A = shift_in (A, ptr_unit.buf, sh4);    /* shift data in */
342             }
343         break;
344 
345     case DEV_TT:                                        /* tti/ttr */
346         if (tti_rdy) {                                  /* char ready? */
347             tti_rdy = 0;                                /* reset ready */
348             if ((tti_buf != FLEX_DEL) &&                /* ignore delete and */
349                 (!Q_LGP21 || ((tti_buf & 3) != 0)))     /* LGP-21 4b? zone == 0 */
350                 A = shift_in (A, tti_buf, sh4);         /* shift data in */
351             }
352         break;
353 
354     default:                                            /* nx device */
355         return STOP_NXDEV;                              /* return error */
356         }
357 
358 if (inp_done) {                                         /* done? */
359     inp_strt = inp_done = 0;                            /* clear start, done */
360     return SCPE_OK;                                     /* no stall */
361     }
362 return STOP_STALL;                                      /* stall */
363 }
364 
365 /* Terminal keyboard unit service */
366 
tti_svc(UNIT * uptr)367 t_stat tti_svc (UNIT *uptr)
368 {
369 int32 c, flex;
370 
371 sim_activate (uptr, tt_wait);                           /* continue poll */
372 if ((c = sim_poll_kbd ()) < SCPE_KFLAG)                 /* no char or error? */
373     return c;
374 flex = ascii_to_flex[c & 0x1FF];                        /* cvt to flex */
375 if (flex > 0) {                                         /* it's a typewriter... */
376     write_tto (flex);                                   /* always echos */
377     if (tto_unit[1].flags & UNIT_ATT)                   /* ttp attached? */
378         write_punch (&tto_unit[1], tto_buf);            /* punch to ttp */
379     }
380 else write_tto ('\a');                                  /* don't echo bad */
381 if (Q_MANI && (flex > 0) && flex_inp_valid[flex]) {     /* wanted, valid? */
382     if (flex == FLEX_CSTOP)                             /* conditional stop? */
383         inp_done = 1;
384     else tti_rdy = 1;                                   /* no, set ready */
385     tti_buf = flex;                                     /* save char */
386     uptr->pos = uptr->pos + 1;
387     }
388 return SCPE_OK;
389 }
390 
391 /* Terminal reader unit service */
392 
ttr_svc(UNIT * uptr)393 t_stat ttr_svc (UNIT *uptr)
394 {
395 t_stat r;
396 
397 if ((r = read_reader (uptr, ttr_stopioe, (int32 *) &tti_buf)))
398     return r;
399 if (!(uptr->flags & UNIT_NOCS) &&                       /* cstop enable? */
400     (tti_buf == FLEX_CSTOP))                            /* cond stop? */
401     inp_done = 1;
402 else {
403     tti_rdy = 1;                                        /* no, set ready */
404     sim_activate (uptr, tt_wait);                       /* cont reading */
405     }
406 write_tto (tti_buf);                                    /* echo to tto */
407 if (tto_unit[1].flags & UNIT_ATT)                       /* ttp attached? */
408     return write_punch (&tto_unit[1], tti_buf);         /* punch to ttp */
409 return SCPE_OK;
410 }
411 
412 /* Paper tape reader unit service */
413 
ptr_svc(UNIT * uptr)414 t_stat ptr_svc (UNIT *uptr)
415 {
416 t_stat r;
417 
418 if ((r = read_reader (uptr, ptr_stopioe, &uptr->buf)))
419     return r;
420 if (uptr->buf == FLEX_CSTOP)                            /* cond stop? */
421     inp_done = 1;
422 else {
423     ptr_rdy = 1;                                        /* no, set ready */
424     sim_activate (uptr, uptr->wait);                    /* cont reading */
425     }
426 return SCPE_OK;
427 }
428 
429 /* Output instruction */
430 
op_p(uint32 dev,uint32 ch)431 t_stat op_p (uint32 dev, uint32 ch)
432 {
433 switch (dev) {                                          /* case on device */
434 
435     case DEV_PT:                                        /* paper tape punch */
436         if (sim_is_active (&ptp_unit))                  /* busy? */
437             return (Q_LGP21? STOP_STALL: SCPE_OK);      /* LGP-21: stall */
438         ptp_unit.buf = ch;                              /* save char */
439         sim_activate (&ptp_unit, ptp_unit.wait);        /* activate ptp */
440         break;
441 
442     case DEV_TT:                                        /* typewriter */
443         if (ch == 0) {                                  /* start input? */
444             if (!Q_LGP21 && !Q_INPT)                    /* ignore if LGP-21, ptr */
445                 op_i_strt (DEV_TT);                     /* start tti */
446             return SCPE_OK;                             /* no stall */
447             }
448         if (sim_is_active (&tto_unit[0]))               /* busy? */
449             return (Q_LGP21? STOP_STALL: SCPE_OK);      /* LGP-21: stall */
450         tto_buf = ch;                                   /* save char */
451         sim_activate (&tto_unit[0], tt_wait);           /* activate tto */
452         break;
453 
454     default:                                            /* unknown */
455         return STOP_NXDEV;                              /* return error */
456         }
457 
458 if (out_strt == 0) {                                    /* output started? */
459     out_strt = 1;                                       /* flag start */
460     out_done = 0;                                       /* clear done */
461     }
462 return SCPE_OK;                                         /* no stall */
463 }
464 
465 /* Terminal printer unit service */
466 
tto_svc(UNIT * uptr)467 t_stat tto_svc (UNIT *uptr)
468 {
469 t_stat r;
470 
471 if ((r = write_tto (tto_buf)) != SCPE_OK) {             /* output; error? */
472     sim_activate (uptr, tt_wait);                       /* try again */
473     return ((r == SCPE_STALL)? SCPE_OK: r);             /* !stall? report */
474     }
475 out_strt = 0;
476 out_done = 1;
477 if (tto_unit[1].flags & UNIT_ATT)                       /* ttp attached? */
478     return write_punch (&tto_unit[1], tto_buf);         /* punch to ttp */
479 return SCPE_OK;
480 }
481 
482 /* Paper tape punch unit service */
483 
ptp_svc(UNIT * uptr)484 t_stat ptp_svc (UNIT *uptr)
485 {
486 out_strt = 0;
487 out_done = 1;
488 if ((uptr->flags & UNIT_ATT) == 0)                      /* not attached? */
489     return IORETURN (ptp_stopioe, SCPE_UNATT);          /* error */
490 return write_punch (uptr, uptr->buf);                   /* write to ptp */
491 }
492 
493 /* Utility routines */
494 
read_reader(UNIT * uptr,int32 stop,int32 * fl)495 t_stat read_reader (UNIT *uptr, int32 stop, int32 *fl)
496 {
497 int32 ch, flex;
498 
499 if ((uptr->flags & UNIT_ATT) == 0)                      /* attached? */
500     return IORETURN (stop, SCPE_UNATT);
501 do {
502     if ((ch = getc (uptr->fileref)) == EOF) {           /* read char */
503         if (feof (uptr->fileref)) {                     /* err or eof? */
504             if (stop)
505                 printf ("Reader end of file\n");
506             else return SCPE_OK;
507             }
508         else perror ("Reader I/O error");
509         clearerr (uptr->fileref);
510         return SCPE_IOERR;
511         }
512     if (uptr->flags & UNIT_FLEX)                        /* transposed flex? */
513         flex = ((ch << 1) | (ch >> 5)) & 0x3F;          /* undo 612345 */
514     else if (ch == '!') {                               /* encoded? */
515         int32 d1 = getc (uptr->fileref);                /* get 2 digits */
516         int32 d2 = getc (uptr->fileref);
517         if ((d1 == EOF) || (d2 == EOF)) {               /* error? */
518             if (feof (uptr->fileref)) {                 /* eof? */
519                 if (stop)
520                     printf ("Reader end of file\n");
521                 else return SCPE_OK;
522                 }
523             else perror ("Reader I/O error");
524             clearerr (uptr->fileref);
525             return SCPE_IOERR;
526             }
527         flex = (((d1 - '0') * 10) + (d2 - '0')) & 0x3F;
528         uptr->pos = uptr->pos + 2;
529         }
530     else flex = ascii_to_flex[ch & 0x7F];               /* convert */
531     uptr->pos = uptr->pos + 1;
532     } while (flex < 0);                                 /* until valid */
533 *fl = flex;                                             /* return char */
534 return SCPE_OK;
535 }
536 
write_tto(int32 flex)537 t_stat write_tto (int32 flex)
538 {
539 int32 ch;
540 t_stat r;
541 
542 if (flex == FLEX_UC)                                    /* UC? set state */
543     tto_uc = 1;
544 else if (flex == FLEX_LC)                               /* LC? set state */
545     tto_uc = 0;
546 else {
547     if (flex == FLEX_BS)                                /* backspace? */
548         ch = '\b';
549     else ch = flex_to_ascii[flex | (tto_uc << 6)];      /* cvt flex to ascii */
550     if (ch > 0) {                                       /* legit? */
551         if ((r = sim_putchar_s (ch)))                   /* write char */
552             return r;
553         tto_unit[0].pos = tto_unit[0].pos + 1;
554         if (flex == FLEX_CR) {                          /* cr? */
555             sim_putchar ('\n');                         /* add lf */
556             tto_unit[0].pos = tto_unit[0].pos + 1;
557             }
558         }
559     }
560 return SCPE_OK;
561 }
562 
write_punch(UNIT * uptr,int32 flex)563 t_stat write_punch (UNIT *uptr, int32 flex)
564 {
565 int32 c, sta;
566 
567 if (uptr->flags & UNIT_FLEX)                            /* transposed flex? */
568     c = ((flex >> 1) | (flex << 5)) & 0x3F;             /* reorder to 612345 */
569 else c = flex_to_ascii[flex];                           /* convert to ASCII */
570 if (c >= 0)                                             /* valid? */
571     sta = fputc (c, uptr->fileref);
572 else sta = fprintf (uptr->fileref, "!%02d", flex);      /* no, encode */
573 if (sta == EOF) {                                       /* error? */
574     perror ("Punch I/O error");                         /* error? */
575     clearerr (uptr->fileref);
576     return SCPE_IOERR;
577     }
578 uptr->pos = uptr->pos + ((c >= 0)? 1: 3);               /* incr position */
579 return SCPE_OK;
580 }
581 
582 /* Reset routines */
583 
tti_reset(DEVICE * dptr)584 t_stat tti_reset (DEVICE *dptr)
585 {
586 sim_activate (&tti_unit[0], tt_wait);
587 sim_cancel (&tti_unit[1]);
588 tti_buf = 0;
589 tti_rdy = 0;
590 return SCPE_OK;
591 }
592 
tto_reset(DEVICE * dptr)593 t_stat tto_reset (DEVICE *dptr)
594 {
595 sim_cancel (&tto_unit[0]);
596 tto_buf = 0;
597 tto_uc = 0;
598 return SCPE_OK;
599 }
600 
ptr_reset(DEVICE * dptr)601 t_stat ptr_reset (DEVICE *dptr)
602 {
603 sim_cancel (&ptr_unit);
604 ptr_unit.buf = 0;
605 ptr_rdy = 0;
606 return SCPE_OK;
607 }
608 
ptp_reset(DEVICE * dptr)609 t_stat ptp_reset (DEVICE *dptr)
610 {
611 sim_cancel (&ptp_unit);
612 ptp_unit.buf = 0;
613 return SCPE_OK;
614 }
615 
616 /* Attach paper tape unit */
617 
tap_attach(UNIT * uptr,char * cptr)618 t_stat tap_attach (UNIT *uptr, char *cptr)
619 {
620 t_stat r;
621 
622 if ((r = attach_unit (uptr,cptr)) != SCPE_OK)
623     return r;
624 if ((sim_switches & SWMASK ('F')) ||
625     ((uptr->flags & UNIT_FLEX_D) && !(sim_switches & SWMASK ('A'))))
626         uptr->flags = uptr->flags | UNIT_FLEX;
627 else uptr->flags = uptr->flags & ~UNIT_FLEX;
628 return SCPE_OK;
629 }
630 
631 /* Validate unit is attachable */
632 
tap_attable(UNIT * uptr,int32 val,char * cptr,void * desc)633 t_stat tap_attable (UNIT *uptr, int32 val, char *cptr, void *desc)
634 {
635 if (uptr->flags & UNIT_ATTABLE)
636     return SCPE_OK;
637 return SCPE_NOFNC;
638 }
639 
640 /* Typewriter reader start/stop */
641 
tti_rdrss(UNIT * uptr,int32 val,char * cptr,void * desc)642 t_stat tti_rdrss (UNIT *uptr, int32 val, char *cptr, void *desc)
643 {
644 if (val) {
645     if ((tti_unit[1].flags & UNIT_ATT) == 0)
646         return SCPE_UNATT;
647     sim_activate (&tti_unit[1], tt_wait);
648     }
649 else sim_cancel (&tti_unit[1]);
650 return SCPE_OK;
651 }
652 
653 /* Punch feed routine */
654 
punch_feed(UNIT * uptr,int32 val,char * cptr,void * desc)655 t_stat punch_feed (UNIT *uptr, int32 val, char *cptr, void *desc)
656 {
657 int32 cnt;
658 t_stat r;
659 
660 if ((uptr->flags & UNIT_ATT) == 0)
661     return SCPE_UNATT;
662 if (cptr) {
663     cnt = (int32) get_uint (cptr, 10, 512, &r);
664     if ((r != SCPE_OK) || (cnt == 0))
665         return SCPE_ARG;
666     }
667 else cnt = 10;
668 while (cnt-- > 0) {
669     r = write_punch (uptr, 0);
670     if (r != SCPE_OK)
671         return r;
672     }
673 return SCPE_OK;
674 }
675 
676 /* Send start signal */
677 
send_start(UNIT * uptr,int32 val,char * cptr,void * desc)678 t_stat send_start (UNIT *uptr, int32 val, char *cptr, void *desc)
679 {
680 if (inp_strt)
681     inp_done = 1;
682 else if (out_strt)
683     out_done = 1;
684 return SCPE_OK;
685 }
686