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