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