First Commit of my working state
[simh.git] / SDS / sds_stddev.c
1 /* sds_stddev.c: SDS 940 standard devices
2
3 Copyright (c) 2001-2005, 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
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) return SCPE_IERR; /* inv conn? err */
236 ptr_sor = 1; /* start of rec */
237 xfr_req = xfr_req & ~XFR_PTR; /* clr xfr flag */
238 sim_activate (&ptr_unit, ptr_unit.wait); /* activate */
239 break;
240
241 case IO_DISC: /* disconnect */
242 ptr_sor = 0; /* clear state */
243 xfr_req = xfr_req & ~XFR_PTR; /* clr xfr flag */
244 sim_cancel (&ptr_unit); /* deactivate unit */
245 break;
246
247 case IO_READ: /* read */
248 xfr_req = xfr_req & ~XFR_PTR; /* clr xfr flag */
249 *dat = ptr_unit.buf & 077; /* get buf data */
250 if (ptr_unit.buf != odd_par[*dat]) /* good parity? */
251 chan_set_flag (ptr_dib.chan, CHF_ERR); /* no, error */
252 break;
253
254 case IO_WREOR: /* write eor */
255 break;
256
257 case IO_EOM1: /* EOM mode 1*/
258 case IO_WRITE: /* write */
259 CRETINS; /* error */
260 }
261
262 return SCPE_OK;
263 }
264
265 /* Unit service */
266
267 t_stat ptr_svc (UNIT *uptr)
268 {
269 int32 temp;
270
271 if ((ptr_unit.flags & UNIT_ATT) == 0) { /* attached? */
272 ptr_set_err (); /* no, err, disc */
273 CRETIOE (ptr_stopioe, SCPE_UNATT);
274 }
275 if ((temp = getc (ptr_unit.fileref)) == EOF) { /* end of file? */
276 ptr_set_err (); /* yes, err, disc */
277 if (feof (ptr_unit.fileref)) { /* end of file? */
278 if (ptr_stopioe) printf ("PTR end of file\n");
279 else return SCPE_OK;
280 }
281 else perror ("PTR I/O error"); /* I/O error */
282 clearerr (ptr_unit.fileref);
283 return SCPE_IOERR;
284 }
285 ptr_unit.pos = ptr_unit.pos + 1; /* inc position */
286 if (temp) { /* leader/gap? */
287 ptr_unit.buf = temp & 0177; /* no, save char */
288 xfr_req = xfr_req | XFR_PTR; /* set xfr flag */
289 ptr_sor = 0; /* in record */
290 }
291 else if (!ptr_sor) /* end record? */
292 chan_set_flag (ptr_dib.chan, CHF_EOR); /* ignore leader */
293 sim_activate (&ptr_unit, ptr_unit.wait); /* get next char */
294 return SCPE_OK;
295 }
296
297 /* Fatal error */
298
299 void ptr_set_err (void)
300 {
301 chan_set_flag (ptr_dib.chan, CHF_EOR | CHF_ERR); /* eor, error */
302 chan_disc (ptr_dib.chan); /* disconnect */
303 xfr_req = xfr_req & ~XFR_PTR; /* clear xfr */
304 sim_cancel (&ptr_unit); /* stop */
305 return;
306 }
307
308 /* Reset routine */
309
310 t_stat ptr_reset (DEVICE *dptr)
311 {
312 chan_disc (ptr_dib.chan); /* disconnect */
313 ptr_sor = 0; /* clear state */
314 ptr_unit.buf = 0;
315 xfr_req = xfr_req & ~XFR_PTR; /* clr xfr flag */
316 sim_cancel (&ptr_unit); /* deactivate unit */
317 return SCPE_OK;
318 }
319
320 /* Boot routine - simulate FILL console command */
321
322 t_stat ptr_boot (int32 unitno, DEVICE *dptr)
323 {
324 extern uint32 P, M[];
325
326 M[0] = 077777771; /* -7B */
327 M[1] = 007100000; /* LDX 0 */
328 M[2] = 000203604; /* EOM 3604B */
329 M[3] = 003200002; /* WIM 2 */
330 M[4] = 000100002; /* BRU 2 */
331 P = 1; /* start at 1 */
332 return SCPE_OK;
333 }
334
335 /* Paper tape punch
336
337 conn - inst = EOM0, dat = NULL
338 eom1 - inst = EOM1, dat = NULL
339 sks - inst = SKS, dat = ptr to result
340 disc - inst = device number, dat = NULL
341 wreor - inst = device number, dat = NULL
342 read - inst = device number, dat = ptr to data
343 write - inst = device number, dat = ptr to result
344
345 The paper tape punch is an asynchronous streaming output device. That is,
346 it can never cause a channel rate error; if no data is available, it waits.
347 */
348
349 t_stat ptp (uint32 fnc, uint32 inst, uint32 *dat)
350 {
351 int32 new_ch;
352
353 switch (fnc) { /* case function */
354
355 case IO_CONN:
356 new_ch = I_GETEOCH (inst); /* get new chan */
357 if (new_ch != ptp_dib.chan) return SCPE_IERR; /* inv conn? err */
358 ptp_ldr = (inst & CHC_NLDR)? 0: 1; /* leader? */
359 xfr_req = xfr_req & ~XFR_PTP; /* clr xfr flag */
360 sim_activate (&ptp_unit, ptp_unit.wait); /* activate */
361 break;
362
363 case IO_DISC: /* disconnect */
364 ptp_ldr = 0; /* clear state */
365 xfr_req = xfr_req & ~XFR_PTP; /* clr xfr flag */
366 sim_cancel (&ptp_unit); /* deactivate unit */
367 break;
368
369 case IO_WRITE: /* write */
370 xfr_req = xfr_req & ~XFR_PTP; /* clr xfr flag */
371 sim_activate (&ptp_unit, ptp_unit.wait); /* activate */
372 ptp_unit.buf = odd_par[(*dat) & 077]; /* save data */
373 return ptp_out (ptp_unit.buf); /* punch w/ par */
374
375 case IO_WREOR: /* write eor */
376 break;
377
378 case IO_EOM1: /* EOM mode 1*/
379 case IO_READ: /* read */
380 CRETINS; /* error */
381 }
382
383 return SCPE_OK;
384 }
385
386 /* Unit service */
387
388 t_stat ptp_svc (UNIT *uptr)
389 {
390 int32 i;
391 t_stat r = SCPE_OK;
392
393 if (ptp_ldr) { /* need leader? */
394 for (i = 0; i < 12; i++) { /* punch leader */
395 if (r = ptp_out (0)) break;
396 }
397 }
398 ptp_ldr = 0; /* clear flag */
399 chan_set_ordy (ptp_dib.chan); /* ptp ready */
400 return r;
401 }
402
403 /* Punch I/O */
404
405 t_stat ptp_out (int32 dat)
406 {
407 if ((ptp_unit.flags & UNIT_ATT) == 0) { /* attached? */
408 ptp_set_err (); /* no, disc, err */
409 CRETIOE (ptp_stopioe, SCPE_UNATT);
410 }
411 if (putc (dat, ptp_unit.fileref) == EOF) { /* I/O error? */
412 ptp_set_err (); /* yes, disc, err */
413 perror ("PTP I/O error"); /* print msg */
414 clearerr (ptp_unit.fileref);
415 return SCPE_IOERR;
416 }
417 ptp_unit.pos = ptp_unit.pos + 1; /* inc position */
418 return SCPE_OK;
419 }
420
421 /* Fatal error */
422
423 void ptp_set_err (void)
424 {
425 chan_set_flag (ptp_dib.chan, CHF_ERR); /* error */
426 chan_disc (ptp_dib.chan); /* disconnect */
427 xfr_req = xfr_req & ~XFR_PTP; /* clear xfr */
428 sim_cancel (&ptp_unit); /* stop */
429 return;
430 }
431
432 /* Reset routine */
433
434 t_stat ptp_reset (DEVICE *dptr)
435 {
436 chan_disc (ptp_dib.chan); /* disconnect */
437 ptp_ldr = 0; /* clear state */
438 ptp_unit.buf = 0;
439 xfr_req = xfr_req & ~XFR_PTP; /* clr xfr flag */
440 sim_cancel (&ptp_unit); /* deactivate unit */
441 return SCPE_OK;
442 }
443
444 /* Typewriter input
445
446 conn - inst = EOM0, dat = NULL
447 eom1 - inst = EOM1, dat = NULL
448 sks - inst = SKS, dat = ptr to result
449 disc - inst = device number, dat = NULL
450 wreor - inst = device number, dat = NULL
451 read - inst = device number, dat = ptr to data
452 write - inst = device number, dat = ptr to result
453
454 The typewriter input is an asynchronous input device. That is, it can
455 never cause a channel rate error; if no data is available, it waits.
456 */
457
458 t_stat tti (uint32 fnc, uint32 inst, uint32 *dat)
459 {
460 int32 new_ch;
461
462 switch (fnc) { /* case function */
463
464 case IO_CONN: /* connect */
465 new_ch = I_GETEOCH (inst); /* get new chan */
466 if (new_ch != tti_dib.chan) return SCPE_IERR; /* inv conn? err */
467 xfr_req = xfr_req & ~XFR_TTI; /* clr xfr flag */
468 break;
469
470 case IO_DISC: /* disconnect */
471 xfr_req = xfr_req & ~XFR_TTI; /* clr xfr flag */
472 break;
473
474 case IO_READ: /* read */
475 xfr_req = xfr_req & ~XFR_TTI; /* clr xfr flag */
476 *dat = tti_unit.buf; /* get buf data */
477 break;
478
479 case IO_WREOR: /* write eor */
480 break;
481
482 case IO_EOM1: /* EOM mode 1*/
483 case IO_WRITE: /* write */
484 CRETINS; /* error */
485 }
486
487 return SCPE_OK;
488 }
489
490 /* Unit service */
491
492 t_stat tti_svc (UNIT *uptr)
493 {
494 int32 temp;
495
496 sim_activate (&tti_unit, tti_unit.wait); /* continue poll */
497 if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */
498 if (temp & SCPE_BREAK) return SCPE_OK; /* ignore break */
499 temp = temp & 0177;
500 tti_unit.pos = tti_unit.pos + 1;
501 if (ascii_to_sds[temp] >= 0) {
502 tti_unit.buf = ascii_to_sds[temp]; /* internal rep */
503 sim_putchar (temp); /* echo */
504 if (temp == '\r') sim_putchar ('\n'); /* lf after cr */
505 xfr_req = xfr_req | XFR_TTI; /* set xfr flag */
506 }
507 else sim_putchar (007); /* ding! */
508 return SCPE_OK;
509 }
510
511 t_stat tti_reset (DEVICE *dptr)
512 {
513 chan_disc (tti_dib.chan); /* disconnect */
514 tti_unit.buf = 0; /* clear state */
515 xfr_req = xfr_req & ~XFR_TTI; /* clr xfr flag */
516 sim_activate (&tti_unit, tti_unit.wait); /* start poll */
517 return SCPE_OK;
518 }
519
520 /* Typewriter output
521
522 conn - inst = EOM0, dat = NULL
523 eom1 - inst = EOM1, dat = NULL
524 sks - inst = SKS, dat = ptr to result
525 disc - inst = device number, dat = NULL
526 wreor - inst = device number, dat = NULL
527 read - inst = device number, dat = ptr to data
528 write - inst = device number, dat = ptr to result
529
530 The typewriter output is an asynchronous streaming output device. That is,
531 it can never cause a channel rate error; if no data is available, it waits.
532 */
533
534 t_stat tto (uint32 fnc, uint32 inst, uint32 *dat)
535 {
536 int32 new_ch;
537
538 switch (fnc) { /* case function */
539
540 case IO_CONN:
541 new_ch = I_GETEOCH (inst); /* get new chan */
542 if (new_ch != tto_dib.chan) return SCPE_IERR; /* inv conn? err */
543 xfr_req = xfr_req & ~XFR_TTO; /* clr xfr flag */
544 sim_activate (&tto_unit, tto_unit.wait); /* activate */
545 break;
546
547 case IO_DISC: /* disconnect */
548 xfr_req = xfr_req & ~XFR_TTO; /* clr xfr flag */
549 sim_cancel (&tto_unit); /* deactivate unit */
550 break;
551
552 case IO_WRITE: /* write */
553 xfr_req = xfr_req & ~XFR_TTO; /* clr xfr flag */
554 tto_unit.buf = (*dat) & 077; /* save data */
555 sim_activate (&tto_unit, tto_unit.wait); /* activate */
556 break;
557
558 case IO_WREOR: /* write eor */
559 break;
560
561 case IO_EOM1: /* EOM mode 1*/
562 case IO_READ: /* read */
563 CRETINS; /* error */
564 }
565
566 return SCPE_OK;
567 }
568
569 /* Unit service */
570
571 t_stat tto_svc (UNIT *uptr)
572 {
573 int32 asc;
574 t_stat r;
575
576 if (uptr->buf == TT_CR) asc = '\r'; /* control chars? */
577 else if (uptr->buf == TT_BS) asc = '\b';
578 else if (uptr->buf == TT_TB) asc = '\t';
579 else asc = sds_to_ascii[uptr->buf]; /* translate */
580 if ((r = sim_putchar_s (asc)) != SCPE_OK) { /* output; error? */
581 sim_activate (uptr, uptr->wait); /* retry */
582 return ((r == SCPE_STALL)? SCPE_OK: r); /* !stall? report */
583 }
584 uptr->pos = uptr->pos + 1; /* inc position */
585 chan_set_ordy (tto_dib.chan); /* tto rdy */
586 if (asc == '\r') { /* CR? */
587 sim_putchar ('\n'); /* add lf */
588 uptr->pos = uptr->pos + 1; /* inc position */
589 }
590 return SCPE_OK;
591 }
592
593 /* Reset routine */
594
595 t_stat tto_reset (DEVICE *dptr)
596 {
597 chan_disc (tto_dib.chan); /* disconnect */
598 tto_unit.buf = 0; /* clear state */
599 xfr_req = xfr_req & ~XFR_TTO; /* clr xfr flag */
600 sim_cancel (&tto_unit); /* deactivate unit */
601 return SCPE_OK;
602 }