1 /* pdp18b_stddev.c: 18b PDP's standard devices
3 Copyright (c) 1993-2007, Robert M Supnik
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:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
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.
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.
32 18-Jun-07 RMS Added UNIT_IDLE to console input, clock
33 18-Oct-06 RMS Added PDP-15 programmable duplex control
34 Fixed handling of non-printable characters in KSR mode
35 Changed clock to be free-running
36 Fixed out-of-tape behavior for PDP-9 vs PDP-15
37 Synced keyboard to clock
38 30-Jun-06 RMS Fixed KSR-28 shift tracking
39 20-Jun-06 RMS Added KSR ASCII reader support
40 13-Jun-06 RMS Fixed Baudot letters/figures inversion for PDP-4
41 Fixed PDP-4/PDP-7 default terminal to be local echo
42 22-Nov-05 RMS Revised for new terminal processing routines
43 28-May-04 RMS Removed SET TTI CTRL-C
44 16-Feb-04 RMS Fixed bug in hardware read-in mode bootstrap
45 14-Jan-04 RMS Revised IO device call interface
46 CAF does not turn off the clock
47 29-Dec-03 RMS Added console backpressure support
48 26-Jul-03 RMS Increased PTP, TTO timeouts for PDP-15 operating systems
49 Added hardware read-in mode support for PDP-7/9/15
50 25-Apr-03 RMS Revised for extended file support
51 14-Mar-03 RMS Clean up flags on detach
52 01-Mar-03 RMS Added SET/SHOW CLK freq, SET TTI CTRL-C
53 22-Dec-02 RMS Added break support
54 01-Nov-02 RMS Added 7B/8B support to terminal
55 05-Oct-02 RMS Added DIBs, device number support, IORS call
56 14-Jul-02 RMS Added ASCII reader/punch support (from Hans Pufal)
57 30-May-02 RMS Widened POS to 32b
58 29-Nov-01 RMS Added read only unit support
59 25-Nov-01 RMS Revised interrupt structure
60 17-Sep-01 RMS Removed multiconsole support
61 07-Sep-01 RMS Added terminal multiplexor support
62 17-Jul-01 RMS Moved function prototype
63 10-Jun-01 RMS Cleaned up IOT decoding to reflect hardware
64 27-May-01 RMS Added multiconsole support
65 10-Mar-01 RMS Added funny format loader support
66 05-Mar-01 RMS Added clock calibration support
67 22-Dec-00 RMS Added PDP-9/15 half duplex support
68 30-Nov-00 RMS Fixed PDP-4/7 bootstrap loader for 4K systems
69 30-Oct-00 RMS Standardized register naming
70 06-Jan-97 RMS Fixed PDP-4 console input
71 16-Dec-96 RMS Fixed bug in binary ptr service
74 #include "pdp18b_defs.h"
77 #define UNIT_V_RASCII (UNIT_V_UF + 0) /* reader ASCII */
78 #define UNIT_RASCII (1 << UNIT_V_RASCII)
79 #define UNIT_V_KASCII (UNIT_V_UF + 1) /* KSR ASCII */
80 #define UNIT_KASCII (1 << UNIT_V_KASCII)
81 #define UNIT_V_PASCII (UNIT_V_UF + 0) /* punch ASCII */
82 #define UNIT_PASCII (1 << UNIT_V_PASCII)
85 extern int32 int_hwre
[API_HLVL
+1], PC
, ASW
;
86 extern int32 sim_switches
;
87 extern int32 sim_is_running
;
91 int32 ptr_err
= 0, ptr_stopioe
= 0, ptr_state
= 0;
92 int32 ptp_err
= 0, ptp_stopioe
= 0;
93 int32 tti_2nd
= 0; /* 2nd char waiting */
94 int32 tty_shift
= 0; /* KSR28 shift state */
95 int32 tti_fdpx
= 0; /* prog mode full duplex */
96 int32 clk_tps
= 60; /* ticks/second */
97 int32 tmxr_poll
= 16000; /* term mux poll */
98 uint32 clk_task_last
= 0;
99 uint32 clk_task_timer
= 0;
101 const int32 asc_to_baud
[128] = {
102 000,000,000,000,000,000,000,064, /* bell */
103 000,000,0110,000,000,0102,000,000, /* lf, cr */
104 000,000,000,000,000,000,000,000,
105 000,000,000,000,000,000,000,000,
106 0104,066,061,045,062,000,053,072, /* space - ' */
107 076,051,000,000,046,070,047,067, /* ( - / */
108 055,075,071,060,052,041,065,074, /* 0 - 7 */
109 054,043,056,057,000,000,000,063, /* 8 - ? */
110 000,030,023,016,022,020,026,013, /* @ - G */
111 005,014,032,036,011,007,006,003, /* H - O */
112 015,035,012,024,001,034,017,031, /* P - W */
113 027,025,021,000,000,000,000,000, /* X - _ */
114 000,030,023,016,022,020,026,013, /* ` - g */
115 005,014,032,036,011,007,006,003, /* h - o */
116 015,035,012,024,001,034,017,031, /* p - w */
117 027,025,021,000,000,000,000,000 /* x - DEL */
120 const char baud_to_asc
[64] = {
121 0 ,'T',015,'O',' ','H','N','M',
122 012,'L','R','G','I','P','C','V',
123 'E','Z','D','B','S','Y','F','X',
124 'A','W','J', 0 ,'U','Q','K', 0,
125 0 ,'5','\r','9',' ','#',',','.',
126 012,')','4','&','8','0',':',';',
127 '3','"','$','?','\a','6','!','/',
128 '-','2','\'',0 ,'7','1','(', 0
131 int32
ptr (int32 dev
, int32 pulse
, int32 dat
);
132 int32
ptp (int32 dev
, int32 pulse
, int32 dat
);
133 int32
tti (int32 dev
, int32 pulse
, int32 dat
);
134 int32
tto (int32 dev
, int32 pulse
, int32 dat
);
135 int32
clk_iors (void);
136 int32
ptr_iors (void);
137 int32
ptp_iors (void);
138 int32
tti_iors (void);
139 int32
tto_iors (void);
140 t_stat
clk_svc (UNIT
*uptr
);
141 t_stat
ptr_svc (UNIT
*uptr
);
142 t_stat
ptp_svc (UNIT
*uptr
);
143 t_stat
tti_svc (UNIT
*uptr
);
144 t_stat
tto_svc (UNIT
*uptr
);
145 t_stat
clk_reset (DEVICE
*dptr
);
146 t_stat
ptr_reset (DEVICE
*dptr
);
147 t_stat
ptp_reset (DEVICE
*dptr
);
148 t_stat
tti_reset (DEVICE
*dptr
);
149 t_stat
tto_reset (DEVICE
*dptr
);
150 t_stat
ptr_attach (UNIT
*uptr
, char *cptr
);
151 t_stat
ptp_attach (UNIT
*uptr
, char *cptr
);
152 t_stat
ptr_detach (UNIT
*uptr
);
153 t_stat
ptp_detach (UNIT
*uptr
);
154 t_stat
ptr_boot (int32 unitno
, DEVICE
*dptr
);
155 t_stat
tty_set_mode (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
);
156 t_stat
clk_set_freq (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
);
157 t_stat
clk_show_freq (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
);
158 int32
clk_task_upd (t_bool clr
);
160 extern int32
upd_iors (void);
162 /* CLK data structures
164 clk_dev CLK device descriptor
166 clk_reg CLK register list
169 DIB clk_dib
= { 0, 0, &clk_iors
, { NULL
} };
171 UNIT clk_unit
= { UDATA (&clk_svc
, UNIT_IDLE
, 0), 16000 };
174 { FLDATA (INT
, int_hwre
[API_CLK
], INT_V_CLK
) },
175 { FLDATA (DONE
, int_hwre
[API_CLK
], INT_V_CLK
) },
176 { FLDATA (ENABLE
, clk_state
, 0) },
178 { ORDATA (TASKTIMER
, clk_task_timer
, 18) },
179 { DRDATA (TASKLAST
, clk_task_last
, 32), REG_HRO
},
181 { DRDATA (TIME
, clk_unit
.wait
, 24), REG_NZ
+ PV_LEFT
},
182 { DRDATA (TPS
, clk_tps
, 8), PV_LEFT
+ REG_HRO
},
187 { MTAB_XTD
|MTAB_VDV
, 50, NULL
, "50HZ",
188 &clk_set_freq
, NULL
, NULL
},
189 { MTAB_XTD
|MTAB_VDV
, 60, NULL
, "60HZ",
190 &clk_set_freq
, NULL
, NULL
},
191 { MTAB_XTD
|MTAB_VDV
, 0, "FREQUENCY", NULL
,
192 NULL
, &clk_show_freq
, NULL
},
193 { MTAB_XTD
|MTAB_VDV
, 0, "DEVNO", NULL
, NULL
, &show_devno
},
198 "CLK", &clk_unit
, clk_reg
, clk_mod
,
200 NULL
, NULL
, &clk_reset
,
205 /* PTR data structures
207 ptr_dev PTR device descriptor
209 ptr_reg PTR register list
212 DIB ptr_dib
= { DEV_PTR
, 1, &ptr_iors
, { &ptr
} };
215 UDATA (&ptr_svc
, UNIT_SEQ
+UNIT_ATTABLE
+UNIT_ROABLE
, 0),
220 { ORDATA (BUF
, ptr_unit
.buf
, 18) },
221 { FLDATA (INT
, int_hwre
[API_PTR
], INT_V_PTR
) },
222 { FLDATA (DONE
, int_hwre
[API_PTR
], INT_V_PTR
) },
223 #if defined (IOS_PTRERR)
224 { FLDATA (ERR
, ptr_err
, 0) },
226 { ORDATA (STATE
, ptr_state
, 5), REG_HRO
},
227 { DRDATA (POS
, ptr_unit
.pos
, T_ADDR_W
), PV_LEFT
},
228 { DRDATA (TIME
, ptr_unit
.wait
, 24), PV_LEFT
},
229 { FLDATA (STOP_IOE
, ptr_stopioe
, 0) },
234 { UNIT_RASCII
, UNIT_RASCII
, "even parity ASCII", NULL
},
235 { UNIT_KASCII
, UNIT_KASCII
, "forced parity ASCII", NULL
},
236 { MTAB_XTD
|MTAB_VDV
, 0, "DEVNO", NULL
, NULL
, &show_devno
},
241 "PTR", &ptr_unit
, ptr_reg
, ptr_mod
,
243 NULL
, NULL
, &ptr_reset
,
244 &ptr_boot
, &ptr_attach
, &ptr_detach
,
248 /* PTP data structures
250 ptp_dev PTP device descriptor
252 ptp_reg PTP register list
255 DIB ptp_dib
= { DEV_PTP
, 1, &ptp_iors
, { &ptp
} };
258 UDATA (&ptp_svc
, UNIT_SEQ
+UNIT_ATTABLE
, 0), SERIAL_OUT_WAIT
262 { ORDATA (BUF
, ptp_unit
.buf
, 8) },
263 { FLDATA (INT
, int_hwre
[API_PTP
], INT_V_PTP
) },
264 { FLDATA (DONE
, int_hwre
[API_PTP
], INT_V_PTP
) },
265 #if defined (IOS_PTPERR)
266 { FLDATA (ERR
, ptp_err
, 0) },
268 { DRDATA (POS
, ptp_unit
.pos
, T_ADDR_W
), PV_LEFT
},
269 { DRDATA (TIME
, ptp_unit
.wait
, 24), PV_LEFT
},
270 { FLDATA (STOP_IOE
, ptp_stopioe
, 0) },
275 { UNIT_PASCII
, UNIT_PASCII
, "7b ASCII", NULL
},
276 { MTAB_XTD
|MTAB_VDV
, 0, "DEVNO", NULL
, NULL
, &show_devno
},
281 "PTP", &ptp_unit
, ptp_reg
, ptp_mod
,
283 NULL
, NULL
, &ptp_reset
,
284 NULL
, &ptp_attach
, &ptp_detach
,
288 /* TTI data structures
290 tti_dev TTI device descriptor
292 tti_reg TTI register list
297 #define TTI_FIGURES (1 << TTI_WIDTH)
298 #define TTI_BOTH (1 << (TTI_WIDTH + 1))
299 #define BAUDOT_LETTERS 037
300 #define BAUDOT_FIGURES 033
307 #define TTI_MASK ((1 << TTI_WIDTH) - 1)
308 #define TTUF_V_HDX (TTUF_V_UF + 0) /* half duplex */
309 #define TTUF_HDX (1 << TTUF_V_HDX)
311 DIB tti_dib
= { DEV_TTI
, 1, &tti_iors
, { &tti
} };
313 UNIT tti_unit
= { UDATA (&tti_svc
, UNIT_IDLE
+TT_MODE_KSR
+TTUF_HDX
, 0), 0 };
316 { ORDATA (BUF
, tti_unit
.buf
, TTI_WIDTH
) },
318 { ORDATA (BUF2ND
, tti_2nd
, TTI_WIDTH
), REG_HRO
},
320 { FLDATA (INT
, int_hwre
[API_TTI
], INT_V_TTI
) },
321 { FLDATA (DONE
, int_hwre
[API_TTI
], INT_V_TTI
) },
323 { FLDATA (FDPX
, tti_fdpx
, 0) },
325 { DRDATA (POS
, tti_unit
.pos
, T_ADDR_W
), PV_LEFT
},
326 { DRDATA (TIME
, tti_unit
.wait
, 24), PV_LEFT
},
332 { TT_MODE
, TT_MODE_KSR
, "KSR", "KSR", &tty_set_mode
},
333 { TT_MODE
, TT_MODE_7B
, "7b", "7B", &tty_set_mode
},
334 { TT_MODE
, TT_MODE_8B
, "8b", "8B", &tty_set_mode
},
335 { TT_MODE
, TT_MODE_7P
, "7b", NULL
, NULL
},
337 { TTUF_HDX
, 0 , "full duplex", "FDX", NULL
},
338 { TTUF_HDX
, TTUF_HDX
, "half duplex", "HDX", NULL
},
339 { MTAB_XTD
|MTAB_VDV
, 0, "DEVNO", NULL
, NULL
, &show_devno
, NULL
},
344 "TTI", &tti_unit
, tti_reg
, tti_mod
,
346 NULL
, NULL
, &tti_reset
,
351 /* TTO data structures
353 tto_dev TTO device descriptor
355 tto_reg TTO register list
360 #define TTO_FIGURES (1 << TTO_WIDTH)
367 #define TTO_MASK ((1 << TTO_WIDTH) - 1)
369 DIB tto_dib
= { DEV_TTO
, 1, &tto_iors
, { &tto
} };
371 UNIT tto_unit
= { UDATA (&tto_svc
, TT_MODE_KSR
, 0), 1000 };
374 { ORDATA (BUF
, tto_unit
.buf
, TTO_WIDTH
) },
376 { FLDATA (SHIFT
, tty_shift
, 0), REG_HRO
},
378 { FLDATA (INT
, int_hwre
[API_TTO
], INT_V_TTO
) },
379 { FLDATA (DONE
, int_hwre
[API_TTO
], INT_V_TTO
) },
380 { DRDATA (POS
, tto_unit
.pos
, T_ADDR_W
), PV_LEFT
},
381 { DRDATA (TIME
, tto_unit
.wait
, 24), PV_LEFT
},
387 { TT_MODE
, TT_MODE_KSR
, "KSR", "KSR", &tty_set_mode
},
388 { TT_MODE
, TT_MODE_7B
, "7b", "7B", &tty_set_mode
},
389 { TT_MODE
, TT_MODE_8B
, "8b", "8B", &tty_set_mode
},
390 { TT_MODE
, TT_MODE_7P
, "7p", "7P", &tty_set_mode
},
392 { MTAB_XTD
|MTAB_VDV
, 0, "DEVNO", NULL
, NULL
, &show_devno
},
397 "TTO", &tto_unit
, tto_reg
, tto_mod
,
399 NULL
, NULL
, &tto_reset
,
404 /* Clock: IOT routine */
406 int32
clk (int32 dev
, int32 pulse
, int32 dat
)
408 if (pulse
& 001) { /* CLSF */
409 if (TST_INT (CLK
)) dat
= dat
| IOT_SKP
;
411 if (pulse
& 004) { /* CLON/CLOF */
412 CLR_INT (CLK
); /* clear flag */
413 if (pulse
& 040) clk_state
= 1; /* CLON */
414 else clk_state
= 0; /* CLOF */
421 t_stat
clk_svc (UNIT
*uptr
)
425 t
= sim_rtc_calb (clk_tps
); /* calibrate clock */
426 tmxr_poll
= t
; /* set mux poll */
427 sim_activate (&clk_unit
, t
); /* reactivate unit */
429 clk_task_upd (FALSE
); /* update task timer */
431 if (clk_state
) { /* clock on? */
432 M
[7] = (M
[7] + 1) & DMASK
; /* incr counter */
433 if (M
[7] == 0) SET_INT (CLK
); /* ovrflo? set flag */
440 /* Task timer update (PDP-15 XVM only)
442 The task timer increments monotonically at 100Khz. Since this can't be
443 simulated accurately, updates are done by interpolation since the last
444 reading. The timer is also updated at clock events to keep the cycle
445 counters from wrapping around more than once between updates. */
447 int32
clk_task_upd (t_bool clr
)
449 uint32 delta
, val
, iusec10
;
450 uint32 cur
= sim_grtime ();
451 uint32 old
= clk_task_timer
;
454 if (cur
> clk_task_last
) delta
= cur
- clk_task_last
;
455 else delta
= clk_task_last
- cur
;
456 usec10
= ((((double) delta
) * 100000.0) /
457 (((double) tmxr_poll
) * ((double) clk_tps
)));
458 iusec10
= (int32
) usec10
;
459 val
= (clk_task_timer
+ iusec10
) & DMASK
;
460 if (clr
) clk_task_timer
= 0;
461 else clk_task_timer
= val
;
463 return ((int32
) val
);
470 int32
clk_iors (void)
472 return (TST_INT (CLK
)? IOS_CLK
: 0);
477 t_stat
clk_reset (DEVICE
*dptr
)
481 CLR_INT (CLK
); /* clear flag */
482 if (!sim_is_running
) { /* RESET (not CAF)? */
483 t
= sim_rtc_init (clk_unit
.wait
); /* init calibration */
484 tmxr_poll
= t
; /* set mux poll */
485 sim_activate_abs (&clk_unit
, t
); /* activate unit */
486 clk_state
= 0; /* clock off */
495 t_stat
clk_set_freq (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
497 if (cptr
) return SCPE_ARG
;
498 if ((val
!= 50) && (val
!= 60)) return SCPE_IERR
;
505 t_stat
clk_show_freq (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
507 fprintf (st
, (clk_tps
== 50)? "50Hz": "60Hz");
511 /* Paper tape reader out-of-tape handling
513 The PDP-4 and PDP-7 readers behaved like most early DEC readers; when
514 they ran out of tape, they hung. It was up to the program to sense this
515 condition by running a timer.
517 The PDP-9 reader controller synthesized the out of tape condition by
518 noticing whether there was a transition on the feed hole within a window.
519 The out-of-tape flag was treated like the reader flag in most cases.
521 The PDP-15 reader controller received the out-of-tape flag as a static
522 condition from the reader itself and simply reported it via IORS. */
524 /* Paper tape reader: IOT routine */
526 int32
ptr (int32 dev
, int32 pulse
, int32 dat
)
528 if (pulse
& 001) { /* RSF */
529 if (TST_INT (PTR
)) dat
= dat
| IOT_SKP
;
531 if (pulse
& 002) { /* RRB, RCF */
532 CLR_INT (PTR
); /* clear flag */
533 dat
= dat
| ptr_unit
.buf
; /* return buffer */
535 if (pulse
& 004) { /* RSA, RSB */
536 ptr_state
= (pulse
& 040)? 18: 0; /* set mode */
537 CLR_INT (PTR
); /* clear flag */
538 #if !defined (PDP15) /* except on PDP15 */
539 ptr_err
= 0; /* clear error */
541 ptr_unit
.buf
= 0; /* clear buffer */
542 sim_activate (&ptr_unit
, ptr_unit
.wait
);
549 t_stat
ptr_svc (UNIT
*uptr
)
553 if ((ptr_unit
.flags
& UNIT_ATT
) == 0) { /* attached? */
554 #if defined (IOS_PTRERR)
555 SET_INT (PTR
); /* if err, set flag */
556 ptr_err
= 1; /* set error */
558 return IORETURN (ptr_stopioe
, SCPE_UNATT
);
560 if ((temp
= getc (ptr_unit
.fileref
)) == EOF
) { /* end of file? */
561 #if defined (IOS_PTRERR)
562 SET_INT (PTR
); /* if err, set flag */
563 ptr_err
= 1; /* set error */
565 if (feof (ptr_unit
.fileref
)) {
566 if (ptr_stopioe
) printf ("PTR end of file\n");
569 else perror ("PTR I/O error");
570 clearerr (ptr_unit
.fileref
);
573 if (ptr_state
== 0) { /* ASCII */
574 if (ptr_unit
.flags
& UNIT_RASCII
) { /* want parity? */
575 ptr_unit
.buf
= temp
= temp
& 0177; /* parity off */
576 while (temp
= temp
& (temp
- 1))
577 ptr_unit
.buf
= ptr_unit
.buf
^ 0200; /* count bits */
578 ptr_unit
.buf
= ptr_unit
.buf
^ 0200; /* set even parity */
580 else if (ptr_unit
.flags
& UNIT_KASCII
) /* KSR ASCII? */
581 ptr_unit
.buf
= (temp
| 0200) & 0377; /* forced parity */
582 else ptr_unit
.buf
= temp
& 0377;
584 else if (temp
& 0200) { /* binary */
585 ptr_state
= ptr_state
- 6;
586 ptr_unit
.buf
= ptr_unit
.buf
| ((temp
& 077) << ptr_state
);
588 if (ptr_state
== 0) SET_INT (PTR
); /* if done, set flag */
589 else sim_activate (&ptr_unit
, ptr_unit
.wait
); /* else restart */
590 ptr_unit
.pos
= ptr_unit
.pos
+ 1;
596 t_stat
ptr_reset (DEVICE
*dptr
)
598 ptr_state
= 0; /* clear state */
600 CLR_INT (PTR
); /* clear flag */
601 #if defined (PDP15) /* PDP15, static err */
602 if (((ptr_unit
.flags
& UNIT_ATT
) == 0) || feof (ptr_unit
.fileref
))
606 ptr_err
= 0; /* all other, clr err */
607 sim_cancel (&ptr_unit
); /* deactivate unit */
613 int32
ptr_iors (void)
615 return ((TST_INT (PTR
)? IOS_PTR
: 0)
616 #if defined (IOS_PTRERR)
617 | (ptr_err
? IOS_PTRERR
: 0)
624 t_stat
ptr_attach (UNIT
*uptr
, char *cptr
)
628 reason
= attach_unit (uptr
, cptr
);
629 if (reason
!= SCPE_OK
) return reason
;
630 ptr_err
= 0; /* attach clrs error */
631 ptr_unit
.flags
= ptr_unit
.flags
& ~(UNIT_RASCII
|UNIT_KASCII
);
632 if (sim_switches
& SWMASK ('A'))
633 ptr_unit
.flags
= ptr_unit
.flags
| UNIT_RASCII
;
634 if (sim_switches
& SWMASK ('K'))
635 ptr_unit
.flags
= ptr_unit
.flags
| UNIT_KASCII
;
641 t_stat
ptr_detach (UNIT
*uptr
)
646 ptr_unit
.flags
= ptr_unit
.flags
& ~UNIT_RASCII
;
647 return detach_unit (uptr
);
650 /* Hardware RIM loader routines, PDP-7/9/15 */
652 int32
ptr_getw (UNIT
*uptr
, int32
*hi
)
654 int32 word
, bits
, st
, ch
;
656 word
= st
= bits
= 0;
658 if ((ch
= getc (uptr
->fileref
)) == EOF
) return -1;
659 uptr
->pos
= uptr
->pos
+ 1;
661 word
= (word
<< 6) | (ch
& 077);
662 bits
= (bits
<< 1) | ((ch
>> 6) & 1);
666 if (hi
!= NULL
) *hi
= bits
;
670 t_stat
ptr_rim_load (UNIT
*uptr
, int32 origin
)
674 for (;;) { /* word loop */
675 if ((val
= ptr_getw (uptr
, &bits
)) < 0) return SCPE_FMT
;
676 if (bits
& 1) { /* end of tape? */
677 if ((val
& 0760000) == OP_JMP
) {
678 PC
= ((origin
- 1) & 060000) | (val
& 017777);
681 else if (val
== OP_HLT
) return STOP_HALT
;
684 else if (MEM_ADDR_OK (origin
)) M
[origin
++] = val
;
689 #if defined (PDP4) || defined (PDP7)
691 /* Bootstrap routine, PDP-4 and PDP-7
693 In a 4K system, the boostrap resides at 7762-7776.
694 In an 8K or greater system, the bootstrap resides at 17762-17776.
695 Because the program is so small, simple masking can be
696 used to remove addr<5> for a 4K system. */
698 #define BOOT_START 017577
699 #define BOOT_FPC 017577 /* funny format loader */
700 #define BOOT_RPC 017770 /* RIM loader */
701 #define BOOT_LEN (sizeof (boot_rom) / sizeof (int))
703 static const int32 boot_rom
[] = {
705 0117762, /* ff, jsb r1b */
706 0057666, /* dac done 1 */
707 0117762, /* jms r1b */
708 0057667, /* dac done 2 */
709 0117762, /* jms r1b */
710 0040007, /* dac conend */
711 0057731, /* dac conbeg */
712 0440007, /* isz conend */
713 0117762, /* blk, jms r1b */
714 0057673, /* dac cai */
716 0617665, /* jmp done */
717 0117762, /* jms r1b */
718 0057777, /* dac tem1 */
719 0317673, /* add cai */
720 0057775, /* dac cks */
721 0117713, /* jms r1a */
722 0140010, /* dzm word */
723 0457777, /* cont, isz tem1 */
724 0617632, /* jmp cont1 */
725 0217775, /* lac cks */
730 0617610, /* jmp blk */
731 0117713, /* cont1, jms r1a */
732 0057762, /* dac tem2 */
733 0117713, /* jms r1a */
738 0317762, /* add tem2 */
739 0057762, /* dac tem2 */
740 0117713, /* jms r1a */
742 0317726, /* add cdsp */
743 0057713, /* dac r1a */
744 0517701, /* and ccma */
746 0317762, /* add tem2 */
747 0437713, /* xct i r1a */
748 0617622, /* jmp cont */
749 0617672, /* dsptch, jmp code0 */
750 0617670, /* jmp code1 */
751 0617700, /* jmp code2 */
752 0617706, /* jmp code3 */
753 0417711, /* xct code4 */
754 0617732, /* jmp const */
758 0200007, /* done, lac conend */
761 0517727, /* code1, and imsk */
762 0337762, /* add i tem2 */
763 0300010, /* code0, add word */
764 0740040, /* cai, xx */
766 0357673, /* tad cai */
767 0057673, /* dac cai */
768 0617621, /* jmp cont-1 */
769 0711101, /* code2, spa cla */
770 0740001, /* ccma, cma */
771 0277762, /* xor i tem2 */
772 0300010, /* add word */
773 0040010, /* code2a, dac word */
774 0617622, /* jmp cont */
775 0057711, /* code3, dac code4 */
776 0217673, /* lac cai */
777 0357701, /* tad ccma */
778 0740040, /* code4, xx */
779 0617622, /* jmp cont */
780 0000000, /* r1a, 0 */
782 0617714, /* jmp .-1 */
785 0057730, /* dac tem */
786 0317775, /* add cks */
787 0057775, /* dac cks */
788 0217730, /* lac tem */
790 0637713, /* jmp i r1a */
791 0017654, /* cdsp, dsptch */
792 0760000, /* imsk, 760000 */
793 0000000, /* tem, 0 */
794 0000000, /* conbeg, 0 */
795 0300010, /* const, add word */
796 0060007, /* dac i conend */
797 0217731, /* lac conbeg */
798 0040010, /* dac index */
799 0220007, /* lac i conend */
800 0560010, /* con1, sad i index */
801 0617752, /* jmp find */
802 0560010, /* sad i index */
803 0617752, /* jmp find */
804 0560010, /* sad i index */
805 0617752, /* jmp find */
806 0560010, /* sad i index */
807 0617752, /* jmp find */
808 0560010, /* sad i index */
809 0617752, /* jmp find */
810 0617737, /* jmp con1 */
811 0200010, /* find, lac index */
812 0540007, /* sad conend */
813 0440007, /* isz conend */
814 0617704, /* jmp code2a */
819 0000000, /* r1b, 0 */
821 0617763, /* jmp .-1 */
824 0637762, /* jmp i r1b */
825 0700144, /* go, rsb */
826 0117762, /* g, jms r1b */
827 0057775, /* dac cks */
828 0417775, /* xct cks */
829 0117762, /* jms r1b */
830 0000000, /* cks, 0 */
834 t_stat
ptr_boot (int32 unitno
, DEVICE
*dptr
)
837 extern int32 sim_switches
;
840 if (sim_switches
& SWMASK ('H')) /* hardware RIM load? */
841 return ptr_rim_load (&ptr_unit
, ASW
);
843 if (ptr_dib
.dev
!= DEV_PTR
) return STOP_NONSTD
; /* non-std addr? */
844 if (MEMSIZE
< 8192) mask
= 0767777; /* 4k? */
846 for (i
= 0; i
< BOOT_LEN
; i
++) {
848 if ((wd
>= 0040000) && (wd
< 0640000)) wd
= wd
& mask
;
849 M
[(BOOT_START
& mask
) + i
] = wd
;
851 PC
= ((sim_switches
& SWMASK ('F'))? BOOT_FPC
: BOOT_RPC
) & mask
;
857 /* PDP-9 and PDP-15 have built-in hardware RIM loaders */
859 t_stat
ptr_boot (int32 unitno
, DEVICE
*dptr
)
861 return ptr_rim_load (&ptr_unit
, ASW
);
866 /* Paper tape punch: IOT routine */
868 int32
ptp (int32 dev
, int32 pulse
, int32 dat
)
870 if (pulse
& 001) { /* PSF */
871 if (TST_INT (PTP
)) dat
= dat
| IOT_SKP
;
873 if (pulse
& 002) CLR_INT (PTP
); /* PCF */
874 if (pulse
& 004) { /* PSA, PSB, PLS */
875 CLR_INT (PTP
); /* clear flag */
876 ptp_unit
.buf
= (pulse
& 040)? /* load punch buf */
877 (dat
& 077) | 0200: dat
& 0377; /* bin or alpha */
878 sim_activate (&ptp_unit
, ptp_unit
.wait
); /* activate unit */
885 t_stat
ptp_svc (UNIT
*uptr
)
887 SET_INT (PTP
); /* set flag */
888 if ((ptp_unit
.flags
& UNIT_ATT
) == 0) { /* not attached? */
889 ptp_err
= 1; /* set error */
890 return IORETURN (ptp_stopioe
, SCPE_UNATT
);
892 if (ptp_unit
.flags
& UNIT_PASCII
) { /* ASCII mode? */
893 ptp_unit
.buf
= ptp_unit
.buf
& 0177; /* force 7b */
894 if ((ptp_unit
.buf
== 0) || (ptp_unit
.buf
== 0177))
895 return SCPE_OK
; /* skip null, del */
897 if (putc (ptp_unit
.buf
, ptp_unit
.fileref
) == EOF
) { /* I/O error? */
898 ptp_err
= 1; /* set error */
899 perror ("PTP I/O error");
900 clearerr (ptp_unit
.fileref
);
903 ptp_unit
.pos
= ptp_unit
.pos
+ 1;
909 int32
ptp_iors (void)
911 return ((TST_INT (PTP
)? IOS_PTP
: 0)
912 #if defined (IOS_PTPERR)
913 | (ptp_err
? IOS_PTPERR
: 0)
920 t_stat
ptp_reset (DEVICE
*dptr
)
923 CLR_INT (PTP
); /* clear flag */
924 ptp_err
= (ptp_unit
.flags
& UNIT_ATT
)? 0: 1;
925 sim_cancel (&ptp_unit
); /* deactivate unit */
931 t_stat
ptp_attach (UNIT
*uptr
, char *cptr
)
935 reason
= attach_unit (uptr
, cptr
);
936 if (reason
!= SCPE_OK
) return reason
;
938 ptp_unit
.flags
= ptp_unit
.flags
& ~UNIT_PASCII
;
939 if (sim_switches
& SWMASK ('A'))
940 ptp_unit
.flags
= ptp_unit
.flags
| UNIT_PASCII
;
946 t_stat
ptp_detach (UNIT
*uptr
)
949 ptp_unit
.flags
= ptp_unit
.flags
& ~UNIT_PASCII
;
950 return detach_unit (uptr
);
953 /* Terminal input: IOT routine */
955 int32
tti (int32 dev
, int32 pulse
, int32 dat
)
957 if (pulse
& 001) { /* KSF */
958 if (TST_INT (TTI
)) dat
= dat
| IOT_SKP
;
960 if (pulse
& 002) { /* KRS/KRB */
961 CLR_INT (TTI
); /* clear flag */
962 dat
= dat
| tti_unit
.buf
& TTI_MASK
; /* return buffer */
964 if (pulse
& 020) tti_fdpx
= 1; /* KRS? */
965 else tti_fdpx
= 0; /* no, KRB */
968 if (pulse
& 004) { /* IORS */
969 dat
= dat
| upd_iors ();
976 t_stat
tti_svc (UNIT
*uptr
)
978 #if defined (KSR28) /* Baudot... */
981 sim_activate (uptr
, KBD_WAIT (uptr
->wait
, tmxr_poll
)); /* continue poll */
982 if (tti_2nd
) { /* char waiting? */
983 uptr
->buf
= tti_2nd
; /* return char */
984 tti_2nd
= 0; /* not waiting */
987 if ((in
= sim_poll_kbd ()) < SCPE_KFLAG
) return in
;
988 c
= asc_to_baud
[in
& 0177]; /* translate char */
989 if (c
== 0) return SCPE_OK
; /* untranslatable? */
990 if ((c
& TTI_BOTH
) || /* case insensitive? */
991 (((c
& TTI_FIGURES
)? 1: 0) == tty_shift
)) /* right case? */
992 uptr
->buf
= c
& TTI_MASK
;
993 else { /* send case change */
994 if (c
& TTI_FIGURES
) { /* to figures? */
995 uptr
->buf
= BAUDOT_FIGURES
;
998 else { /* no, to letters */
999 uptr
->buf
= BAUDOT_LETTERS
;
1002 tti_2nd
= c
& TTI_MASK
; /* save actual char */
1004 if ((uptr
->flags
& TTUF_HDX
) && /* half duplex? */
1005 ((out
= sim_tt_outcvt (in
, TT_GET_MODE (uptr
->flags
) | TTUF_KSR
)) >= 0)) {
1007 tto_unit
.pos
= tto_unit
.pos
+ 1;
1011 #else /* ASCII... */
1014 sim_activate (uptr
, KBD_WAIT (uptr
->wait
, tmxr_poll
)); /* continue poll */
1015 if ((c
= sim_poll_kbd ()) < SCPE_KFLAG
) return c
; /* no char or error? */
1016 out
= c
& 0177; /* mask echo to 7b */
1017 if (c
& SCPE_BREAK
) c
= 0; /* break? */
1018 else c
= sim_tt_inpcvt (c
, TT_GET_MODE (uptr
->flags
) | TTUF_KSR
);
1019 if ((uptr
->flags
& TTUF_HDX
) && !tti_fdpx
&& out
&& /* half duplex and */
1020 ((out
= sim_tt_outcvt (out
, TT_GET_MODE (uptr
->flags
) | TTUF_KSR
)) >= 0)) {
1021 sim_putchar (out
); /* echo */
1022 tto_unit
.pos
= tto_unit
.pos
+ 1;
1024 uptr
->buf
= c
; /* got char */
1027 uptr
->pos
= uptr
->pos
+ 1;
1028 SET_INT (TTI
); /* set flag */
1034 int32
tti_iors (void)
1036 return (TST_INT (TTI
)? IOS_TTI
: 0);
1041 t_stat
tti_reset (DEVICE
*dptr
)
1043 tti_unit
.buf
= 0; /* clear buffer */
1045 tty_shift
= 0; /* clear state */
1046 tti_fdpx
= 0; /* clear dpx mode */
1047 CLR_INT (TTI
); /* clear flag */
1048 sim_activate_abs (&tti_unit
, KBD_WAIT (tti_unit
.wait
, tmxr_poll
));
1052 /* Terminal output: IOT routine */
1054 int32
tto (int32 dev
, int32 pulse
, int32 dat
)
1056 if (pulse
& 001) { /* TSF */
1057 if (TST_INT (TTO
)) dat
= dat
| IOT_SKP
;
1059 if (pulse
& 002) CLR_INT (TTO
); /* clear flag */
1060 if (pulse
& 004) { /* load buffer */
1061 sim_activate (&tto_unit
, tto_unit
.wait
); /* activate unit */
1062 tto_unit
.buf
= dat
& TTO_MASK
; /* load buffer */
1069 t_stat
tto_svc (UNIT
*uptr
)
1074 #if defined (KSR28) /* Baudot... */
1075 if (uptr
->buf
== BAUDOT_FIGURES
) /* set figures? */
1077 else if (uptr
->buf
== BAUDOT_LETTERS
) /* set letters? */
1080 c
= baud_to_asc
[uptr
->buf
| (tty_shift
<< 5)]; /* translate */
1083 c
= sim_tt_outcvt (uptr
->buf
, TT_GET_MODE (uptr
->flags
) | TTUF_KSR
);
1088 if ((r
= sim_putchar_s (c
)) != SCPE_OK
) { /* output; error? */
1089 sim_activate (uptr
, uptr
->wait
); /* retry? */
1090 return ((r
== SCPE_STALL
)? SCPE_OK
: r
);
1093 SET_INT (TTO
); /* set flag */
1094 uptr
->pos
= uptr
->pos
+ 1;
1100 int32
tto_iors (void)
1102 return (TST_INT (TTO
)? IOS_TTO
: 0);
1107 t_stat
tto_reset (DEVICE
*dptr
)
1109 tto_unit
.buf
= 0; /* clear buffer */
1110 tty_shift
= 0; /* clear state */
1111 CLR_INT (TTO
); /* clear flag */
1112 sim_cancel (&tto_unit
); /* deactivate unit */
1118 t_stat
tty_set_mode (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
1120 tti_unit
.flags
= (tti_unit
.flags
& ~TT_MODE
) | val
;
1121 tto_unit
.flags
= (tto_unit
.flags
& ~TT_MODE
) | val
;