First Commit of my working state
[simh.git] / PDP18B / pdp18b_stddev.c
1 /* pdp18b_stddev.c: 18b PDP's standard devices
2
3 Copyright (c) 1993-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 paper tape reader
27 ptp paper tape punch
28 tti keyboard
29 tto teleprinter
30 clk clock
31
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
72 */
73
74 #include "pdp18b_defs.h"
75 #include <ctype.h>
76
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)
83
84 extern int32 M[];
85 extern int32 int_hwre[API_HLVL+1], PC, ASW;
86 extern int32 sim_switches;
87 extern int32 sim_is_running;
88 extern UNIT cpu_unit;
89
90 int32 clk_state = 0;
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;
100
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 */
118 };
119
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
129 };
130
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);
159
160 extern int32 upd_iors (void);
161
162 /* CLK data structures
163
164 clk_dev CLK device descriptor
165 clk_unit CLK unit
166 clk_reg CLK register list
167 */
168
169 DIB clk_dib = { 0, 0, &clk_iors, { NULL } };
170
171 UNIT clk_unit = { UDATA (&clk_svc, UNIT_IDLE, 0), 16000 };
172
173 REG clk_reg[] = {
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) },
177 #if defined (PDP15)
178 { ORDATA (TASKTIMER, clk_task_timer, 18) },
179 { DRDATA (TASKLAST, clk_task_last, 32), REG_HRO },
180 #endif
181 { DRDATA (TIME, clk_unit.wait, 24), REG_NZ + PV_LEFT },
182 { DRDATA (TPS, clk_tps, 8), PV_LEFT + REG_HRO },
183 { NULL }
184 };
185
186 MTAB clk_mod[] = {
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 },
194 { 0 }
195 };
196
197 DEVICE clk_dev = {
198 "CLK", &clk_unit, clk_reg, clk_mod,
199 1, 0, 0, 0, 0, 0,
200 NULL, NULL, &clk_reset,
201 NULL, NULL, NULL,
202 &clk_dib, 0
203 };
204
205 /* PTR data structures
206
207 ptr_dev PTR device descriptor
208 ptr_unit PTR unit
209 ptr_reg PTR register list
210 */
211
212 DIB ptr_dib = { DEV_PTR, 1, &ptr_iors, { &ptr } };
213
214 UNIT ptr_unit = {
215 UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0),
216 SERIAL_IN_WAIT
217 };
218
219 REG ptr_reg[] = {
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) },
225 #endif
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) },
230 { NULL }
231 };
232
233 MTAB ptr_mod[] = {
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 },
237 { 0 }
238 };
239
240 DEVICE ptr_dev = {
241 "PTR", &ptr_unit, ptr_reg, ptr_mod,
242 1, 10, 31, 1, 8, 8,
243 NULL, NULL, &ptr_reset,
244 &ptr_boot, &ptr_attach, &ptr_detach,
245 &ptr_dib, 0
246 };
247
248 /* PTP data structures
249
250 ptp_dev PTP device descriptor
251 ptp_unit PTP unit
252 ptp_reg PTP register list
253 */
254
255 DIB ptp_dib = { DEV_PTP, 1, &ptp_iors, { &ptp } };
256
257 UNIT ptp_unit = {
258 UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT
259 };
260
261 REG ptp_reg[] = {
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) },
267 #endif
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) },
271 { NULL }
272 };
273
274 MTAB ptp_mod[] = {
275 { UNIT_PASCII, UNIT_PASCII, "7b ASCII", NULL },
276 { MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_devno },
277 { 0 }
278 };
279
280 DEVICE ptp_dev = {
281 "PTP", &ptp_unit, ptp_reg, ptp_mod,
282 1, 10, 31, 1, 8, 8,
283 NULL, NULL, &ptp_reset,
284 NULL, &ptp_attach, &ptp_detach,
285 &ptp_dib, 0
286 };
287
288 /* TTI data structures
289
290 tti_dev TTI device descriptor
291 tti_unit TTI unit
292 tti_reg TTI register list
293 */
294
295 #if defined (KSR28)
296 #define TTI_WIDTH 5
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
301
302 #else
303
304 #define TTI_WIDTH 8
305 #endif
306
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)
310
311 DIB tti_dib = { DEV_TTI, 1, &tti_iors, { &tti } };
312
313 UNIT tti_unit = { UDATA (&tti_svc, UNIT_IDLE+TT_MODE_KSR+TTUF_HDX, 0), 0 };
314
315 REG tti_reg[] = {
316 { ORDATA (BUF, tti_unit.buf, TTI_WIDTH) },
317 #if defined (KSR28)
318 { ORDATA (BUF2ND, tti_2nd, TTI_WIDTH), REG_HRO },
319 #endif
320 { FLDATA (INT, int_hwre[API_TTI], INT_V_TTI) },
321 { FLDATA (DONE, int_hwre[API_TTI], INT_V_TTI) },
322 #if defined (PDP15)
323 { FLDATA (FDPX, tti_fdpx, 0) },
324 #endif
325 { DRDATA (POS, tti_unit.pos, T_ADDR_W), PV_LEFT },
326 { DRDATA (TIME, tti_unit.wait, 24), PV_LEFT },
327 { NULL }
328 };
329
330 MTAB tti_mod[] = {
331 #if !defined (KSR28)
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 },
336 #endif
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 },
340 { 0 }
341 };
342
343 DEVICE tti_dev = {
344 "TTI", &tti_unit, tti_reg, tti_mod,
345 1, 10, 31, 1, 8, 8,
346 NULL, NULL, &tti_reset,
347 NULL, NULL, NULL,
348 &tti_dib, 0
349 };
350
351 /* TTO data structures
352
353 tto_dev TTO device descriptor
354 tto_unit TTO unit
355 tto_reg TTO register list
356 */
357
358 #if defined (KSR28)
359 #define TTO_WIDTH 5
360 #define TTO_FIGURES (1 << TTO_WIDTH)
361
362 #else
363
364 #define TTO_WIDTH 8
365 #endif
366
367 #define TTO_MASK ((1 << TTO_WIDTH) - 1)
368
369 DIB tto_dib = { DEV_TTO, 1, &tto_iors, { &tto } };
370
371 UNIT tto_unit = { UDATA (&tto_svc, TT_MODE_KSR, 0), 1000 };
372
373 REG tto_reg[] = {
374 { ORDATA (BUF, tto_unit.buf, TTO_WIDTH) },
375 #if defined (KSR28)
376 { FLDATA (SHIFT, tty_shift, 0), REG_HRO },
377 #endif
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 },
382 { NULL }
383 };
384
385 MTAB tto_mod[] = {
386 #if !defined (KSR28)
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 },
391 #endif
392 { MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_devno },
393 { 0 }
394 };
395
396 DEVICE tto_dev = {
397 "TTO", &tto_unit, tto_reg, tto_mod,
398 1, 10, 31, 1, 8, 8,
399 NULL, NULL, &tto_reset,
400 NULL, NULL, NULL,
401 &tto_dib, 0
402 };
403
404 /* Clock: IOT routine */
405
406 int32 clk (int32 dev, int32 pulse, int32 dat)
407 {
408 if (pulse & 001) { /* CLSF */
409 if (TST_INT (CLK)) dat = dat | IOT_SKP;
410 }
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 */
415 }
416 return dat;
417 }
418
419 /* Unit service */
420
421 t_stat clk_svc (UNIT *uptr)
422 {
423 int32 t;
424
425 t = sim_rtc_calb (clk_tps); /* calibrate clock */
426 tmxr_poll = t; /* set mux poll */
427 sim_activate (&clk_unit, t); /* reactivate unit */
428 #if defined (PDP15)
429 clk_task_upd (FALSE); /* update task timer */
430 #endif
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 */
434 }
435 return SCPE_OK;
436 }
437
438 #if defined (PDP15)
439
440 /* Task timer update (PDP-15 XVM only)
441
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. */
446
447 int32 clk_task_upd (t_bool clr)
448 {
449 uint32 delta, val, iusec10;
450 uint32 cur = sim_grtime ();
451 uint32 old = clk_task_timer;
452 double usec10;
453
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;
462 clk_task_last = cur;
463 return ((int32) val);
464 }
465
466 #endif
467
468 /* IORS service */
469
470 int32 clk_iors (void)
471 {
472 return (TST_INT (CLK)? IOS_CLK: 0);
473 }
474
475 /* Reset routine */
476
477 t_stat clk_reset (DEVICE *dptr)
478 {
479 int32 t;
480
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 */
487 clk_task_timer = 0;
488 clk_task_last = 0;
489 }
490 return SCPE_OK;
491 }
492
493 /* Set frequency */
494
495 t_stat clk_set_freq (UNIT *uptr, int32 val, char *cptr, void *desc)
496 {
497 if (cptr) return SCPE_ARG;
498 if ((val != 50) && (val != 60)) return SCPE_IERR;
499 clk_tps = val;
500 return SCPE_OK;
501 }
502
503 /* Show frequency */
504
505 t_stat clk_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc)
506 {
507 fprintf (st, (clk_tps == 50)? "50Hz": "60Hz");
508 return SCPE_OK;
509 }
510
511 /* Paper tape reader out-of-tape handling
512
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.
516
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.
520
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. */
523
524 /* Paper tape reader: IOT routine */
525
526 int32 ptr (int32 dev, int32 pulse, int32 dat)
527 {
528 if (pulse & 001) { /* RSF */
529 if (TST_INT (PTR)) dat = dat | IOT_SKP;
530 }
531 if (pulse & 002) { /* RRB, RCF */
532 CLR_INT (PTR); /* clear flag */
533 dat = dat | ptr_unit.buf; /* return buffer */
534 }
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 */
540 #endif
541 ptr_unit.buf = 0; /* clear buffer */
542 sim_activate (&ptr_unit, ptr_unit.wait);
543 }
544 return dat;
545 }
546
547 /* Unit service */
548
549 t_stat ptr_svc (UNIT *uptr)
550 {
551 int32 temp;
552
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 */
557 #endif
558 return IORETURN (ptr_stopioe, SCPE_UNATT);
559 }
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 */
564 #endif
565 if (feof (ptr_unit.fileref)) {
566 if (ptr_stopioe) printf ("PTR end of file\n");
567 else return SCPE_OK;
568 }
569 else perror ("PTR I/O error");
570 clearerr (ptr_unit.fileref);
571 return SCPE_IOERR;
572 }
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 */
579 }
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;
583 }
584 else if (temp & 0200) { /* binary */
585 ptr_state = ptr_state - 6;
586 ptr_unit.buf = ptr_unit.buf | ((temp & 077) << ptr_state);
587 }
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;
591 return SCPE_OK;
592 }
593
594 /* Reset routine */
595
596 t_stat ptr_reset (DEVICE *dptr)
597 {
598 ptr_state = 0; /* clear state */
599 ptr_unit.buf = 0;
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))
603 ptr_err = 1;
604 else
605 #endif
606 ptr_err = 0; /* all other, clr err */
607 sim_cancel (&ptr_unit); /* deactivate unit */
608 return SCPE_OK;
609 }
610
611 /* IORS service */
612
613 int32 ptr_iors (void)
614 {
615 return ((TST_INT (PTR)? IOS_PTR: 0)
616 #if defined (IOS_PTRERR)
617 | (ptr_err? IOS_PTRERR: 0)
618 #endif
619 );
620 }
621
622 /* Attach routine */
623
624 t_stat ptr_attach (UNIT *uptr, char *cptr)
625 {
626 t_stat reason;
627
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;
636 return SCPE_OK;
637 }
638
639 /* Detach routine */
640
641 t_stat ptr_detach (UNIT *uptr)
642 {
643 #if defined (PDP15)
644 ptr_err = 1;
645 #endif
646 ptr_unit.flags = ptr_unit.flags & ~UNIT_RASCII;
647 return detach_unit (uptr);
648 }
649
650 /* Hardware RIM loader routines, PDP-7/9/15 */
651
652 int32 ptr_getw (UNIT *uptr, int32 *hi)
653 {
654 int32 word, bits, st, ch;
655
656 word = st = bits = 0;
657 do {
658 if ((ch = getc (uptr->fileref)) == EOF) return -1;
659 uptr->pos = uptr->pos + 1;
660 if (ch & 0200) {
661 word = (word << 6) | (ch & 077);
662 bits = (bits << 1) | ((ch >> 6) & 1);
663 st++;
664 }
665 } while (st < 3);
666 if (hi != NULL) *hi = bits;
667 return word;
668 }
669
670 t_stat ptr_rim_load (UNIT *uptr, int32 origin)
671 {
672 int32 bits, val;
673
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);
679 return SCPE_OK;
680 }
681 else if (val == OP_HLT) return STOP_HALT;
682 break;
683 }
684 else if (MEM_ADDR_OK (origin)) M[origin++] = val;
685 }
686 return SCPE_FMT;
687 }
688
689 #if defined (PDP4) || defined (PDP7)
690
691 /* Bootstrap routine, PDP-4 and PDP-7
692
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. */
697
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))
702
703 static const int32 boot_rom[] = {
704 0700144, /* rsb */
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 */
715 0741100, /* spa */
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 */
726 0740001, /* cma */
727 0740200, /* sza */
728 0740040, /* hlt */
729 0700144, /* rsb */
730 0617610, /* jmp blk */
731 0117713, /* cont1, jms r1a */
732 0057762, /* dac tem2 */
733 0117713, /* jms r1a */
734 0742010, /* rtl */
735 0742010, /* rtl */
736 0742010, /* rtl */
737 0742010, /* rtl */
738 0317762, /* add tem2 */
739 0057762, /* dac tem2 */
740 0117713, /* jms r1a */
741 0742020, /* rtr */
742 0317726, /* add cdsp */
743 0057713, /* dac r1a */
744 0517701, /* and ccma */
745 0740020, /* rar */
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 */
755 0740000, /* nop */
756 0740000, /* nop */
757 0740000, /* nop */
758 0200007, /* done, lac conend */
759 0740040, /* xx */
760 0740040, /* xx */
761 0517727, /* code1, and imsk */
762 0337762, /* add i tem2 */
763 0300010, /* code0, add word */
764 0740040, /* cai, xx */
765 0750001, /* clc */
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 */
781 0700101, /* rsf */
782 0617714, /* jmp .-1 */
783 0700112, /* rrb */
784 0700104, /* rsa */
785 0057730, /* dac tem */
786 0317775, /* add cks */
787 0057775, /* dac cks */
788 0217730, /* lac tem */
789 0744000, /* cll */
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 */
815 0000000,
816 0000000,
817 0000000,
818 0000000,
819 0000000, /* r1b, 0 */
820 0700101, /* rsf */
821 0617763, /* jmp .-1 */
822 0700112, /* rrb */
823 0700144, /* rsb */
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 */
831 0617771 /* jmp g */
832 };
833
834 t_stat ptr_boot (int32 unitno, DEVICE *dptr)
835 {
836 int32 i, mask, wd;
837 extern int32 sim_switches;
838
839 #if defined (PDP7)
840 if (sim_switches & SWMASK ('H')) /* hardware RIM load? */
841 return ptr_rim_load (&ptr_unit, ASW);
842 #endif
843 if (ptr_dib.dev != DEV_PTR) return STOP_NONSTD; /* non-std addr? */
844 if (MEMSIZE < 8192) mask = 0767777; /* 4k? */
845 else mask = 0777777;
846 for (i = 0; i < BOOT_LEN; i++) {
847 wd = boot_rom[i];
848 if ((wd >= 0040000) && (wd < 0640000)) wd = wd & mask;
849 M[(BOOT_START & mask) + i] = wd;
850 }
851 PC = ((sim_switches & SWMASK ('F'))? BOOT_FPC: BOOT_RPC) & mask;
852 return SCPE_OK;
853 }
854
855 #else
856
857 /* PDP-9 and PDP-15 have built-in hardware RIM loaders */
858
859 t_stat ptr_boot (int32 unitno, DEVICE *dptr)
860 {
861 return ptr_rim_load (&ptr_unit, ASW);
862 }
863
864 #endif
865
866 /* Paper tape punch: IOT routine */
867
868 int32 ptp (int32 dev, int32 pulse, int32 dat)
869 {
870 if (pulse & 001) { /* PSF */
871 if (TST_INT (PTP)) dat = dat | IOT_SKP;
872 }
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 */
879 }
880 return dat;
881 }
882
883 /* Unit service */
884
885 t_stat ptp_svc (UNIT *uptr)
886 {
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);
891 }
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 */
896 }
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);
901 return SCPE_IOERR;
902 }
903 ptp_unit.pos = ptp_unit.pos + 1;
904 return SCPE_OK;
905 }
906
907 /* IORS service */
908
909 int32 ptp_iors (void)
910 {
911 return ((TST_INT (PTP)? IOS_PTP: 0)
912 #if defined (IOS_PTPERR)
913 | (ptp_err? IOS_PTPERR: 0)
914 #endif
915 );
916 }
917
918 /* Reset routine */
919
920 t_stat ptp_reset (DEVICE *dptr)
921 {
922 ptp_unit.buf = 0;
923 CLR_INT (PTP); /* clear flag */
924 ptp_err = (ptp_unit.flags & UNIT_ATT)? 0: 1;
925 sim_cancel (&ptp_unit); /* deactivate unit */
926 return SCPE_OK;
927 }
928
929 /* Attach routine */
930
931 t_stat ptp_attach (UNIT *uptr, char *cptr)
932 {
933 t_stat reason;
934
935 reason = attach_unit (uptr, cptr);
936 if (reason != SCPE_OK) return reason;
937 ptp_err = 0;
938 ptp_unit.flags = ptp_unit.flags & ~UNIT_PASCII;
939 if (sim_switches & SWMASK ('A'))
940 ptp_unit.flags = ptp_unit.flags | UNIT_PASCII;
941 return reason;
942 }
943
944 /* Detach routine */
945
946 t_stat ptp_detach (UNIT *uptr)
947 {
948 ptp_err = 1;
949 ptp_unit.flags = ptp_unit.flags & ~UNIT_PASCII;
950 return detach_unit (uptr);
951 }
952
953 /* Terminal input: IOT routine */
954
955 int32 tti (int32 dev, int32 pulse, int32 dat)
956 {
957 if (pulse & 001) { /* KSF */
958 if (TST_INT (TTI)) dat = dat | IOT_SKP;
959 }
960 if (pulse & 002) { /* KRS/KRB */
961 CLR_INT (TTI); /* clear flag */
962 dat = dat | tti_unit.buf & TTI_MASK; /* return buffer */
963 #if defined (PDP15)
964 if (pulse & 020) tti_fdpx = 1; /* KRS? */
965 else tti_fdpx = 0; /* no, KRB */
966 #endif
967 }
968 if (pulse & 004) { /* IORS */
969 dat = dat | upd_iors ();
970 }
971 return dat;
972 }
973
974 /* Unit service */
975
976 t_stat tti_svc (UNIT *uptr)
977 {
978 #if defined (KSR28) /* Baudot... */
979 int32 in, c, out;
980
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 */
985 }
986 else {
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;
996 tty_shift = 1;
997 }
998 else { /* no, to letters */
999 uptr->buf = BAUDOT_LETTERS;
1000 tty_shift = 0;
1001 }
1002 tti_2nd = c & TTI_MASK; /* save actual char */
1003 }
1004 if ((uptr->flags & TTUF_HDX) && /* half duplex? */
1005 ((out = sim_tt_outcvt (in, TT_GET_MODE (uptr->flags) | TTUF_KSR)) >= 0)) {
1006 sim_putchar (out);
1007 tto_unit.pos = tto_unit.pos + 1;
1008 }
1009 }
1010
1011 #else /* ASCII... */
1012 int32 c, out;
1013
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;
1023 }
1024 uptr->buf = c; /* got char */
1025
1026 #endif
1027 uptr->pos = uptr->pos + 1;
1028 SET_INT (TTI); /* set flag */
1029 return SCPE_OK;
1030 }
1031
1032 /* IORS service */
1033
1034 int32 tti_iors (void)
1035 {
1036 return (TST_INT (TTI)? IOS_TTI: 0);
1037 }
1038
1039 /* Reset routine */
1040
1041 t_stat tti_reset (DEVICE *dptr)
1042 {
1043 tti_unit.buf = 0; /* clear buffer */
1044 tti_2nd = 0;
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));
1049 return SCPE_OK;
1050 }
1051
1052 /* Terminal output: IOT routine */
1053
1054 int32 tto (int32 dev, int32 pulse, int32 dat)
1055 {
1056 if (pulse & 001) { /* TSF */
1057 if (TST_INT (TTO)) dat = dat | IOT_SKP;
1058 }
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 */
1063 }
1064 return dat;
1065 }
1066
1067 /* Unit service */
1068
1069 t_stat tto_svc (UNIT *uptr)
1070 {
1071 int32 c;
1072 t_stat r;
1073
1074 #if defined (KSR28) /* Baudot... */
1075 if (uptr->buf == BAUDOT_FIGURES) /* set figures? */
1076 tty_shift = 1;
1077 else if (uptr->buf == BAUDOT_LETTERS) /* set letters? */
1078 tty_shift = 0;
1079 else {
1080 c = baud_to_asc[uptr->buf | (tty_shift << 5)]; /* translate */
1081
1082 #else
1083 c = sim_tt_outcvt (uptr->buf, TT_GET_MODE (uptr->flags) | TTUF_KSR);
1084 if (c >= 0) {
1085
1086 #endif
1087
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);
1091 }
1092 }
1093 SET_INT (TTO); /* set flag */
1094 uptr->pos = uptr->pos + 1;
1095 return SCPE_OK;
1096 }
1097
1098 /* IORS service */
1099
1100 int32 tto_iors (void)
1101 {
1102 return (TST_INT (TTO)? IOS_TTO: 0);
1103 }
1104
1105 /* Reset routine */
1106
1107 t_stat tto_reset (DEVICE *dptr)
1108 {
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 */
1113 return SCPE_OK;
1114 }
1115
1116 /* Set mode */
1117
1118 t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc)
1119 {
1120 tti_unit.flags = (tti_unit.flags & ~TT_MODE) | val;
1121 tto_unit.flags = (tto_unit.flags & ~TT_MODE) | val;
1122 return SCPE_OK;
1123 }