1 /* pdp18b_stddev.c: 18b PDP's standard devices
2
3 Copyright (c) 1993-2012, 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-Apr-12 RMS Added clk_cosched routine
33 Revised clk and tti scheduling
34 18-Jun-07 RMS Added UNIT_IDLE to console input, clock
35 18-Oct-06 RMS Added PDP-15 programmable duplex control
36 Fixed handling of non-printable characters in KSR mode
37 Changed clock to be free-running
38 Fixed out-of-tape behavior for PDP-9 vs PDP-15
39 Synced keyboard to clock
40 30-Jun-06 RMS Fixed KSR-28 shift tracking
41 20-Jun-06 RMS Added KSR ASCII reader support
42 13-Jun-06 RMS Fixed Baudot letters/figures inversion for PDP-4
43 Fixed PDP-4/PDP-7 default terminal to be local echo
44 22-Nov-05 RMS Revised for new terminal processing routines
45 28-May-04 RMS Removed SET TTI CTRL-C
46 16-Feb-04 RMS Fixed bug in hardware read-in mode bootstrap
47 14-Jan-04 RMS Revised IO device call interface
48 CAF does not turn off the clock
49 29-Dec-03 RMS Added console backpressure support
50 26-Jul-03 RMS Increased PTP, TTO timeouts for PDP-15 operating systems
51 Added hardware read-in mode support for PDP-7/9/15
52 25-Apr-03 RMS Revised for extended file support
53 14-Mar-03 RMS Clean up flags on detach
54 01-Mar-03 RMS Added SET/SHOW CLK freq, SET TTI CTRL-C
55 22-Dec-02 RMS Added break support
56 01-Nov-02 RMS Added 7B/8B support to terminal
57 05-Oct-02 RMS Added DIBs, device number support, IORS call
58 14-Jul-02 RMS Added ASCII reader/punch support (Hans Pufal)
59 30-May-02 RMS Widened POS to 32b
60 29-Nov-01 RMS Added read only unit support
61 25-Nov-01 RMS Revised interrupt structure
62 17-Sep-01 RMS Removed multiconsole support
63 07-Sep-01 RMS Added terminal multiplexor support
64 17-Jul-01 RMS Moved function prototype
65 10-Jun-01 RMS Cleaned up IOT decoding to reflect hardware
66 27-May-01 RMS Added multiconsole support
67 10-Mar-01 RMS Added funny format loader support
68 05-Mar-01 RMS Added clock calibration support
69 22-Dec-00 RMS Added PDP-9/15 half duplex support
70 30-Nov-00 RMS Fixed PDP-4/7 bootstrap loader for 4K systems
71 30-Oct-00 RMS Standardized register naming
72 06-Jan-97 RMS Fixed PDP-4 console input
73 16-Dec-96 RMS Fixed bug in binary ptr service
74 */
75
76 #include "pdp18b_defs.h"
77 #include <ctype.h>
78
79 #define UNIT_V_RASCII (UNIT_V_UF + 0) /* reader ASCII */
80 #define UNIT_RASCII (1 << UNIT_V_RASCII)
81 #define UNIT_V_KASCII (UNIT_V_UF + 1) /* KSR ASCII */
82 #define UNIT_KASCII (1 << UNIT_V_KASCII)
83 #define UNIT_V_PASCII (UNIT_V_UF + 0) /* punch ASCII */
84 #define UNIT_PASCII (1 << UNIT_V_PASCII)
85
86 extern int32 M[];
87 extern int32 int_hwre[API_HLVL+1], PC, ASW;
88 extern int32 sim_switches;
89 extern int32 sim_is_running;
90 extern UNIT cpu_unit;
91
92 int32 clk_state = 0;
93 int32 ptr_err = 0, ptr_stopioe = 0, ptr_state = 0;
94 int32 ptp_err = 0, ptp_stopioe = 0;
95 int32 tti_2nd = 0; /* 2nd char waiting */
96 int32 tty_shift = 0; /* KSR28 shift state */
97 int32 tti_fdpx = 0; /* prog mode full duplex */
98 int32 clk_tps = 60; /* ticks/second */
99 int32 tmxr_poll = 16000; /* term mux poll */
100 uint32 clk_task_last = 0;
101 uint32 clk_task_timer = 0;
102
103 const int32 asc_to_baud[128] = {
104 000,000,000,000,000,000,000,064, /* bell */
105 000,000,0110,000,000,0102,000,000, /* lf, cr */
106 000,000,000,000,000,000,000,000,
107 000,000,000,000,000,000,000,000,
108 0104,066,061,045,062,000,053,072, /* space - ' */
109 076,051,000,000,046,070,047,067, /* ( - / */
110 055,075,071,060,052,041,065,074, /* 0 - 7 */
111 054,043,056,057,000,000,000,063, /* 8 - ? */
112 000,030,023,016,022,020,026,013, /* @ - G */
113 005,014,032,036,011,007,006,003, /* H - O */
114 015,035,012,024,001,034,017,031, /* P - W */
115 027,025,021,000,000,000,000,000, /* X - _ */
116 000,030,023,016,022,020,026,013, /* ` - g */
117 005,014,032,036,011,007,006,003, /* h - o */
118 015,035,012,024,001,034,017,031, /* p - w */
119 027,025,021,000,000,000,000,000 /* x - DEL */
120 };
121
122 const char baud_to_asc[64] = {
123 0 ,'T',015,'O',' ','H','N','M',
124 012,'L','R','G','I','P','C','V',
125 'E','Z','D','B','S','Y','F','X',
126 'A','W','J', 0 ,'U','Q','K', 0,
127 0 ,'5','\r','9',' ','#',',','.',
128 012,')','4','&','8','0',':',';',
129 '3','"','$','?','\a','6','!','/',
130 '-','2','\'',0 ,'7','1','(', 0
131 };
132
133 int32 ptr (int32 dev, int32 pulse, int32 dat);
134 int32 ptp (int32 dev, int32 pulse, int32 dat);
135 int32 tti (int32 dev, int32 pulse, int32 dat);
136 int32 tto (int32 dev, int32 pulse, int32 dat);
137 int32 clk_iors (void);
138 int32 ptr_iors (void);
139 int32 ptp_iors (void);
140 int32 tti_iors (void);
141 int32 tto_iors (void);
142 t_stat clk_svc (UNIT *uptr);
143 t_stat ptr_svc (UNIT *uptr);
144 t_stat ptp_svc (UNIT *uptr);
145 t_stat tti_svc (UNIT *uptr);
146 t_stat tto_svc (UNIT *uptr);
147 t_stat clk_reset (DEVICE *dptr);
148 t_stat ptr_reset (DEVICE *dptr);
149 t_stat ptp_reset (DEVICE *dptr);
150 t_stat tti_reset (DEVICE *dptr);
151 t_stat tto_reset (DEVICE *dptr);
152 t_stat ptr_attach (UNIT *uptr, char *cptr);
153 t_stat ptp_attach (UNIT *uptr, char *cptr);
154 t_stat ptr_detach (UNIT *uptr);
155 t_stat ptp_detach (UNIT *uptr);
156 t_stat ptr_boot (int32 unitno, DEVICE *dptr);
157 t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc);
158 t_stat clk_set_freq (UNIT *uptr, int32 val, char *cptr, void *desc);
159 t_stat clk_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc);
160 int32 clk_task_upd (t_bool clr);
161
162 extern int32 upd_iors (void);
163
164 /* CLK data structures
165
166 clk_dev CLK device descriptor
167 clk_unit CLK unit
168 clk_reg CLK register list
169 */
170
171 DIB clk_dib = { 0, 0, &clk_iors, { NULL } };
172
173 UNIT clk_unit = { UDATA (&clk_svc, UNIT_IDLE, 0), 16000 };
174
175 REG clk_reg[] = {
176 { FLDATA (INT, int_hwre[API_CLK], INT_V_CLK) },
177 { FLDATA (DONE, int_hwre[API_CLK], INT_V_CLK) },
178 { FLDATA (ENABLE, clk_state, 0) },
179 #if defined (PDP15)
180 { ORDATA (TASKTIMER, clk_task_timer, 18) },
181 { DRDATA (TASKLAST, clk_task_last, 32), REG_HRO },
182 #endif
183 { DRDATA (TIME, clk_unit.wait, 24), REG_NZ + PV_LEFT },
184 { DRDATA (TPS, clk_tps, 8), PV_LEFT + REG_HRO },
185 { NULL }
186 };
187
188 MTAB clk_mod[] = {
189 { MTAB_XTD|MTAB_VDV, 50, NULL, "50HZ",
190 &clk_set_freq, NULL, NULL },
191 { MTAB_XTD|MTAB_VDV, 60, NULL, "60HZ",
192 &clk_set_freq, NULL, NULL },
193 { MTAB_XTD|MTAB_VDV, 0, "FREQUENCY", NULL,
194 NULL, &clk_show_freq, NULL },
195 { MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_devno },
196 { 0 }
197 };
198
199 DEVICE clk_dev = {
200 "CLK", &clk_unit, clk_reg, clk_mod,
201 1, 0, 0, 0, 0, 0,
202 NULL, NULL, &clk_reset,
203 NULL, NULL, NULL,
204 &clk_dib, 0
205 };
206
207 /* PTR data structures
208
209 ptr_dev PTR device descriptor
210 ptr_unit PTR unit
211 ptr_reg PTR register list
212 */
213
214 DIB ptr_dib = { DEV_PTR, 1, &ptr_iors, { &ptr } };
215
216 UNIT ptr_unit = {
217 UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0),
218 SERIAL_IN_WAIT
219 };
220
221 REG ptr_reg[] = {
222 { ORDATA (BUF, ptr_unit.buf, 18) },
223 { FLDATA (INT, int_hwre[API_PTR], INT_V_PTR) },
224 { FLDATA (DONE, int_hwre[API_PTR], INT_V_PTR) },
225 #if defined (IOS_PTRERR)
226 { FLDATA (ERR, ptr_err, 0) },
227 #endif
228 { ORDATA (STATE, ptr_state, 5), REG_HRO },
229 { DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT },
230 { DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT },
231 { FLDATA (STOP_IOE, ptr_stopioe, 0) },
232 { NULL }
233 };
234
235 MTAB ptr_mod[] = {
236 { UNIT_RASCII, UNIT_RASCII, "even parity ASCII", NULL },
237 { UNIT_KASCII, UNIT_KASCII, "forced parity ASCII", NULL },
238 { MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_devno },
239 { 0 }
240 };
241
242 DEVICE ptr_dev = {
243 "PTR", &ptr_unit, ptr_reg, ptr_mod,
244 1, 10, 31, 1, 8, 8,
245 NULL, NULL, &ptr_reset,
246 &ptr_boot, &ptr_attach, &ptr_detach,
247 &ptr_dib, 0
248 };
249
250 /* PTP data structures
251
252 ptp_dev PTP device descriptor
253 ptp_unit PTP unit
254 ptp_reg PTP register list
255 */
256
257 DIB ptp_dib = { DEV_PTP, 1, &ptp_iors, { &ptp } };
258
259 UNIT ptp_unit = {
260 UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT
261 };
262
263 REG ptp_reg[] = {
264 { ORDATA (BUF, ptp_unit.buf, 8) },
265 { FLDATA (INT, int_hwre[API_PTP], INT_V_PTP) },
266 { FLDATA (DONE, int_hwre[API_PTP], INT_V_PTP) },
267 #if defined (IOS_PTPERR)
268 { FLDATA (ERR, ptp_err, 0) },
269 #endif
270 { DRDATA (POS, ptp_unit.pos, T_ADDR_W), PV_LEFT },
271 { DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT },
272 { FLDATA (STOP_IOE, ptp_stopioe, 0) },
273 { NULL }
274 };
275
276 MTAB ptp_mod[] = {
277 { UNIT_PASCII, UNIT_PASCII, "7b ASCII", NULL },
278 { MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_devno },
279 { 0 }
280 };
281
282 DEVICE ptp_dev = {
283 "PTP", &ptp_unit, ptp_reg, ptp_mod,
284 1, 10, 31, 1, 8, 8,
285 NULL, NULL, &ptp_reset,
286 NULL, &ptp_attach, &ptp_detach,
287 &ptp_dib, 0
288 };
289
290 /* TTI data structures
291
292 tti_dev TTI device descriptor
293 tti_unit TTI unit
294 tti_reg TTI register list
295 */
296
297 #if defined (KSR28)
298 #define TTI_WIDTH 5
299 #define TTI_FIGURES (1 << TTI_WIDTH)
300 #define TTI_BOTH (1 << (TTI_WIDTH + 1))
301 #define BAUDOT_LETTERS 037
302 #define BAUDOT_FIGURES 033
303
304 #else
305
306 #define TTI_WIDTH 8
307 #endif
308
309 #define TTI_MASK ((1 << TTI_WIDTH) - 1)
310 #define TTUF_V_HDX (TTUF_V_UF + 0) /* half duplex */
311 #define TTUF_HDX (1 << TTUF_V_HDX)
312
313 DIB tti_dib = { DEV_TTI, 1, &tti_iors, { &tti } };
314
315 UNIT tti_unit = { UDATA (&tti_svc, UNIT_IDLE+TT_MODE_KSR+TTUF_HDX, 0), 0 };
316
317 REG tti_reg[] = {
318 { ORDATA (BUF, tti_unit.buf, TTI_WIDTH) },
319 #if defined (KSR28)
320 { ORDATA (BUF2ND, tti_2nd, TTI_WIDTH), REG_HRO },
321 #endif
322 { FLDATA (INT, int_hwre[API_TTI], INT_V_TTI) },
323 { FLDATA (DONE, int_hwre[API_TTI], INT_V_TTI) },
324 #if defined (PDP15)
325 { FLDATA (FDPX, tti_fdpx, 0) },
326 #endif
327 { DRDATA (POS, tti_unit.pos, T_ADDR_W), PV_LEFT },
328 { DRDATA (TIME, tti_unit.wait, 24), PV_LEFT },
329 { NULL }
330 };
331
332 MTAB tti_mod[] = {
333 #if !defined (KSR28)
334 { TT_MODE, TT_MODE_KSR, "KSR", "KSR", &tty_set_mode },
335 { TT_MODE, TT_MODE_7B, "7b", "7B", &tty_set_mode },
336 { TT_MODE, TT_MODE_8B, "8b", "8B", &tty_set_mode },
337 { TT_MODE, TT_MODE_7P, "7b", NULL, NULL },
338 #endif
339 { TTUF_HDX, 0 , "full duplex", "FDX", NULL },
340 { TTUF_HDX, TTUF_HDX, "half duplex", "HDX", NULL },
341 { MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_devno, NULL },
342 { 0 }
343 };
344
345 DEVICE tti_dev = {
346 "TTI", &tti_unit, tti_reg, tti_mod,
347 1, 10, 31, 1, 8, 8,
348 NULL, NULL, &tti_reset,
349 NULL, NULL, NULL,
350 &tti_dib, 0
351 };
352
353 /* TTO data structures
354
355 tto_dev TTO device descriptor
356 tto_unit TTO unit
357 tto_reg TTO register list
358 */
359
360 #if defined (KSR28)
361 #define TTO_WIDTH 5
362 #define TTO_FIGURES (1 << TTO_WIDTH)
363
364 #else
365
366 #define TTO_WIDTH 8
367 #endif
368
369 #define TTO_MASK ((1 << TTO_WIDTH) - 1)
370
371 DIB tto_dib = { DEV_TTO, 1, &tto_iors, { &tto } };
372
373 UNIT tto_unit = { UDATA (&tto_svc, TT_MODE_KSR, 0), 1000 };
374
375 REG tto_reg[] = {
376 { ORDATA (BUF, tto_unit.buf, TTO_WIDTH) },
377 #if defined (KSR28)
378 { FLDATA (SHIFT, tty_shift, 0), REG_HRO },
379 #endif
380 { FLDATA (INT, int_hwre[API_TTO], INT_V_TTO) },
381 { FLDATA (DONE, int_hwre[API_TTO], INT_V_TTO) },
382 { DRDATA (POS, tto_unit.pos, T_ADDR_W), PV_LEFT },
383 { DRDATA (TIME, tto_unit.wait, 24), PV_LEFT },
384 { NULL }
385 };
386
387 MTAB tto_mod[] = {
388 #if !defined (KSR28)
389 { TT_MODE, TT_MODE_KSR, "KSR", "KSR", &tty_set_mode },
390 { TT_MODE, TT_MODE_7B, "7b", "7B", &tty_set_mode },
391 { TT_MODE, TT_MODE_8B, "8b", "8B", &tty_set_mode },
392 { TT_MODE, TT_MODE_7P, "7p", "7P", &tty_set_mode },
393 #endif
394 { MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_devno },
395 { 0 }
396 };
397
398 DEVICE tto_dev = {
399 "TTO", &tto_unit, tto_reg, tto_mod,
400 1, 10, 31, 1, 8, 8,
401 NULL, NULL, &tto_reset,
402 NULL, NULL, NULL,
403 &tto_dib, 0
404 };
405
406 /* Clock: IOT routine */
407
clk(int32 dev,int32 pulse,int32 dat)408 int32 clk (int32 dev, int32 pulse, int32 dat)
409 {
410 if (pulse & 001) { /* CLSF */
411 if (TST_INT (CLK))
412 dat = dat | IOT_SKP;
413 }
414 if (pulse & 004) { /* CLON/CLOF */
415 CLR_INT (CLK); /* clear flag */
416 if (pulse & 040) /* CLON */
417 clk_state = 1;
418 else clk_state = 0; /* CLOF */
419 }
420 return dat;
421 }
422
423 /* Unit service */
424
clk_svc(UNIT * uptr)425 t_stat clk_svc (UNIT *uptr)
426 {
427 int32 t;
428
429 t = sim_rtc_calb (clk_tps); /* calibrate clock */
430 tmxr_poll = t; /* set mux poll */
431 sim_activate (&clk_unit, t); /* reactivate unit */
432 #if defined (PDP15)
433 clk_task_upd (FALSE); /* update task timer */
434 #endif
435 if (clk_state) { /* clock on? */
436 M[7] = (M[7] + 1) & DMASK; /* incr counter */
437 if (M[7] == 0) /* ovrflo? set flag */
438 SET_INT (CLK);
439 }
440 return SCPE_OK;
441 }
442
443 #if defined (PDP15)
444
445 /* Task timer update (PDP-15 XVM only)
446
447 The task timer increments monotonically at 100Khz. Since this can't be
448 simulated accurately, updates are done by interpolation since the last
449 reading. The timer is also updated at clock events to keep the cycle
450 counters from wrapping around more than once between updates. */
451
clk_task_upd(t_bool clr)452 int32 clk_task_upd (t_bool clr)
453 {
454 uint32 delta, val, iusec10;
455 uint32 cur = sim_grtime ();
456 uint32 old = clk_task_timer;
457 double usec10;
458
459 if (cur > clk_task_last)
460 delta = cur - clk_task_last;
461 else delta = clk_task_last - cur;
462 usec10 = ((((double) delta) * 100000.0) /
463 (((double) tmxr_poll) * ((double) clk_tps)));
464 iusec10 = (int32) usec10;
465 val = (clk_task_timer + iusec10) & DMASK;
466 if (clr)
467 clk_task_timer = 0;
468 else clk_task_timer = val;
469 clk_task_last = cur;
470 return ((int32) val);
471 }
472
473 #endif
474
475 /* IORS service */
476
clk_iors(void)477 int32 clk_iors (void)
478 {
479 return (TST_INT (CLK)? IOS_CLK: 0);
480 }
481
482 /* Clock coscheduling routine */
483
clk_cosched(int32 wait)484 int32 clk_cosched (int32 wait)
485 {
486 int32 t;
487
488 t = sim_is_active (&clk_unit);
489 return (t? t - 1: wait);
490 }
491
492 /* Reset routine */
493
clk_reset(DEVICE * dptr)494 t_stat clk_reset (DEVICE *dptr)
495 {
496 int32 t;
497
498 CLR_INT (CLK); /* clear flag */
499 if (!sim_is_running) { /* RESET (not CAF)? */
500 t = sim_rtc_init (clk_unit.wait); /* init calibration */
501 tmxr_poll = t; /* set mux poll */
502 sim_activate_abs (&clk_unit, t); /* activate unit */
503 clk_state = 0; /* clock off */
504 clk_task_timer = 0;
505 clk_task_last = 0;
506 }
507 return SCPE_OK;
508 }
509
510 /* Set frequency */
511
clk_set_freq(UNIT * uptr,int32 val,char * cptr,void * desc)512 t_stat clk_set_freq (UNIT *uptr, int32 val, char *cptr, void *desc)
513 {
514 if (cptr)
515 return SCPE_ARG;
516 if ((val != 50) && (val != 60))
517 return SCPE_IERR;
518 clk_tps = val;
519 return SCPE_OK;
520 }
521
522 /* Show frequency */
523
clk_show_freq(FILE * st,UNIT * uptr,int32 val,void * desc)524 t_stat clk_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc)
525 {
526 fprintf (st, (clk_tps == 50)? "50Hz": "60Hz");
527 return SCPE_OK;
528 }
529
530 /* Paper tape reader out-of-tape handling
531
532 The PDP-4 and PDP-7 readers behaved like most early DEC readers; when
533 they ran out of tape, they hung. It was up to the program to sense this
534 condition by running a timer.
535
536 The PDP-9 reader controller synthesized the out of tape condition by
537 noticing whether there was a transition on the feed hole within a window.
538 The out-of-tape flag was treated like the reader flag in most cases.
539
540 The PDP-15 reader controller received the out-of-tape flag as a static
541 condition from the reader itself and simply reported it via IORS. */
542
543 /* Paper tape reader: IOT routine */
544
ptr(int32 dev,int32 pulse,int32 dat)545 int32 ptr (int32 dev, int32 pulse, int32 dat)
546 {
547 if (pulse & 001) { /* RSF */
548 if (TST_INT (PTR))
549 dat = dat | IOT_SKP;
550 }
551 if (pulse & 002) { /* RRB, RCF */
552 CLR_INT (PTR); /* clear flag */
553 dat = dat | ptr_unit.buf; /* return buffer */
554 }
555 if (pulse & 004) { /* RSA, RSB */
556 ptr_state = (pulse & 040)? 18: 0; /* set mode */
557 CLR_INT (PTR); /* clear flag */
558 #if !defined (PDP15) /* except on PDP15 */
559 ptr_err = 0; /* clear error */
560 #endif
561 ptr_unit.buf = 0; /* clear buffer */
562 sim_activate (&ptr_unit, ptr_unit.wait);
563 }
564 return dat;
565 }
566
567 /* Unit service */
568
ptr_svc(UNIT * uptr)569 t_stat ptr_svc (UNIT *uptr)
570 {
571 int32 temp;
572
573 if ((ptr_unit.flags & UNIT_ATT) == 0) { /* attached? */
574 #if defined (IOS_PTRERR)
575 SET_INT (PTR); /* if err, set flag */
576 ptr_err = 1; /* set error */
577 #endif
578 return IORETURN (ptr_stopioe, SCPE_UNATT);
579 }
580 if ((temp = getc (ptr_unit.fileref)) == EOF) { /* end of file? */
581 #if defined (IOS_PTRERR)
582 SET_INT (PTR); /* if err, set flag */
583 ptr_err = 1; /* set error */
584 #endif
585 if (feof (ptr_unit.fileref)) {
586 if (ptr_stopioe)
587 printf ("PTR end of file\n");
588 else return SCPE_OK;
589 }
590 else perror ("PTR I/O error");
591 clearerr (ptr_unit.fileref);
592 return SCPE_IOERR;
593 }
594 if (ptr_state == 0) { /* ASCII */
595 if (ptr_unit.flags & UNIT_RASCII) { /* want parity? */
596 ptr_unit.buf = temp = temp & 0177; /* parity off */
597 while ((temp = temp & (temp - 1)))
598 ptr_unit.buf = ptr_unit.buf ^ 0200; /* count bits */
599 ptr_unit.buf = ptr_unit.buf ^ 0200; /* set even parity */
600 }
601 else if (ptr_unit.flags & UNIT_KASCII) /* KSR ASCII? */
602 ptr_unit.buf = (temp | 0200) & 0377; /* forced parity */
603 else ptr_unit.buf = temp & 0377;
604 }
605 else if (temp & 0200) { /* binary */
606 ptr_state = ptr_state - 6;
607 ptr_unit.buf = ptr_unit.buf | ((temp & 077) << ptr_state);
608 }
609 if (ptr_state == 0) /* if done, set flag */
610 SET_INT (PTR);
611 else sim_activate (&ptr_unit, ptr_unit.wait); /* else restart */
612 ptr_unit.pos = ptr_unit.pos + 1;
613 return SCPE_OK;
614 }
615
616 /* Reset routine */
617
ptr_reset(DEVICE * dptr)618 t_stat ptr_reset (DEVICE *dptr)
619 {
620 ptr_state = 0; /* clear state */
621 ptr_unit.buf = 0;
622 CLR_INT (PTR); /* clear flag */
623 #if defined (PDP15) /* PDP15, static err */
624 if (((ptr_unit.flags & UNIT_ATT) == 0) || feof (ptr_unit.fileref))
625 ptr_err = 1;
626 else
627 #endif
628 ptr_err = 0; /* all other, clr err */
629 sim_cancel (&ptr_unit); /* deactivate unit */
630 return SCPE_OK;
631 }
632
633 /* IORS service */
634
ptr_iors(void)635 int32 ptr_iors (void)
636 {
637 return ((TST_INT (PTR)? IOS_PTR: 0)
638 #if defined (IOS_PTRERR)
639 | (ptr_err? IOS_PTRERR: 0)
640 #endif
641 );
642 }
643
644 /* Attach routine */
645
ptr_attach(UNIT * uptr,char * cptr)646 t_stat ptr_attach (UNIT *uptr, char *cptr)
647 {
648 t_stat reason;
649
650 reason = attach_unit (uptr, cptr);
651 if (reason != SCPE_OK)
652 return reason;
653 ptr_err = 0; /* attach clrs error */
654 ptr_unit.flags = ptr_unit.flags & ~(UNIT_RASCII|UNIT_KASCII);
655 if (sim_switches & SWMASK ('A'))
656 ptr_unit.flags = ptr_unit.flags | UNIT_RASCII;
657 if (sim_switches & SWMASK ('K'))
658 ptr_unit.flags = ptr_unit.flags | UNIT_KASCII;
659 return SCPE_OK;
660 }
661
662 /* Detach routine */
663
ptr_detach(UNIT * uptr)664 t_stat ptr_detach (UNIT *uptr)
665 {
666 #if defined (PDP15)
667 ptr_err = 1;
668 #endif
669 ptr_unit.flags = ptr_unit.flags & ~UNIT_RASCII;
670 return detach_unit (uptr);
671 }
672
673 /* Hardware RIM loader routines, PDP-7/9/15 */
674
ptr_getw(UNIT * uptr,int32 * hi)675 int32 ptr_getw (UNIT *uptr, int32 *hi)
676 {
677 int32 word, bits, st, ch;
678
679 word = st = bits = 0;
680 do {
681 if ((ch = getc (uptr->fileref)) == EOF)
682 return -1;
683 uptr->pos = uptr->pos + 1;
684 if (ch & 0200) {
685 word = (word << 6) | (ch & 077);
686 bits = (bits << 1) | ((ch >> 6) & 1);
687 st++;
688 }
689 } while (st < 3);
690 if (hi != NULL)
691 *hi = bits;
692 return word;
693 }
694
ptr_rim_load(UNIT * uptr,int32 origin)695 t_stat ptr_rim_load (UNIT *uptr, int32 origin)
696 {
697 int32 bits, val;
698
699 for (;;) { /* word loop */
700 if ((val = ptr_getw (uptr, &bits)) < 0)
701 return SCPE_FMT;
702 if (bits & 1) { /* end of tape? */
703 if ((val & 0760000) == OP_JMP) {
704 PC = ((origin - 1) & 060000) | (val & 017777);
705 return SCPE_OK;
706 }
707 else if (val == OP_HLT)
708 return STOP_HALT;
709 break;
710 }
711 else if (MEM_ADDR_OK (origin))
712 M[origin++] = val;
713 }
714 return SCPE_FMT;
715 }
716
717 #if defined (PDP4) || defined (PDP7)
718
719 /* Bootstrap routine, PDP-4 and PDP-7
720
721 In a 4K system, the boostrap resides at 7762-7776.
722 In an 8K or greater system, the bootstrap resides at 17762-17776.
723 Because the program is so small, simple masking can be
724 used to remove addr<5> for a 4K system. */
725
726 #define BOOT_START 017577
727 #define BOOT_FPC 017577 /* funny format loader */
728 #define BOOT_RPC 017770 /* RIM loader */
729 #define BOOT_LEN (sizeof (boot_rom) / sizeof (int))
730
731 static const int32 boot_rom[] = {
732 0700144, /* rsb */
733 0117762, /* ff, jsb r1b */
734 0057666, /* dac done 1 */
735 0117762, /* jms r1b */
736 0057667, /* dac done 2 */
737 0117762, /* jms r1b */
738 0040007, /* dac conend */
739 0057731, /* dac conbeg */
740 0440007, /* isz conend */
741 0117762, /* blk, jms r1b */
742 0057673, /* dac cai */
743 0741100, /* spa */
744 0617665, /* jmp done */
745 0117762, /* jms r1b */
746 0057777, /* dac tem1 */
747 0317673, /* add cai */
748 0057775, /* dac cks */
749 0117713, /* jms r1a */
750 0140010, /* dzm word */
751 0457777, /* cont, isz tem1 */
752 0617632, /* jmp cont1 */
753 0217775, /* lac cks */
754 0740001, /* cma */
755 0740200, /* sza */
756 0740040, /* hlt */
757 0700144, /* rsb */
758 0617610, /* jmp blk */
759 0117713, /* cont1, jms r1a */
760 0057762, /* dac tem2 */
761 0117713, /* jms r1a */
762 0742010, /* rtl */
763 0742010, /* rtl */
764 0742010, /* rtl */
765 0742010, /* rtl */
766 0317762, /* add tem2 */
767 0057762, /* dac tem2 */
768 0117713, /* jms r1a */
769 0742020, /* rtr */
770 0317726, /* add cdsp */
771 0057713, /* dac r1a */
772 0517701, /* and ccma */
773 0740020, /* rar */
774 0317762, /* add tem2 */
775 0437713, /* xct i r1a */
776 0617622, /* jmp cont */
777 0617672, /* dsptch, jmp code0 */
778 0617670, /* jmp code1 */
779 0617700, /* jmp code2 */
780 0617706, /* jmp code3 */
781 0417711, /* xct code4 */
782 0617732, /* jmp const */
783 0740000, /* nop */
784 0740000, /* nop */
785 0740000, /* nop */
786 0200007, /* done, lac conend */
787 0740040, /* xx */
788 0740040, /* xx */
789 0517727, /* code1, and imsk */
790 0337762, /* add i tem2 */
791 0300010, /* code0, add word */
792 0740040, /* cai, xx */
793 0750001, /* clc */
794 0357673, /* tad cai */
795 0057673, /* dac cai */
796 0617621, /* jmp cont-1 */
797 0711101, /* code2, spa cla */
798 0740001, /* ccma, cma */
799 0277762, /* xor i tem2 */
800 0300010, /* add word */
801 0040010, /* code2a, dac word */
802 0617622, /* jmp cont */
803 0057711, /* code3, dac code4 */
804 0217673, /* lac cai */
805 0357701, /* tad ccma */
806 0740040, /* code4, xx */
807 0617622, /* jmp cont */
808 0000000, /* r1a, 0 */
809 0700101, /* rsf */
810 0617714, /* jmp .-1 */
811 0700112, /* rrb */
812 0700104, /* rsa */
813 0057730, /* dac tem */
814 0317775, /* add cks */
815 0057775, /* dac cks */
816 0217730, /* lac tem */
817 0744000, /* cll */
818 0637713, /* jmp i r1a */
819 0017654, /* cdsp, dsptch */
820 0760000, /* imsk, 760000 */
821 0000000, /* tem, 0 */
822 0000000, /* conbeg, 0 */
823 0300010, /* const, add word */
824 0060007, /* dac i conend */
825 0217731, /* lac conbeg */
826 0040010, /* dac index */
827 0220007, /* lac i conend */
828 0560010, /* con1, sad i index */
829 0617752, /* jmp find */
830 0560010, /* sad i index */
831 0617752, /* jmp find */
832 0560010, /* sad i index */
833 0617752, /* jmp find */
834 0560010, /* sad i index */
835 0617752, /* jmp find */
836 0560010, /* sad i index */
837 0617752, /* jmp find */
838 0617737, /* jmp con1 */
839 0200010, /* find, lac index */
840 0540007, /* sad conend */
841 0440007, /* isz conend */
842 0617704, /* jmp code2a */
843 0000000,
844 0000000,
845 0000000,
846 0000000,
847 0000000, /* r1b, 0 */
848 0700101, /* rsf */
849 0617763, /* jmp .-1 */
850 0700112, /* rrb */
851 0700144, /* rsb */
852 0637762, /* jmp i r1b */
853 0700144, /* go, rsb */
854 0117762, /* g, jms r1b */
855 0057775, /* dac cks */
856 0417775, /* xct cks */
857 0117762, /* jms r1b */
858 0000000, /* cks, 0 */
859 0617771 /* jmp g */
860 };
861
ptr_boot(int32 unitno,DEVICE * dptr)862 t_stat ptr_boot (int32 unitno, DEVICE *dptr)
863 {
864 int32 i, mask, wd;
865 extern int32 sim_switches;
866
867 #if defined (PDP7)
868 if (sim_switches & SWMASK ('H')) /* hardware RIM load? */
869 return ptr_rim_load (&ptr_unit, ASW);
870 #endif
871 if (ptr_dib.dev != DEV_PTR) /* non-std addr? */
872 return STOP_NONSTD;
873 if (MEMSIZE < 8192) /* 4k? */
874 mask = 0767777;
875 else mask = 0777777;
876 for (i = 0; i < BOOT_LEN; i++) {
877 wd = boot_rom[i];
878 if ((wd >= 0040000) && (wd < 0640000))
879 wd = wd & mask;
880 M[(BOOT_START & mask) + i] = wd;
881 }
882 PC = ((sim_switches & SWMASK ('F'))? BOOT_FPC: BOOT_RPC) & mask;
883 return SCPE_OK;
884 }
885
886 #else
887
888 /* PDP-9 and PDP-15 have built-in hardware RIM loaders */
889
ptr_boot(int32 unitno,DEVICE * dptr)890 t_stat ptr_boot (int32 unitno, DEVICE *dptr)
891 {
892 return ptr_rim_load (&ptr_unit, ASW);
893 }
894
895 #endif
896
897 /* Paper tape punch: IOT routine */
898
ptp(int32 dev,int32 pulse,int32 dat)899 int32 ptp (int32 dev, int32 pulse, int32 dat)
900 {
901 if (pulse & 001) { /* PSF */
902 if (TST_INT (PTP))
903 dat = dat | IOT_SKP;
904 }
905 if (pulse & 002) /* PCF */
906 CLR_INT (PTP);
907 if (pulse & 004) { /* PSA, PSB, PLS */
908 CLR_INT (PTP); /* clear flag */
909 ptp_unit.buf = (pulse & 040)? /* load punch buf */
910 (dat & 077) | 0200: dat & 0377; /* bin or alpha */
911 sim_activate (&ptp_unit, ptp_unit.wait); /* activate unit */
912 }
913 return dat;
914 }
915
916 /* Unit service */
917
ptp_svc(UNIT * uptr)918 t_stat ptp_svc (UNIT *uptr)
919 {
920 SET_INT (PTP); /* set flag */
921 if ((ptp_unit.flags & UNIT_ATT) == 0) { /* not attached? */
922 ptp_err = 1; /* set error */
923 return IORETURN (ptp_stopioe, SCPE_UNATT);
924 }
925 if (ptp_unit.flags & UNIT_PASCII) { /* ASCII mode? */
926 ptp_unit.buf = ptp_unit.buf & 0177; /* force 7b */
927 if ((ptp_unit.buf == 0) || (ptp_unit.buf == 0177))
928 return SCPE_OK; /* skip null, del */
929 }
930 if (putc (ptp_unit.buf, ptp_unit.fileref) == EOF) { /* I/O error? */
931 ptp_err = 1; /* set error */
932 perror ("PTP I/O error");
933 clearerr (ptp_unit.fileref);
934 return SCPE_IOERR;
935 }
936 ptp_unit.pos = ptp_unit.pos + 1;
937 return SCPE_OK;
938 }
939
940 /* IORS service */
941
ptp_iors(void)942 int32 ptp_iors (void)
943 {
944 return ((TST_INT (PTP)? IOS_PTP: 0)
945 #if defined (IOS_PTPERR)
946 | (ptp_err? IOS_PTPERR: 0)
947 #endif
948 );
949 }
950
951 /* Reset routine */
952
ptp_reset(DEVICE * dptr)953 t_stat ptp_reset (DEVICE *dptr)
954 {
955 ptp_unit.buf = 0;
956 CLR_INT (PTP); /* clear flag */
957 ptp_err = (ptp_unit.flags & UNIT_ATT)? 0: 1;
958 sim_cancel (&ptp_unit); /* deactivate unit */
959 return SCPE_OK;
960 }
961
962 /* Attach routine */
963
ptp_attach(UNIT * uptr,char * cptr)964 t_stat ptp_attach (UNIT *uptr, char *cptr)
965 {
966 t_stat reason;
967
968 reason = attach_unit (uptr, cptr);
969 if (reason != SCPE_OK)
970 return reason;
971 ptp_err = 0;
972 ptp_unit.flags = ptp_unit.flags & ~UNIT_PASCII;
973 if (sim_switches & SWMASK ('A'))
974 ptp_unit.flags = ptp_unit.flags | UNIT_PASCII;
975 return reason;
976 }
977
978 /* Detach routine */
979
ptp_detach(UNIT * uptr)980 t_stat ptp_detach (UNIT *uptr)
981 {
982 ptp_err = 1;
983 ptp_unit.flags = ptp_unit.flags & ~UNIT_PASCII;
984 return detach_unit (uptr);
985 }
986
987 /* Terminal input: IOT routine */
988
tti(int32 dev,int32 pulse,int32 dat)989 int32 tti (int32 dev, int32 pulse, int32 dat)
990 {
991 if (pulse & 001) { /* KSF */
992 if (TST_INT (TTI))
993 dat = dat | IOT_SKP;
994 }
995 if (pulse & 002) { /* KRS/KRB */
996 CLR_INT (TTI); /* clear flag */
997 dat = dat | tti_unit.buf & TTI_MASK; /* return buffer */
998 #if defined (PDP15)
999 if (pulse & 020) /* KRS? */
1000 tti_fdpx = 1;
1001 else tti_fdpx = 0; /* no, KRB */
1002 #endif
1003 }
1004 if (pulse & 004) { /* IORS */
1005 dat = dat | upd_iors ();
1006 }
1007 return dat;
1008 }
1009
1010 /* Unit service */
1011
tti_svc(UNIT * uptr)1012 t_stat tti_svc (UNIT *uptr)
1013 {
1014 #if defined (KSR28) /* Baudot... */
1015 int32 in, c, out;
1016
1017 sim_activate (uptr, KBD_WAIT (uptr->wait, clk_cosched (tmxr_poll)));
1018 /* continue poll */
1019 if (tti_2nd) { /* char waiting? */
1020 uptr->buf = tti_2nd; /* return char */
1021 tti_2nd = 0; /* not waiting */
1022 }
1023 else {
1024 if ((in = sim_poll_kbd ()) < SCPE_KFLAG)
1025 return in;
1026 c = asc_to_baud[in & 0177]; /* translate char */
1027 if (c == 0) /* untranslatable? */
1028 return SCPE_OK;
1029 if ((c & TTI_BOTH) || /* case insensitive? */
1030 (((c & TTI_FIGURES)? 1: 0) == tty_shift)) /* right case? */
1031 uptr->buf = c & TTI_MASK;
1032 else { /* send case change */
1033 if (c & TTI_FIGURES) { /* to figures? */
1034 uptr->buf = BAUDOT_FIGURES;
1035 tty_shift = 1;
1036 }
1037 else { /* no, to letters */
1038 uptr->buf = BAUDOT_LETTERS;
1039 tty_shift = 0;
1040 }
1041 tti_2nd = c & TTI_MASK; /* save actual char */
1042 }
1043 if ((uptr->flags & TTUF_HDX) && /* half duplex? */
1044 ((out = sim_tt_outcvt (in, TT_GET_MODE (uptr->flags) | TTUF_KSR)) >= 0)) {
1045 sim_putchar (out);
1046 tto_unit.pos = tto_unit.pos + 1;
1047 }
1048 }
1049
1050 #else /* ASCII... */
1051 int32 c, out;
1052
1053 sim_activate (uptr, KBD_WAIT (uptr->wait, clk_cosched (tmxr_poll)));
1054 /* continue poll */
1055 if ((c = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or error? */
1056 return c;
1057 out = c & 0177; /* mask echo to 7b */
1058 if (c & SCPE_BREAK) /* break? */
1059 c = 0;
1060 else c = sim_tt_inpcvt (c, TT_GET_MODE (uptr->flags) | TTUF_KSR);
1061 if ((uptr->flags & TTUF_HDX) && !tti_fdpx && out && /* half duplex and */
1062 ((out = sim_tt_outcvt (out, TT_GET_MODE (uptr->flags) | TTUF_KSR)) >= 0)) {
1063 sim_putchar (out); /* echo */
1064 tto_unit.pos = tto_unit.pos + 1;
1065 }
1066 uptr->buf = c; /* got char */
1067
1068 #endif
1069 uptr->pos = uptr->pos + 1;
1070 SET_INT (TTI); /* set flag */
1071 return SCPE_OK;
1072 }
1073
1074 /* IORS service */
1075
tti_iors(void)1076 int32 tti_iors (void)
1077 {
1078 return (TST_INT (TTI)? IOS_TTI: 0);
1079 }
1080
1081 /* Reset routine */
1082
tti_reset(DEVICE * dptr)1083 t_stat tti_reset (DEVICE *dptr)
1084 {
1085 CLR_INT (TTI); /* clear flag */
1086 if (!sim_is_running) { /* RESET (not CAF)? */
1087 tti_unit.buf = 0; /* clear buffer */
1088 tti_2nd = 0;
1089 tty_shift = 0; /* clear state */
1090 tti_fdpx = 0; /* clear dpx mode */
1091 }
1092 sim_activate (&tti_unit, KBD_WAIT (tti_unit.wait, tmxr_poll));
1093 return SCPE_OK;
1094 }
1095
1096 /* Terminal output: IOT routine */
1097
tto(int32 dev,int32 pulse,int32 dat)1098 int32 tto (int32 dev, int32 pulse, int32 dat)
1099 {
1100 if (pulse & 001) { /* TSF */
1101 if (TST_INT (TTO))
1102 dat = dat | IOT_SKP;
1103 }
1104 if (pulse & 002) /* clear flag */
1105 CLR_INT (TTO);
1106 if (pulse & 004) { /* load buffer */
1107 sim_activate (&tto_unit, tto_unit.wait); /* activate unit */
1108 tto_unit.buf = dat & TTO_MASK; /* load buffer */
1109 }
1110 return dat;
1111 }
1112
1113 /* Unit service */
1114
tto_svc(UNIT * uptr)1115 t_stat tto_svc (UNIT *uptr)
1116 {
1117 int32 c;
1118 t_stat r;
1119
1120 #if defined (KSR28) /* Baudot... */
1121 if (uptr->buf == BAUDOT_FIGURES) /* set figures? */
1122 tty_shift = 1;
1123 else if (uptr->buf == BAUDOT_LETTERS) /* set letters? */
1124 tty_shift = 0;
1125 else {
1126 c = baud_to_asc[uptr->buf | (tty_shift << 5)]; /* translate */
1127
1128 #else
1129 c = sim_tt_outcvt (uptr->buf, TT_GET_MODE (uptr->flags) | TTUF_KSR);
1130 if (c >= 0) {
1131
1132 #endif
1133
1134 if ((r = sim_putchar_s (c)) != SCPE_OK) { /* output; error? */
1135 sim_activate (uptr, uptr->wait); /* retry? */
1136 return ((r == SCPE_STALL)? SCPE_OK: r);
1137 }
1138 }
1139 SET_INT (TTO); /* set flag */
1140 uptr->pos = uptr->pos + 1;
1141 return SCPE_OK;
1142 }
1143
1144 /* IORS service */
1145
1146 int32 tto_iors (void)
1147 {
1148 return (TST_INT (TTO)? IOS_TTO: 0);
1149 }
1150
1151 /* Reset routine */
1152
1153 t_stat tto_reset (DEVICE *dptr)
1154 {
1155 tto_unit.buf = 0; /* clear buffer */
1156 tty_shift = 0; /* clear state */
1157 CLR_INT (TTO); /* clear flag */
1158 sim_cancel (&tto_unit); /* deactivate unit */
1159 return SCPE_OK;
1160 }
1161
1162 /* Set mode */
1163
1164 t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc)
1165 {
1166 tti_unit.flags = (tti_unit.flags & ~TT_MODE) | val;
1167 tto_unit.flags = (tto_unit.flags & ~TT_MODE) | val;
1168 return SCPE_OK;
1169 }
1170