1 /* sds_stddev.c: SDS 940 standard devices
2
3 Copyright (c) 2001-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 paper tape reader
27 ptp paper tape punch
28 tti keyboard
29 tto teleprinter
30
31 29-Dec-03 RMS Added console backpressure support
32 25-Apr-03 RMS Revised for extended file support
33 */
34
35 #include "sds_defs.h"
36
37 #define TT_CR 052 /* typewriter */
38 #define TT_TB 072
39 #define TT_BS 032
40
41 extern uint32 xfr_req;
42 extern int32 stop_invins, stop_invdev, stop_inviop;
43 int32 ptr_sor = 0; /* start of rec */
44 int32 ptr_stopioe = 1; /* stop on err */
45 int32 ptp_ldr = 0; /* no leader */
46 int32 ptp_stopioe = 1;
47 DSPT std_tplt[] = { { 1, 0 }, { 0, 0 } }; /* template */
48
49 DEVICE ptr_dev, ptp_dev;
50 t_stat ptr (uint32 fnc, uint32 inst, uint32 *dat);
51 t_stat ptr_svc (UNIT *uptr);
52 t_stat ptr_reset (DEVICE *dptr);
53 t_stat ptr_boot (int32 unitno, DEVICE *dptr);
54 void ptr_set_err (void);
55 t_stat ptp (uint32 fnc, uint32 inst, uint32 *dat);
56 t_stat ptp_svc (UNIT *uptr);
57 t_stat ptp_reset (DEVICE *dptr);
58 t_stat ptp_out (int32 dat);
59 void ptp_set_err (void);
60 t_stat tti (uint32 fnc, uint32 inst, uint32 *dat);
61 t_stat tti_svc (UNIT *uptr);
62 t_stat tti_reset (DEVICE *dptr);
63 t_stat tto (uint32 fnc, uint32 inst, uint32 *dat);
64 t_stat tto_svc (UNIT *uptr);
65 t_stat tto_reset (DEVICE *dptr);
66
67 extern const char ascii_to_sds[128];
68 extern const char sds_to_ascii[64];
69 extern const char odd_par[64];
70
71 /* PTR data structures
72
73 ptr_dev PTR device descriptor
74 ptr_unit PTR unit
75 ptr_reg PTR register list
76 */
77
78 DIB ptr_dib = { CHAN_W, DEV_PTR, XFR_PTR, std_tplt, &ptr };
79
80 UNIT ptr_unit = {
81 UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0),
82 SERIAL_IN_WAIT
83 };
84
85 REG ptr_reg[] = {
86 { ORDATA (BUF, ptr_unit.buf, 7) },
87 { FLDATA (XFR, xfr_req, XFR_V_PTR) },
88 { FLDATA (SOR, ptr_sor, 0) },
89 { DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT },
90 { DRDATA (TIME, ptr_unit.wait, 24), REG_NZ + PV_LEFT },
91 { FLDATA (STOP_IOE, ptr_stopioe, 0) },
92 { NULL }
93 };
94
95 MTAB ptr_mod[] = {
96 { MTAB_XTD|MTAB_VDV, 0, "CHANNEL", "CHANNEL",
97 &set_chan, &show_chan, NULL },
98 { 0 }
99 };
100
101 DEVICE ptr_dev = {
102 "PTR", &ptr_unit, ptr_reg, ptr_mod,
103 1, 10, 31, 1, 8, 8,
104 NULL, NULL, &ptr_reset,
105 &ptr_boot, NULL, NULL,
106 &ptr_dib, DEV_DISABLE
107 };
108
109 /* PTP data structures
110
111 ptp_dev PTP device descriptor
112 ptp_unit PTP unit
113 ptp_reg PTP register list
114 */
115
116 DIB ptp_dib = { CHAN_W, DEV_PTP, XFR_PTP, std_tplt, &ptp };
117
118 UNIT ptp_unit = {
119 UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT
120 };
121
122 REG ptp_reg[] = {
123 { ORDATA (BUF, ptp_unit.buf, 7) },
124 { FLDATA (XFR, xfr_req, XFR_V_PTP) },
125 { FLDATA (LDR, ptp_ldr, 0) },
126 { DRDATA (POS, ptp_unit.pos, T_ADDR_W), PV_LEFT },
127 { DRDATA (TIME, ptp_unit.wait, 24), REG_NZ + PV_LEFT },
128 { FLDATA (STOP_IOE, ptp_stopioe, 0) },
129 { NULL }
130 };
131
132 MTAB ptp_mod[] = {
133 { MTAB_XTD|MTAB_VDV, 0, "CHANNEL", "CHANNEL",
134 &set_chan, &show_chan, NULL },
135 { 0 }
136 };
137
138 DEVICE ptp_dev = {
139 "PTP", &ptp_unit, ptp_reg, ptp_mod,
140 1, 10, 31, 1, 8, 8,
141 NULL, NULL, &ptp_reset,
142 NULL, NULL, NULL,
143 &ptp_dib, DEV_DISABLE
144 };
145
146 /* TTI data structures
147
148 tti_dev TTI device descriptor
149 tti_unit TTI unit
150 tti_reg TTI register list
151 */
152
153 DIB tti_dib = { CHAN_W, DEV_TTI, XFR_TTI, std_tplt, &tti };
154
155 UNIT tti_unit = { UDATA (&tti_svc, 0, 0), KBD_POLL_WAIT };
156
157 REG tti_reg[] = {
158 { ORDATA (BUF, tti_unit.buf, 6) },
159 { FLDATA (XFR, xfr_req, XFR_V_TTI) },
160 { DRDATA (POS, tti_unit.pos, T_ADDR_W), PV_LEFT },
161 { DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT },
162 { NULL }
163 };
164
165 MTAB tti_mod[] = {
166 { MTAB_XTD|MTAB_VDV, 0, "CHANNEL", "CHANNEL",
167 &set_chan, &show_chan, &tti_dib },
168 { 0 }
169 };
170
171 DEVICE tti_dev = {
172 "TTI", &tti_unit, tti_reg, tti_mod,
173 1, 10, 31, 1, 8, 8,
174 NULL, NULL, &tti_reset,
175 NULL, NULL, NULL,
176 &tti_dib, 0
177 };
178
179 /* TTO data structures
180
181 tto_dev TTO device descriptor
182 tto_unit TTO unit
183 tto_reg TTO register list
184 */
185
186 DIB tto_dib = { CHAN_W, DEV_TTO, XFR_TTO, std_tplt, &tto };
187
188 UNIT tto_unit = { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT };
189
190 REG tto_reg[] = {
191 { ORDATA (BUF, tto_unit.buf, 6) },
192 { FLDATA (XFR, xfr_req, XFR_V_TTO) },
193 { DRDATA (POS, tto_unit.pos, T_ADDR_W), PV_LEFT },
194 { DRDATA (TIME, tto_unit.wait, 24), REG_NZ + PV_LEFT },
195 { NULL }
196 };
197
198 MTAB tto_mod[] = {
199 { MTAB_XTD|MTAB_VDV, 0, "CHANNEL", "CHANNEL",
200 &set_chan, &show_chan, &tto_dib },
201 { 0 }
202 };
203
204 DEVICE tto_dev = {
205 "TTO", &tto_unit, tto_reg, tto_mod,
206 1, 10, 31, 1, 8, 8,
207 NULL, NULL, &tto_reset,
208 NULL, NULL, NULL,
209 &tto_dib, 0
210 };
211
212 /* Paper tape reader
213
214 conn - inst = EOM0, dat = NULL
215 eom1 - inst = EOM1, dat = NULL
216 sks - inst = SKS, dat = ptr to result
217 disc - inst = device number, dat = NULL
218 wreor - inst = device number, dat = NULL
219 read - inst = device number, dat = ptr to data
220 write - inst = device number, dat = ptr to result
221
222 The paper tape reader is a streaming input device. Once started, it
223 continues to read until disconnected. Leader before the current record
224 is ignored; leader after the current record sets channel EndOfRecord.
225 */
226
ptr(uint32 fnc,uint32 inst,uint32 * dat)227 t_stat ptr (uint32 fnc, uint32 inst, uint32 *dat)
228 {
229 int32 new_ch;
230
231 switch (fnc) { /* case function */
232
233 case IO_CONN: /* connect */
234 new_ch = I_GETEOCH (inst); /* get new chan */
235 if (new_ch != ptr_dib.chan) /* inv conn? err */
236 return SCPE_IERR;
237 ptr_sor = 1; /* start of rec */
238 xfr_req = xfr_req & ~XFR_PTR; /* clr xfr flag */
239 sim_activate (&ptr_unit, ptr_unit.wait); /* activate */
240 break;
241
242 case IO_DISC: /* disconnect */
243 ptr_sor = 0; /* clear state */
244 xfr_req = xfr_req & ~XFR_PTR; /* clr xfr flag */
245 sim_cancel (&ptr_unit); /* deactivate unit */
246 break;
247
248 case IO_READ: /* read */
249 xfr_req = xfr_req & ~XFR_PTR; /* clr xfr flag */
250 *dat = ptr_unit.buf & 077; /* get buf data */
251 if (ptr_unit.buf != odd_par[*dat]) /* good parity? */
252 chan_set_flag (ptr_dib.chan, CHF_ERR); /* no, error */
253 break;
254
255 case IO_WREOR: /* write eor */
256 break;
257
258 case IO_EOM1: /* EOM mode 1*/
259 case IO_WRITE: /* write */
260 CRETINS; /* error */
261 }
262
263 return SCPE_OK;
264 }
265
266 /* Unit service */
267
ptr_svc(UNIT * uptr)268 t_stat ptr_svc (UNIT *uptr)
269 {
270 int32 temp;
271
272 if ((ptr_unit.flags & UNIT_ATT) == 0) { /* attached? */
273 ptr_set_err (); /* no, err, disc */
274 CRETIOE (ptr_stopioe, SCPE_UNATT);
275 }
276 if ((temp = getc (ptr_unit.fileref)) == EOF) { /* end of file? */
277 ptr_set_err (); /* yes, err, disc */
278 if (feof (ptr_unit.fileref)) { /* end of file? */
279 if (ptr_stopioe)
280 printf ("PTR end of file\n");
281 else return SCPE_OK;
282 }
283 else perror ("PTR I/O error"); /* I/O error */
284 clearerr (ptr_unit.fileref);
285 return SCPE_IOERR;
286 }
287 ptr_unit.pos = ptr_unit.pos + 1; /* inc position */
288 if (temp) { /* leader/gap? */
289 ptr_unit.buf = temp & 0177; /* no, save char */
290 xfr_req = xfr_req | XFR_PTR; /* set xfr flag */
291 ptr_sor = 0; /* in record */
292 }
293 else if (!ptr_sor) /* end record? */
294 chan_set_flag (ptr_dib.chan, CHF_EOR); /* ignore leader */
295 sim_activate (&ptr_unit, ptr_unit.wait); /* get next char */
296 return SCPE_OK;
297 }
298
299 /* Fatal error */
300
ptr_set_err(void)301 void ptr_set_err (void)
302 {
303 chan_set_flag (ptr_dib.chan, CHF_EOR | CHF_ERR); /* eor, error */
304 chan_disc (ptr_dib.chan); /* disconnect */
305 xfr_req = xfr_req & ~XFR_PTR; /* clear xfr */
306 sim_cancel (&ptr_unit); /* stop */
307 return;
308 }
309
310 /* Reset routine */
311
ptr_reset(DEVICE * dptr)312 t_stat ptr_reset (DEVICE *dptr)
313 {
314 chan_disc (ptr_dib.chan); /* disconnect */
315 ptr_sor = 0; /* clear state */
316 ptr_unit.buf = 0;
317 xfr_req = xfr_req & ~XFR_PTR; /* clr xfr flag */
318 sim_cancel (&ptr_unit); /* deactivate unit */
319 return SCPE_OK;
320 }
321
322 /* Boot routine - simulate FILL console command */
323
ptr_boot(int32 unitno,DEVICE * dptr)324 t_stat ptr_boot (int32 unitno, DEVICE *dptr)
325 {
326 extern uint32 P, M[];
327
328 M[0] = 077777771; /* -7B */
329 M[1] = 007100000; /* LDX 0 */
330 M[2] = 000203604; /* EOM 3604B */
331 M[3] = 003200002; /* WIM 2 */
332 M[4] = 000100002; /* BRU 2 */
333 P = 1; /* start at 1 */
334 return SCPE_OK;
335 }
336
337 /* Paper tape punch
338
339 conn - inst = EOM0, dat = NULL
340 eom1 - inst = EOM1, dat = NULL
341 sks - inst = SKS, dat = ptr to result
342 disc - inst = device number, dat = NULL
343 wreor - inst = device number, dat = NULL
344 read - inst = device number, dat = ptr to data
345 write - inst = device number, dat = ptr to result
346
347 The paper tape punch is an asynchronous streaming output device. That is,
348 it can never cause a channel rate error; if no data is available, it waits.
349 */
350
ptp(uint32 fnc,uint32 inst,uint32 * dat)351 t_stat ptp (uint32 fnc, uint32 inst, uint32 *dat)
352 {
353 int32 new_ch;
354
355 switch (fnc) { /* case function */
356
357 case IO_CONN:
358 new_ch = I_GETEOCH (inst); /* get new chan */
359 if (new_ch != ptp_dib.chan) /* inv conn? err */
360 return SCPE_IERR;
361 ptp_ldr = (inst & CHC_NLDR)? 0: 1; /* leader? */
362 xfr_req = xfr_req & ~XFR_PTP; /* clr xfr flag */
363 sim_activate (&ptp_unit, ptp_unit.wait); /* activate */
364 break;
365
366 case IO_DISC: /* disconnect */
367 ptp_ldr = 0; /* clear state */
368 xfr_req = xfr_req & ~XFR_PTP; /* clr xfr flag */
369 sim_cancel (&ptp_unit); /* deactivate unit */
370 break;
371
372 case IO_WRITE: /* write */
373 xfr_req = xfr_req & ~XFR_PTP; /* clr xfr flag */
374 sim_activate (&ptp_unit, ptp_unit.wait); /* activate */
375 ptp_unit.buf = odd_par[(*dat) & 077]; /* save data */
376 return ptp_out (ptp_unit.buf); /* punch w/ par */
377
378 case IO_WREOR: /* write eor */
379 break;
380
381 case IO_EOM1: /* EOM mode 1*/
382 case IO_READ: /* read */
383 CRETINS; /* error */
384 }
385
386 return SCPE_OK;
387 }
388
389 /* Unit service */
390
ptp_svc(UNIT * uptr)391 t_stat ptp_svc (UNIT *uptr)
392 {
393 int32 i;
394 t_stat r = SCPE_OK;
395
396 if (ptp_ldr) { /* need leader? */
397 for (i = 0; i < 12; i++) { /* punch leader */
398 if ((r = ptp_out (0)))
399 break;
400 }
401 }
402 ptp_ldr = 0; /* clear flag */
403 chan_set_ordy (ptp_dib.chan); /* ptp ready */
404 return r;
405 }
406
407 /* Punch I/O */
408
ptp_out(int32 dat)409 t_stat ptp_out (int32 dat)
410 {
411 if ((ptp_unit.flags & UNIT_ATT) == 0) { /* attached? */
412 ptp_set_err (); /* no, disc, err */
413 CRETIOE (ptp_stopioe, SCPE_UNATT);
414 }
415 if (putc (dat, ptp_unit.fileref) == EOF) { /* I/O error? */
416 ptp_set_err (); /* yes, disc, err */
417 perror ("PTP I/O error"); /* print msg */
418 clearerr (ptp_unit.fileref);
419 return SCPE_IOERR;
420 }
421 ptp_unit.pos = ptp_unit.pos + 1; /* inc position */
422 return SCPE_OK;
423 }
424
425 /* Fatal error */
426
ptp_set_err(void)427 void ptp_set_err (void)
428 {
429 chan_set_flag (ptp_dib.chan, CHF_ERR); /* error */
430 chan_disc (ptp_dib.chan); /* disconnect */
431 xfr_req = xfr_req & ~XFR_PTP; /* clear xfr */
432 sim_cancel (&ptp_unit); /* stop */
433 return;
434 }
435
436 /* Reset routine */
437
ptp_reset(DEVICE * dptr)438 t_stat ptp_reset (DEVICE *dptr)
439 {
440 chan_disc (ptp_dib.chan); /* disconnect */
441 ptp_ldr = 0; /* clear state */
442 ptp_unit.buf = 0;
443 xfr_req = xfr_req & ~XFR_PTP; /* clr xfr flag */
444 sim_cancel (&ptp_unit); /* deactivate unit */
445 return SCPE_OK;
446 }
447
448 /* Typewriter input
449
450 conn - inst = EOM0, dat = NULL
451 eom1 - inst = EOM1, dat = NULL
452 sks - inst = SKS, dat = ptr to result
453 disc - inst = device number, dat = NULL
454 wreor - inst = device number, dat = NULL
455 read - inst = device number, dat = ptr to data
456 write - inst = device number, dat = ptr to result
457
458 The typewriter input is an asynchronous input device. That is, it can
459 never cause a channel rate error; if no data is available, it waits.
460 */
461
tti(uint32 fnc,uint32 inst,uint32 * dat)462 t_stat tti (uint32 fnc, uint32 inst, uint32 *dat)
463 {
464 int32 new_ch;
465
466 switch (fnc) { /* case function */
467
468 case IO_CONN: /* connect */
469 new_ch = I_GETEOCH (inst); /* get new chan */
470 if (new_ch != tti_dib.chan) /* inv conn? err */
471 return SCPE_IERR;
472 xfr_req = xfr_req & ~XFR_TTI; /* clr xfr flag */
473 break;
474
475 case IO_DISC: /* disconnect */
476 xfr_req = xfr_req & ~XFR_TTI; /* clr xfr flag */
477 break;
478
479 case IO_READ: /* read */
480 xfr_req = xfr_req & ~XFR_TTI; /* clr xfr flag */
481 *dat = tti_unit.buf; /* get buf data */
482 break;
483
484 case IO_WREOR: /* write eor */
485 break;
486
487 case IO_EOM1: /* EOM mode 1*/
488 case IO_WRITE: /* write */
489 CRETINS; /* error */
490 }
491
492 return SCPE_OK;
493 }
494
495 /* Unit service */
496
tti_svc(UNIT * uptr)497 t_stat tti_svc (UNIT *uptr)
498 {
499 int32 temp;
500
501 sim_activate (&tti_unit, tti_unit.wait); /* continue poll */
502 if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or error? */
503 return temp;
504 if (temp & SCPE_BREAK) /* ignore break */
505 return SCPE_OK;
506 temp = temp & 0177;
507 tti_unit.pos = tti_unit.pos + 1;
508 if (ascii_to_sds[temp] >= 0) {
509 tti_unit.buf = ascii_to_sds[temp]; /* internal rep */
510 sim_putchar (temp); /* echo */
511 if (temp == '\r') /* lf after cr */
512 sim_putchar ('\n');
513 xfr_req = xfr_req | XFR_TTI; /* set xfr flag */
514 }
515 else sim_putchar (007); /* ding! */
516 return SCPE_OK;
517 }
518
tti_reset(DEVICE * dptr)519 t_stat tti_reset (DEVICE *dptr)
520 {
521 chan_disc (tti_dib.chan); /* disconnect */
522 tti_unit.buf = 0; /* clear state */
523 xfr_req = xfr_req & ~XFR_TTI; /* clr xfr flag */
524 sim_activate (&tti_unit, tti_unit.wait); /* start poll */
525 return SCPE_OK;
526 }
527
528 /* Typewriter output
529
530 conn - inst = EOM0, dat = NULL
531 eom1 - inst = EOM1, dat = NULL
532 sks - inst = SKS, dat = ptr to result
533 disc - inst = device number, dat = NULL
534 wreor - inst = device number, dat = NULL
535 read - inst = device number, dat = ptr to data
536 write - inst = device number, dat = ptr to result
537
538 The typewriter output is an asynchronous streaming output device. That is,
539 it can never cause a channel rate error; if no data is available, it waits.
540 */
541
tto(uint32 fnc,uint32 inst,uint32 * dat)542 t_stat tto (uint32 fnc, uint32 inst, uint32 *dat)
543 {
544 int32 new_ch;
545
546 switch (fnc) { /* case function */
547
548 case IO_CONN:
549 new_ch = I_GETEOCH (inst); /* get new chan */
550 if (new_ch != tto_dib.chan) /* inv conn? err */
551 return SCPE_IERR;
552 xfr_req = xfr_req & ~XFR_TTO; /* clr xfr flag */
553 sim_activate (&tto_unit, tto_unit.wait); /* activate */
554 break;
555
556 case IO_DISC: /* disconnect */
557 xfr_req = xfr_req & ~XFR_TTO; /* clr xfr flag */
558 sim_cancel (&tto_unit); /* deactivate unit */
559 break;
560
561 case IO_WRITE: /* write */
562 xfr_req = xfr_req & ~XFR_TTO; /* clr xfr flag */
563 tto_unit.buf = (*dat) & 077; /* save data */
564 sim_activate (&tto_unit, tto_unit.wait); /* activate */
565 break;
566
567 case IO_WREOR: /* write eor */
568 break;
569
570 case IO_EOM1: /* EOM mode 1*/
571 case IO_READ: /* read */
572 CRETINS; /* error */
573 }
574
575 return SCPE_OK;
576 }
577
578 /* Unit service */
579
tto_svc(UNIT * uptr)580 t_stat tto_svc (UNIT *uptr)
581 {
582 int32 asc;
583 t_stat r;
584
585 if (uptr->buf == TT_CR) /* control chars? */
586 asc = '\r';
587 else if (uptr->buf == TT_BS)
588 asc = '\b';
589 else if (uptr->buf == TT_TB)
590 asc = '\t';
591 else asc = sds_to_ascii[uptr->buf]; /* translate */
592 if ((r = sim_putchar_s (asc)) != SCPE_OK) { /* output; error? */
593 sim_activate (uptr, uptr->wait); /* retry */
594 return ((r == SCPE_STALL)? SCPE_OK: r); /* !stall? report */
595 }
596 uptr->pos = uptr->pos + 1; /* inc position */
597 chan_set_ordy (tto_dib.chan); /* tto rdy */
598 if (asc == '\r') { /* CR? */
599 sim_putchar ('\n'); /* add lf */
600 uptr->pos = uptr->pos + 1; /* inc position */
601 }
602 return SCPE_OK;
603 }
604
605 /* Reset routine */
606
tto_reset(DEVICE * dptr)607 t_stat tto_reset (DEVICE *dptr)
608 {
609 chan_disc (tto_dib.chan); /* disconnect */
610 tto_unit.buf = 0; /* clear state */
611 xfr_req = xfr_req & ~XFR_TTO; /* clr xfr flag */
612 sim_cancel (&tto_unit); /* deactivate unit */
613 return SCPE_OK;
614 }
615