First Commit of my working state
[simh.git] / H316 / h316_stddev.c
1 /* h316_stddev.c: Honeywell 316/516 standard devices
2
3 Copyright (c) 1999-2007, 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 (found by 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 (from Theo Engel)
34 22-Nov-05 RMS Revised for new terminal processing routines
35 05-Feb-05 RMS Fixed bug in OCP '0001 (found by Philipp Hachtmann)
36 31-Jan-05 RMS Fixed bug in TTY print (found by Philipp Hachtmann)
37 01-Dec-04 RMS Fixed problem in SKS '104 (reported by 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
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) return IOBADFNC (dat); /* only fnc 0,1 */
319 ptr_motion = fnc ^ 1;
320 if (fnc) sim_cancel (&ptr_unit); /* fnc 1? stop */
321 else sim_activate (&ptr_unit, ptr_unit.wait); /* fnc 0? start */
322 break;
323
324 case ioSKS: /* SKS */
325 if (fnc & 013) return IOBADFNC (dat); /* only fnc 0,4 */
326 if (((fnc == 000) && TST_INT (INT_PTR)) || /* fnc 0? skip rdy */
327 ((fnc == 004) && !TST_INTREQ (INT_PTR))) /* fnc 4? skip !int */
328 return IOSKIP (dat);
329 break;
330
331 case ioINA: /* INA */
332 if (fnc) return IOBADFNC (dat); /* only fnc 0 */
333 if (TST_INT (INT_PTR)) { /* ready? */
334 CLR_INT (INT_PTR); /* clear ready */
335 if (ptr_motion) /* if motion, restart */
336 sim_activate (&ptr_unit, ptr_unit.wait);
337 return IOSKIP (ptr_unit.buf | dat); /* ret buf, skip */
338 }
339 break;
340 } /* end case op */
341
342 return dat;
343 }
344
345 /* Unit service */
346
347 t_stat ptr_svc (UNIT *uptr)
348 {
349 int32 c;
350
351 if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
352 return IORETURN (ptr_stopioe, SCPE_UNATT);
353 if (uptr->STA & LF_PEND) { /* lf pending? */
354 uptr->STA &= ~LF_PEND; /* clear flag */
355 c = 0212; /* insert LF */
356 }
357 else {
358 if ((c = getc (uptr->fileref)) == EOF) { /* read byte */
359 if (feof (uptr->fileref)) {
360 if (ptr_stopioe) printf ("PTR end of file\n");
361 else return SCPE_OK;
362 }
363 else perror ("PTR I/O error");
364 clearerr (uptr->fileref);
365 return SCPE_IOERR;
366 }
367 if ((uptr->flags & UNIT_UASC) && (c == '\n')) { /* Unix newline? */
368 c = 0215; /* insert CR */
369 uptr->STA |= LF_PEND; /* lf pending */
370 }
371 else if ((uptr->flags & UNIT_ASC) && (c != 0)) /* ASCII? */
372 c = c | 0200;
373 uptr->pos = ftell (uptr->fileref); /* update pos */
374 }
375 SET_INT (INT_PTR); /* set ready flag */
376 uptr->buf = c & 0377; /* get byte */
377 return SCPE_OK;
378 }
379
380 /* Paper tape attach routine - set or clear ASC/UASC flags if specified */
381
382 t_stat pt_attach (UNIT *uptr, char *cptr)
383 {
384 t_stat r;
385
386 if (!(uptr->flags & UNIT_ATTABLE)) return SCPE_NOFNC;
387 if (r = attach_unit (uptr, cptr)) return r;
388 if (sim_switches & SWMASK ('A')) /* -a? ASCII */
389 uptr->flags |= UNIT_ASC;
390 else if (sim_switches & SWMASK ('U')) /* -u? Unix ASCII */
391 uptr->flags |= (UNIT_ASC|UNIT_UASC);
392 else if (sim_switches & SWMASK ('B')) /* -b? binary */
393 uptr->flags &= ~(UNIT_ASC|UNIT_UASC);
394 uptr->STA = 0;
395 return r;
396 }
397
398 /* Detach routine - stop motion if not restore */
399
400 t_stat pt_detach (UNIT *uptr)
401 {
402 if (!(sim_switches & SIM_SW_REST)) sim_cancel (uptr); /* stop motion */
403 uptr->STA = 0;
404 return detach_unit (uptr);
405 }
406
407 /* Reset routine */
408
409 t_stat ptr_reset (DEVICE *dptr)
410 {
411 CLR_INT (INT_PTR); /* clear ready, enb */
412 CLR_ENB (INT_PTR);
413 ptr_unit.buf = 0; /* clear buffer */
414 ptr_unit.STA = 0;
415 ptr_motion = 0; /* unit stopped */
416 sim_cancel (&ptr_unit); /* deactivate unit */
417 return SCPE_OK;
418 }
419
420 /* Paper tape reader bootstrap routine */
421
422 #define PBOOT_START 1
423 #define PBOOT_SIZE (sizeof (pboot) / sizeof (int32))
424
425 static const int32 pboot[] = {
426 0010057, /* STA 57 */
427 0030001, /* OCP 1 */
428 0131001, /* READ, INA 1001 */
429 0002003, /* JMP READ */
430 0101040, /* SNZ */
431 0002003, /* JMP READ */
432 0010000, /* STA 0 */
433 0131001, /* READ1, INA 1001 */
434 0002010, /* JMP READ1 */
435 0041470, /* LGL 8 */
436 0130001, /* READ2, INA 1 */
437 0002013, /* JMP READ2 */
438 0110000, /* STA* 0 */
439 0024000, /* IRS 0 */
440 0100040 /* SZE */
441 };
442
443 t_stat ptr_boot (int32 unitno, DEVICE *dptr)
444 {
445 int32 i;
446
447 for (i = 0; i < PBOOT_SIZE; i++) /* copy bootstrap */
448 M[PBOOT_START + i] = pboot[i];
449 PC = PBOOT_START;
450 return SCPE_OK;
451 }
452
453 /* Paper tape punch: IO routine */
454
455 int32 ptpio (int32 inst, int32 fnc, int32 dat, int32 dev)
456 {
457 switch (inst) { /* case on opcode */
458
459 case ioOCP: /* OCP */
460 if (fnc & 016) return IOBADFNC (dat); /* only fnc 0,1 */
461 if (fnc) { /* fnc 1? pwr off */
462 CLR_INT (INT_PTP); /* not ready */
463 ptp_power = 0; /* turn off power */
464 sim_cancel (&ptp_unit); /* stop punch */
465 }
466 else if (ptp_power == 0) /* fnc 0? start */
467 sim_activate (&ptp_unit, ptp_ptime);
468 break;
469
470 case ioSKS: /* SKS */
471 if ((fnc & 012) || (fnc == 005)) /* only 0, 1, 4 */
472 return IOBADFNC (dat);
473 if (((fnc == 000) && TST_INT (INT_PTP)) || /* fnc 0? skip rdy */
474 ((fnc == 001) && /* fnc 1? skip ptp on */
475 (ptp_power || sim_is_active (&ptp_unit))) ||
476 ((fnc == 004) && !TST_INTREQ (INT_PTP))) /* fnc 4? skip !int */
477 return IOSKIP (dat);
478 break;
479
480 case ioOTA: /* OTA */
481 if (fnc) return IOBADFNC (dat); /* only fnc 0 */
482 if (TST_INT (INT_PTP)) { /* if ptp ready */
483 CLR_INT (INT_PTP); /* clear ready */
484 ptp_unit.buf = dat & 0377; /* store byte */
485 sim_activate (&ptp_unit, ptp_unit.wait);
486 return IOSKIP (dat); /* skip return */
487 }
488 break;
489 }
490
491 return dat;
492 }
493
494 /* Unit service */
495
496 t_stat ptp_svc (UNIT *uptr)
497 {
498 int32 c;
499
500 SET_INT (INT_PTP); /* set flag */
501 if (ptp_power == 0) { /* power on? */
502 ptp_power = 1; /* ptp is ready */
503 return SCPE_OK;
504 }
505 if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
506 return IORETURN (ptp_stopioe, SCPE_UNATT);
507 if (uptr->flags & UNIT_ASC) { /* ASCII? */
508 c = uptr->buf & 0177; /* mask to 7b */
509 if ((uptr->flags & UNIT_UASC) && (c == 015)) /* cr? drop if Unix */
510 return SCPE_OK;
511 else if (c == 012) c = '\n'; /* lf? cvt to nl */
512 }
513 else c = uptr->buf & 0377; /* no, binary */
514 if (putc (c, uptr->fileref) == EOF) { /* output byte */
515 perror ("PTP I/O error");
516 clearerr (uptr->fileref);
517 return SCPE_IOERR;
518 }
519 uptr->pos = ftell (uptr->fileref); /* update pos */
520 return SCPE_OK;
521 }
522
523 /* Reset routine */
524
525 t_stat ptp_reset (DEVICE *dptr)
526 {
527 CLR_INT (INT_PTP); /* clear ready, enb */
528 CLR_ENB (INT_PTP);
529 ptp_power = 0; /* power off */
530 ptp_unit.buf = 0; /* clear buffer */
531 ptp_unit.STA = 0;
532 sim_cancel (&ptp_unit); /* deactivate unit */
533 return SCPE_OK;
534 }
535
536 /* Terminal: IO routine */
537
538 int32 ttyio (int32 inst, int32 fnc, int32 dat, int32 dev)
539 {
540 switch (inst) { /* case on opcode */
541
542 case ioOCP: /* OCP */
543 if (fnc & 016) return IOBADFNC (dat); /* only fnc 0,1 */
544 if (fnc && (tty_mode == 0)) { /* input to output? */
545 if (!sim_is_active (&tty_unit[TTO])) /* set ready */
546 SET_INT (INT_TTY);
547 tty_mode = 1; /* mode is output */
548 }
549 else if ((fnc == 0) && tty_mode) { /* output to input? */
550 CLR_INT (INT_TTY); /* clear ready */
551 tty_mode = 0; /* mode is input */
552 }
553 break;
554
555 case ioSKS: /* SKS */
556 if (fnc & 012) return IOBADFNC (dat); /* fnc 0,1,4,5 */
557 if (((fnc == 000) && TST_INT (INT_TTY)) || /* fnc 0? skip rdy */
558 ((fnc == 001) && /* fnc 1? skip !busy */
559 (!tty_mode || !sim_is_active (&tty_unit[TTO]))) ||
560 ((fnc == 004) && !TST_INTREQ (INT_TTY)) || /* fnc 4? skip !int */
561 ((fnc == 005) && (tty_mode || /* fnc 5? skip !xoff */
562 ((tty_buf & 0177) != XOFF)))) /* input & XOFF char */
563 return IOSKIP (dat);
564 break;
565
566 case ioINA: /* INA */
567 if (fnc & 005) return IOBADFNC (dat); /* only 0,2 */
568 if (TST_INT (INT_TTY)) { /* ready? */
569 if (tty_mode == 0) CLR_INT (INT_TTY); /* inp? clear rdy */
570 return IOSKIP (dat |
571 (tty_buf & ((fnc & 002)? 077: 0377)));
572 }
573 break;
574
575 case ioOTA:
576 if (fnc & 015) return IOBADFNC (dat); /* only 0,2 */
577 if (TST_INT (INT_TTY)) { /* ready? */
578 tty_buf = dat & 0377; /* store char */
579 if (fnc & 002) { /* binary mode? */
580 tty_buf = tty_buf | 0100; /* set ch 7 */
581 if (tty_buf & 040) tty_buf = tty_buf & 0277;
582 }
583 if (tty_mode) {
584 sim_activate (&tty_unit[TTO], tty_unit[TTO].wait);
585 CLR_INT (INT_TTY);
586 }
587 return IOSKIP (dat);
588 }
589 break;
590 } /* end case op */
591
592 return dat;
593 }
594
595 /* Input service - keyboard and reader */
596
597 t_stat tti_svc (UNIT *uptr)
598 {
599 int32 out, c;
600 UNIT *ruptr = &tty_unit[TTR];
601
602 sim_activate (uptr, uptr->wait); /* continue poll */
603 if ((c = sim_poll_kbd ()) >= SCPE_KFLAG) { /* character? */
604 out = c & 0177; /* mask echo to 7b */
605 if (c & SCPE_BREAK) c = 0; /* break? */
606 else c = sim_tt_inpcvt (c, TT_GET_MODE (uptr->flags) | TTUF_KSR);
607 uptr->pos = uptr->pos + 1;
608 }
609 else if (c != SCPE_OK) return c; /* error? */
610 else if ((ruptr->flags & UNIT_ATT) && /* TTR attached */
611 (ruptr->STA & RUNNING)) { /* and running? */
612 if (ruptr->STA & LF_PEND) { /* lf pending? */
613 c = 0212; /* char is lf */
614 ruptr->STA &= ~LF_PEND; /* clear flag */
615 }
616 else { /* normal read */
617 if ((c = getc (ruptr->fileref)) == EOF) { /* read byte */
618 if (feof (ruptr->fileref)) { /* EOF? */
619 ruptr->STA &= ~RUNNING; /* stop reader */
620 if (ttr_stopioe) printf ("TTR end of file\n");
621 else return SCPE_OK;
622 }
623 else perror ("TTR I/O error");
624 clearerr (ruptr->fileref);
625 return SCPE_IOERR;
626 }
627 if ((ruptr->flags & UNIT_UASC) && (c == '\n')) {
628 c = 0215; /* Unix ASCII NL? */
629 ruptr->STA |= LF_PEND; /* LF pending */
630 }
631 else if ((ruptr->flags & UNIT_ASC) && (c != 0))
632 c = c | 0200; /* ASCII nz? cvt */
633 ruptr->pos = ftell (ruptr->fileref);
634 }
635 if (ttr_xoff_read != 0) { /* reader stopping? */
636 if (c == RUBOUT) ttr_xoff_read = 0; /* rubout? stop */
637 else ttr_xoff_read--; /* else decr state */
638 if (ttr_xoff_read == 0) /* delay done? */
639 ruptr->STA &= ~RUNNING; /* stop reader */
640 }
641 else if ((c & 0177) == XOFF) ttr_xoff_read = 2; /* XOFF read? */
642 out = c; /* echo char */
643 }
644 else return SCPE_OK; /* no char */
645 if (tty_mode == 0) { /* input mode? */
646 tty_buf = c & 0377; /* put char in buf */
647 SET_INT (INT_TTY); /* set flag */
648 }
649 tto_write (out); /* echo to printer */
650 return ttp_write (out); /* and punch */
651 }
652
653 /* Output service - printer and punch */
654
655 t_stat tto_svc (UNIT *uptr)
656 {
657 uint32 c7b;
658 UNIT *ruptr = &tty_unit[TTR];
659 UNIT *puptr = &tty_unit[TTP];
660 t_stat r;
661
662 c7b = tty_buf & 0177;
663 if (ttp_tape_rcvd != 0) { /* prev = tape? */
664 ttp_tape_rcvd--; /* decrement state */
665 if ((ttp_tape_rcvd == 0) && (puptr->flags & UNIT_ATT))
666 puptr->STA |= RUNNING; /* start after delay */
667 }
668 else if (c7b == TAPE) ttp_tape_rcvd = 2; /* char = TAPE? */
669 if (ttp_xoff_rcvd != 0) { /* prev = XOFF? */
670 ttp_xoff_rcvd--; /* decrement state */
671 if (ttp_xoff_rcvd == 0) puptr->STA &= ~RUNNING; /* stop after delay */
672 }
673 else if (c7b == XOFF) ttp_xoff_rcvd = 2; /* char = XOFF? */
674 if ((c7b == XON) && (ruptr->flags & UNIT_ATT)) { /* char = XON? */
675 ruptr->STA |= RUNNING; /* start reader */
676 ttr_xoff_read = 0; /* cancel stop */
677 }
678 if ((r = tto_write (tty_buf)) != SCPE_OK) { /* print; error? */
679 sim_activate (uptr, uptr->wait); /* try again */
680 return ((r == SCPE_STALL)? SCPE_OK: r); /* !stall? report */
681 }
682 if ((r = ttp_write (tty_buf)) != SCPE_OK) return r; /* punch; error? */
683 SET_INT (INT_TTY); /* set done flag */
684 return SCPE_OK;
685 }
686
687 /* Output to printer */
688
689 t_stat tto_write (int32 c)
690 {
691 UNIT *tuptr = &tty_unit[TTO];
692
693 c = sim_tt_outcvt (c, TT_GET_MODE (tuptr->flags) | TTUF_KSR);
694 tuptr->pos = tuptr->pos + 1;
695 if (c >= 0) return sim_putchar_s (c);
696 else return SCPE_OK;
697 }
698
699 /* Output to punch */
700
701 t_stat ttp_write (int32 c)
702 {
703 uint32 p, c7b;
704 UNIT *puptr = &tty_unit[TTP];
705
706 if ((puptr->flags & UNIT_ATT) && /* TTP attached */
707 (puptr->STA & RUNNING)) { /* and running? */
708 c7b = c & 0177;
709 if (!(puptr->flags & UNIT_UASC) || (c7b != 015)) {
710 if (puptr->flags & UNIT_ASC) { /* ASCII? */
711 if (c7b == 012) p = '\n'; /* cvt LF */
712 else p = c7b; /* else 7b */
713 }
714 else p = c; /* untouched */
715 if (putc (p, puptr->fileref) == EOF) { /* output byte */
716 perror ("TTP I/O error");
717 clearerr (puptr->fileref);
718 return SCPE_IOERR;
719 }
720 puptr->pos = ftell (puptr->fileref); /* update pos */
721 }
722 }
723 return SCPE_OK;
724 }
725
726 /* Reset routine */
727
728 t_stat tty_reset (DEVICE *dptr)
729 {
730 CLR_INT (INT_TTY); /* clear ready, enb */
731 CLR_ENB (INT_TTY);
732 tty_mode = 0; /* mode = input */
733 tty_buf = 0;
734 ttr_xoff_read = 0; /* clr TTR, TTP flags */
735 ttp_tape_rcvd = 0;
736 ttp_xoff_rcvd = 0;
737 tty_unit[TTR].STA = 0;
738 tty_unit[TTP].STA = 0;
739 sim_activate (&tty_unit[TTI], tty_unit[TTI].wait); /* activate poll */
740 sim_cancel (&tty_unit[TTO]); /* cancel output */
741 return SCPE_OK;
742 }
743
744 /* Set keyboard/printer mode - make sure flags agree */
745
746 t_stat ttio_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc)
747 {
748 if (uptr->flags & UNIT_ATTABLE) return SCPE_NOFNC; /* not TTR, TTP */
749 tty_unit[TTO].flags = (tty_unit[TTO].flags & ~TT_MODE) | val;
750 if (val == TT_MODE_7P) val = TT_MODE_7B;
751 tty_unit[TTI].flags = (tty_unit[TTI].flags & ~TT_MODE) | val;
752 return SCPE_OK;
753 }
754
755 /* Set reader/punch mode */
756
757 t_stat ttrp_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc)
758 {
759 if (!(uptr->flags & UNIT_ATTABLE)) return SCPE_NOFNC; /* TTR, TTP only */
760 if (!(val & UNIT_UASC)) uptr->STA &= ~LF_PEND;
761 return SCPE_OK;
762 }
763
764 /* Set reader/punch start/stop */
765
766 t_stat ttrp_set_start_stop (UNIT *uptr, int32 val, char *cptr, void *desc)
767 {
768 if (!(uptr->flags & UNIT_ATTABLE)) return SCPE_NOFNC; /* TTR, TTP only */
769 if (!(uptr->flags & UNIT_ATT)) return SCPE_UNATT; /* must be attached */
770 if (val) uptr->STA |= RUNNING; /* start? set running */
771 else uptr->STA &= ~RUNNING; /* stop? clr running */
772 if (uptr->flags & UNIT_ROABLE) ttr_xoff_read = 0; /* TTR? cancel stop */
773 else ttp_tape_rcvd = ttp_xoff_rcvd = 0; /* TTP? cancel all */
774 return SCPE_OK;
775 }
776
777 /* Clock/options: IO routine */
778
779 int32 clkio (int32 inst, int32 fnc, int32 dat, int32 dev)
780 {
781 switch (inst) { /* case on opcode */
782
783 case ioOCP: /* OCP */
784 if (fnc & 015) return IOBADFNC (dat); /* only fnc 0,2 */
785 CLR_INT (INT_CLK); /* reset ready */
786 if (fnc) sim_cancel (&clk_unit); /* fnc = 2? stop */
787 else { /* fnc = 0? */
788 if (!sim_is_active (&clk_unit))
789 sim_activate (&clk_unit, /* activate */
790 sim_rtc_init (clk_unit.wait)); /* init calibr */
791 }
792 break;
793
794 case ioSKS: /* SKS */
795 if (fnc == 000) { /* clock skip !int */
796 if (!TST_INTREQ (INT_CLK)) return IOSKIP (dat);
797 }
798 else if ((fnc & 007) == 002) { /* mem parity? */
799 if (((fnc == 002) && !TST_INT (INT_MPE)) ||
800 ((fnc == 012) && TST_INT (INT_MPE)))
801 return IOSKIP (dat);
802 }
803 else return IOBADFNC (dat); /* invalid fnc */
804 break;
805
806 case ioOTA: /* OTA */
807 if (fnc == 000) dev_enb = dat; /* SMK */
808 else if (fnc == 010) { /* OTK */
809 C = (dat >> 15) & 1; /* set C */
810 if (cpu_unit.flags & UNIT_HSA) /* HSA included? */
811 dp = (dat >> 14) & 1; /* set dp */
812 if (cpu_unit.flags & UNIT_EXT) { /* ext opt? */
813 if (dat & 020000) { /* ext set? */
814 ext = 1; /* yes, set */
815 extoff_pending = 0;
816 }
817 else extoff_pending = 1; /* no, clr later */
818 }
819 sc = dat & 037; /* set sc */
820 }
821 else return IOBADFNC (dat);
822 break;
823 }
824
825 return dat;
826 }
827
828 /* Unit service */
829
830 t_stat clk_svc (UNIT *uptr)
831 {
832
833 M[M_CLK] = (M[M_CLK] + 1) & DMASK; /* increment mem ctr */
834 if (M[M_CLK] == 0) SET_INT (INT_CLK); /* = 0? set flag */
835 sim_activate (&clk_unit, sim_rtc_calb (clk_tps)); /* reactivate */
836 return SCPE_OK;
837 }
838
839 /* Reset routine */
840
841 t_stat clk_reset (DEVICE *dptr)
842 {
843 CLR_INT (INT_CLK); /* clear ready, enb */
844 CLR_ENB (INT_CLK);
845 sim_cancel (&clk_unit); /* deactivate unit */
846 return SCPE_OK;
847 }
848
849 /* Set frequency */
850
851 t_stat clk_set_freq (UNIT *uptr, int32 val, char *cptr, void *desc)
852 {
853 if (cptr) return SCPE_ARG;
854 if ((val != 50) && (val != 60)) return SCPE_IERR;
855 clk_tps = val;
856 return SCPE_OK;
857 }
858
859 /* Show frequency */
860
861 t_stat clk_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc)
862 {
863 fprintf (st, (clk_tps == 50)? "50Hz": "60Hz");
864 return SCPE_OK;
865 }