1 /*
2 * Copyright (c) 2007-2013 Michael Mondy
3 * Copyright (c) 2012-2016 Harry Reed
4 * Copyright (c) 2013-2017 Charles Anthony
5 * Copyright (c) 2016 Michal Tomek
6 * Copyright (c) 2021 Jeffrey H. Johnson <trnsz@pobox.com>
7 * Copyright (c) 2021 The DPS8M Development Team
8 *
9 * All rights reserved.
10 *
11 * This software is made available under the terms of the ICU
12 * License, version 1.8.1 or later. For more details, see the
13 * LICENSE.md file at the top-level directory of this distribution.
14 */
15
16 #include <stdio.h>
17 #ifndef __MINGW64__
18 # ifndef __MINGW32__
19 # ifndef CROSS_MINGW64
20 # ifndef CROSS_MINGW32
21 # ifndef __OpenBSD__
22 # include <wordexp.h>
23 # endif /* ifndef __OpenBSD__ */
24 # include <signal.h>
25 # endif /* ifndef CROSS_MINGW32 */
26 # endif /* ifndef CROSS_MINGW64 */
27 # endif /* ifndef __MINGW32__ */
28 #endif /* ifndef __MINGW64__ */
29 #include <unistd.h>
30 #include <ctype.h>
31
32 #ifdef __APPLE__
33 # include <pthread.h>
34 #endif
35
36 #include "dps8.h"
37 #include "dps8_sys.h"
38 #include "dps8_faults.h"
39 #include "dps8_scu.h"
40 #include "dps8_iom.h"
41 #include "dps8_console.h"
42 #include "dps8_cable.h"
43 #include "dps8_cpu.h"
44 #include "dps8_state.h"
45 #include "dps8_ins.h"
46 #include "dps8_math.h"
47 #include "dps8_mt.h"
48 #include "dps8_socket_dev.h"
49 #include "dps8_disk.h"
50 #include "dps8_append.h"
51 #include "dps8_fnp2.h"
52 #include "dps8_crdrdr.h"
53 #include "dps8_crdpun.h"
54 #include "dps8_prt.h"
55 #include "dps8_urp.h"
56 #include "dps8_absi.h"
57 #include "dps8_utils.h"
58 #include "shm.h"
59 #include "utlist.h"
60 #include "ver.h"
61 #if defined(THREADZ) || defined(LOCKLESS)
62 # include "threadz.h"
63 #endif
64
65 #ifdef PANEL
66 # include "panelScraper.h"
67 #endif
68
69 #include "segldr.h"
70
71 #define DBG_CTR cpu.cycleCnt
72
73 #define ASSUME0 0
74
75 // Strictly speaking, memory belongs in the SCU.
76 // We will treat memory as viewed from the CPU and elide the
77 // SCU configuration that maps memory across multiple SCUs.
78 // I would guess that multiple SCUs helped relieve memory
79 // contention across multiple CPUs, but that is a level of
80 // emulation that will be ignored.
81 // Building with SCUMEM defined puts the memory in the SCUs.
82
83 struct system_state_s * system_state;
84
85 #ifndef SCUMEM
86 vol word36 * M = NULL; // memory
87 #endif
88
89 //
90 // These are part of the simh interface
91 //
92
93 #ifdef DPS8M
94 char sim_name[] = "DPS8/M";
95 #endif
96 #ifdef L68
97 char sim_name[] = "L68";
98 #endif
99 int32 sim_emax = 4; // some EIS can take up to 4-words
100 static void dps8_init(void);
101 void (*sim_vm_init) (void) = & dps8_init; // CustomCmds;
102
103 #ifdef TESTING
104 static t_addr parse_addr(DEVICE *dptr, const char *cptr, const char **optr);
105 static void fprint_addr(FILE *stream, DEVICE *dptr, t_addr addr);
106 #endif // TESTING
107
108 int32 luf_flag = 1;
109
110 ////////////////////////////////////////////////////////////////////////////////
111 //
112 // simh Commands
113 //
114
115 //
116 // System configuration commands
117 //
118
119 // Script to string cables and set switches
120
121 static char * default_base_system_script [] =
122 {
123 // ;
124 // ; Configure test system
125 // ;
126 // ; CPU, IOM * 2, MPC, TAPE * 16, DISK * 16, SCU * 4, OPC * 2, FNP, URP * 3,
127 // ; PRT, RDR, PUN
128 // ;
129 // ;
130 // ; From AN70-1 System Initialization PLM May 84, pg 8-4:
131 // ;
132 // ; All CPUs and IOMs must share the same layout of port assignments to
133 // ; SCUs. Thus, if memory port B of CPU C goes to SCU D, the memory port
134 // ; B of all other CPUs and IOMs must go to SCU D. All CPUs and IOMs must
135 // ; describe this SCU the same; all must agree in memory sizes. Also, all
136 // ; SCUs must agree on port assignments of CPUs and IOMs. This, if port 3
137 // ; of SCU C goes to CPU A, the port 3 of all other SCUs must also go to
138 // ; CPU A.
139 // ;
140 // ; Pg. 8-6:
141 // ;
142 // ; The actual memory size of the memory attached to the SCU attached to
143 // ; the processor port in questions is 32K * 2 ** (encoded memory size).
144 // ; The port assignment couples with the memory size to determine the base
145 // ; address of the SCU connected to the specified CPU port (absoulte
146 // ; address of the first location in the memory attached to that SCU). The
147 // ; base address of the SCU is the (actual memory size) * (port assignment).
148 // ;
149 // ; Pg. 8-6
150 // ;
151 // ; [bits 09-11 lower store size]
152 // ;
153 // ; A DPS-8 SCU may have up to four store units attached to it. If this is
154 // ; the case, two stores units form a pair of units. The size of a pair of
155 // ; units (or a single unit) is 32K * 2 ** (lower store size) above.
156 // ;
157 // ;
158 // ;
159 // ; Looking at bootload_io, it would appear that Multics is happier with
160 // ; IOM0 being the bootload IOM, despite suggestions elsewhere that was
161 // ; not a requirement.
162
163 //
164 // IOM channel assignments
165 //
166 // IOM A
167 //
168 // 012 MTP0 tape drives
169 // 013 IPC0 port 0 FIPS disk controller
170 // 014 MSP0 port 0 disk controller
171 // 015 URP0 card reader controller
172 // 016 URP1 card punch controller
173 // 017 URP2 printer controller
174 // 020 FNPD comm line controller
175 // 021 FNPA comm line controller
176 // 022 FNPB comm line controller
177 // 023 FNPC comm line controller
178 // 024 FNPE comm line controller
179 // 025 FNPF comm line controller
180 // 026 FNPG comm line controller
181 // 027 FNPH comm line controller
182 // 032 ABSI0 IMP controller
183 // 036 OPC0 operator console
184 // 040 SKCA
185 // 041 SKCB
186 // 042 SKCC
187 // 043 SKCD
188 // 044 SKCE
189 // 045 SKCF
190 // 046 SKCG
191 // 047 SKCH
192 //
193 // IOM B
194 //
195 // 013 IPC0 port 1 FIPS disk controller
196 // 014 MSP0 port 1 disk controller
197
198 // ; Disconnect everything...
199 "cable_ripout",
200
201 "set cpu nunits=6",
202 "set iom nunits=2",
203 // ; 16 drives plus a placeholder for the controller
204 "set tape nunits=17",
205 "set mtp nunits=1",
206 // ; 4 3381 drives; 2 controllers
207 // ; 4 d501 drives; 2 controller
208 // ; 4 d451 drives; same controller has d501s
209 // ; 2 d500 drives; same controller has d501s
210 "set ipc nunits=2",
211 "set msp nunits=2",
212 "set disk nunits=26",
213 "set scu nunits=4",
214 "set opc nunits=2",
215 "set fnp nunits=8",
216 "set urp nunits=10",
217 "set rdr nunits=3",
218 "set pun nunits=3",
219 "set prt nunits=4",
220 #ifndef __MINGW64__
221 # ifndef __MINGW32__
222 # ifndef CROSS_MINGW64
223 # ifndef CROSS_MINGW32
224 "set skc nunits=64",
225 "set absi nunits=1",
226 # endif /* ifndef CROSS_MINGW32 */
227 # endif /* ifndef CROSS_MINGW64 */
228 # endif /* ifndef __MINGW32__ */
229 #endif /* ifndef __MINGW64__ */
230
231
232 // CPU0
233
234 "set cpu0 config=faultbase=Multics",
235
236 "set cpu0 config=num=0",
237 // ; As per GB61-01 Operators Guide, App. A
238 // ; switches: 4, 6, 18, 19, 20, 23, 24, 25, 26, 28
239 "set cpu0 config=data=024000717200",
240
241 // ; enable ports 0 and 1 (scu connections)
242 // ; portconfig: ABCD
243 // ; each is 3 bits addr assignment
244 // ; 1 bit enabled
245 // ; 1 bit sysinit enabled
246 // ; 1 bit interlace enabled (interlace?)
247 // ; 3 bit memory size
248 // ; 0 - 32K
249 // ; 1 - 64K
250 // ; 2 - 128K
251 // ; 3 - 256K
252 // ; 4 - 512K
253 // ; 5 - 1M
254 // ; 6 - 2M
255 // ; 7 - 4M
256
257 "set cpu0 config=port=A",
258 "set cpu0 config=assignment=0",
259 "set cpu0 config=interlace=0",
260 "set cpu0 config=enable=1",
261 "set cpu0 config=init_enable=1",
262 "set cpu0 config=store_size=4M",
263
264 "set cpu0 config=port=B",
265 "set cpu0 config=assignment=1",
266 "set cpu0 config=interlace=0",
267 "set cpu0 config=enable=1",
268 "set cpu0 config=init_enable=1",
269 "set cpu0 config=store_size=4M",
270
271 "set cpu0 config=port=C",
272 "set cpu0 config=assignment=2",
273 "set cpu0 config=interlace=0",
274 "set cpu0 config=enable=1",
275 "set cpu0 config=init_enable=1",
276 "set cpu0 config=store_size=4M",
277
278 "set cpu0 config=port=D",
279 "set cpu0 config=assignment=3",
280 "set cpu0 config=interlace=0",
281 "set cpu0 config=enable=1",
282 "set cpu0 config=init_enable=1",
283 "set cpu0 config=store_size=4M",
284
285 // ; 0 = GCOS 1 = VMS
286 "set cpu0 config=mode=Multics",
287
288 "set cpu0 config=cache=enable",
289 "set cpu0 config=sdwam=enable",
290 "set cpu0 config=ptwam=enable",
291
292 // ; 0 = 8/70
293 "set cpu0 config=speed=0",
294
295 "set cpu0 config=dis_enable=enable",
296 "set cpu0 config=steady_clock=disable",
297 "set cpu0 config=halt_on_unimplemented=disable",
298 "set cpu0 config=disable_wam=enable",
299 "set cpu0 config=tro_enable=enable",
300 "set cpu0 config=y2k=disable",
301
302 // CPU1
303
304 "set cpu1 config=faultbase=Multics",
305
306 "set cpu1 config=num=1",
307 // ; As per GB61-01 Operators Guide, App. A
308 // ; switches: 4, 6, 18, 19, 20, 23, 24, 25, 26, 28
309 "set cpu1 config=data=024000717200",
310
311 // ; enable ports 0 and 1 (scu connections)
312 // ; portconfig: ABCD
313 // ; each is 3 bits addr assignment
314 // ; 1 bit enabled
315 // ; 1 bit sysinit enabled
316 // ; 1 bit interlace enabled (interlace?)
317 // ; 3 bit memory size
318 // ; 0 - 32K
319 // ; 1 - 64K
320 // ; 2 - 128K
321 // ; 3 - 256K
322 // ; 4 - 512K
323 // ; 5 - 1M
324 // ; 6 - 2M
325 // ; 7 - 4M
326
327 "set cpu1 config=port=A",
328 "set cpu1 config=assignment=0",
329 "set cpu1 config=interlace=0",
330 "set cpu1 config=enable=1",
331 "set cpu1 config=init_enable=1",
332 "set cpu1 config=store_size=4M",
333
334 "set cpu1 config=port=B",
335 "set cpu1 config=assignment=1",
336 "set cpu1 config=interlace=0",
337 "set cpu1 config=enable=1",
338 "set cpu1 config=init_enable=1",
339 "set cpu1 config=store_size=4M",
340
341 "set cpu1 config=port=C",
342 "set cpu1 config=assignment=2",
343 "set cpu1 config=interlace=0",
344 "set cpu1 config=enable=1",
345 "set cpu1 config=init_enable=1",
346 "set cpu1 config=store_size=4M",
347
348 "set cpu1 config=port=D",
349 "set cpu1 config=assignment=3",
350 "set cpu1 config=interlace=0",
351 "set cpu1 config=enable=1",
352 "set cpu1 config=init_enable=1",
353 "set cpu1 config=store_size=4M",
354
355 // ; 0 = GCOS 1 = VMS
356 "set cpu1 config=mode=Multics",
357
358 "set cpu1 config=cache=enable",
359 "set cpu1 config=sdwam=enable",
360 "set cpu1 config=ptwam=enable",
361
362 // ; 0 = 8/70
363 "set cpu1 config=speed=0",
364
365 "set cpu1 config=dis_enable=enable",
366 "set cpu1 config=steady_clock=disable",
367 "set cpu1 config=halt_on_unimplemented=disable",
368 "set cpu1 config=disable_wam=enable",
369 "set cpu1 config=tro_enable=enable",
370 "set cpu1 config=y2k=disable",
371
372
373 // CPU2
374
375 "set cpu2 config=faultbase=Multics",
376
377 "set cpu2 config=num=2",
378 // ; As per GB61-01 Operators Guide, App. A
379 // ; switches: 4, 6, 18, 19, 20, 23, 24, 25, 26, 28
380 "set cpu2 config=data=024000717200",
381
382 // ; enable ports 0 and 1 (scu connections)
383 // ; portconfig: ABCD
384 // ; each is 3 bits addr assignment
385 // ; 1 bit enabled
386 // ; 1 bit sysinit enabled
387 // ; 1 bit interlace enabled (interlace?)
388 // ; 3 bit memory size
389 // ; 0 - 32K
390 // ; 1 - 64K
391 // ; 2 - 128K
392 // ; 3 - 256K
393 // ; 4 - 512K
394 // ; 5 - 1M
395 // ; 6 - 2M
396 // ; 7 - 4M
397
398 "set cpu2 config=port=A",
399 "set cpu2 config=assignment=0",
400 "set cpu2 config=interlace=0",
401 "set cpu2 config=enable=1",
402 "set cpu2 config=init_enable=1",
403 "set cpu2 config=store_size=4M",
404
405 "set cpu2 config=port=B",
406 "set cpu2 config=assignment=1",
407 "set cpu2 config=interlace=0",
408 "set cpu2 config=enable=1",
409 "set cpu2 config=init_enable=1",
410 "set cpu2 config=store_size=4M",
411
412 "set cpu2 config=port=C",
413 "set cpu2 config=assignment=2",
414 "set cpu2 config=interlace=0",
415 "set cpu2 config=enable=1",
416 "set cpu2 config=init_enable=1",
417 "set cpu2 config=store_size=4M",
418
419 "set cpu2 config=port=D",
420 "set cpu2 config=assignment=3",
421 "set cpu2 config=interlace=0",
422 "set cpu2 config=enable=1",
423 "set cpu2 config=init_enable=1",
424 "set cpu2 config=store_size=4M",
425
426 // ; 0 = GCOS 1 = VMS
427 "set cpu2 config=mode=Multics",
428
429 "set cpu2 config=cache=enable",
430 "set cpu2 config=sdwam=enable",
431 "set cpu2 config=ptwam=enable",
432
433 // ; 0 = 8/70
434 "set cpu2 config=speed=0",
435
436 "set cpu2 config=dis_enable=enable",
437 "set cpu2 config=steady_clock=disable",
438 "set cpu2 config=halt_on_unimplemented=disable",
439 "set cpu2 config=disable_wam=enable",
440 "set cpu2 config=tro_enable=enable",
441 "set cpu2 config=y2k=disable",
442
443
444 // CPU3
445
446 "set cpu3 config=faultbase=Multics",
447
448 "set cpu3 config=num=3",
449 // ; As per GB61-01 Operators Guide, App. A
450 // ; switches: 4, 6, 18, 19, 20, 23, 24, 25, 26, 28
451 "set cpu3 config=data=024000717200",
452
453 // ; enable ports 0 and 1 (scu connections)
454 // ; portconfig: ABCD
455 // ; each is 3 bits addr assignment
456 // ; 1 bit enabled
457 // ; 1 bit sysinit enabled
458 // ; 1 bit interlace enabled (interlace?)
459 // ; 3 bit memory size
460 // ; 0 - 32K
461 // ; 1 - 64K
462 // ; 2 - 128K
463 // ; 3 - 256K
464 // ; 4 - 512K
465 // ; 5 - 1M
466 // ; 6 - 2M
467 // ; 7 - 4M
468
469 "set cpu3 config=port=A",
470 "set cpu3 config=assignment=0",
471 "set cpu3 config=interlace=0",
472 "set cpu3 config=enable=1",
473 "set cpu3 config=init_enable=1",
474 "set cpu3 config=store_size=4M",
475
476 "set cpu3 config=port=B",
477 "set cpu3 config=assignment=1",
478 "set cpu3 config=interlace=0",
479 "set cpu3 config=enable=1",
480 "set cpu3 config=init_enable=1",
481 "set cpu3 config=store_size=4M",
482
483 "set cpu3 config=port=C",
484 "set cpu3 config=assignment=2",
485 "set cpu3 config=interlace=0",
486 "set cpu3 config=enable=1",
487 "set cpu3 config=init_enable=1",
488 "set cpu3 config=store_size=4M",
489
490 "set cpu3 config=port=D",
491 "set cpu3 config=assignment=3",
492 "set cpu3 config=interlace=0",
493 "set cpu3 config=enable=1",
494 "set cpu3 config=init_enable=1",
495 "set cpu3 config=store_size=4M",
496
497 // ; 0 = GCOS 1 = VMS
498 "set cpu3 config=mode=Multics",
499
500 "set cpu3 config=cache=enable",
501 "set cpu3 config=sdwam=enable",
502 "set cpu3 config=ptwam=enable",
503
504 // ; 0 = 8/70
505 "set cpu3 config=speed=0",
506
507 "set cpu3 config=dis_enable=enable",
508 "set cpu3 config=steady_clock=disable",
509 "set cpu3 config=halt_on_unimplemented=disable",
510 "set cpu3 config=disable_wam=enable",
511 "set cpu3 config=tro_enable=enable",
512 "set cpu3 config=y2k=disable",
513
514
515 // CPU4
516
517 "set cpu4 config=faultbase=Multics",
518
519 "set cpu4 config=num=4",
520 // ; As per GB61-01 Operators Guide, App. A
521 // ; switches: 4, 6, 18, 19, 20, 23, 24, 25, 26, 28
522 "set cpu4 config=data=024000717200",
523
524 // ; enable ports 0 and 1 (scu connections)
525 // ; portconfig: ABCD
526 // ; each is 3 bits addr assignment
527 // ; 1 bit enabled
528 // ; 1 bit sysinit enabled
529 // ; 1 bit interlace enabled (interlace?)
530 // ; 3 bit memory size
531 // ; 0 - 32K
532 // ; 1 - 64K
533 // ; 2 - 128K
534 // ; 3 - 256K
535 // ; 4 - 512K
536 // ; 5 - 1M
537 // ; 6 - 2M
538 // ; 7 - 4M
539
540 "set cpu4 config=port=A",
541 "set cpu4 config=assignment=0",
542 "set cpu4 config=interlace=0",
543 "set cpu4 config=enable=1",
544 "set cpu4 config=init_enable=1",
545 "set cpu4 config=store_size=4M",
546
547 "set cpu4 config=port=B",
548 "set cpu4 config=assignment=1",
549 "set cpu4 config=interlace=0",
550 "set cpu4 config=enable=1",
551 "set cpu4 config=init_enable=1",
552 "set cpu4 config=store_size=4M",
553
554 "set cpu4 config=port=C",
555 "set cpu4 config=assignment=2",
556 "set cpu4 config=interlace=0",
557 "set cpu4 config=enable=1",
558 "set cpu4 config=init_enable=1",
559 "set cpu4 config=store_size=4M",
560
561 "set cpu4 config=port=D",
562 "set cpu4 config=assignment=3",
563 "set cpu4 config=interlace=0",
564 "set cpu4 config=enable=1",
565 "set cpu4 config=init_enable=1",
566 "set cpu4 config=store_size=4M",
567
568 // ; 0 = GCOS 1 = VMS
569 "set cpu4 config=mode=Multics",
570
571 "set cpu4 config=cache=enable",
572 "set cpu4 config=sdwam=enable",
573 "set cpu4 config=ptwam=enable",
574
575 // ; 0 = 8/70
576 "set cpu4 config=speed=0",
577
578 "set cpu4 config=dis_enable=enable",
579 "set cpu4 config=steady_clock=disable",
580 "set cpu4 config=halt_on_unimplemented=disable",
581 "set cpu4 config=disable_wam=enable",
582 "set cpu4 config=tro_enable=enable",
583 "set cpu4 config=y2k=disable",
584
585
586 // CPU5
587
588 "set cpu5 config=faultbase=Multics",
589
590 "set cpu5 config=num=5",
591 // ; As per GB61-01 Operators Guide, App. A
592 // ; switches: 4, 6, 18, 19, 20, 23, 24, 25, 26, 28
593 "set cpu5 config=data=024000717200",
594
595 // ; enable ports 0 and 1 (scu connections)
596 // ; portconfig: ABCD
597 // ; each is 3 bits addr assignment
598 // ; 1 bit enabled
599 // ; 1 bit sysinit enabled
600 // ; 1 bit interlace enabled (interlace?)
601 // ; 3 bit memory size
602 // ; 0 - 32K
603 // ; 1 - 64K
604 // ; 2 - 128K
605 // ; 3 - 256K
606 // ; 4 - 512K
607 // ; 5 - 1M
608 // ; 6 - 2M
609 // ; 7 - 4M
610
611 "set cpu5 config=port=A",
612 "set cpu5 config=assignment=0",
613 "set cpu5 config=interlace=0",
614 "set cpu5 config=enable=1",
615 "set cpu5 config=init_enable=1",
616 "set cpu5 config=store_size=4M",
617
618 "set cpu5 config=port=B",
619 "set cpu5 config=assignment=1",
620 "set cpu5 config=interlace=0",
621 "set cpu5 config=enable=1",
622 "set cpu5 config=init_enable=1",
623 "set cpu5 config=store_size=4M",
624
625 "set cpu5 config=port=C",
626 "set cpu5 config=assignment=2",
627 "set cpu5 config=interlace=0",
628 "set cpu5 config=enable=1",
629 "set cpu5 config=init_enable=1",
630 "set cpu5 config=store_size=4M",
631
632 "set cpu5 config=port=D",
633 "set cpu5 config=assignment=3",
634 "set cpu5 config=interlace=0",
635 "set cpu5 config=enable=1",
636 "set cpu5 config=init_enable=1",
637 "set cpu5 config=store_size=4M",
638
639 // ; 0 = GCOS 1 = VMS
640 "set cpu5 config=mode=Multics",
641
642 "set cpu5 config=cache=enable",
643 "set cpu5 config=sdwam=enable",
644 "set cpu5 config=ptwam=enable",
645
646 // ; 0 = 8/70
647 "set cpu5 config=speed=0",
648
649 "set cpu5 config=dis_enable=enable",
650 "set cpu5 config=steady_clock=disable",
651 "set cpu5 config=halt_on_unimplemented=disable",
652 "set cpu5 config=disable_wam=enable",
653 "set cpu5 config=tro_enable=enable",
654 "set cpu5 config=y2k=disable",
655
656
657 #if 0 // Until the port expander code is working
658 // CPU6
659
660 "set cpu6 config=faultbase=Multics",
661
662 "set cpu6 config=num=6",
663 // ; As per GB61-01 Operators Guide, App. A
664 // ; switches: 4, 6, 18, 19, 20, 23, 24, 25, 26, 28
665 "set cpu6 config=data=024000717200",
666
667 // ; enable ports 0 and 1 (scu connections)
668 // ; portconfig: ABCD
669 // ; each is 3 bits addr assignment
670 // ; 1 bit enabled
671 // ; 1 bit sysinit enabled
672 // ; 1 bit interlace enabled (interlace?)
673 // ; 3 bit memory size
674 // ; 0 - 32K
675 // ; 1 - 64K
676 // ; 2 - 128K
677 // ; 3 - 256K
678 // ; 4 - 512K
679 // ; 5 - 1M
680 // ; 6 - 2M
681 // ; 7 - 4M
682
683 "set cpu6 config=port=A",
684 "set cpu6 config=assignment=0",
685 "set cpu6 config=interlace=0",
686 "set cpu6 config=enable=1",
687 "set cpu6 config=init_enable=1",
688 "set cpu6 config=store_size=4M",
689
690 "set cpu6 config=port=B",
691 "set cpu6 config=assignment=1",
692 "set cpu6 config=interlace=0",
693 "set cpu6 config=enable=1",
694 "set cpu6 config=init_enable=1",
695 "set cpu6 config=store_size=4M",
696
697 "set cpu6 config=port=C",
698 "set cpu6 config=assignment=2",
699 "set cpu6 config=interlace=0",
700 "set cpu6 config=enable=1",
701 "set cpu6 config=init_enable=1",
702 "set cpu6 config=store_size=4M",
703
704 "set cpu6 config=port=D",
705 "set cpu6 config=assignment=3",
706 "set cpu6 config=interlace=0",
707 "set cpu6 config=enable=1",
708 "set cpu6 config=init_enable=1",
709 "set cpu6 config=store_size=4M",
710
711 // ; 0 = GCOS 1 = VMS
712 "set cpu6 config=mode=Multics",
713
714 "set cpu6 config=cache=enable",
715 "set cpu6 config=sdwam=enable",
716 "set cpu6 config=ptwam=enable",
717
718 // ; 0 = 8/70
719 "set cpu6 config=speed=0",
720
721 "set cpu6 config=dis_enable=enable",
722 "set cpu6 config=steady_clock=disable",
723 "set cpu6 config=halt_on_unimplemented=disable",
724 "set cpu6 config=disable_wam=enable",
725 "set cpu6 config=tro_enable=enable",
726 "set cpu6 config=y2k=disable",
727 #endif
728
729 #if 0 // Until the port expander code is working
730
731 // CPU7
732
733 "set cpu7 config=faultbase=Multics",
734
735 "set cpu7 config=num=7",
736 // ; As per GB61-01 Operators Guide, App. A
737 // ; switches: 4, 6, 18, 19, 20, 23, 24, 25, 26, 28
738 "set cpu7 config=data=024000717200",
739
740 // ; enable ports 0 and 1 (scu connections)
741 // ; portconfig: ABCD
742 // ; each is 3 bits addr assignment
743 // ; 1 bit enabled
744 // ; 1 bit sysinit enabled
745 // ; 1 bit interlace enabled (interlace?)
746 // ; 3 bit memory size
747 // ; 0 - 32K
748 // ; 1 - 64K
749 // ; 2 - 128K
750 // ; 3 - 256K
751 // ; 4 - 512K
752 // ; 5 - 1M
753 // ; 6 - 2M
754 // ; 7 - 4M
755
756 "set cpu7 config=port=A",
757 "set cpu7 config=assignment=0",
758 "set cpu7 config=interlace=0",
759 "set cpu7 config=enable=1",
760 "set cpu7 config=init_enable=1",
761 "set cpu7 config=store_size=4M",
762
763 "set cpu7 config=port=B",
764 "set cpu7 config=assignment=1",
765 "set cpu7 config=interlace=0",
766 "set cpu7 config=enable=1",
767 "set cpu7 config=init_enable=1",
768 "set cpu7 config=store_size=4M",
769
770 "set cpu7 config=port=C",
771 "set cpu7 config=assignment=2",
772 "set cpu7 config=interlace=0",
773 "set cpu7 config=enable=1",
774 "set cpu7 config=init_enable=1",
775 "set cpu7 config=store_size=4M",
776
777 "set cpu7 config=port=D",
778 "set cpu7 config=assignment=3",
779 "set cpu7 config=interlace=0",
780 "set cpu7 config=enable=1",
781 "set cpu7 config=init_enable=1",
782 "set cpu7 config=store_size=4M",
783
784 // ; 0 = GCOS 1 = VMS
785 "set cpu7 config=mode=Multics",
786
787 "set cpu7 config=cache=enable",
788 "set cpu7 config=sdwam=enable",
789 "set cpu7 config=ptwam=enable",
790
791 // ; 0 = 8/70
792 "set cpu7 config=speed=0",
793
794 "set cpu7 config=dis_enable=enable",
795 "set cpu7 config=steady_clock=disable",
796 "set cpu7 config=halt_on_unimplemented=disable",
797 "set cpu7 config=disable_wam=enable",
798 "set cpu7 config=tro_enable=enable",
799 "set cpu7 config=y2k=disable",
800 #endif
801
802
803 // IOM0
804
805 "set iom0 config=iom_base=Multics",
806 "set iom0 config=multiplex_base=0120",
807 "set iom0 config=os=Multics",
808 "set iom0 config=boot=tape",
809 "set iom0 config=tapechan=012",
810 "set iom0 config=cardchan=011",
811 "set iom0 config=scuport=0",
812
813 "set iom0 config=port=0",
814 "set iom0 config=addr=0",
815 "set iom0 config=interlace=0",
816 "set iom0 config=enable=1",
817 "set iom0 config=initenable=0",
818 "set iom0 config=halfsize=0",
819 "set iom0 config=store_size=4M",
820
821 "set iom0 config=port=1",
822 "set iom0 config=addr=1",
823 "set iom0 config=interlace=0",
824 "set iom0 config=enable=1",
825 "set iom0 config=initenable=0",
826 "set iom0 config=halfsize=0",
827 "set iom0 config=store_size=4M",
828
829 "set iom0 config=port=2",
830 "set iom0 config=addr=2",
831 "set iom0 config=interlace=0",
832 "set iom0 config=enable=1",
833 "set iom0 config=initenable=0",
834 "set iom0 config=halfsize=0",
835 "set iom0 config=store_size=4M",
836
837 "set iom0 config=port=3",
838 "set iom0 config=addr=3",
839 "set iom0 config=interlace=0",
840 "set iom0 config=enable=1",
841 "set iom0 config=initenable=0",
842 "set iom0 config=halfsize=0",
843 "set iom0 config=store_size=4M",
844
845 "set iom0 config=port=4",
846 "set iom0 config=enable=0",
847
848 "set iom0 config=port=5",
849 "set iom0 config=enable=0",
850
851 "set iom0 config=port=6",
852 "set iom0 config=enable=0",
853
854 "set iom0 config=port=7",
855 "set iom0 config=enable=0",
856
857 // IOM1
858
859 "set iom1 config=iom_base=Multics2",
860 "set iom1 config=multiplex_base=0121",
861 "set iom1 config=os=Multics",
862 "set iom1 config=boot=tape",
863 "set iom1 config=tapechan=012",
864 "set iom1 config=cardchan=011",
865 "set iom1 config=scuport=0",
866
867 "set iom1 config=port=0",
868 "set iom1 config=addr=0",
869 "set iom1 config=interlace=0",
870 "set iom1 config=enable=1",
871 "set iom1 config=initenable=0",
872 "set iom1 config=halfsize=0;",
873
874 "set iom1 config=port=1",
875 "set iom1 config=addr=1",
876 "set iom1 config=interlace=0",
877 "set iom1 config=enable=1",
878 "set iom1 config=initenable=0",
879 "set iom1 config=halfsize=0;",
880
881 "set iom1 config=port=2",
882 "set iom1 config=enable=0",
883 "set iom1 config=port=3",
884 "set iom1 config=enable=0",
885 "set iom1 config=port=4",
886 "set iom1 config=enable=0",
887 "set iom1 config=port=5",
888 "set iom1 config=enable=0",
889 "set iom1 config=port=6",
890 "set iom1 config=enable=0",
891 "set iom1 config=port=7",
892 "set iom1 config=enable=0",
893
894 #if 0
895
896 // IOM2
897
898 "set iom2 config=iom_base=Multics2",
899 "set iom2 config=multiplex_base=0121",
900 "set iom2 config=os=Multics",
901 "set iom2 config=boot=tape",
902 "set iom2 config=tapechan=012",
903 "set iom2 config=cardchan=011",
904 "set iom2 config=scuport=0",
905
906 "set iom2 config=port=0",
907 "set iom2 config=addr=0",
908 "set iom2 config=interlace=0",
909 "set iom2 config=enable=1",
910 "set iom2 config=initenable=0",
911 "set iom2 config=halfsize=0;",
912
913 "set iom2 config=port=1",
914 "set iom2 config=addr=1",
915 "set iom2 config=interlace=0",
916 "set iom2 config=enable=1",
917 "set iom2 config=initenable=0",
918 "set iom2 config=halfsize=0;",
919
920 "set iom2 config=port=2",
921 "set iom2 config=enable=0",
922 "set iom2 config=port=3",
923 "set iom2 config=enable=0",
924 "set iom2 config=port=4",
925 "set iom2 config=enable=0",
926 "set iom2 config=port=5",
927 "set iom2 config=enable=0",
928 "set iom2 config=port=6",
929 "set iom2 config=enable=0",
930 "set iom2 config=port=7",
931 "set iom2 config=enable=0",
932
933
934 // IOM3
935
936 "set iom3 config=iom_base=Multics2",
937 "set iom3 config=multiplex_base=0121",
938 "set iom3 config=os=Multics",
939 "set iom3 config=boot=tape",
940 "set iom3 config=tapechan=012",
941 "set iom3 config=cardchan=011",
942 "set iom3 config=scuport=0",
943
944 "set iom3 config=port=0",
945 "set iom3 config=addr=0",
946 "set iom3 config=interlace=0",
947 "set iom3 config=enable=1",
948 "set iom3 config=initenable=0",
949 "set iom3 config=halfsize=0;",
950
951 "set iom3 config=port=1",
952 "set iom3 config=addr=1",
953 "set iom3 config=interlace=0",
954 "set iom3 config=enable=1",
955 "set iom3 config=initenable=0",
956 "set iom3 config=halfsize=0;",
957
958 "set iom3 config=port=2",
959 "set iom3 config=enable=0",
960 "set iom3 config=port=3",
961 "set iom3 config=enable=0",
962 "set iom3 config=port=4",
963 "set iom3 config=enable=0",
964 "set iom3 config=port=5",
965 "set iom3 config=enable=0",
966 "set iom3 config=port=6",
967 "set iom3 config=enable=0",
968 "set iom3 config=port=7",
969 "set iom3 config=enable=0",
970 #endif
971
972 // SCU0
973
974 "set scu0 config=mode=program",
975 "set scu0 config=port0=enable",
976 "set scu0 config=port1=enable",
977 "set scu0 config=port2=enable",
978 "set scu0 config=port3=enable",
979 "set scu0 config=port4=enable",
980 "set scu0 config=port5=enable",
981 "set scu0 config=port6=enable",
982 "set scu0 config=port7=enable",
983 "set scu0 config=maska=7",
984 "set scu0 config=maskb=off",
985 "set scu0 config=lwrstoresize=7",
986 "set scu0 config=cyclic=0040",
987 "set scu0 config=nea=0200",
988 "set scu0 config=onl=014",
989 "set scu0 config=int=0",
990 "set scu0 config=lwr=0",
991
992 // SCU1
993
994 "set scu1 config=mode=program",
995 "set scu1 config=port0=enable",
996 "set scu1 config=port1=enable",
997 "set scu1 config=port2=enable",
998 "set scu1 config=port3=enable",
999 "set scu1 config=port4=enable",
1000 "set scu1 config=port5=enable",
1001 "set scu1 config=port6=enable",
1002 "set scu1 config=port7=enable",
1003 "set scu1 config=maska=off",
1004 "set scu1 config=maskb=off",
1005 "set scu1 config=lwrstoresize=7",
1006 "set scu1 config=cyclic=0040",
1007 "set scu1 config=nea=0200",
1008 "set scu1 config=onl=014",
1009 "set scu1 config=int=0",
1010 "set scu1 config=lwr=0",
1011
1012 // SCU2
1013
1014 "set scu2 config=mode=program",
1015 "set scu2 config=port0=enable",
1016 "set scu2 config=port1=enable",
1017 "set scu2 config=port2=enable",
1018 "set scu2 config=port3=enable",
1019 "set scu2 config=port4=enable",
1020 "set scu2 config=port5=enable",
1021 "set scu2 config=port6=enable",
1022 "set scu2 config=port7=enable",
1023 "set scu2 config=maska=off",
1024 "set scu2 config=maskb=off",
1025 "set scu2 config=lwrstoresize=7",
1026 "set scu2 config=cyclic=0040",
1027 "set scu2 config=nea=0200",
1028 "set scu2 config=onl=014",
1029 "set scu2 config=int=0",
1030 "set scu2 config=lwr=0",
1031
1032 // SCU3
1033
1034 "set scu3 config=mode=program",
1035 "set scu3 config=port0=enable",
1036 "set scu3 config=port1=enable",
1037 "set scu3 config=port2=enable",
1038 "set scu3 config=port3=enable",
1039 "set scu3 config=port4=enable",
1040 "set scu3 config=port5=enable",
1041 "set scu3 config=port6=enable",
1042 "set scu3 config=port7=enable",
1043 "set scu3 config=maska=off",
1044 "set scu3 config=maskb=off",
1045 "set scu3 config=lwrstoresize=7",
1046 "set scu3 config=cyclic=0040",
1047 "set scu3 config=nea=0200",
1048 "set scu3 config=onl=014",
1049 "set scu3 config=int=0",
1050 "set scu3 config=lwr=0",
1051
1052 #if 0
1053 // SCU4
1054
1055 "set scu4 config=mode=program",
1056 "set scu4 config=port0=enable",
1057 "set scu4 config=port1=enable",
1058 "set scu4 config=port2=enable",
1059 "set scu4 config=port3=enable",
1060 "set scu4 config=port4=enable",
1061 "set scu4 config=port5=enable",
1062 "set scu4 config=port6=enable",
1063 "set scu4 config=port7=enable",
1064 "set scu4 config=maska=off",
1065 "set scu4 config=maskb=off",
1066 "set scu4 config=lwrstoresize=7",
1067 "set scu4 config=cyclic=0040",
1068 "set scu4 config=nea=0200",
1069 "set scu4 config=onl=014",
1070 "set scu4 config=int=0",
1071 "set scu4 config=lwr=0",
1072
1073 // SCU5
1074
1075 "set scu5 config=mode=program",
1076 "set scu5 config=port0=enable",
1077 "set scu5 config=port1=enable",
1078 "set scu5 config=port2=enable",
1079 "set scu5 config=port3=enable",
1080 "set scu5 config=port4=enable",
1081 "set scu5 config=port5=enable",
1082 "set scu5 config=port6=enable",
1083 "set scu5 config=port7=enable",
1084 "set scu5 config=maska=off",
1085 "set scu5 config=maskb=off",
1086 "set scu5 config=lwrstoresize=7",
1087 "set scu5 config=cyclic=0040",
1088 "set scu5 config=nea=0200",
1089 "set scu5 config=onl=014",
1090 "set scu5 config=int=0",
1091 "set scu5 config=lwr=0",
1092
1093 // SCU6
1094
1095 "set scu6 config=mode=program",
1096 "set scu6 config=port0=enable",
1097 "set scu6 config=port1=enable",
1098 "set scu6 config=port2=enable",
1099 "set scu6 config=port3=enable",
1100 "set scu6 config=port4=enable",
1101 "set scu6 config=port5=enable",
1102 "set scu6 config=port6=enable",
1103 "set scu6 config=port7=enable",
1104 "set scu6 config=maska=off",
1105 "set scu6 config=maskb=off",
1106 "set scu6 config=lwrstoresize=7",
1107 "set scu6 config=cyclic=0040",
1108 "set scu6 config=nea=0200",
1109 "set scu6 config=onl=014",
1110 "set scu6 config=int=0",
1111 "set scu6 config=lwr=0",
1112
1113 // SCU7
1114
1115 "set scu7 config=mode=program",
1116 "set scu7 config=port0=enable",
1117 "set scu7 config=port1=enable",
1118 "set scu7 config=port2=enable",
1119 "set scu7 config=port3=enable",
1120 "set scu7 config=port4=enable",
1121 "set scu7 config=port5=enable",
1122 "set scu7 config=port6=enable",
1123 "set scu7 config=port7=enable",
1124 "set scu7 config=maska=off",
1125 "set scu7 config=maskb=off",
1126 "set scu7 config=lwrstoresize=7",
1127 "set scu7 config=cyclic=0040",
1128 "set scu7 config=nea=0200",
1129 "set scu7 config=onl=014",
1130 "set scu7 config=int=0",
1131 "set scu7 config=lwr=0",
1132 #endif
1133
1134 // ; There are bugs in the FNP code that require sim unit number
1135 // ; to be the same as the Multics unit number; ie fnp0 == fnpa, etc.
1136 // ;
1137 // ; fnp a 3400
1138 // ; fnp b 3700
1139 // ; fnp c 4200
1140 // ; fnp d 4500
1141 // ; fnp e 5000
1142 // ; fnp f 5300
1143 // ; fnp g 5600
1144 // ; fnp h 6100
1145
1146 "set fnp0 config=mailbox=03400",
1147 "set fnp0 ipc_name=fnp-a",
1148 "set fnp1 config=mailbox=03700",
1149 "set fnp1 ipc_name=fnp-b",
1150 "set fnp2 config=mailbox=04200",
1151 "set fnp2 ipc_name=fnp-c",
1152 "set fnp3 config=mailbox=04500",
1153 "set fnp3 ipc_name=fnp-d",
1154 "set fnp4 config=mailbox=05000",
1155 "set fnp4 ipc_name=fnp-e",
1156 "set fnp5 config=mailbox=05300",
1157 "set fnp5 ipc_name=fnp-f",
1158 "set fnp6 config=mailbox=05600",
1159 "set fnp6 ipc_name=fnp-g",
1160 "set fnp7 config=mailbox=06100",
1161 "set fnp7 ipc_name=fnp-h",
1162
1163
1164 //XXX"set mtp0 boot_drive=1",
1165 // ; Attach tape MPC to IOM 0, chan 012, dev_code 0
1166 "set mtp0 boot_drive=0",
1167 "set mtp0 name=MTP0",
1168 // ; Attach TAPE unit 0 to IOM 0, chan 012, dev_code 1
1169 "cable IOM0 012 MTP0 0",
1170 "cable IOM1 012 MTP0 1",
1171 "cable MTP0 1 TAPE1",
1172 "set tape1 name=tapa_01",
1173 "cable MTP0 2 TAPE2",
1174 "set tape2 name=tapa_02",
1175 "cable MTP0 3 TAPE3",
1176 "set tape3 name=tapa_03",
1177 "cable MTP0 4 TAPE4",
1178 "set tape4 name=tapa_04",
1179 "cable MTP0 5 TAPE5",
1180 "set tape5 name=tapa_05",
1181 "cable MTP0 6 TAPE6",
1182 "set tape6 name=tapa_06",
1183 "cable MTP0 7 TAPE7",
1184 "set tape7 name=tapa_07",
1185 "cable MTP0 8 TAPE8",
1186 "set tape8 name=tapa_08",
1187 "cable MTP0 9 TAPE9",
1188 "set tape9 name=tapa_09",
1189 "cable MTP0 10 TAPE10",
1190 "set tape10 name=tapa_10",
1191 "cable MTP0 11 TAPE11",
1192 "set tape11 name=tapa_11",
1193 "cable MTP0 12 TAPE12",
1194 "set tape12 name=tapa_12",
1195 "cable MTP0 13 TAPE13",
1196 "set tape13 name=tapa_13",
1197 "cable MTP0 14 TAPE14",
1198 "set tape14 name=tapa_14",
1199 "cable MTP0 15 TAPE15",
1200 "set tape15 name=tapa_15",
1201 "cable MTP0 16 TAPE16",
1202 "set tape16 name=tapa_16",
1203
1204 // 4 3381 disks
1205
1206 "set ipc0 name=IPC0",
1207 "cable IOM0 013 IPC0 0",
1208 "cable IOM1 013 IPC0 1",
1209 // ; Attach DISK unit 0 to IPC0 dev_code 0",
1210 "cable IPC0 0 DISK0",
1211 "set disk0 type=3381",
1212 "set disk0 name=dska_00",
1213 // ; Attach DISK unit 1 to IPC0 dev_code 1",
1214 "cable IPC0 1 DISK1",
1215 "set disk1 type=3381",
1216 "set disk1 name=dska_01",
1217 // ; Attach DISK unit 2 to IPC0 dev_code 2",
1218 "cable IPC0 2 DISK2",
1219 "set disk2 type=3381",
1220 "set disk2 name=dska_02",
1221 // ; Attach DISK unit 3 to IPC0 dev_code 3",
1222 "cable IPC0 3 DISK3",
1223 "set disk3 type=3381",
1224 "set disk3 name=dska_03",
1225
1226 // 4 d501 disks + 4 d451 disks + 2 d500 disks
1227
1228 "set msp0 name=MSP0",
1229 "cable IOM0 014 MSP0 0",
1230 "cable IOM1 014 MSP0 1",
1231
1232 // ; Attach DISK unit 4 to MSP0 dev_code 1",
1233 "cable MSP0 1 DISK4",
1234 "set disk4 type=d501",
1235 "set disk4 name=dskb_01",
1236 // ; Attach DISK unit 5 to MSP0 dev_code 2",
1237 "cable MSP0 2 DISK5",
1238 "set disk5 type=d501",
1239 "set disk5 name=dskb_02",
1240 // ; Attach DISK unit 6 to MSP0 dev_code 3",
1241 "cable MSP0 3 DISK6",
1242 "set disk6 type=d501",
1243 "set disk6 name=dskb_03",
1244 // ; Attach DISK unit 7 to MSP0 dev_code 4",
1245 "cable MSP0 4 DISK7",
1246 "set disk7 type=d501",
1247 "set disk7 name=dskb_04",
1248
1249 // ; Attach DISK unit 8 to MSP0 dev_code 5",
1250 "cable MSP0 5 DISK8",
1251 "set disk8 type=d451",
1252 "set disk8 name=dskb_05",
1253 // ; Attach DISK unit 9 to MSP0 dev_code 6",
1254 "cable MSP0 6 DISK9",
1255 "set disk9 type=d451",
1256 "set disk9 name=dskb_06",
1257 // ; Attach DISK unit 10 to MSP0 dev_code 7",
1258 "cable MSP0 7 DISK10",
1259 "set disk10 type=d451",
1260 "set disk10 name=dskb_07",
1261 // ; Attach DISK unit 11 to MSP0 dev_code 8",
1262 "cable MSP0 8 DISK11",
1263 "set disk11 type=d451",
1264 "set disk11 name=dskb_08",
1265 // ; Attach DISK unit 12 to MSP0 dev_code 9",
1266 "cable MSP0 9 DISK12",
1267 "set disk12 type=d500",
1268 "set disk12 name=dskb_09",
1269 // ; Attach DISK unit 13 to MSP0 dev_code 10",
1270 "cable MSP0 10 DISK13",
1271 "set disk13 type=d500",
1272 "set disk13 name=dskb_10",
1273
1274 // since we define 16 (decimal) 3381s in the default config deck, we need to add another 12
1275 // ; Attach DISK unit 14 to IPC0 dev_code 4",
1276 "cable IPC0 4 DISK14",
1277 "set disk14 type=3381",
1278 "set disk14 name=dska_04",
1279 // ; Attach DISK unit 15 to IPC0 dev_code 5",
1280 "cable IPC0 5 DISK15",
1281 "set disk15 type=3381",
1282 "set disk15 name=dska_05",
1283 // ; Attach DISK unit 16 to IPC0 dev_code 6",
1284 "cable IPC0 6 DISK16",
1285 "set disk16 type=3381",
1286 "set disk16 name=dska_06",
1287 // ; Attach DISK unit 17 to IPC0 dev_code 7",
1288 "cable IPC0 7 DISK17",
1289 "set disk17 type=3381",
1290 "set disk17 name=dska_07",
1291 // ; Attach DISK unit 18 to IPC0 dev_code 8",
1292 "cable IPC0 8 DISK18",
1293 "set disk18 type=3381",
1294 "set disk18 name=dska_08",
1295 // ; Attach DISK unit 19 to IPC0 dev_code 9",
1296 "cable IPC0 9 DISK19",
1297 "set disk19 type=3381",
1298 "set disk19 name=dska_09",
1299 // ; Attach DISK unit 20 to IPC0 dev_code 10",
1300 "cable IPC0 10 DISK20",
1301 "set disk20 type=3381",
1302 "set disk20 name=dska_10",
1303 // ; Attach DISK unit 21 to IPC0 dev_code 11",
1304 "cable IPC0 11 DISK21",
1305 "set disk21 type=3381",
1306 "set disk21 name=dska_11",
1307 // ; Attach DISK unit 22 to IPC0 dev_code 12",
1308 "cable IPC0 12 DISK22",
1309 "set disk22 type=3381",
1310 "set disk22 name=dska_12",
1311 // ; Attach DISK unit 23 to IPC0 dev_code 13",
1312 "cable IPC0 13 DISK23",
1313 "set disk23 type=3381",
1314 "set disk23 name=dska_13",
1315 // ; Attach DISK unit 24 to IPC0 dev_code 14",
1316 "cable IPC0 14 DISK24",
1317 "set disk24 type=3381",
1318 "set disk24 name=dska_14",
1319 // ; Attach DISK unit 25 to IPC0 dev_code 15",
1320 "cable IPC0 15 DISK25",
1321 "set disk25 type=3381",
1322 "set disk25 name=dska_15",
1323
1324 // ; Attach OPC unit 0 to IOM A, chan 036, dev_code 0
1325 "cable IOMA 036 opc0",
1326 "cable IOMA 053 opc1",
1327 "set opc1 config=model=m6601",
1328 // No devices for console, so no 'cable OPC0 # CONx'
1329
1330 // ;;;
1331 // ;;; FNP
1332 // ;;;
1333
1334 // ; Attach FNP unit 3 (d) to IOM A, chan 020, dev_code 0
1335 "cable IOMA 020 FNPD",
1336 // ; Attach FNP unit 0 (a) to IOM A, chan 021, dev_code 0
1337 "cable IOMA 021 FNPA",
1338 // ; Attach FNP unit 1 (b) to IOM A, chan 022, dev_code 0
1339 "cable IOMA 022 FNPB",
1340 // ; Attach FNP unit 2 (c) to IOM A, chan 023, dev_code 0
1341 "cable IOMA 023 FNPC",
1342 // ; Attach FNP unit 4 (e) to IOM A, chan 024, dev_code 0
1343 "cable IOMA 024 FNPE",
1344 // ; Attach FNP unit 5 (f) to IOM A, chan 025, dev_code 0
1345 "cable IOMA 025 FNPF",
1346 // ; Attach FNP unit 6 (g) to IOM A, chan 026, dev_code 0
1347 "cable IOMA 026 FNPG",
1348 // ; Attach FNP unit 7 (h) to IOM A, chan 027, dev_code 0
1349 "cable IOMA 027 FNPH",
1350
1351 // ;;;
1352 // ;;; MPC
1353 // ;;;
1354
1355 // ; Attach MPC unit 0 to IOM 0, char 015, dev_code 0
1356 "cable IOM0 015 URP0",
1357 "set urp0 name=urpa",
1358
1359 // ; Attach RDR unit 0 to IOM 0, chan 015, dev_code 1
1360 "cable URP0 1 RDR0",
1361 "set rdr0 name=rdra",
1362
1363 // ; Attach MPC unit 1 to IOM 0, char 016, dev_code 0
1364 "cable IOM0 016 URP1",
1365 "set urp1 name=urpb",
1366
1367 // ; Attach PUN unit 0 to IOM 0, chan 016, dev_code 1
1368 "cable URP1 1 PUN0",
1369 "set pun0 name=puna",
1370
1371 // ; Attach MPC unit 2 to IOM 0, char 017, dev_code 0
1372 "cable IOM0 017 URP2",
1373 "set urp2 name=urpc",
1374
1375 // ; Attach PRT unit 0 to IOM 0, chan 017, dev_code 1
1376 "set prt0 name=prta",
1377 // "set prt0 model=1600", // Needs polts fixes
1378 "cable URP2 1 PRT0",
1379
1380 // ; Attach MPC unit 3 to IOM 0, char 050, dev_code 0
1381 "cable ioma 050 urp3",
1382 "set urp3 name=urpd",
1383
1384 // ; Attach PRT unit 1 to IOM 0, chan 050, dev_code 1
1385 "set prt1 name=prtb",
1386 // "set prt1 model=303", // Needs polts fixes
1387 "cable urp3 1 prt1",
1388
1389 // ; Attach MPC unit 4 to IOM 0, char 051, dev_code 0
1390 "cable ioma 051 urp4",
1391 "set urp4 name=urpe",
1392
1393 // ; Attach PRT unit 2 to IOM 0, chan 051, dev_code 1
1394 "set prt2 name=prtc",
1395 // "set prt2 model=300", // Needs polts fixes
1396 "cable urp4 1 prt2",
1397
1398 // ; Attach MPC unit 5 to IOM 0, chan 052, dev_code 0
1399 "cable ioma 052 urp5",
1400 "set urp5 name=urpf",
1401
1402 // ; Attach PRT unit 3 to IOM 0, chan 052, dev_code 1
1403 "set prt3 name=prtd",
1404 // "set prt3 model=202", // Needs polts fixes
1405 "cable urp5 1 prt3",
1406
1407 // ; Attach MPC unit 6 to IOM 0, chan 055, dev_code 0
1408 "cable ioma 055 urp6",
1409 "set urp6 name=urpg",
1410
1411 // ; Attach RDR unit 1 to IOM 0, chan 055, dev_code 1
1412 "set rdr1 name=rdrb",
1413 "cable urp6 1 rdrb",
1414
1415 // ; Attach MPC unit 7 to IOM 0, chan 056, dev_code 0
1416 "cable ioma 056 urp7",
1417 "set urp7 name=urph",
1418
1419 // ; Attach RDR unit 2 to IOM 0, chan 056, dev_code 1
1420 "set rdr2 name=rdrc",
1421 "cable urp7 1 rdrc",
1422
1423 // ; Attach MPC unit 8 to IOM 0, chan 057, dev_code 0
1424 "cable ioma 057 urp8",
1425 "set urp8 name=urpi",
1426
1427 // ; Attach PUN unit 1 to IOM 0, chan 057, dev_code 1
1428 "set pun1 name=punb",
1429 "cable urp8 1 punb",
1430
1431 // ; Attach MPC unit 9 to IOM 0, chan 060, dev_code 0
1432 "cable ioma 060 urp9",
1433 "set urp9 name=urpj",
1434
1435 // ; Attach PUN unit 2 to IOM 0, chan 060, dev_code 1
1436 "set pun2 name=punc",
1437 "cable urp9 1 punc",
1438
1439 #ifndef __MINGW64__
1440 # ifndef __MINGW32__
1441 # ifndef CROSS_MINGW32
1442 # ifndef CROSS_MINGW64
1443 "cable IOMA 040 SKCA",
1444 "cable IOMA 041 SKCB",
1445 "cable IOMA 042 SKCC",
1446 "cable IOMA 043 SKCD",
1447 "cable IOMA 044 SKCE",
1448 "cable IOMA 045 SKCF",
1449 "cable IOMA 046 SKCG",
1450 "cable IOMA 047 SKCH",
1451 # endif /* ifndef CROSS_MINGW64 */
1452 # endif /* ifndef CROSS_MINGW32 */
1453 # endif /* ifndef __MINGW32__ */
1454 #endif /* ifndef __MINGW64__ */
1455
1456 #if 0
1457 // ; Attach PRT unit 1 to IOM 0, chan 017, dev_code 2
1458 "set prt1 name=prtb",
1459 "cable URP2 2 PRT1",
1460
1461 // ; Attach PRT unit 2 to IOM 0, chan 017, dev_code 3
1462 "set prt2 name=prtc",
1463 "cable URP2 3 PRT2",
1464
1465 // ; Attach PRT unit 3 to IOM 0, chan 017, dev_code 4
1466 "cable URP2 4 PRT3",
1467 "set prt3 name=prtd",
1468
1469 // ; Attach PRT unit 4 to IOM 0, chan 017, dev_code 5
1470 "cable URP2 5 PRT4",
1471 "set prt4 name=prte",
1472
1473 // ; Attach PRT unit 5 to IOM 0, chan 017, dev_code 6
1474 "cable URP2 6 PRT5",
1475 "set prt5 name=prtf",
1476
1477 // ; Attach PRT unit 6 to IOM 0, chan 017, dev_code 7
1478 "cable URP2 7 PRT6",
1479 "set prt6 name=prtg",
1480
1481 // ; Attach PRT unit 7 to IOM 0, chan 017, dev_code 8
1482 "cable URP2 8 PRT7",
1483 "set prt7 name=prth",
1484
1485 // ; Attach PRT unit 8 to IOM 0, chan 017, dev_code 9
1486 "cable URP2 9 PRT8",
1487 "set prt8 name=prti",
1488
1489 // ; Attach PRT unit 9 to IOM 0, chan 017, dev_code 10
1490 "cable URP2 10 PRT9",
1491 "set prt9 name=prtj",
1492
1493 // ; Attach PRT unit 10 to IOM 0, chan 017, dev_code 11
1494 "cable URP2 11 PRT10",
1495 "set prt10 name=prtk",
1496
1497 // ; Attach PRT unit 11 to IOM 0, chan 017, dev_code 12
1498 "cable URP2 12 PRT11",
1499 "set prt11 name=prtl",
1500
1501 // ; Attach PRT unit 12 to IOM 0, chan 017, dev_code 13
1502 "cable URP2 13 PRT12",
1503 "set prt12 name=prtm",
1504
1505 // ; Attach PRT unit 13 to IOM 0, chan 017, dev_code 14
1506 "cable URP2 14 PRT13",
1507 "set prt13 name=prtn",
1508
1509 // ; Attach PRT unit 14 to IOM 0, chan 017, dev_code 15
1510 "cable URP2 15 PRT14",
1511 "set prt14 name=prto",
1512
1513 // ; Attach PRT unit 15 to IOM 0, chan 017, dev_code 16
1514 "set prt15 name=prtp",
1515
1516 // ; Attach PRT unit 16 to IOM 0, chan 017, dev_code 17
1517 "set prt16 name=prtq",
1518 #endif
1519
1520 #ifndef __MINGW64__
1521 # ifndef __MINGW32__
1522 # ifndef CROSS_MINGW64
1523 # ifndef CROSS_MINGW32
1524 // ; Attach ABSI unit 0 to IOM 0, chan 032, dev_code 0
1525 "cable IOM0 032 ABSI0",
1526 # endif /* CROSS_MINGW32 */
1527 # endif /* CROSS_MINGW64 */
1528 # endif /* __MINGW32__ */
1529 #endif /* __MINGW64__ */
1530
1531 // ; Attach IOM unit 0 port A (0) to SCU unit 0, port 0
1532 "cable SCU0 0 IOM0 0", // SCU0 port 0 IOM0 port 0
1533
1534 // ; Attach IOM unit 0 port B (1) to SCU unit 1, port 0
1535 "cable SCU1 0 IOM0 1", // SCU1 port 0 IOM0 port 1
1536
1537 // ; Attach IOM unit 0 port C (2) to SCU unit 2, port 0
1538 "cable SCU2 0 IOM0 2", // SCU2 port 0 IOM0 port 2
1539
1540 // ; Attach IOM unit 0 port D (3) to SCU unit 3, port 0
1541 "cable SCU3 0 IOM0 3", // SCU3 port 0 IOM0 port 3
1542
1543 // ; Attach IOM unit 1 port A (0) to SCU unit 0, port 1
1544 "cable SCU0 1 IOM1 0", // SCU0 port 0 IOM0 port 0
1545
1546 // ; Attach IOM unit 1 port B (1) to SCU unit 1, port 1
1547 "cable SCU1 1 IOM1 1", // SCU1 port 0 IOM0 port 1
1548
1549 // ; Attach IOM unit 1 port C (2) to SCU unit 2, port 1
1550 "cable SCU2 1 IOM1 2", // SCU2 port 0 IOM0 port 2
1551
1552 // ; Attach IOM unit 1 port D (3) to SCU unit 3, port 1
1553 "cable SCU3 1 IOM1 3", // SCU3 port 0 IOM0 port 3
1554
1555 // SCU0 --> CPU0-5
1556
1557 // ; Attach SCU unit 0 port 7 to CPU unit A (1), port 0
1558 "cable SCU0 7 CPU0 0",
1559
1560 // ; Attach SCU unit 0 port 6 to CPU unit B (1), port 0
1561 "cable SCU0 6 CPU1 0",
1562
1563 // ; Attach SCU unit 0 port 5 to CPU unit C (2), port 0
1564 "cable SCU0 5 CPU2 0",
1565
1566 // ; Attach SCU unit 0 port 4 to CPU unit D (3), port 0
1567 "cable SCU0 4 CPU3 0",
1568
1569 // ; Attach SCU unit 0 port 3 to CPU unit E (4), port 0
1570 "cable SCU0 3 CPU4 0",
1571
1572 // ; Attach SCU unit 0 port 2 to CPU unit F (5), port 0
1573 "cable SCU0 2 CPU5 0",
1574
1575 // SCU1 --> CPU0-5
1576
1577 // ; Attach SCU unit 1 port 7 to CPU unit A (1), port 1
1578 "cable SCU1 7 CPU0 1",
1579
1580 // ; Attach SCU unit 1 port 6 to CPU unit B (1), port 1
1581 "cable SCU1 6 CPU1 1",
1582
1583 // ; Attach SCU unit 1 port 5 to CPU unit C (2), port 1
1584 "cable SCU1 5 CPU2 1",
1585
1586 // ; Attach SCU unit 1 port 4 to CPU unit D (3), port 1
1587 "cable SCU1 4 CPU3 1",
1588
1589 // ; Attach SCU unit 1 port 3 to CPU unit E (4), port 0
1590 "cable SCU1 3 CPU4 1",
1591
1592 // ; Attach SCU unit 1 port 2 to CPU unit F (5), port 0
1593 "cable SCU1 2 CPU5 1",
1594
1595 // SCU2 --> CPU0-5
1596
1597 // ; Attach SCU unit 2 port 7 to CPU unit A (1), port 2
1598 "cable SCU2 7 CPU0 2",
1599
1600 // ; Attach SCU unit 2 port 6 to CPU unit B (1), port 2
1601 "cable SCU2 6 CPU1 2",
1602
1603 // ; Attach SCU unit 2 port 5 to CPU unit C (2), port 2
1604 "cable SCU2 5 CPU2 2",
1605
1606 // ; Attach SCU unit 2 port 4 to CPU unit D (3), port 2
1607 "cable SCU2 4 CPU3 2",
1608
1609 // ; Attach SCU unit 2 port 3 to CPU unit E (4), port 0
1610 "cable SCU2 3 CPU4 2",
1611
1612 // ; Attach SCU unit 2 port 2 to CPU unit F (5), port 0
1613 "cable SCU2 2 CPU5 2",
1614
1615
1616 // SCU3 --> CPU0-5
1617
1618 // ; Attach SCU unit 3 port 7 to CPU unit A (1), port 3
1619 "cable SCU3 7 CPU0 3",
1620
1621 // ; Attach SCU unit 3 port 6 to CPU unit B (1), port 3
1622 "cable SCU3 6 CPU1 3",
1623
1624 // ; Attach SCU unit 3 port 5 to CPU unit C (2), port 3
1625 "cable SCU3 5 CPU2 3",
1626
1627 // ; Attach SCU unit 3 port 4 to CPU unit D (3), port 3
1628 "cable SCU3 4 CPU3 3",
1629
1630 // ; Attach SCU unit 3 port 3 to CPU unit E (4), port 0
1631 "cable SCU3 3 CPU4 3",
1632
1633 // ; Attach SCU unit 3 port 2 to CPU unit F (5), port 0
1634 "cable SCU3 2 CPU5 3",
1635
1636
1637 "set cpu0 reset",
1638 "set scu0 reset",
1639 "set scu1 reset",
1640 "set scu2 reset",
1641 "set scu3 reset",
1642 "set iom0 reset",
1643
1644 #if defined(THREADZ) || defined(LOCKLESS)
1645 "set cpu nunits=6",
1646 #else
1647 "set cpu nunits=1",
1648 #endif // THREADZ
1649 // "set sys config=activate_time=8",
1650 // "set sys config=terminate_time=8",
1651 "set sys config=connect_time=-1",
1652
1653 #if 0
1654 "fnpload Devices.txt",
1655 #endif
1656 "fnpserverport 6180"
1657 }; // default_base_system_script
1658
1659 // Execute a line of script
1660
do_ini_line(char * text)1661 static void do_ini_line (char * text)
1662 {
1663 //sim_msg ("<%s?\n", text);
1664 char gbuf[257];
1665 const char * cptr = get_glyph (text, gbuf, 0); /* get command glyph */
1666 CTAB *cmdp;
1667 if ((cmdp = find_cmd (gbuf))) /* lookup command */
1668 {
1669 t_stat stat = cmdp->action (cmdp->arg, cptr); /* if found, exec */
1670 if (stat != SCPE_OK)
1671 sim_warn ("%s: %s\n", sim_error_text (SCPE_UNK), text);
1672 }
1673 else
1674 sim_warn ("%s: %s\n", sim_error_text (SCPE_UNK), text);
1675 }
1676
1677 // Execute the base system script; this strings the cables
1678 // and sets the switches
1679
set_default_base_system(UNUSED int32 arg,UNUSED const char * buf)1680 static t_stat set_default_base_system (UNUSED int32 arg, UNUSED const char * buf)
1681 {
1682 #ifdef PERF_STRIP
1683 cpu_dev.numunits = 1;
1684 #else
1685 int n_lines = sizeof (default_base_system_script) / sizeof (char *);
1686 for (int line = 0; line < n_lines; line ++)
1687 do_ini_line (default_base_system_script [line]);
1688 #endif
1689 return SCPE_OK;
1690 }
1691
1692 // Control access to the 'machine room' HTTP server
1693
set_machine_room_port(UNUSED int32 arg,const char * buf)1694 static t_stat set_machine_room_port (UNUSED int32 arg, const char * buf)
1695 {
1696 if (! buf)
1697 return SCPE_ARG;
1698 int n = atoi (buf);
1699 if (n < 0 || n > 65535) // 0 is 'disable'
1700 return SCPE_ARG;
1701 sys_opts.machine_room_access.port = n;
1702 sim_msg ("Machine room port set to %d\n", n);
1703 return SCPE_OK;
1704 }
1705
set_machine_room_address(UNUSED int32 arg,const char * buf)1706 static t_stat set_machine_room_address (UNUSED int32 arg, const char * buf)
1707 {
1708 if (sys_opts.machine_room_access.address)
1709 free (sys_opts.machine_room_access.address);
1710 sys_opts.machine_room_access.address = strdup (buf);
1711 sim_msg ("Machine room address set to %s\n", sys_opts.machine_room_access.address);
1712 return SCPE_OK;
1713 }
1714
set_machine_room_pw(UNUSED int32 arg,UNUSED const char * buf)1715 static t_stat set_machine_room_pw (UNUSED int32 arg, UNUSED const char * buf)
1716 {
1717 if (strlen (buf) == 0)
1718 {
1719 sim_warn ("no password\n");
1720 sys_opts.machine_room_access.pw[0] = 0;
1721 return SCPE_OK;
1722 }
1723 char token[strlen (buf)];
1724 //sim_msg ("<%s>\n", buf);
1725 int rc = sscanf (buf, "%s", token);
1726 if (rc != 1)
1727 return SCPE_ARG;
1728 if (strlen (token) > PW_SIZE)
1729 return SCPE_ARG;
1730 strcpy (sys_opts.machine_room_access.pw, token);
1731 //sim_msg ("<%s>\n", token);
1732 return SCPE_OK;
1733 }
1734
1735 // Skip records on the boot tape.
1736 // The T&D tape first record is for testing DPS8s, the
1737 // second record (1st record / tape mark / 2nd record)
1738 // is for testing DPS8/Ms.
1739 // XXX assumes the boot tape is on SIMH tape unit 0 XXX
1740
boot_skip(int32 UNUSED arg,UNUSED const char * buf)1741 static t_stat boot_skip (int32 UNUSED arg, UNUSED const char * buf)
1742 {
1743 uint32 skipped;
1744 t_stat rc = sim_tape_sprecsf (& mt_unit[0], 1, & skipped);
1745 if (rc == SCPE_OK)
1746 tape_states[0].rec_num ++;
1747 return rc;
1748 }
1749
1750 // Simulate pressing the 'EXECUTE FAULT' button. Used as an
1751 // emergency interrupt of Multics if it hangs and becomes
1752 // unresponive to the operators console.
1753
do_execute_fault(UNUSED int32 arg,UNUSED const char * buf)1754 static t_stat do_execute_fault (UNUSED int32 arg, UNUSED const char * buf)
1755 {
1756 // Assume bootload CPU
1757 setG7fault (0, FAULT_EXF, fst_zero);
1758 return SCPE_OK;
1759 }
1760
1761 // Simulate pressing the 'XED 10000' sequence; this starts BCE
1762 //
1763 // sim> restart
1764 // sim> go
1765
do_restart(UNUSED int32 arg,UNUSED const char * buf)1766 static t_stat do_restart (UNUSED int32 arg, UNUSED const char * buf)
1767 {
1768 if (sim_is_running)
1769 {
1770 sim_printf ("Don't restart a running system....\r\n");
1771 return SCPE_ARG;
1772 }
1773 int n = 010000;
1774 if (buf)
1775 {
1776 n = (int) strtol (buf, NULL, 0);
1777 }
1778 sim_printf ("Restart entry 0%o\n", n);
1779
1780 #if 0
1781 // Assume bootload CPU
1782 cpu.cu.IWB = M [n] & MASK36;
1783 cpu.cu.IRODD = M [n + 1] & MASK36;
1784 cpu.cu.xde = 1;
1785 cpu.cu.xdo = 1;
1786 cpu.isExec = true;
1787 cpu.isXED = true;
1788 cpu.cycle = FAULT_EXEC_cycle;
1789 set_addr_mode (ABSOLUTE_mode);
1790 #endif
1791
1792 cpu_reset_unit_idx (0, false);
1793 cpu.restart = true;
1794 cpu.restart_address = (uint) n;
1795
1796 t_stat rc = run_cmd (RU_CONT, "");
1797 return rc;
1798 }
1799
set_sys_polling_interval(UNUSED int32 arg,const char * buf)1800 static t_stat set_sys_polling_interval (UNUSED int32 arg, const char * buf)
1801 {
1802 if (! buf)
1803 return SCPE_ARG;
1804 int n = atoi (buf);
1805 if (n < 1 || n > 1000) // 1 millisecond to 1 second
1806 {
1807 sim_printf ("POLL %d: must be 1 (1 millisecond) to 1000 (1 second)\r\n", n);
1808 return SCPE_ARG;
1809 }
1810 sim_printf ("Polling set to %d milliseconds\r\n", n);
1811 sys_opts.sys_poll_interval = (uint) n;
1812 return SCPE_OK;
1813 }
1814
set_sys_slow_polling_interval(UNUSED int32 arg,const char * buf)1815 static t_stat set_sys_slow_polling_interval (UNUSED int32 arg, const char * buf)
1816 {
1817 if (! buf)
1818 return SCPE_ARG;
1819 int n = atoi (buf);
1820 if (n < 1 || n > 1000) // 1 - slow poll every pool; 1000 - slow poll every 1000 polls
1821 {
1822 sim_printf ("SLOWPOLL %d: must be 1 (1 slow poll per pol) to 1000 (1 slow poll per 1000 polls)\r\n", n);
1823 return SCPE_ARG;
1824 }
1825 sim_printf ("Slow polling set to %d polls\r\n", n);
1826 sys_opts.sys_slow_poll_interval = (uint) n;
1827 return SCPE_OK;
1828 }
1829
set_sys_poll_check_rate(UNUSED int32 arg,const char * buf)1830 static t_stat set_sys_poll_check_rate (UNUSED int32 arg, const char * buf)
1831 {
1832 if (! buf)
1833 return SCPE_ARG;
1834 int n = atoi (buf);
1835 if (n < 1 || n > 1024*1024) // 1 - poll check rate in CPY cycles: 1 - check every cycle; 1024 check every 1024 cycles
1836 {
1837 sim_printf ("CHECKPOLL %d: must be 1 (check every cycle) to 1048576 (ckeck every million cycles\r\n", n);
1838 return SCPE_ARG;
1839 }
1840 sim_printf ("Poll check rate set to %d CPU cycles\r\n", n);
1841 sys_opts.sys_poll_check_rate = (uint) n;
1842 return SCPE_OK;
1843 }
1844
1845 //
1846 // Debugging commands
1847 //
1848
1849 #ifdef TESTING
1850
1851 // Filter settings for our customized sim_debug
1852
1853 // Start debug output at CPU cycle N.
1854 uint64 sim_deb_start = 0;
1855 // Stop debug outout at CPU cycle N.
1856 uint64 sim_deb_stop = 0;
1857 // Break to simh prompt at CPU cycle N.
1858 uint64 sim_deb_break = 0;
1859 // Enable CPU sim_debug iff PPR.PSR == N
1860 bool sim_deb_segno_on = false;
1861 # ifdef NO_C_ELLIPSIS
1862 bool sim_deb_segno[DEBUG_SEGNO_LIMIT];
1863 # else
1864 bool sim_deb_segno[DEBUG_SEGNO_LIMIT] = { [0 ... DEBUG_SEGNO_LIMIT - 1] = false };
1865 # endif
1866 // Enable CPU sim_debug iff PPR.PRR == N
1867 uint64 sim_deb_ringno = NO_SUCH_RINGNO;
1868 // Supress CPU sim_debug calls that pass all
1869 // of the filters after N times
1870 uint64 sim_deb_skip_limit = 0;
1871 // Supress the first N CPU sim_debug calls
1872 // that pass all of the filters
1873 uint64 sim_deb_skip_cnt = 0;
1874 // Supress sim_debug until the MME instruction
1875 // has been executed N times
1876 uint64 sim_deb_mme_cntdwn = 0;
1877 // Supress CPU sim_debug unless CPU number bit set
1878 uint dbgCPUMask = 0377; // default all 8 on
1879
1880 // Supress CPU sim_debug unless BAR mode
1881 bool sim_deb_bar = false;
1882
1883 // Set the various filters
1884
dps_debug_mme_cntdwn(UNUSED int32 arg,const char * buf)1885 static t_stat dps_debug_mme_cntdwn (UNUSED int32 arg, const char * buf)
1886 {
1887 sim_deb_mme_cntdwn = strtoull (buf, NULL, 0);
1888 sim_msg ("Debug MME countdown set to %"PRId64"\n", sim_deb_mme_cntdwn);
1889 return SCPE_OK;
1890 }
1891
dps_debug_skip(UNUSED int32 arg,const char * buf)1892 static t_stat dps_debug_skip (UNUSED int32 arg, const char * buf)
1893 {
1894 sim_deb_skip_cnt = 0;
1895 sim_deb_skip_limit = strtoull (buf, NULL, 0);
1896 sim_msg ("Debug skip set to %"PRId64"\n", sim_deb_skip_limit);
1897 return SCPE_OK;
1898 }
1899
dps_debug_start(UNUSED int32 arg,const char * buf)1900 static t_stat dps_debug_start (UNUSED int32 arg, const char * buf)
1901 {
1902 sim_deb_start = strtoull (buf, NULL, 0);
1903 sim_msg ("Debug set to start at cycle: %"PRId64"\n", sim_deb_start);
1904 return SCPE_OK;
1905 }
1906
dps_debug_stop(UNUSED int32 arg,const char * buf)1907 static t_stat dps_debug_stop (UNUSED int32 arg, const char * buf)
1908 {
1909 sim_deb_stop = strtoull (buf, NULL, 0);
1910 sim_msg ("Debug set to stop at cycle: %"PRId64"\n", sim_deb_stop);
1911 return SCPE_OK;
1912 }
1913
dps_debug_break(UNUSED int32 arg,const char * buf)1914 static t_stat dps_debug_break (UNUSED int32 arg, const char * buf)
1915 {
1916 sim_deb_break = strtoull (buf, NULL, 0);
1917 if (buf[0] == '+')
1918 sim_deb_break += sim_deb_start;
1919 sim_msg ("Debug set to break at cycle: %"PRId64"\n", sim_deb_break);
1920 return SCPE_OK;
1921 }
1922
dps_debug_segno(int32 arg,const char * buf)1923 static t_stat dps_debug_segno (int32 arg, const char * buf)
1924 {
1925 if (arg)
1926 {
1927 unsigned long segno = strtoul (buf, NULL, 0);
1928 if (segno >= DEBUG_SEGNO_LIMIT)
1929 {
1930 sim_printf ("out of range; 0 to %u %d.\n", DEBUG_SEGNO_LIMIT, DEBUG_SEGNO_LIMIT);
1931 return SCPE_ARG;
1932 }
1933 sim_deb_segno[segno] = true;
1934 sim_deb_segno_on = true;
1935 sim_msg ("Debug set for segno %lo %ld.\n", segno, segno);
1936 }
1937 else
1938 {
1939 memset (sim_deb_segno, 0, sizeof (sim_deb_segno));
1940 sim_deb_segno_on = false;
1941 sim_msg ("Debug set for all segments\n");
1942 }
1943 return SCPE_OK;
1944 }
1945
dps_debug_ringno(UNUSED int32 arg,const char * buf)1946 static t_stat dps_debug_ringno (UNUSED int32 arg, const char * buf)
1947 {
1948 sim_deb_ringno = strtoull (buf, NULL, 0);
1949 sim_msg ("Debug set to ringno %"PRIo64"\n", sim_deb_ringno);
1950 return SCPE_OK;
1951 }
1952
dps_debug_bar(int32 arg,UNUSED const char * buf)1953 static t_stat dps_debug_bar (int32 arg, UNUSED const char * buf)
1954 {
1955 sim_deb_bar = arg;
1956 if (arg)
1957 sim_msg ("Debug set BAR %"PRIo64"\n", sim_deb_ringno);
1958 else
1959 sim_msg ("Debug unset BAR %"PRIo64"\n", sim_deb_ringno);
1960 return SCPE_OK;
1961 }
1962
1963 # if 0
1964 t_stat computeAbsAddrN (word24 * abs_addr, int segno, uint offset)
1965 {
1966 word24 res;
1967
1968 if (get_addr_mode () != APPEND_mode)
1969 {
1970 sim_warn ("CPU not in append mode\n");
1971 return SCPE_ARG;
1972 }
1973
1974 if (cpu.DSBR.U == 1) // Unpaged
1975 {
1976 if (2 * (uint) /*TPR.TSR*/ segno >= 16 * ((uint) cpu.DSBR.BND + 1))
1977 {
1978 sim_warn ("DSBR boundary violation.\n");
1979 return SCPE_ARG;
1980 }
1981
1982 // 2. Fetch the target segment SDW from cpu.DSBR.ADDR + 2 * segno.
1983
1984 word36 SDWe, SDWo;
1985 core_read ((cpu.DSBR.ADDR + 2U * /*TPR.TSR*/ (uint) segno) & PAMASK,
1986 & SDWe, __func__);
1987 core_read ((cpu.DSBR.ADDR + 2U * /*TPR.TSR*/ (uint) segno + 1) & PAMASK,
1988 & SDWo, __func__);
1989
1990 // 3. If SDW.DF = 0, then generate directed fault n where n is given in
1991 // SDW.FC. The value of n used here is the value assigned to define a
1992 // missing segment fault or, simply, a segment fault.
1993
1994 // abs_addr doesn't care if the page isn't resident
1995
1996
1997 // 4. If offset >= 16 * (SDW.BOUND + 1), then generate an access
1998 // violation, out of segment bounds, fault.
1999
2000 word14 BOUND = (SDWo >> (35 - 14)) & 037777;
2001 if (/*TPR.CA*/ offset >= 16 * (BOUND + 1))
2002 {
2003 sim_warn ("SDW boundary violation.\n");
2004 return SCPE_ARG;
2005 }
2006
2007 // 5. If the access bits (SDW.R, SDW.E, etc.) of the segment are
2008 // incompatible with the reference, generate the appropriate access
2009 // violation fault.
2010
2011 // abs_addr doesn't care
2012
2013 // 6. Generate 24-bit absolute main memory address SDW.ADDR + offset.
2014
2015 word24 ADDR = (SDWe >> 12) & 077777760;
2016 res = (word24) ADDR + (word24) /*TPR.CA*/ offset;
2017 res &= PAMASK; //24 bit math
2018 //res <<= 12; // 24:12 format
2019
2020 }
2021 else
2022 {
2023 //word15 segno = TPR.TSR;
2024 //word18 offset = TPR.CA;
2025
2026 // 1. If 2 * segno >= 16 * (cpu.DSBR.BND + 1), then generate an access
2027 // violation, out of segment bounds, fault.
2028
2029 if (2 * (uint) segno >= 16 * ((uint) cpu.DSBR.BND + 1))
2030 {
2031 sim_warn ("DSBR boundary violation.\n");
2032 return SCPE_ARG;
2033 }
2034
2035 // 2. Form the quantities:
2036 // y1 = (2 * segno) modulo 1024
2037 // x1 = (2 * segno y1) / 1024
2038
2039 word24 y1 = (2 * (uint) segno) % 1024;
2040 word24 x1 = (2 * (uint) segno - y1) / 1024;
2041
2042 // 3. Fetch the descriptor segment PTW(x1) from DSBR.ADR + x1.
2043
2044 word36 PTWx1;
2045 core_read ((cpu.DSBR.ADDR + x1) & PAMASK, & PTWx1, __func__);
2046
2047 ptw_s PTW1;
2048 PTW1.ADDR = GETHI(PTWx1);
2049 PTW1.U = TSTBIT(PTWx1, 9);
2050 PTW1.M = TSTBIT(PTWx1, 6);
2051 PTW1.DF = TSTBIT(PTWx1, 2);
2052 PTW1.FC = PTWx1 & 3;
2053
2054 // 4. If PTW(x1).DF = 0, then generate directed fault n where n is
2055 // given in PTW(x1).FC. The value of n used here is the value
2056 // assigned to define a missing page fault or, simply, a
2057 // page fault.
2058
2059 if (!PTW1.DF)
2060 {
2061 sim_warn ("!PTW1.DF\n");
2062 return SCPE_ARG;
2063 }
2064
2065 // 5. Fetch the target segment SDW, SDW(segno), from the
2066 // descriptor segment page at PTW(x1).ADDR + y1.
2067
2068 word36 SDWeven, SDWodd;
2069 core_read2(((PTW1.ADDR << 6) + y1) & PAMASK, & SDWeven, & SDWodd,
2070 __func__);
2071
2072 sdw0_s SDW0;
2073 // even word
2074 SDW0.ADDR = (SDWeven >> 12) & PAMASK;
2075 SDW0.R1 = (SDWeven >> 9) & 7;
2076 SDW0.R2 = (SDWeven >> 6) & 7;
2077 SDW0.R3 = (SDWeven >> 3) & 7;
2078 SDW0.DF = TSTBIT(SDWeven, 2);
2079 SDW0.FC = SDWeven & 3;
2080
2081 // odd word
2082 SDW0.BOUND = (SDWodd >> 21) & 037777;
2083 SDW0.R = TSTBIT(SDWodd, 20);
2084 SDW0.E = TSTBIT(SDWodd, 19);
2085 SDW0.W = TSTBIT(SDWodd, 18);
2086 SDW0.P = TSTBIT(SDWodd, 17);
2087 SDW0.U = TSTBIT(SDWodd, 16);
2088 SDW0.G = TSTBIT(SDWodd, 15);
2089 SDW0.C = TSTBIT(SDWodd, 14);
2090 SDW0.EB = SDWodd & 037777;
2091
2092 // 6. If SDW(segno).DF = 0, then generate directed fault n where
2093 // n is given in SDW(segno).FC.
2094 // This is a segment fault as discussed earlier in this section.
2095
2096 if (!SDW0.DF)
2097 {
2098 sim_warn ("!SDW0.DF\n");
2099 return SCPE_ARG;
2100 }
2101
2102 // 7. If offset >= 16 * (SDW(segno).BOUND + 1), then generate an
2103 // access violation, out of segment bounds, fault.
2104
2105 if (((offset >> 4) & 037777) > SDW0.BOUND)
2106 {
2107 sim_warn ("SDW boundary violation\n");
2108 return SCPE_ARG;
2109 }
2110
2111 // 8. If the access bits (SDW(segno).R, SDW(segno).E, etc.) of the
2112 // segment are incompatible with the reference, generate the
2113 // appropriate access violation fault.
2114
2115 // Only the address is wanted, so no check
2116
2117 if (SDW0.U == 0)
2118 {
2119 // Segment is paged
2120 // 9. Form the quantities:
2121 // y2 = offset modulo 1024
2122 // x2 = (offset - y2) / 1024
2123
2124 word24 y2 = offset % 1024;
2125 word24 x2 = (offset - y2) / 1024;
2126
2127 // 10. Fetch the target segment PTW(x2) from SDW(segno).ADDR + x2.
2128
2129 word36 PTWx2;
2130 core_read ((SDW0.ADDR + x2) & PAMASK, & PTWx2, __func__);
2131
2132 ptw_s PTW2;
2133 PTW2.ADDR = GETHI(PTWx2);
2134 PTW2.U = TSTBIT(PTWx2, 9);
2135 PTW2.M = TSTBIT(PTWx2, 6);
2136 PTW2.DF = TSTBIT(PTWx2, 2);
2137 PTW2.FC = PTWx2 & 3;
2138
2139 // 11.If PTW(x2).DF = 0, then generate directed fault n where n is
2140 // given in PTW(x2).FC. This is a page fault as in Step 4 above.
2141
2142 // abs_addr only wants the address; it doesn't care if the page is
2143 // resident
2144
2145 // if (!PTW2.DF)
2146 // {
2147 // sim_debug (DBG_APPENDING, & cpu_dev, "absa fault !PTW2.DF\n");
2148 // // initiate a directed fault
2149 // doFault(FAULT_DF0 + PTW2.FC, 0, "ABSA !PTW2.DF");
2150 // }
2151
2152 // 12. Generate the 24-bit absolute main memory address
2153 // PTW(x2).ADDR + y2.
2154
2155 res = (((word24) PTW2.ADDR) << 6) + (word24) y2;
2156 res &= PAMASK; //24 bit math
2157 //res <<= 12; // 24:12 format
2158 }
2159 else
2160 {
2161 // Segment is unpaged
2162 // SDW0.ADDR is the base address of the segment
2163 res = (word24) SDW0.ADDR + offset;
2164 res &= PAMASK; //24 bit math
2165 res <<= 12; // 24:12 format
2166 }
2167 }
2168
2169 * abs_addr = res;
2170 return SCPE_OK;
2171 }
2172 # endif
2173
2174 // Translate seg:offset to absolute address
2175
abs_addr_n(int segno,uint offset)2176 static t_stat abs_addr_n (int segno, uint offset)
2177 {
2178 word24 res;
2179
2180 //t_stat rc = computeAbsAddrN (& res, segno, offset);
2181 if (dbgLookupAddress ((word18) segno, offset, & res, NULL))
2182 return SCPE_ARG;
2183
2184 sim_msg ("Address is %08o\n", res);
2185 return SCPE_OK;
2186 }
2187
2188 // ABS segno:offset
2189 // simh command to translate segno:offset to absolute address
2190
abs_addr(UNUSED int32 arg,const char * buf)2191 static t_stat abs_addr (UNUSED int32 arg, const char * buf)
2192 {
2193 uint segno;
2194 uint offset;
2195 if (sscanf (buf, "%o:%o", & segno, & offset) != 2)
2196 return SCPE_ARG;
2197 return abs_addr_n ((int) segno, offset);
2198 }
2199
2200 // LOAD_SYSTEM_BOOK <filename>
2201
2202 // Read a system_book segment, extracting segment names and numbers
2203 // and component names, offsets, and lengths
2204
2205 # define BOOT_SEGMENTS_MAX 1024
2206 # define BOOT_COMPONENTS_MAX 4096
2207 # define BOOK_SEGMENT_NAME_LEN 33
2208
2209 static struct book_segment
2210 {
2211 char * segname;
2212 int segno;
2213 } book_segments[BOOT_SEGMENTS_MAX];
2214
2215 static int n_book_segments = 0;
2216
2217 static struct book_component
2218 {
2219 char * compname;
2220 int book_segment_number;
2221 uint txt_start, txt_length;
2222 int intstat_start, intstat_length, symbol_start, symbol_length;
2223 } book_components[BOOT_COMPONENTS_MAX];
2224
2225 static int n_book_components = 0;
2226
lookup_book_segment(char * name)2227 static int lookup_book_segment (char * name)
2228 {
2229 for (int i = 0; i < n_book_segments; i ++)
2230 if (strcmp (name, book_segments[i].segname) == 0)
2231 return i;
2232 return -1;
2233 }
2234
add_book_segment(char * name,int segno)2235 static int add_book_segment (char * name, int segno)
2236 {
2237 int n = lookup_book_segment (name);
2238 if (n >= 0)
2239 return n;
2240 if (n_book_segments >= BOOT_SEGMENTS_MAX)
2241 return -1;
2242 book_segments[n_book_segments].segname = strdup (name);
2243 book_segments[n_book_segments].segno = segno;
2244 n = n_book_segments;
2245 n_book_segments ++;
2246 return n;
2247 }
2248
add_book_component(int segnum,char * name,uint txt_start,uint txt_length,int intstat_start,int intstat_length,int symbol_start,int symbol_length)2249 static int add_book_component (int segnum, char * name, uint txt_start,
2250 uint txt_length, int intstat_start,
2251 int intstat_length, int symbol_start,
2252 int symbol_length)
2253 {
2254 if (n_book_components >= BOOT_COMPONENTS_MAX)
2255 return -1;
2256 book_components[n_book_components].compname = strdup (name);
2257 book_components[n_book_components].book_segment_number = segnum;
2258 book_components[n_book_components].txt_start = txt_start;
2259 book_components[n_book_components].txt_length = txt_length;
2260 book_components[n_book_components].intstat_start = intstat_start;
2261 book_components[n_book_components].intstat_length = intstat_length;
2262 book_components[n_book_components].symbol_start = symbol_start;
2263 book_components[n_book_components].symbol_length = symbol_length;
2264 int n = n_book_components;
2265 n_book_components ++;
2266 return n;
2267 }
2268
2269
2270 // Given a segno:offset, try to translate to
2271 // component name and offset in the component
2272
2273 // Warning: returns ptr to static buffer
lookup_system_book_address(word18 segno,word18 offset,char ** compname,word18 * compoffset)2274 static char * lookup_system_book_address (word18 segno, word18 offset,
2275 char * * compname, word18 * compoffset)
2276 {
2277 static char buf[129];
2278 int i;
2279
2280 for (i = 0; i < n_book_segments; i ++)
2281 if (book_segments[i].segno == (int) segno)
2282 break;
2283
2284 if (i >= n_book_segments)
2285 return NULL;
2286
2287 int best = -1;
2288 uint bestoffset = 0;
2289
2290 for (int j = 0; j < n_book_components; j ++)
2291 {
2292 if (book_components[j].book_segment_number != i)
2293 continue;
2294 if (book_components[j].txt_start <= offset &&
2295 book_components[j].txt_start + book_components[j].txt_length > offset)
2296 {
2297 sprintf (buf, "%s:%s+0%0o", book_segments[i].segname,
2298 book_components[j].compname,
2299 offset - book_components[j].txt_start);
2300 if (compname)
2301 * compname = book_components[j].compname;
2302 if (compoffset)
2303 * compoffset = offset - book_components[j].txt_start;
2304 return buf;
2305 }
2306 if (book_components[j].txt_start <= offset &&
2307 book_components[j].txt_start > bestoffset)
2308 {
2309 best = j;
2310 bestoffset = book_components[j].txt_start;
2311 }
2312 }
2313
2314 if (best != -1)
2315 {
2316 // Didn't find a component track bracketed the offset; return the
2317 // component that was before the offset
2318 if (compname)
2319 * compname = book_components[best].compname;
2320 if (compoffset)
2321 * compoffset = offset - book_components[best].txt_start;
2322 sprintf (buf, "%s:%s+0%0o", book_segments[i].segname,
2323 book_components[best].compname,
2324 offset - book_components[best].txt_start);
2325 return buf;
2326 }
2327
2328 // Found a segment, but it had no components. Return the segment name
2329 // as the component name
2330
2331 if (compname)
2332 * compname = book_segments[i].segname;
2333 if (compoffset)
2334 * compoffset = offset;
2335 sprintf (buf, "%s:+0%0o", book_segments[i].segname,
2336 offset);
2337 return buf;
2338 }
2339
2340 // Given a segno and offset, find the component name and its
2341 // offset in the segment
2342
lookup_address(word18 segno,word18 offset,char ** compname,word18 * compoffset)2343 char * lookup_address (word18 segno, word18 offset, char * * compname,
2344 word18 * compoffset)
2345 {
2346 if (compname)
2347 * compname = NULL;
2348 if (compoffset)
2349 * compoffset = 0;
2350
2351 // Magic numbers!
2352 // Multics seems to have a copy of hpchs_ (segno 0162) in segment 0322;
2353 // This little tweak allows source code level tracing for segment 0322,
2354 // and has no operational significance to the emulator
2355 // Hmmm. What is happening is that these segments are being loaded into
2356 // ring 4, and assigned segment #'s; the assigned number will vary
2357 // depending on the exact sequence of events.
2358 if (segno == 0322)
2359 segno = 0162;
2360 if (segno == 0310)
2361 segno = 041;
2362 if (segno == 0314)
2363 segno = 041;
2364 if (segno == 0313)
2365 segno = 040;
2366 if (segno == 0317)
2367 segno = 0161;
2368
2369 # if 0
2370 // Hack to support formline debugging
2371 # define IOPOS 02006 // interpret_op_ptr_ offset
2372 if (segno == 0371)
2373 {
2374 if (offset < IOPOS)
2375 {
2376 if (compname)
2377 * compname = "find_condition_info_";
2378 if (compoffset)
2379 * compoffset = offset;
2380 static char buf[129];
2381 sprintf (buf, "bound_debug_util_:find_condition_info_+0%0o",
2382 offset - 0);
2383 return buf;
2384 }
2385 else
2386 {
2387 if (compname)
2388 * compname = "interpret_op_ptr_";
2389 if (compoffset)
2390 * compoffset = offset - IOPOS;
2391 static char buf[129];
2392 sprintf (buf, "bound_debug_util_:interpret_op_ptr_+0%0o",
2393 offset - IOPOS);
2394 return buf;
2395 }
2396
2397 }
2398 # endif
2399
2400 char * ret = lookup_system_book_address (segno, offset, compname, compoffset);
2401 return ret;
2402 }
2403
2404 // Given a segment name and component name, return the
2405 // components segment number and offset
2406
2407 // Warning: returns ptr to static buffer
lookup_system_book_name(char * segname,char * compname,long * segno,long * offset)2408 static int lookup_system_book_name (char * segname, char * compname, long * segno,
2409 long * offset)
2410 {
2411 int i;
2412 for (i = 0; i < n_book_segments; i ++)
2413 if (strcmp (book_segments[i].segname, segname) == 0)
2414 break;
2415 if (i >= n_book_segments)
2416 return -1;
2417
2418 for (int j = 0; j < n_book_components; j ++)
2419 {
2420 if (book_components[j].book_segment_number != i)
2421 continue;
2422 if (strcmp (book_components[j].compname, compname) == 0)
2423 {
2424 * segno = book_segments[i].segno;
2425 * offset = (long) book_components[j].txt_start;
2426 return 0;
2427 }
2428 }
2429
2430 return -1;
2431 }
2432
2433 static char * source_search_path = NULL;
2434
2435 // Given a component name and an offset in the component,
2436 // find the listing file of the component and try to
2437 // print the source code line that generated the code at
2438 // component:offset
2439
list_source(char * compname,word18 offset,uint dflag)2440 void list_source (char * compname, word18 offset, uint dflag)
2441 {
2442 const int offset_str_len = 10;
2443 //char offset_str[offset_str_len + 1];
2444 char offset_str[17];
2445 sprintf (offset_str, " %06o", offset);
2446
2447 char path[(source_search_path ? strlen (source_search_path) : 1) +
2448 1 + // "/"
2449 (compname ? strlen (compname) : 1) +
2450 1 + strlen (".list") + 1];
2451 char * searchp = source_search_path ? source_search_path : ".";
2452 // find <search path>/<compname>.list
2453 while (* searchp)
2454 {
2455 size_t pathlen = strcspn (searchp, ":");
2456 strncpy (path, searchp, pathlen);
2457 path[pathlen] = '\0';
2458 if (searchp[pathlen] == ':')
2459 searchp += pathlen + 1;
2460 else
2461 searchp += pathlen;
2462
2463 if (compname)
2464 {
2465 strcat (path, "/");
2466 strcat (path, compname);
2467 }
2468 strcat (path, ".list");
2469 //sim_msg ("<%s>\n", path);
2470 FILE * listing = fopen (path, "r");
2471 if (listing)
2472 {
2473 char line[1025];
2474 if (feof (listing))
2475 goto fileDone;
2476 fgets (line, 1024, listing);
2477 if (strncmp (line, "ASSEMBLY LISTING", 16) == 0)
2478 {
2479 // Search ALM listing file
2480 // sim_msg ("found <%s>\n", path);
2481
2482 // ALM listing files look like:
2483 // 000226 4a 4 00010 7421 20 \tstx2]tbootload_0$entry_stack_ptr,id
2484 while (! feof (listing))
2485 {
2486 fgets (line, 1024, listing);
2487 if (strncmp (line, offset_str, (size_t) offset_str_len) == 0)
2488 {
2489 if (! dflag)
2490 sim_msg ("%s", line);
2491 else
2492 sim_debug (dflag, & cpu_dev, "%s", line);
2493 //break;
2494 }
2495 if (strcmp (line, "\fLITERALS\n") == 0)
2496 break;
2497 }
2498 } // if assembly listing
2499 else if (strncmp (line, "\tCOMPILATION LISTING", 20) == 0)
2500 {
2501 // Search PL/I listing file
2502
2503 // PL/I files have a line location table
2504 // " LINE LOC LINE LOC ...."
2505
2506 bool foundTable = false;
2507 while (! feof (listing))
2508 {
2509 fgets (line, 1024, listing);
2510 if (strncmp (line, " LINE LOC", 14) != 0)
2511 continue;
2512 foundTable = true;
2513 // Found the table
2514 // Table lines look like
2515 // " 13 000705 275 000713 ...
2516 // But some times
2517 // " 10 000156 21 84 000164
2518 // " 8 000214 65 000222 4 84 000225
2519 //
2520 // " 349 001442 351 001445 353 001454 1 9 001456 1 11 001461 1 12 001463 1 13 001470
2521 // " 1 18 001477 357 001522 361 001525 363 001544 364 001546 365 001547 366 001553
2522
2523 // I think the numbers refer to include files...
2524 // But of course the format is slightly off...
2525 // table ".1...18
2526 // listing ".1....18
2527 int best = -1;
2528 char bestLines[8] = {0, 0, 0, 0, 0, 0, 0};
2529 while (! feof (listing))
2530 {
2531 int loc[7];
2532 char linenos[7][8];
2533 memset (linenos, 0, sizeof (linenos));
2534 fgets (line, 1024, listing);
2535 // sometimes the leading columns are blank...
2536 while (strncmp (line,
2537 " ", 8 + 6 + 3) == 0)
2538 memmove (line, line + 8 + 6 + 3,
2539 strlen (line + 8 + 6 + 3));
2540 // deal with the extra numbers...
2541
2542 int cnt = sscanf (line,
2543 // " %d %o %d %o %d %o %d %o %d %o %d %o %d %o",
2544 "%8c%o%*3c"
2545 "%8c%o%*3c"
2546 "%8c%o%*3c"
2547 "%8c%o%*3c"
2548 "%8c%o%*3c"
2549 "%8c%o%*3c"
2550 "%8c%o",
2551 (char *) & linenos[0], (uint *) & loc[0],
2552 (char *) & linenos[1], (uint *) & loc[1],
2553 (char *) & linenos[2], (uint *) & loc[2],
2554 (char *) & linenos[3], (uint *) & loc[3],
2555 (char *) & linenos[4], (uint *) & loc[4],
2556 (char *) & linenos[5], (uint *) & loc[5],
2557 (char *) & linenos[6], (uint *) & loc[6]);
2558 if (! (cnt == 2 || cnt == 4 || cnt == 6 ||
2559 cnt == 8 || cnt == 10 || cnt == 12 ||
2560 cnt == 14))
2561 break; // end of table
2562 int n;
2563 for (n = 0; n < cnt / 2; n ++)
2564 {
2565 if (loc[n] > best && loc[n] <= (int) offset)
2566 {
2567 best = loc[n];
2568 memcpy (bestLines, linenos[n],
2569 sizeof (bestLines));
2570 }
2571 }
2572 if (best == (int) offset)
2573 break;
2574 }
2575 if (best == -1)
2576 goto fileDone; // Not found in table
2577
2578 // But of course the format is slightly off...
2579 // table ".1...18
2580 // listing ".1....18
2581 // bestLines "21 84 "
2582 // listing " 21 84 "
2583 char searchPrefix[10];
2584 searchPrefix[0] = ' ';
2585 searchPrefix[1] = bestLines[0];
2586 searchPrefix[2] = bestLines[1];
2587 searchPrefix[3] = ' ';
2588 searchPrefix[4] = bestLines[2];
2589 searchPrefix[5] = bestLines[3];
2590 searchPrefix[6] = bestLines[4];
2591 searchPrefix[7] = bestLines[5];
2592 searchPrefix[8] = bestLines[6];
2593 // ignore trailing space; some times its a tab
2594 // searchPrefix[ 9] = bestLines[ 7];
2595 searchPrefix[9] = '\0';
2596
2597 // Look for the line in the listing
2598 rewind (listing);
2599 while (! feof (listing))
2600 {
2601 fgets (line, 1024, listing);
2602 if (strncmp (line, "\f\tSOURCE", 8) == 0)
2603 goto fileDone; // end of source code listing
2604 char prefix[10];
2605 strncpy (prefix, line, 9);
2606 prefix[9] = '\0';
2607 if (strcmp (prefix, searchPrefix) != 0)
2608 continue;
2609 // Got it
2610 if (!dflag)
2611 sim_msg ("%s", line);
2612 else
2613 sim_debug (dflag, & cpu_dev, "%s", line);
2614 //break;
2615 }
2616 goto fileDone;
2617 } // if table start
2618 if (! foundTable)
2619 {
2620 // Can't find the LINE/LOC table; look for listing
2621 rewind (listing);
2622 while (! feof (listing))
2623 {
2624 fgets (line, 1024, listing);
2625 if (strncmp (line,
2626 offset_str + 4,
2627 offset_str_len - 4) == 0)
2628 {
2629 if (! dflag)
2630 sim_msg ("%s", line);
2631 else
2632 sim_debug (dflag, & cpu_dev, "%s", line);
2633 //break;
2634 }
2635 //if (strcmp (line, "\fLITERALS\n") == 0)
2636 //break;
2637 }
2638 } // if ! tableFound
2639 } // if PL/I listing
2640
2641 fileDone:
2642 fclose (listing);
2643 } // if (listing)
2644 }
2645 }
2646
2647 // STK
2648
2649 # ifndef SCUMEM
stack_trace(UNUSED int32 arg,UNUSED const char * buf)2650 static t_stat stack_trace (UNUSED int32 arg, UNUSED const char * buf)
2651 {
2652 char * msg;
2653
2654 word15 icSegno = cpu.PPR.PSR;
2655 word18 icOffset = cpu.PPR.IC;
2656
2657 sim_msg ("Entry ptr %05o:%06o\n", icSegno, icOffset);
2658
2659 char * compname;
2660 word18 compoffset;
2661 char * where = lookup_address (icSegno, icOffset,
2662 & compname, & compoffset);
2663 if (where)
2664 {
2665 sim_msg ("%05o:%06o %s\n", icSegno, icOffset, where);
2666 list_source (compname, compoffset, 0);
2667 }
2668 sim_msg ("\n");
2669
2670 // According to AK92
2671 //
2672 // pr0/ap operator segment pointer
2673 // pr6/sp stack frame pointer
2674 // pr4/lp linkage section for the executing procedure
2675 // pr7/sb stack base
2676
2677 word15 fpSegno = cpu.PR[6].SNR;
2678 word18 fpOffset = cpu.PR[6].WORDNO;
2679
2680 for (uint frameNo = 1; ; frameNo ++)
2681 {
2682 sim_msg ("Frame %d %05o:%06o\n",
2683 frameNo, fpSegno, fpOffset);
2684
2685 word24 fp;
2686 if (dbgLookupAddress (fpSegno, fpOffset, & fp, & msg))
2687 {
2688 sim_msg ("can't lookup fp (%05o:%06o) because %s\n",
2689 fpSegno, fpOffset, msg);
2690 break;
2691 }
2692
2693 word15 prevfpSegno = (word15) ((M[fp + 16] >> 18) & MASK15);
2694 word18 prevfpOffset = (word18) ((M[fp + 17] >> 18) & MASK18);
2695
2696 sim_msg ("Previous FP %05o:%06o\n", prevfpSegno, prevfpOffset);
2697
2698 word15 returnSegno = (word15) ((M[fp + 20] >> 18) & MASK15);
2699 word18 returnOffset = (word18) ((M[fp + 21] >> 18) & MASK18);
2700
2701 sim_msg ("Return ptr %05o:%06o\n", returnSegno, returnOffset);
2702
2703 if (returnOffset == 0)
2704 {
2705 if (frameNo == 1)
2706 {
2707 // try rX[7] as the return address
2708 sim_msg ("guessing X7 has a return address....\n");
2709 where = lookup_address (icSegno, cpu.rX[7] - 1,
2710 & compname, & compoffset);
2711 if (where)
2712 {
2713 sim_msg ("%05o:%06o %s\n", icSegno, cpu.rX[7] - 1, where);
2714 list_source (compname, compoffset, 0);
2715 }
2716 }
2717 }
2718 else
2719 {
2720 where = lookup_address (returnSegno, returnOffset - 1,
2721 & compname, & compoffset);
2722 if (where)
2723 {
2724 sim_msg ("%05o:%06o %s\n",
2725 returnSegno, returnOffset - 1, where);
2726 list_source (compname, compoffset, 0);
2727 }
2728 }
2729
2730 word15 entrySegno = (word15) ((M[fp + 22] >> 18) & MASK15);
2731 word18 entryOffset = (word18) ((M[fp + 23] >> 18) & MASK18);
2732
2733 sim_msg ("Entry ptr %05o:%06o\n", entrySegno, entryOffset);
2734
2735 where = lookup_address (entrySegno, entryOffset,
2736 & compname, & compoffset);
2737 if (where)
2738 {
2739 sim_msg ("%05o:%06o %s\n", entrySegno, entryOffset, where);
2740 list_source (compname, compoffset, 0);
2741 }
2742
2743 word15 argSegno = (word15) ((M[fp + 26] >> 18) & MASK15);
2744 word18 argOffset = (word18) ((M[fp + 27] >> 18) & MASK18);
2745 sim_msg ("Arg ptr %05o:%06o\n", argSegno, argOffset);
2746
2747 word24 ap;
2748 if (dbgLookupAddress (argSegno, argOffset, & ap, & msg))
2749 {
2750 sim_msg ("can't lookup arg ptr (%05o:%06o) because %s\n",
2751 argSegno, argOffset, msg);
2752 goto skipArgs;
2753 }
2754
2755 word16 argCount = (word16) ((M[ap + 0] >> 19) & MASK17);
2756 word18 callType = (word18) (M[ap + 0] & MASK18);
2757 word16 descCount = (word16) ((M[ap + 1] >> 19) & MASK17);
2758 sim_msg ("arg_count %d\n", argCount);
2759 switch (callType)
2760 {
2761 case 0u:
2762 sim_msg ("call_type Quick internal call\n");
2763 break;
2764 case 4u:
2765 sim_msg ("call_type Inter-segment\n");
2766 break;
2767 case 8u:
2768 sim_msg ("call_type Enviroment pointer\n");
2769 break;
2770 default:
2771 sim_msg ("call_type Unknown (%o)\n", callType);
2772 goto skipArgs;
2773 }
2774 sim_msg ("desc_count %d\n", descCount);
2775
2776 # if 0
2777 if (descCount)
2778 {
2779 // XXX walk descriptor and arg list together
2780 }
2781 else
2782 # endif
2783 {
2784 for (uint argno = 0; argno < argCount; argno ++)
2785 {
2786 uint argnoos = ap + 2 + argno * 2;
2787 word15 argnoSegno = (word15) ((M[argnoos] >> 18) & MASK15);
2788 word18 argnoOffset = (word18) ((M[argnoos + 1] >> 18) & MASK18);
2789 word24 argnop;
2790 if (dbgLookupAddress (argnoSegno, argnoOffset, & argnop, & msg))
2791 {
2792 sim_msg ("can't lookup arg%d ptr (%05o:%06o) because %s\n",
2793 argno, argSegno, argOffset, msg);
2794 continue;
2795 }
2796 word36 argv = M[argnop];
2797 sim_msg ("arg%d value %05o:%06o[%08o] "
2798 "%012"PRIo64" (%"PRIu64")\n",
2799 argno, argSegno, argOffset, argnop, argv, argv);
2800 sim_msg ("\n");
2801 }
2802 }
2803 skipArgs:;
2804
2805 sim_msg ("End of frame %d\n\n", frameNo);
2806
2807 if (prevfpSegno == 077777 && prevfpOffset == 1)
2808 break;
2809 fpSegno = prevfpSegno;
2810 fpOffset = prevfpOffset;
2811 }
2812 return SCPE_OK;
2813 }
2814 # endif
2815
list_source_at(UNUSED int32 arg,UNUSED const char * buf)2816 static t_stat list_source_at (UNUSED int32 arg, UNUSED const char * buf)
2817 {
2818 // list seg:offset
2819 uint segno;
2820 uint offset;
2821 if (sscanf (buf, "%o:%o", & segno, & offset) != 2)
2822 return SCPE_ARG;
2823 char * compname;
2824 word18 compoffset;
2825 char * where = lookup_address ((word18) segno, offset,
2826 & compname, & compoffset);
2827 if (where)
2828 {
2829 sim_msg ("%05o:%06o %s\n", segno, offset, where);
2830 list_source (compname, compoffset, 0);
2831 }
2832 return SCPE_OK;
2833 }
2834
load_system_book(UNUSED int32 arg,UNUSED const char * buf)2835 static t_stat load_system_book (UNUSED int32 arg, UNUSED const char * buf)
2836 {
2837 // Quietly ignore if not debug enabled
2838 # ifndef SPEED
2839 // Multics 12.5 assigns segment number to collection 3 starting at 0244.
2840 uint c3 = 0244;
2841
2842 # define bufSz 257
2843 char filebuf[bufSz];
2844 int current = -1;
2845
2846 FILE * fp = fopen (buf, "r");
2847 if (! fp)
2848 {
2849 sim_msg ("error opening file %s\n", buf);
2850 return SCPE_ARG;
2851 }
2852 for (;;)
2853 {
2854 char * bufp = fgets (filebuf, bufSz, fp);
2855 if (! bufp)
2856 break;
2857 //sim_msg ("<%s\n>", filebuf);
2858 char name[BOOK_SEGMENT_NAME_LEN];
2859 uint segno, p0, p1, p2;
2860
2861 // 32 is BOOK_SEGMENT_NAME_LEN - 1
2862 int cnt = sscanf (filebuf, "%32s %o (%o, %o, %o)", name, & segno,
2863 & p0, & p1, & p2);
2864 if (filebuf[0] != '\t' && cnt == 5)
2865 {
2866 //sim_msg ("A: %s %d\n", name, segno);
2867 int rc = add_book_segment (name, (int) segno);
2868 if (rc < 0)
2869 {
2870 sim_warn ("error adding segment name\n");
2871 fclose (fp);
2872 return SCPE_ARG;
2873 }
2874 continue;
2875 }
2876 else
2877 {
2878 // Check for collection 3 segment
2879 // 32 is BOOK_SEGMENT_NAME_LEN - 1
2880 cnt = sscanf (filebuf, "%32s (%o, %o, %o)", name,
2881 & p0, & p1, & p2);
2882 if (filebuf[0] != '\t' && cnt == 4)
2883 {
2884 if (strstr (name, "fw.") || strstr (name, ".ec"))
2885 continue;
2886 //sim_msg ("A: %s %d\n", name, segno);
2887 int rc = add_book_segment (name, (int) (c3 ++));
2888 if (rc < 0)
2889 {
2890 sim_warn ("error adding segment name\n");
2891 fclose (fp);
2892 return SCPE_ARG;
2893 }
2894 continue;
2895 }
2896 }
2897 cnt = sscanf (filebuf, "Bindmap for >ldd>h>e>%32s", name);
2898 if (cnt != 1)
2899 cnt = sscanf (filebuf, "Bindmap for >ldd>hard>e>%32s", name);
2900 if (cnt == 1)
2901 {
2902 //sim_msg ("B: %s\n", name);
2903 //int rc = add_book_segment (name);
2904 int rc = lookup_book_segment (name);
2905 if (rc < 0)
2906 {
2907 // The collection 3.0 segments do not have segment numbers,
2908 // and the 1st digit of the 3-tuple is 1, not 0. Ignore
2909 // them for now.
2910 current = -1;
2911 continue;
2912 //sim_warn ("error adding segment name\n");
2913 //return SCPE_ARG;
2914 }
2915 current = rc;
2916 continue;
2917 }
2918
2919 uint txt_start, txt_length;
2920 int intstat_start, intstat_length, symbol_start, symbol_length;
2921 cnt = sscanf (filebuf, "%32s %o %o %o %o %o %o", name, & txt_start,
2922 & txt_length, & intstat_start, & intstat_length,
2923 & symbol_start, & symbol_length);
2924
2925 if (cnt == 7)
2926 {
2927 //sim_msg ("C: %s\n", name);
2928 if (current >= 0)
2929 {
2930 add_book_component (current, name, txt_start, txt_length,
2931 intstat_start, intstat_length, symbol_start,
2932 symbol_length);
2933 }
2934 continue;
2935 }
2936
2937 cnt = sscanf (filebuf, "%32s %o (%o, %o, %o)", name, & segno,
2938 & p0, & p1, & p2);
2939 if (filebuf[0] == '\t' && cnt == 5)
2940 {
2941 //sim_msg ("D: %s %d\n", name, segno);
2942 int rc = add_book_segment (name, (int) segno);
2943 if (rc < 0)
2944 {
2945 sim_warn ("error adding segment name\n");
2946 fclose (fp);
2947 return SCPE_ARG;
2948 }
2949 continue;
2950 }
2951
2952 }
2953 fclose (fp);
2954 # if 0
2955 for (int i = 0; i < n_book_segments; i ++)
2956 {
2957 sim_msg (" %-32s %6o\n", book_segments[i].segname,
2958 book_segments[i].segno);
2959 for (int j = 0; j < n_book_components; j ++)
2960 {
2961 if (book_components[j].book_segment_number == i)
2962 {
2963 fprintf (stderr, " %-32s %6o %6o %6o %6o %6o %6o\n",
2964 book_components[j].compname,
2965 book_components[j].txt_start,
2966 book_components[j].txt_length,
2967 book_components[j].intstat_start,
2968 book_components[j].intstat_length,
2969 book_components[j].symbol_start,
2970 book_components[j].symbol_length);
2971 }
2972 }
2973 }
2974 # endif
2975 # endif
2976 return SCPE_OK;
2977 }
2978
add_system_book_entry(UNUSED int32 arg,const char * buf)2979 static t_stat add_system_book_entry (UNUSED int32 arg, const char * buf)
2980 {
2981 // asbe segname compname seg txt_start txt_len intstat_start intstat_length
2982 // symbol_start symbol_length
2983 char segname[BOOK_SEGMENT_NAME_LEN];
2984 char compname[BOOK_SEGMENT_NAME_LEN];
2985 uint segno;
2986 uint txt_start, txt_len;
2987 uint intstat_start, intstat_length;
2988 uint symbol_start, symbol_length;
2989
2990 // 32 is BOOK_SEGMENT_NAME_LEN - 1
2991 if (sscanf (buf, "%32s %32s %o %o %o %o %o %o %o",
2992 segname, compname, & segno,
2993 & txt_start, & txt_len, & intstat_start, & intstat_length,
2994 & symbol_start, & symbol_length) != 9)
2995 return SCPE_ARG;
2996
2997 int idx = add_book_segment (segname, (int) segno);
2998 if (idx < 0)
2999 return SCPE_ARG;
3000
3001 if (add_book_component (idx, compname, txt_start, txt_len, (int) intstat_start,
3002 (int) intstat_length, (int) symbol_start,
3003 (int) symbol_length) < 0)
3004 return SCPE_ARG;
3005
3006 return SCPE_OK;
3007 }
3008
3009 // LSB n:n given a segment number and offset, return a segment name,
3010 // component and offset in that component
3011 // sname:cname+offset
3012 // given a segment name, component name and offset, return
3013 // the segment number and offset
3014
lookup_system_book(UNUSED int32 arg,const char * buf)3015 static t_stat lookup_system_book (UNUSED int32 arg, const char * buf)
3016 {
3017 char w1[strlen (buf)];
3018 char w2[strlen (buf)];
3019 char w3[strlen (buf)];
3020 long segno, offset;
3021
3022 size_t colon = strcspn (buf, ":");
3023 if (buf[colon] != ':')
3024 return SCPE_ARG;
3025
3026 strncpy (w1, buf, colon);
3027 w1[colon] = '\0';
3028 //sim_msg ("w1 <%s>\n", w1);
3029
3030 size_t plus = strcspn (buf + colon + 1, "+");
3031 if (buf[colon + 1 + plus] == '+')
3032 {
3033 strncpy (w2, buf + colon + 1, plus);
3034 w2[plus] = '\0';
3035 strcpy (w3, buf + colon + 1 + plus + 1);
3036 }
3037 else
3038 {
3039 strcpy (w2, buf + colon + 1);
3040 strcpy (w3, "");
3041 }
3042 //sim_msg ("w1 <%s>\n", w1);
3043 //sim_msg ("w2 <%s>\n", w2);
3044 //sim_msg ("w3 <%s>\n", w3);
3045
3046 char * end1;
3047 segno = strtol (w1, & end1, 8);
3048 char * end2;
3049 offset = strtol (w2, & end2, 8);
3050
3051 if (* end1 == '\0' && * end2 == '\0' && * w3 == '\0')
3052 {
3053 // n:n
3054 char * ans = lookup_address ((word18) segno, (word18) offset, NULL, NULL);
3055 sim_warn ("%s\n", ans ? ans : "not found");
3056 }
3057 else
3058 {
3059 if (* w3)
3060 {
3061 char * end3;
3062 offset = strtol (w3, & end3, 8);
3063 if (* end3 != '\0')
3064 return SCPE_ARG;
3065 }
3066 else
3067 offset = 0;
3068 long comp_offset;
3069 int rc = lookup_system_book_name (w1, w2, & segno, & comp_offset);
3070 if (rc)
3071 {
3072 sim_warn ("not found\n");
3073 return SCPE_OK;
3074 }
3075 sim_msg ("0%o:0%o\n", (uint) segno, (uint) (comp_offset + offset));
3076 abs_addr_n ((int) segno, (uint) (comp_offset + offset));
3077 }
3078 /*
3079 if (sscanf (buf, "%o:%o", & segno, & offset) != 2)
3080 return SCPE_ARG;
3081 char * ans = lookup_address (segno, offset);
3082 sim_msg ("%s\n", ans ? ans : "not found");
3083 */
3084 return SCPE_OK;
3085 }
3086
3087 # ifndef SCUMEM
3088 // Assumes unpaged DSBR
3089
fetchSDW(word15 segno)3090 static sdw0_s *fetchSDW (word15 segno)
3091 {
3092 word36 SDWeven, SDWodd;
3093
3094 core_read2 ((cpu.DSBR.ADDR + 2u * segno) & PAMASK, & SDWeven, & SDWodd,
3095 __func__);
3096
3097 // even word
3098
3099 sdw0_s *SDW = & cpu._s;
3100 memset (SDW, 0, sizeof (cpu._s));
3101
3102 SDW->ADDR = (SDWeven >> 12) & 077777777;
3103 SDW->R1 = (SDWeven >> 9) & 7;
3104 SDW->R2 = (SDWeven >> 6) & 7;
3105 SDW->R3 = (SDWeven >> 3) & 7;
3106 SDW->DF = TSTBIT (SDWeven, 2);
3107 SDW->FC = SDWeven & 3;
3108
3109 // odd word
3110 SDW->BOUND = (SDWodd >> 21) & 037777;
3111 SDW->R = TSTBIT (SDWodd, 20);
3112 SDW->E = TSTBIT (SDWodd, 19);
3113 SDW->W = TSTBIT (SDWodd, 18);
3114 SDW->P = TSTBIT (SDWodd, 17);
3115 SDW->U = TSTBIT (SDWodd, 16);
3116 SDW->G = TSTBIT (SDWodd, 15);
3117 SDW->C = TSTBIT (SDWodd, 14);
3118 SDW->EB = SDWodd & 037777;
3119
3120 return SDW;
3121 }
3122
virtAddrN(uint address)3123 static t_stat virtAddrN (uint address)
3124 {
3125 if (cpu.DSBR.U) {
3126 for(word15 segno = 0; 2u * segno < 16u * (cpu.DSBR.BND + 1u); segno += 1)
3127 {
3128 sdw0_s *s = fetchSDW(segno);
3129 if (address >= s -> ADDR && address < s -> ADDR + s -> BOUND * 16u)
3130 sim_msg (" %06o:%06o\n", segno, address - s -> ADDR);
3131 }
3132 } else {
3133 for(word15 segno = 0;
3134 2u * segno < 16u * (cpu.DSBR.BND + 1u);
3135 segno += 512u)
3136 {
3137 word24 y1 = (2u * segno) % 1024u;
3138 word24 x1 = (2u * segno - y1) / 1024u;
3139 word36 PTWx1;
3140 core_read ((cpu.DSBR.ADDR + x1) & PAMASK, & PTWx1, __func__);
3141
3142 ptw_s PTW1;
3143 PTW1.ADDR = GETHI(PTWx1);
3144 PTW1.U = TSTBIT(PTWx1, 9);
3145 PTW1.M = TSTBIT(PTWx1, 6);
3146 PTW1.DF = TSTBIT(PTWx1, 2);
3147 PTW1.FC = PTWx1 & 3;
3148
3149 if (PTW1.DF == 0)
3150 continue;
3151 //sim_msg ("%06o Addr %06o U %o M %o DF %o FC %o\n",
3152 // segno, PTW1.ADDR, PTW1.U, PTW1.M, PTW1.DF, PTW1.FC);
3153 //sim_msg (" Target segment page table\n");
3154 for (word15 tspt = 0; tspt < 512u; tspt ++)
3155 {
3156 word36 SDWeven, SDWodd;
3157 core_read2(((PTW1.ADDR << 6) + tspt * 2u) & PAMASK, & SDWeven,
3158 & SDWodd, __func__);
3159 sdw0_s SDW0;
3160 // even word
3161 SDW0.ADDR = (SDWeven >> 12) & PAMASK;
3162 SDW0.R1 = (SDWeven >> 9) & 7u;
3163 SDW0.R2 = (SDWeven >> 6) & 7u;
3164 SDW0.R3 = (SDWeven >> 3) & 7u;
3165 SDW0.DF = TSTBIT(SDWeven, 2);
3166 SDW0.FC = SDWeven & 3u;
3167
3168 // odd word
3169 SDW0.BOUND = (SDWodd >> 21) & 037777;
3170 SDW0.R = TSTBIT(SDWodd, 20);
3171 SDW0.E = TSTBIT(SDWodd, 19);
3172 SDW0.W = TSTBIT(SDWodd, 18);
3173 SDW0.P = TSTBIT(SDWodd, 17);
3174 SDW0.U = TSTBIT(SDWodd, 16);
3175 SDW0.G = TSTBIT(SDWodd, 15);
3176 SDW0.C = TSTBIT(SDWodd, 14);
3177 SDW0.EB = SDWodd & 037777;
3178
3179 if (SDW0.DF == 0)
3180 continue;
3181 //sim_msg (" %06o Addr %06o %o,%o,%o F%o BOUND %06o "
3182 // "%c%c%c%c%c\n",
3183 // tspt, SDW0.ADDR, SDW0.R1, SDW0.R2, SDW0.R3, SDW0.F,
3184 // SDW0.BOUND, SDW0.R ? 'R' : '.', SDW0.E ? 'E' : '.',
3185 // SDW0.W ? 'W' : '.', SDW0.P ? 'P' : '.',
3186 // SDW0.U ? 'U' : '.');
3187 if (SDW0.U == 0)
3188 {
3189 for (word18 offset = 0;
3190 offset < 16u * (SDW0.BOUND + 1u);
3191 offset += 1024)
3192 {
3193 word24 y2 = offset % 1024;
3194 word24 x2 = (offset - y2) / 1024;
3195
3196 // 10. Fetch the target segment PTW(x2) from
3197 // SDW(segno).ADDR + x2.
3198
3199 word36 PTWx2;
3200 core_read ((SDW0.ADDR + x2) & PAMASK, & PTWx2, __func__);
3201
3202 ptw_s PTW2;
3203 PTW2.ADDR = GETHI(PTWx2);
3204 PTW2.U = TSTBIT(PTWx2, 9);
3205 PTW2.M = TSTBIT(PTWx2, 6);
3206 PTW2.DF = TSTBIT(PTWx2, 2);
3207 PTW2.FC = PTWx2 & 3;
3208
3209 //sim_msg (" %06o Addr %06o U %o M %o F %o "
3210 // "FC %o\n",
3211 // offset, PTW2.ADDR, PTW2.U, PTW2.M, PTW2.F,
3212 // PTW2.FC);
3213 if (address >= PTW2.ADDR + offset &&
3214 address < PTW2.ADDR + offset + 1024)
3215 sim_msg (" %06o:%06o\n", tspt, (address - offset) - PTW2.ADDR);
3216
3217 }
3218 }
3219 else
3220 {
3221 if (address >= SDW0.ADDR &&
3222 address < SDW0.ADDR + SDW0.BOUND * 16u)
3223 sim_msg (" %06o:%06o\n", tspt, address - SDW0.ADDR);
3224 }
3225 }
3226 }
3227 }
3228
3229 return SCPE_OK;
3230
3231 }
3232 # endif
3233
3234 // VIRTUAL address
3235
3236 # ifndef SCUMEM
virt_address(UNUSED int32 arg,const char * buf)3237 static t_stat virt_address (UNUSED int32 arg, const char * buf)
3238 {
3239 uint address;
3240 if (sscanf (buf, "%o", & address) != 1)
3241 return SCPE_ARG;
3242 return virtAddrN (address);
3243 }
3244 # endif
3245
3246 // search path is path:path:path....
3247
set_search_path(UNUSED int32 arg,UNUSED const char * buf)3248 static t_stat set_search_path (UNUSED int32 arg, UNUSED const char * buf)
3249 {
3250 // Quietly ignore if debugging not enabled
3251 # ifndef SPEED
3252 if (source_search_path)
3253 free (source_search_path);
3254 source_search_path = strdup (buf);
3255 # endif
3256 return SCPE_OK;
3257 }
3258
3259 // Hook for gdb
3260 //
3261 // The idea is that if you want to set a gdb breakpoint for a particulary
3262 // complex condition, you can add a test for the condtion to the emulator
3263 // code and call brkbrk() when the condition is met; by doing a gdb
3264 // 'b brkbrk', gdb will see when the condition is met.
3265 //
3266
brkbrk(UNUSED int32 arg,UNUSED const char * buf)3267 t_stat brkbrk (UNUSED int32 arg, UNUSED const char * buf)
3268 {
3269 //list_source (buf, 0);
3270 return SCPE_OK;
3271 }
3272
3273 // SBREAK segno:offset
3274
sbreak(int32 arg,const char * buf)3275 static t_stat sbreak (int32 arg, const char * buf)
3276 {
3277 //printf (">> <%s>\n", buf);
3278 int segno, offset;
3279 int where;
3280 int cnt = sscanf (buf, "%o:%o%n", & segno, & offset, & where);
3281 if (cnt != 2)
3282 {
3283 return SCPE_ARG;
3284 }
3285 char reformatted[strlen (buf) + 20];
3286 sprintf (reformatted, "0%04o%06o%s", segno, offset, buf + where);
3287 //printf (">> <%s>\n", reformatted);
3288 t_stat rc = brk_cmd (arg, reformatted);
3289 return rc;
3290 }
3291
3292 # ifdef DVFDBG
dfx1entry(UNUSED int32 arg,UNUSED const char * buf)3293 static t_stat dfx1entry (UNUSED int32 arg, UNUSED const char * buf)
3294 {
3295 // divide_fx1, divide_fx3
3296 sim_msg ("dfx1entry\n");
3297 sim_msg ("rA %012"PRIo64" (%llu)\n", rA, rA);
3298 sim_msg ("rQ %012"PRIo64" (%llu)\n", rQ, rQ);
3299 // Figure out the caller's text segment, according to pli_operators.
3300 // sp:tbp -> PR[6].SNR:046
3301 word24 pa;
3302 char * msg;
3303 if (dbgLookupAddress (cpu.PR[6].SNR, 046, & pa, & msg))
3304 {
3305 sim_msg ("text segment number lookup failed because %s\n", msg);
3306 }
3307 else
3308 {
3309 sim_msg ("text segno %012"PRIo64" (%llu)\n", M[pa], M[pa]);
3310 }
3311 sim_msg ("%05o:%06o\n", cpu.PR[2].SNR, cpu.rX[0]);
3312 //dbgStackTrace ();
3313 if (dbgLookupAddress (cpu.PR[2].SNR, cpu.rX[0], & pa, & msg))
3314 {
3315 sim_msg ("return address lookup failed because %s\n", msg);
3316 }
3317 else
3318 {
3319 sim_msg ("scale %012"PRIo64" (%llu)\n", M[pa], M[pa]);
3320 }
3321 if (dbgLookupAddress (cpu.PR[2].SNR, cpu.PR[2].WORDNO, & pa, & msg))
3322 {
3323 sim_msg ("divisor address lookup failed because %s\n", msg);
3324 }
3325 else
3326 {
3327 sim_msg ("divisor %012"PRIo64" (%llu)\n", M[pa], M[pa]);
3328 }
3329 return SCPE_OK;
3330 }
3331
dfx1exit(UNUSED int32 arg,UNUSED const char * buf)3332 static t_stat dfx1exit (UNUSED int32 arg, UNUSED const char * buf)
3333 {
3334 sim_msg ("dfx1exit\n");
3335 sim_msg ("rA %012"PRIo64" (%llu)\n", rA, rA);
3336 sim_msg ("rQ %012"PRIo64" (%llu)\n", rQ, rQ);
3337 return SCPE_OK;
3338 }
3339
dv2scale(UNUSED int32 arg,UNUSED const char * buf)3340 static t_stat dv2scale (UNUSED int32 arg, UNUSED const char * buf)
3341 {
3342 sim_msg ("dv2scale\n");
3343 sim_msg ("rQ %012"PRIo64" (%llu)\n", rQ, rQ);
3344 return SCPE_OK;
3345 }
3346
dfx2entry(UNUSED int32 arg,UNUSED const char * buf)3347 static t_stat dfx2entry (UNUSED int32 arg, UNUSED const char * buf)
3348 {
3349 // divide_fx2
3350 sim_msg ("dfx2entry\n");
3351 sim_msg ("rA %012"PRIo64" (%llu)\n", rA, rA);
3352 sim_msg ("rQ %012"PRIo64" (%llu)\n", rQ, rQ);
3353 // Figure out the caller's text segment, according to pli_operators.
3354 // sp:tbp -> PR[6].SNR:046
3355 word24 pa;
3356 char * msg;
3357 if (dbgLookupAddress (cpu.PR[6].SNR, 046, & pa, & msg))
3358 {
3359 sim_msg ("text segment number lookup failed because %s\n", msg);
3360 }
3361 else
3362 {
3363 sim_msg ("text segno %012"PRIo64" (%llu)\n", M[pa], M[pa]);
3364 }
3365 # if 0
3366 sim_msg ("%05o:%06o\n", cpu.PR[2].SNR, cpu.rX[0]);
3367 //dbgStackTrace ();
3368 if (dbgLookupAddress (cpu.PR[2].SNR, cpu.rX[0], & pa, & msg))
3369 {
3370 sim_msg ("return address lookup failed because %s\n", msg);
3371 }
3372 else
3373 {
3374 sim_msg ("scale ptr %012"PRIo64" (%llu)\n", M[pa], M[pa]);
3375 if ((M[pa] & 077) == 043)
3376 {
3377 word15 segno = (M[pa] >> 18u) & MASK15;
3378 word18 offset = (M[pa + 1] >> 18u) & MASK18;
3379 word24 ipa;
3380 if (dbgLookupAddress (segno, offset, & ipa, & msg))
3381 {
3382 sim_msg ("divisor address lookup failed because %s\n", msg);
3383 }
3384 else
3385 {
3386 sim_msg ("scale %012"PRIo64" (%llu)\n", M[ipa], M[ipa]);
3387 }
3388 }
3389 }
3390 # endif
3391 if (dbgLookupAddress (cpu.PR[2].SNR, cpu.PR[2].WORDNO, & pa, & msg))
3392 {
3393 sim_msg ("divisor address lookup failed because %s\n", msg);
3394 }
3395 else
3396 {
3397 sim_msg ("divisor %012"PRIo64" (%llu)\n", M[pa], M[pa]);
3398 sim_msg ("divisor %012"PRIo64" (%llu)\n", M[pa + 1], M[pa + 1]);
3399 }
3400 return SCPE_OK;
3401 }
3402
mdfx3entry(UNUSED int32 arg,UNUSED const char * buf)3403 static t_stat mdfx3entry (UNUSED int32 arg, UNUSED const char * buf)
3404 {
3405 // operator to form mod(fx2,fx1)
3406 // entered with first arg in q, bp pointing at second
3407
3408 // divide_fx1, divide_fx2
3409 sim_msg ("mdfx3entry\n");
3410 //sim_msg ("rA %012"PRIo64" (%llu)\n", rA, rA);
3411 sim_msg ("rQ %012"PRIo64" (%llu)\n", rQ, rQ);
3412 // Figure out the caller's text segment, according to pli_operators.
3413 // sp:tbp -> PR[6].SNR:046
3414 word24 pa;
3415 char * msg;
3416 if (dbgLookupAddress (cpu.PR[6].SNR, 046, & pa, & msg))
3417 {
3418 sim_msg ("text segment number lookup failed because %s\n", msg);
3419 }
3420 else
3421 {
3422 sim_msg ("text segno %012"PRIo64" (%llu)\n", M[pa], M[pa]);
3423 }
3424 //sim_msg ("%05o:%06o\n", cpu.PR[2].SNR, cpu.rX[0]);
3425 //dbgStackTrace ();
3426 # if 0
3427 if (dbgLookupAddress (cpu.PR[2].SNR, cpu.rX[0], & pa, & msg))
3428 {
3429 sim_msg ("return address lookup failed because %s\n", msg);
3430 }
3431 else
3432 {
3433 sim_msg ("scale %012"PRIo64" (%llu)\n", M[pa], M[pa]);
3434 }
3435 # endif
3436 if (dbgLookupAddress (cpu.PR[2].SNR, cpu.PR[2].WORDNO, & pa, & msg))
3437 {
3438 sim_msg ("divisor address lookup failed because %s\n", msg);
3439 }
3440 else
3441 {
3442 sim_msg ("divisor %012"PRIo64" (%llu)\n", M[pa], M[pa]);
3443 }
3444 return SCPE_OK;
3445 }
3446
smfx1entry(UNUSED int32 arg,UNUSED const char * buf)3447 static t_stat smfx1entry (UNUSED int32 arg, UNUSED const char * buf)
3448 {
3449 // operator to form mod(fx2,fx1)
3450 // entered with first arg in q, bp pointing at second
3451
3452 // divide_fx1, divide_fx2
3453 sim_msg ("smfx1entry\n");
3454 //sim_msg ("rA %012"PRIo64" (%llu)\n", rA, rA);
3455 sim_msg ("rQ %012"PRIo64" (%llu)\n", rQ, rQ);
3456 // Figure out the caller's text segment, according to pli_operators.
3457 // sp:tbp -> PR[6].SNR:046
3458 word24 pa;
3459 char * msg;
3460 if (dbgLookupAddress (cpu.PR[6].SNR, 046, & pa, & msg))
3461 {
3462 sim_msg ("text segment number lookup failed because %s\n", msg);
3463 }
3464 else
3465 {
3466 sim_msg ("text segno %012"PRIo64" (%llu)\n", M[pa], M[pa]);
3467 }
3468 sim_msg ("%05o:%06o\n", cpu.PR[2].SNR, cpu.rX[0]);
3469 //dbgStackTrace ();
3470 if (dbgLookupAddress (cpu.PR[2].SNR, cpu.rX[0], & pa, & msg))
3471 {
3472 sim_msg ("return address lookup failed because %s\n", msg);
3473 }
3474 else
3475 {
3476 sim_msg ("scale %012"PRIo64" (%llu)\n", M[pa], M[pa]);
3477 }
3478 if (dbgLookupAddress (cpu.PR[2].SNR, cpu.PR[2].WORDNO, & pa, & msg))
3479 {
3480 sim_msg ("divisor address lookup failed because %s\n", msg);
3481 }
3482 else
3483 {
3484 sim_msg ("divisor %012"PRIo64" (%llu)\n", M[pa], M[pa]);
3485 }
3486 return SCPE_OK;
3487 }
3488 # endif // DVFDBG
3489
3490 // SEARCHMEMORY value
3491
3492 # ifndef SCUMEM
search_memory(UNUSED int32 arg,const char * buf)3493 static t_stat search_memory (UNUSED int32 arg, const char * buf)
3494 {
3495 word36 value;
3496 if (sscanf (buf, "%"PRIo64"", & value) != 1)
3497 return SCPE_ARG;
3498
3499 uint i;
3500 for (i = 0; i < MEMSIZE; i ++)
3501 if ((M[i] & DMASK) == value)
3502 sim_msg ("%08o\n", i);
3503 return SCPE_OK;
3504 }
3505 # endif
3506
set_dbg_cpu_mask(int32 UNUSED arg,const char * UNUSED buf)3507 static t_stat set_dbg_cpu_mask (int32 UNUSED arg, const char * UNUSED buf)
3508 {
3509 uint msk;
3510 int cnt = sscanf (buf, "%u", & msk);
3511 if (cnt != 1)
3512 {
3513 sim_msg ("Huh?\n");
3514 return SCPE_ARG;
3515 }
3516 sim_msg ("mask set to %u\n", msk);
3517 dbgCPUMask = msk;
3518 return SCPE_OK;
3519 }
3520
3521 #endif // TESTING
3522
3523 //
3524 // Misc. commands
3525 //
3526
3527 #ifdef PANEL
scraper(UNUSED int32 arg,const char * buf)3528 static t_stat scraper (UNUSED int32 arg, const char * buf)
3529 {
3530 if (strcasecmp (buf, "start") == 0)
3531 return panelScraperStart ();
3532 if (strcasecmp (buf, "stop") == 0)
3533 return panelScraperStop ();
3534 if (strcasecmp (buf, "msg") == 0)
3535 {
3536 return panelScraperMsg (NULL);
3537 }
3538 if (strncasecmp (buf, "msg ", 4) == 0)
3539 {
3540 const char * p = buf + 4;
3541 while (* p == ' ')
3542 p ++;
3543 return panelScraperMsg (p);
3544 }
3545 sim_msg ("err: scraper start|stop|msg\n");
3546 return SCPE_ARG;
3547 }
3548 #endif
3549
3550 #ifdef YIELD
clear_yield(int32 flag,UNUSED const char * cptr)3551 static t_stat clear_yield (int32 flag, UNUSED const char * cptr)
3552 {
3553 return SCPE_OK;
3554 }
3555
yield(int32 flag,UNUSED const char * cptr)3556 static t_stat yield (int32 flag, UNUSED const char * cptr)
3557 {
3558 return SCPE_OK;
3559 }
3560 #endif
3561
set_luf(int32 flag,UNUSED const char * cptr)3562 static t_stat set_luf (int32 flag, UNUSED const char * cptr)
3563 {
3564 luf_flag = flag;
3565 return SCPE_OK;
3566 }
3567
3568 #ifdef DBGEVENT
3569 uint n_dbgevents;
3570 struct dbgevent_t dbgevents[max_dbgevents];
3571 struct timespec dbgevent_t0;
3572
dbgevent_compar(const void * a,const void * b)3573 static int dbgevent_compar (const void * a, const void * b)
3574 {
3575 struct dbgevent_t * ea = (struct dbgevent_t *) a;
3576 struct dbgevent_t * eb = (struct dbgevent_t *) b;
3577 if (ea->segno < eb->segno)
3578 return -1;
3579 if (ea->segno > eb->segno)
3580 return 1;
3581 if (ea->offset < eb->offset)
3582 return -1;
3583 if (ea->offset > eb->offset)
3584 return 1;
3585 return 0;
3586 }
3587
dbgevent_lookup(word15 segno,word18 offset)3588 int dbgevent_lookup (word15 segno, word18 offset)
3589 {
3590 struct dbgevent_t key = {segno, offset, false};
3591 struct dbgevent_t * p = (struct dbgevent_t *) bsearch (& key, dbgevents, (size_t) n_dbgevents, sizeof (struct dbgevent_t), dbgevent_compar);
3592 if (! p)
3593 return -1;
3594 return (int) (p - dbgevents);
3595 }
3596
3597 // "dbbevent segno:offset"
3598 //
3599 // arg: 0 set t0 event
3600 // 1 set event
3601 // 2 clear event
3602 // 3 list events
3603 // 4 clear all events
3604
3605 // XXX think about per-thread timing?
3606
set_dbgevent(int32 arg,const char * buf)3607 static t_stat set_dbgevent (int32 arg, const char * buf)
3608 {
3609 if (arg == 0 || arg == 1)
3610 {
3611 if (n_dbgevents >= max_dbgevents)
3612 {
3613 sim_printf ("too many dbgevents %u/%u\r\n", n_dbgevents, max_dbgevents);
3614 return SCPE_ARG;
3615 }
3616 if (strlen (buf) > dbgevent_tagsize - 1)
3617 {
3618 sim_printf ("command too long %lu/%u\r\n", strlen (buf), dbgevent_tagsize -1);
3619 return SCPE_ARG;
3620 }
3621
3622 uint segno;
3623 uint offset;
3624 if (sscanf (buf, "%o:%o", & segno, & offset) != 2)
3625 return SCPE_ARG;
3626 if (segno > MASK15 || offset > MASK18)
3627 return SCPE_ARG;
3628 if (dbgevent_lookup ((word15) segno, (word18) offset) != -1)
3629 {
3630 sim_printf ("not adding duplicate 0%o:0%o\r\n", segno, offset);
3631 return SCPE_ARG;
3632 }
3633 dbgevents[n_dbgevents].segno = (word15) segno;
3634 dbgevents[n_dbgevents].offset = (word18) offset;
3635 dbgevents[n_dbgevents].t0 = arg == 0;
3636 strncpy (dbgevents[n_dbgevents].tag, buf, dbgevent_tagsize - 1);
3637 dbgevents[n_dbgevents].tag[dbgevent_tagsize - 1] = 0;
3638 sim_printf ("%o:%o %u(%d) %s\r\n", dbgevents[n_dbgevents].segno, dbgevents[n_dbgevents].offset, dbgevents[n_dbgevents].t0, arg, dbgevents[n_dbgevents].tag);
3639 n_dbgevents ++;
3640 qsort (dbgevents, n_dbgevents, sizeof (struct dbgevent_t), dbgevent_compar);
3641 }
3642 else if (arg == 2)
3643 {
3644 uint segno;
3645 uint offset;
3646 if (sscanf (buf, "%o:%o", & segno, & offset) != 2)
3647 return SCPE_ARG;
3648 int n = dbgevent_lookup ((word15) segno, (word18) offset);
3649 if (n < 0)
3650 {
3651 sim_printf ("0%o:0%o not found\r\n", segno, offset);
3652 return SCPE_ARG;
3653 }
3654 for (int i = n; i < n_dbgevents - 1; i ++)
3655 dbgevents[i] = dbgevents[i + 1];
3656 n_dbgevents --;
3657 }
3658 else if (arg == 3)
3659 {
3660 for (int i = 0; i < n_dbgevents; i ++)
3661 sim_printf (" %s %05o:%06o %s\r\n", dbgevents[i].t0 ? "T0" : " ", dbgevents[i].segno, dbgevents[i].offset,dbgevents[i].tag);
3662 }
3663 else if (arg == 4)
3664 {
3665 n_dbgevents = 0;
3666 sim_printf ("dbgevents cleared\r\n");
3667 }
3668 else
3669 {
3670 sim_printf ("set_dbgevent bad arg %d\r\n", arg);
3671 return SCPE_ARG;
3672 }
3673 return SCPE_OK;
3674 }
3675 #endif
3676
3677 // [UN]LOAD name image_name ro|rw
3678 //
3679 // load tapea_05 data.tap ro
3680 //
3681 // load diskb_01 data.dsk rw
3682 //
3683
load_media(int32 arg,const char * buf)3684 t_stat load_media (int32 arg, const char * buf)
3685 {
3686 // arg 1: load
3687 // 0: unload
3688
3689 char name[strlen (buf)];
3690 char fname[strlen (buf)];
3691 char perm[strlen (buf)];
3692 bool ro = false;
3693 if (arg)
3694 {
3695 int rc = sscanf (buf, "%s %s %s", name, fname, perm);
3696 if (rc != 3)
3697 return SCPE_ARG;
3698 if (strcasecmp (perm, "rw") == 0)
3699 ro = false;
3700 else if (strcasecmp (perm, "ro") == 0)
3701 ro = true;
3702 else
3703 {
3704 sim_print ("'%s' not 'ro' or 'rw'\r\n", perm);
3705 goto usage;
3706 }
3707 }
3708 else
3709 {
3710 int rc = sscanf (buf, "%s", name);
3711 if (rc != 1)
3712 return SCPE_ARG;
3713 }
3714
3715 for (uint i = 0; i < N_DSK_UNITS_MAX; i ++)
3716 if (strcmp (dsk_states[i].device_name, name) == 0)
3717 {
3718 if (arg)
3719 return loadDisk (i, fname, ro);
3720 return unloadDisk (i);
3721 }
3722
3723 for (uint i = 0; i < N_MT_UNITS_MAX; i ++)
3724 if (strcmp (tape_states[i].device_name, name) == 0)
3725 {
3726 if (arg)
3727 return loadTape (i, fname, ro);
3728 return unloadTape (i);
3729 }
3730
3731 sim_printf ("Can't find name '%s'\r\n", name);
3732 usage:
3733 sim_printf ("[UN]LOAD device_name image_name ro|rw\r\n");
3734 return SCPE_ARG;
3735 }
3736
ready_media(int32 arg,const char * buf)3737 t_stat ready_media (int32 arg, const char * buf) {
3738 char name[strlen (buf)];
3739 int rc = sscanf (buf, "%s", name);
3740 if (rc != 1)
3741 return SCPE_ARG;
3742
3743 for (uint i = 0; i < N_DSK_UNITS_MAX; i ++) {
3744 if (strcmp (dsk_states[i].device_name, name) == 0) {
3745 return signal_disk_ready (i);
3746 }
3747 }
3748
3749 for (uint i = 0; i < N_MT_UNITS_MAX; i ++) {
3750 if (strcmp (tape_states[i].device_name, name) == 0) {
3751 return signal_tape (i, 0, 020 /* tape drive to ready */);
3752 }
3753 }
3754
3755 sim_printf ("Can't find name '%s'\r\n", name);
3756 sim_printf ("[UN]LOAD device_name image_name ro|rw\r\n");
3757 return SCPE_ARG;
3758 }
3759
3760 ////////////////////////////////////////////////////////////////////////////////
3761 //
3762 // s*mh Command table
3763 //
3764
3765 #ifdef TESTING
3766 # include "tracker.h"
3767
trkw(UNUSED int32 arg,const char * buf)3768 static t_stat trkw (UNUSED int32 arg, const char * buf)
3769 {
3770 trk_init (true);
3771 return SCPE_OK;
3772 }
3773
trkr(UNUSED int32 arg,const char * buf)3774 static t_stat trkr (UNUSED int32 arg, const char * buf)
3775 {
3776 trk_init (false);
3777 return SCPE_OK;
3778 }
3779 #endif
3780
3781 static CTAB dps8_cmds[] =
3782 {
3783
3784 //
3785 // System configuration
3786 //
3787
3788 {"DEFAULT_BASE_SYSTEM", set_default_base_system, 0, "default_base_system: Set configuration to defaults\n", NULL, NULL},
3789
3790 {"CABLE", sys_cable, 0, "cable: String a cable\n" , NULL, NULL},
3791 {"UNCABLE", sys_cable, 1, "uncable: Unstring a cable\n" , NULL, NULL},
3792 {"CABLE_RIPOUT", sys_cable_ripout, 0, "cable: Unstring all cables\n" , NULL, NULL},
3793 {"CABLE_SHOW", sys_cable_show, 0, "cable: Show cables\n" , NULL, NULL},
3794
3795 {"FNPSERVERPORT", set_fnp_server_port, 0, "fnpserverport: Set the FNP dialin telnet port number\n", NULL, NULL},
3796 {"FNPSERVERADDRESS", set_fnp_server_address, 0, "fnpserveraddress: Set the FNP dialin telnet address\n", NULL, NULL},
3797 {"FNPSERVER3270PORT", set_fnp_3270_server_port, 0, "fnpserver3270port: Set the FNP 3270 port number\n", NULL, NULL},
3798
3799 {"CONSOLEPORT", set_console_port, 0, "consoleport: Set the Operator Console port number\n", NULL, NULL},
3800 {"CONSOLEADDRESS", set_console_address, 0, "consoleport: Set the Operator Console address\n", NULL, NULL},
3801 {"CONSOLEPW", set_console_pw, 0, "consolepw: Set the Operator Console port password\n", NULL, NULL},
3802 {"CONSOLEPORT1", set_console_port, 1, "consoleport1: Set the CPU-B Operator Console port number\n", NULL, NULL},
3803 {"CONSOLEADDRESS1", set_console_address, 1, "consoleport: Set the Operator Console address\n", NULL, NULL},
3804 {"CONSOLEPW1", set_console_pw, 1, "consolepw1: Set the CPU-B Operator Console port password\n", NULL, NULL},
3805
3806 {"MACHINEROOMPORT", set_machine_room_port, 0, "machineroomport: set the machine room port number\n", NULL, NULL},
3807 {"MACHINEROOMADDRESS", set_machine_room_address, 0, "machineroomaddress: set the machine room address\n", NULL, NULL},
3808 {"MACHINEROOMPW", set_machine_room_pw, 0, "machineroompW: set the machine room port password\n", NULL, NULL},
3809
3810 //
3811 // System contol
3812 //
3813
3814 {"SKIPBOOT", boot_skip, 0, "skipboot: Skip forward on boot tape\n", NULL, NULL},
3815 {"FNPSTART", fnp_start, 0, "fnpstart: Force immediate FNP initialization\n", NULL, NULL},
3816 {"MOUNT", mount_tape, 0, "mount: Mount tape image and signal Mulitcs\n", NULL, NULL },
3817 {"LOAD", load_media, 1, "mount: Mount disk or tape image and signal Mulitcs\n", NULL, NULL },
3818 {"UNLOAD", load_media, 0, "mount: Unmount disk or tape image and signal Mulitcs\n", NULL, NULL },
3819 {"READY", ready_media, 0, "ready: Signal Mulitcs that media is ready\n", NULL, NULL },
3820 {"XF", do_execute_fault, 0, "xf: Execute fault: Press the execute fault button\n", NULL, NULL},
3821 {"RESTART", do_restart, 0, "xf: Execute fault: Press the execute fault button\n", NULL, NULL},
3822 {"POLL", set_sys_polling_interval, 0, "Set polling interval in milliseconds", NULL, NULL },
3823 {"SLOWPOLL", set_sys_slow_polling_interval, 0, "Set slow polling interval in polling intervals", NULL, NULL },
3824 {"CHECKPOLL", set_sys_poll_check_rate, 0, "Set slow polling interval in polling intervals", NULL, NULL },
3825 {"BURST", burst_printer, 0, "Burst output from printrt", NULL, NULL },
3826
3827 //
3828 // Debugging
3829 //
3830
3831 #ifdef TESTING
3832 {"TRKW", trkw, 0, "tracker: Start tracking to track.dat\n", NULL, NULL},
3833 {"TRKR", trkr, 0, "tracker: Start comparing with track.dat\n", NULL, NULL},
3834 {"DBGMMECNTDWN", dps_debug_mme_cntdwn, 0, "dbgmmecntdwn: Enable debug after n MMEs\n", NULL, NULL},
3835 {"DBGSKIP", dps_debug_skip, 0, "dbgskip: Skip first n TRACE debugs\n", NULL, NULL},
3836 {"DBGSTART", dps_debug_start, 0, "dbgstart: Limit debugging to N > Cycle count\n", NULL, NULL},
3837 {"DBGSTOP", dps_debug_stop, 0, "dbgstop: Limit debugging to N < Cycle count\n", NULL, NULL},
3838 {"DBGBREAK", dps_debug_break, 0, "dbgstop: Break when N >= Cycle count\n", NULL, NULL},
3839 {"DBGSEGNO", dps_debug_segno, 1, "dbgsegno: Limit debugging to PSR == segno\n", NULL, NULL},
3840 {"NODBGSEGNO", dps_debug_segno, 0, "nodbgsegno: Reset to debugging all segments\n", NULL, NULL},
3841 {"DBGRINGNO", dps_debug_ringno, 0, "dbgsegno: Limit debugging to PRR == ringno\n", NULL, NULL},
3842 {"DBGBAR", dps_debug_bar, 1, "dbgbar: Limit debugging to BAR mode\n", NULL, NULL},
3843 {"NODBGBAR", dps_debug_bar, 0, "dbgbar: Limit debugging to BAR mode\n", NULL, NULL},
3844 {"HDBG", hdbg_size, 0, "hdbg: set history debugger buffer size\n", NULL, NULL},
3845 {"HDSEG", hdbgSegmentNumber, 0, "hdseg: set history debugger segment number\n", NULL, NULL},
3846 {"HDBL", hdbgBlacklist, 0, "hdbl: set history debugger blacklist\n", NULL, NULL},
3847 {"PHDBG", hdbg_print, 0, "phdbg: display history size\n", NULL, NULL},
3848 {"HDBG_CPU_MASK", hdbg_cpu_mask, 0, "hdbg_cpu_mask: Which CPUS to track\n", NULL, NULL},
3849 {"ABSOLUTE", abs_addr, 0, "abs: Compute the absolute address of segno:offset\n", NULL, NULL},
3850 # ifndef SCUMEM
3851 {"STK", stack_trace, 0, "stk: Print a stack trace\n", NULL, NULL},
3852 # endif
3853 {"LIST", list_source_at, 0, "list segno:offet: List source for an address\n", NULL, NULL},
3854 {"LD_SYSTEM_BOOK", load_system_book, 0, "load_system_book: Load a Multics system book for symbolic debugging\n", NULL, NULL},
3855 {"ASBE", add_system_book_entry, 0, "asbe: Add an entry to the system book\n", NULL, NULL},
3856 {"LOOKUP_SYSTEM_BOOK", lookup_system_book, 0, "lookup_system_book: Lookup an address or symbol in the Multics system book\n", NULL, NULL},
3857 {"LSB", lookup_system_book, 0, "lsb: Lookup an address or symbol in the Multics system book\n", NULL, NULL},
3858 # ifndef SCUMEM
3859 {"VIRTUAL", virt_address, 0, "virtual: Compute the virtural address(es) of segno:offset\n", NULL, NULL},
3860 # endif
3861 {"SPATH", set_search_path, 0, "spath: Set source code search path\n", NULL, NULL},
3862 {"TEST", brkbrk, 0, "test: GDB hook\n", NULL, NULL},
3863 # ifdef DBGEVENT
3864 {"DBG0EVENT", set_dbgevent, 0, "dbg0event: set t0 event\n", NULL, NULL},
3865 {"DBGEVENT", set_dbgevent, 1, "dbgevent: set event\n", NULL, NULL},
3866 {"DBGNOEVENT", set_dbgevent, 2, "dbgnoevent: clear event\n", NULL, NULL},
3867 {"DBGLISTEVENTS", set_dbgevent, 3, "dbglistevents: list events\n", NULL, NULL},
3868 {"DBGCLEAREVENTS", set_dbgevent, 4, "dbgevent: clear events\n", NULL, NULL},
3869 # endif
3870
3871 // copied from scp.c
3872 # define SSH_ST 0 /* set */
3873 # define SSH_SH 1 /* show */
3874 # define SSH_CL 2 /* clear */
3875 {"SBREAK", sbreak, SSH_ST, "sbreak: Set a breakpoint with segno:offset syntax\n", NULL, NULL},
3876 {"NOSBREAK", sbreak, SSH_CL, "nosbreak: Unset an SBREAK\n", NULL, NULL},
3877 # ifdef DVFDBG
3878 // dvf debugging
3879 {"DFX1ENTRY", dfx1entry, 0, "\n", NULL, NULL},
3880 {"DFX2ENTRY", dfx2entry, 0, "\n", NULL, NULL},
3881 {"DFX1EXIT", dfx1exit, 0, "\n", NULL, NULL},
3882 {"DV2SCALE", dv2scale, 0, "\n", NULL, NULL},
3883 {"MDFX3ENTRY", mdfx3entry, 0, "\n", NULL, NULL},
3884 {"SMFX1ENTRY", smfx1entry, 0, "\n", NULL, NULL},
3885 # endif
3886 // doesn't work
3887 //{"DUMPKST", dumpKST, 0, "dumpkst: dump the Known Segment Table\n", NULL},
3888 # ifndef SPEED
3889 {"WATCH", set_mem_watch, 1, "watch: Watch memory location\n", NULL, NULL},
3890 {"NOWATCH", set_mem_watch, 0, "watch: Unwatch memory location\n", NULL, NULL},
3891 # endif
3892 # ifndef SCUMEM
3893 {"SEARCHMEMORY", search_memory, 0, "searchmemory: Search memory for value\n", NULL, NULL},
3894 # endif
3895 {"DBGCPUMASK", set_dbg_cpu_mask, 0, "dbgcpumask: Set per CPU debug enable", NULL, NULL},
3896 #endif // TESTING
3897
3898 {"SEGLDR", segment_loader, 0, "Segment Loader", NULL, NULL},
3899
3900 //
3901 // Statistics
3902 //
3903
3904 #ifdef MATRIX
3905 {"DISPLAYMATRIX", display_the_matrix, 0, "displaymatrix: Display instruction usage counts\n", NULL, NULL},
3906 #endif
3907
3908
3909 //
3910 // Console scripting
3911 //
3912
3913 {"AUTOINPUT", add_opc_autoinput, 0, "autoinput: Set console auto-input\n", NULL, NULL},
3914 {"AI", add_opc_autoinput, 0, "ai: Set console auto-input\n", NULL, NULL},
3915 {"AUTOINPUT2", add_opc_autoinput, 1, "autoinput2: Set CPU-B console auto-input\n", NULL, NULL},
3916 {"AI2", add_opc_autoinput, 1, "ai2: Set console CPU-B auto-input\n", NULL, NULL},
3917 {"CLRAUTOINPUT", clear_opc_autoinput, 0, "clrautoinput: Clear console auto-input\n", NULL, NULL},
3918 {"CLRAUTOINPUT2", clear_opc_autoinput, 1, "clrautoinput1: Clear CPU-B console auto-input\n", NULL, NULL},
3919
3920
3921 //
3922 // Tuning
3923 //
3924
3925 #if YIELD
3926 {"CLEAR_YIELD", clear_yield, 1, "clear_yield: clear yield data\n", NULL, NULL},
3927 {"YIELD", yield, 1, "yield: define yield point\n", NULL, NULL},
3928 #endif
3929
3930 //
3931
3932 //
3933 // Hacks
3934 //
3935
3936 {"LUF", set_luf, 1, "Enable normal LUF handling\n", NULL, NULL},
3937 {"NOLUF", set_luf, 0, "Disable normal LUF handling\n", NULL, NULL},
3938
3939 //
3940 // Misc.
3941 //
3942
3943 #ifdef PANEL
3944 {"SCRAPER", scraper, 0, "scraper: Control scraper\n", NULL, NULL},
3945 #endif
3946 { NULL, NULL, 0, NULL, NULL, NULL}
3947 }; // dps8_cmds
3948
3949 #ifndef __MINGW64__
3950 # ifndef __MINGW32__
3951 # ifndef CROSS_MINGW64
3952 # ifndef CROSS_MINGW32
usr1_signal_handler(UNUSED int sig)3953 static void usr1_signal_handler (UNUSED int sig)
3954 {
3955 sim_msg ("USR1 signal caught; pressing the EXF button\n");
3956 // Assume the bootload CPU
3957 setG7fault (ASSUME0, FAULT_EXF, fst_zero);
3958 return;
3959 }
3960 # endif /* ifndef CROSS_MINGW32 */
3961 # endif /* ifndef CROSS_MINGW64 */
3962 # endif /* ifndef __MINGW32__ */
3963 #endif /* ifndef __MINGW64__ */
3964
3965 static struct symbol_s symbols [] = {
3966 { "commit_id", SYM_STATE_OFFSET, SYM_STRING, offsetof (struct system_state_s, commit_id) },
3967 { "M[]", SYM_STATE_OFFSET, SYM_ARRAY, offsetof (struct system_state_s, M) },
3968 { "sizeof(*M)", SYM_STRUCT_SZ, SYM_SZ, sizeof (word36) },
3969
3970 { "cpus[]", SYM_STATE_OFFSET, SYM_ARRAY, offsetof (struct system_state_s, cpus) },
3971 { "sizeof(*cpus)", SYM_STRUCT_SZ, SYM_SZ, sizeof (cpu_state_t) },
3972
3973 { "cpus[].PPR", SYM_STRUCT_OFFSET, SYM_PTR, offsetof (cpu_state_t, PPR) },
3974 { "cpus[].PPR.PRR", SYM_STRUCT_OFFSET, SYM_UINT8_3, offsetof (struct ppr_s, PRR) },
3975 { "cpus[].PPR.PSR", SYM_STRUCT_OFFSET, SYM_UINT16_15, offsetof (struct ppr_s, PSR) },
3976 { "cpus[].PPR.P", SYM_STRUCT_OFFSET, SYM_UINT8_1, offsetof (struct ppr_s, P) },
3977 { "cpus[].PPR.IC", SYM_STRUCT_OFFSET, SYM_UINT32_18, offsetof (struct ppr_s, IC) },
3978
3979 { "cpus[].cu", SYM_STRUCT_OFFSET, SYM_PTR, offsetof (cpu_state_t, cu) },
3980 { "cpus[].cu.IWB", SYM_STRUCT_OFFSET, SYM_UINT64_36, offsetof (ctl_unit_data_t, IWB) },
3981 { "cpus[].cu.IR", SYM_STRUCT_OFFSET, SYM_UINT32_18, offsetof (ctl_unit_data_t, IR) },
3982
3983 { "cpus[].rA", SYM_STRUCT_OFFSET, SYM_UINT64_36, offsetof (cpu_state_t, rA) },
3984
3985 { "cpus[].rQ", SYM_STRUCT_OFFSET, SYM_UINT64_36, offsetof (cpu_state_t, rQ) },
3986
3987 { "cpus[].rE", SYM_STRUCT_OFFSET, SYM_UINT64_36, offsetof (cpu_state_t, rE) },
3988
3989 { "cpus[].rX[]", SYM_STRUCT_OFFSET, SYM_ARRAY, offsetof (cpu_state_t, rX) },
3990 { "sizeof(*rX)", SYM_STRUCT_SZ, SYM_SZ, sizeof (word18) },
3991 { "cpus[].rX", SYM_STRUCT_OFFSET, SYM_UINT32_18, 0 },
3992
3993
3994 { "cpus[].rTR", SYM_STRUCT_OFFSET, SYM_UINT32_27, offsetof (cpu_state_t, rTR) },
3995
3996 { "cpus[].rRALR", SYM_STRUCT_OFFSET, SYM_UINT8_3, offsetof (cpu_state_t, rRALR) },
3997
3998 { "cpus[].PAR[]", SYM_STRUCT_OFFSET, SYM_ARRAY, offsetof (cpu_state_t, PAR) },
3999 { "sizeof(*PAR)", SYM_STRUCT_SZ, SYM_SZ, sizeof (struct par_s) },
4000
4001 { "cpus[].PAR[].SNR", SYM_STRUCT_OFFSET, SYM_UINT16_15, offsetof (struct par_s, SNR) },
4002 { "cpus[].PAR[].RNR", SYM_STRUCT_OFFSET, SYM_UINT8_3, offsetof (struct par_s, RNR) },
4003 { "cpus[].PAR[].PR_BITNO", SYM_STRUCT_OFFSET, SYM_UINT8_6, offsetof (struct par_s, PR_BITNO) },
4004 { "cpus[].PAR[].WORDNO", SYM_STRUCT_OFFSET, SYM_UINT32_18, offsetof (struct par_s, WORDNO) },
4005
4006 { "cpus[].BAR", SYM_STRUCT_OFFSET, SYM_PTR, offsetof (cpu_state_t, BAR) },
4007 { "cpus[].BAR.BASE", SYM_STRUCT_OFFSET, SYM_UINT16_9, offsetof (struct bar_s, BASE) },
4008 { "cpus[].BAR.BOUND", SYM_STRUCT_OFFSET, SYM_UINT16_9, offsetof (struct bar_s, BOUND) },
4009
4010 { "cpus[].TPR", SYM_STRUCT_OFFSET, SYM_PTR, offsetof (cpu_state_t, TPR) },
4011 { "cpus[].TPR.TRR", SYM_STRUCT_OFFSET, SYM_UINT8_3, offsetof (struct tpr_s, TRR) },
4012 { "cpus[].TPR.TSR", SYM_STRUCT_OFFSET, SYM_UINT16_15, offsetof (struct tpr_s, TSR) },
4013 { "cpus[].TPR.TBR", SYM_STRUCT_OFFSET, SYM_UINT8_6, offsetof (struct tpr_s, TBR) },
4014 { "cpus[].TPR.CA", SYM_STRUCT_OFFSET, SYM_UINT32_18, offsetof (struct tpr_s, CA) },
4015
4016 { "cpus[].DSBR", SYM_STRUCT_OFFSET, SYM_PTR, offsetof (cpu_state_t, DSBR) },
4017 { "cpus[].DSBR.ADDR", SYM_STRUCT_OFFSET, SYM_UINT32_24, offsetof (struct dsbr_s, ADDR) },
4018 { "cpus[].DSBR.BND", SYM_STRUCT_OFFSET, SYM_UINT16_14, offsetof (struct dsbr_s, BND) },
4019 { "cpus[].DSBR.U", SYM_STRUCT_OFFSET, SYM_UINT8_1, offsetof (struct dsbr_s, U) },
4020 { "cpus[].DSBR.STACK", SYM_STRUCT_OFFSET, SYM_UINT16_12, offsetof (struct dsbr_s, STACK) },
4021
4022 { "cpus[].faultNumber", SYM_STRUCT_OFFSET, SYM_UINT32, offsetof (cpu_state_t, faultNumber) },
4023 #define SYMTAB_ENUM32(e) { #e, SYM_ENUM, SYM_UINT32, e }
4024 SYMTAB_ENUM32 (FAULT_SDF),
4025 SYMTAB_ENUM32 (FAULT_STR),
4026 SYMTAB_ENUM32 (FAULT_MME),
4027 SYMTAB_ENUM32 (FAULT_F1),
4028 SYMTAB_ENUM32 (FAULT_TRO),
4029 SYMTAB_ENUM32 (FAULT_CMD),
4030 SYMTAB_ENUM32 (FAULT_DRL),
4031 SYMTAB_ENUM32 (FAULT_LUF),
4032 SYMTAB_ENUM32 (FAULT_CON),
4033 SYMTAB_ENUM32 (FAULT_PAR),
4034 SYMTAB_ENUM32 (FAULT_IPR),
4035 SYMTAB_ENUM32 (FAULT_ONC),
4036 SYMTAB_ENUM32 (FAULT_SUF),
4037 SYMTAB_ENUM32 (FAULT_OFL),
4038 SYMTAB_ENUM32 (FAULT_DIV),
4039 SYMTAB_ENUM32 (FAULT_EXF),
4040 SYMTAB_ENUM32 (FAULT_DF0),
4041 SYMTAB_ENUM32 (FAULT_DF1),
4042 SYMTAB_ENUM32 (FAULT_DF2),
4043 SYMTAB_ENUM32 (FAULT_DF3),
4044 SYMTAB_ENUM32 (FAULT_ACV),
4045 SYMTAB_ENUM32 (FAULT_MME2),
4046 SYMTAB_ENUM32 (FAULT_MME3),
4047 SYMTAB_ENUM32 (FAULT_MME4),
4048 SYMTAB_ENUM32 (FAULT_F2),
4049 SYMTAB_ENUM32 (FAULT_F3),
4050 SYMTAB_ENUM32 (FAULT_UN1),
4051 SYMTAB_ENUM32 (FAULT_UN2),
4052 SYMTAB_ENUM32 (FAULT_UN3),
4053 SYMTAB_ENUM32 (FAULT_UN4),
4054 SYMTAB_ENUM32 (FAULT_UN5),
4055 SYMTAB_ENUM32 (FAULT_TRB),
4056
4057 { "", SYM_EMPTY, SYM_UNDEF, 0 },
4058 };
4059
systabInit(void)4060 static void systabInit (void) {
4061 strncpy (system_state->symbolTable.symtabHdr, SYMTAB_HDR, sizeof (system_state->symbolTable.symtabHdr));
4062 system_state->symbolTable.symtabVer = SYMTAB_VER;
4063 memcpy (system_state->symbolTable.symbols, symbols, sizeof (symbols));
4064 }
4065
4066
4067 // Once-only initialization; invoked by simh
4068
dps8_init(void)4069 static void dps8_init (void) {
4070 fflush(stderr); fflush(stdout);
4071 #ifndef PERF_STRIP
4072 if (!sim_quiet) {
4073 # if defined(GENERATED_MAKE_VER_H) && defined(VER_H_GIT_VERSION)
4074 # if defined(VER_H_GIT_PATCH_INT) && defined(VER_H_GIT_PATCH)
4075 # if VER_H_GIT_PATCH_INT < 1
4076 sim_msg ("%s simulator %s", sim_name, VER_H_GIT_VERSION);
4077 # else
4078 sim_msg ("%s simulator %s+%s", sim_name, VER_H_GIT_VERSION, VER_H_GIT_PATCH);
4079 # endif
4080 # else
4081 sim_msg ("%s simulator %s", sim_name, VER_H_GIT_VERSION);
4082 # endif
4083 # endif
4084 # if !defined(VER_H_GIT_VERSION) || !defined(GENERATED_MAKE_VER_H)
4085 sim_msg ("%s simulator", sim_name);
4086 # endif
4087 # ifdef TESTING
4088 sim_msg ("\n Options: ");
4089 # ifndef HAVE_DPSOPT
4090 # define HAVE_DPSOPT 1
4091 # endif
4092 sim_msg ("TESTING");
4093 # endif
4094 # ifdef NEED_128
4095 # ifdef HAVE_DPSOPT
4096 sim_msg (", ");
4097 # else
4098 sim_msg ("\n Options: ");
4099 # endif
4100 # ifndef HAVE_DPSOPT
4101 # define HAVE_DPSOPT 1
4102 # endif
4103 sim_msg ("NEED_128");
4104 # endif
4105 # ifdef ROUND_ROBIN
4106 # ifdef HAVE_DPSOPT
4107 sim_msg (", ");
4108 # else
4109 sim_msg ("\n Options: ");
4110 # endif
4111 # ifndef HAVE_DPSOPT
4112 # define HAVE_DPSOPT 1
4113 # endif
4114 sim_msg ("ROUND_ROBIN");
4115 # endif
4116 # ifndef LOCKLESS
4117 # ifdef HAVE_DPSOPT
4118 sim_msg (", ");
4119 # else
4120 sim_msg ("\n Options: ");
4121 # endif
4122 # ifndef HAVE_DPSOPT
4123 # define HAVE_DPSOPT 1
4124 # endif
4125 sim_msg ("NO_LOCKLESS");
4126 # endif
4127 # if defined(GENERATED_MAKE_VER_H) && defined(VER_H_GIT_HASH)
4128 sim_msg ("\n Commit: %s", VER_H_GIT_HASH);
4129 # endif
4130 sim_msg ("\r\n\r\n");
4131 fflush(stderr); fflush(stdout);
4132 }
4133
4134 // special dps8 initialization stuff that cant be done in reset, etc .....
4135
4136 # ifdef TESTING
4137 // These are part of the simh interface
4138 sim_vm_parse_addr = parse_addr;
4139 sim_vm_fprint_addr = fprint_addr;
4140 # endif // TESTING
4141
4142 sim_vm_cmd = dps8_cmds;
4143
4144 // This is needed to make sbreak work
4145 sim_brk_types = sim_brk_dflt = SWMASK ('E');
4146
4147 # ifndef __MINGW64__
4148 # ifndef __MINGW32__
4149 # ifndef CROSS_MINGW32
4150 # ifndef CROSS_MINGW64
4151 // Wire the XF button to signal USR1
4152 signal (SIGUSR1, usr1_signal_handler);
4153 // On line 4,739 of the libuv man page, it recommends this.
4154 signal(SIGPIPE, SIG_IGN);
4155 # endif /* ifndef CROSS_MINGW64 */
4156 # endif /* ifndef CROSS_MINGW32 */
4157 # endif /* ifndef __MINGW32__ */
4158 # endif /* ifndef __MINGW64__ */
4159
4160 # ifdef SCUMEM
4161 # error SCUMEM not working with new shared memory model
4162 # endif
4163 #endif // ! PERF_STRIP
4164
4165 #if defined(__MINGW64__) || defined(__MINGW32__)
4166 # include "bsd_random.h"
4167 # define random bsd_random
4168 # define srandom bsd_srandom
4169 #endif /* if defined(__MINGW64__) || defined(__MINGW32__) */
4170
4171 int rcap = 0;
4172 int rnum = 0;
4173 char rssuffix[20];
4174 char statenme[30];
4175 struct timespec ts;
4176
4177 memset(statenme, 0, sizeof(&statenme));
4178 memset(rssuffix, 0, sizeof(&rssuffix));
4179 (void)clock_gettime(CLOCK_REALTIME, &ts);
4180 srandom((unsigned int)(getpid() ^ (ts.tv_sec * ts.tv_nsec)));
4181
4182 for (int i = 1; i < 21; ++i) {
4183 rcap = (int)random() % 2;
4184 rnum = (int)random() % 3;
4185 if (!rnum) rnum = (((int)random() % 10) + 48);
4186 if (!rcap) rcap = 33;
4187 if (rnum >= 48) rssuffix[i-1]=rnum;
4188 else rssuffix[i-1]=(char)(((long)random() % 26) + 64) + rcap;
4189 }
4190
4191
4192 #if defined(__MINGW64__) || \
4193 defined(__MINGW32__) || \
4194 defined(CROSS_MINGW32) || \
4195 defined(CROSS_MINGW64)
4196 system_state = malloc (sizeof (struct system_state_s));
4197 #else
4198 if (sim_randstate)
4199 sprintf(statenme, "%s.state", rssuffix);
4200 else
4201 sprintf(statenme, "state");
4202 system_state = (struct system_state_s *)
4203 create_shm (statenme, sizeof (struct system_state_s));
4204 #endif
4205
4206 if (!system_state) {
4207 int svErrno = errno;
4208 fflush(stderr); fflush(stdout);
4209 sim_warn ("FATAL: %s, aborting %s()\r\n",
4210 strerror (svErrno), __func__);
4211 exit (svErrno);
4212 }
4213
4214 #ifndef PERF_STRIP
4215
4216 # ifndef VER_H_GIT_HASH
4217 # define VER_H_GIT_HASH "0000000000000000000000000000000000000000"
4218 # endif
4219
4220 fflush(stdout); fflush(stderr);
4221 if (strlen (system_state->commit_id) == 0) {
4222 if (!sim_quiet && sim_randstate && sim_randompst)
4223 # ifdef L68
4224 sim_printf ("Initialized new system state file \"l68.%s\"\r\n",
4225 statenme);
4226 # else
4227 sim_printf ("Initialized new system state file \"dps8m.%s\"\r\n",
4228 statenme);
4229 # endif /* ifdef L68 */
4230 } else {
4231 if (strcmp (system_state->commit_id, VER_H_GIT_HASH) != 0) {
4232 sim_warn ("WARNING: System state hash mismatch; \"%s\" may be corrupt!\r\n",
4233 statenme);
4234 }
4235 }
4236 fflush(stderr); fflush(stdout);
4237
4238 strncpy (system_state->stateHdr, STATE_HDR, sizeof (system_state->stateHdr));
4239 system_state->stateVer = STATE_VER;
4240 strncpy (system_state->commit_id, VER_H_GIT_HASH, sizeof (system_state->commit_id));
4241
4242 systabInit ();
4243
4244 // sets connect to 0
4245 memset (& sys_opts, 0, sizeof (sys_opts));
4246 // sys_poll_interval 10 ms (100 Hz)
4247 sys_opts.sys_poll_interval = 10;
4248 // sys_slow_poll_interval 100 polls (1 Hz)
4249 sys_opts.sys_slow_poll_interval = 100;
4250 // sys_poll_check_rate in CPU cycles
4251 sys_opts.sys_poll_check_rate = 1024;
4252 #endif // ! PERF_STRIP
4253
4254 #ifdef PERF_STRIP
4255 cpu_init ();
4256 #else
4257 sysCableInit ();
4258 iom_init ();
4259 disk_init ();
4260 mt_init ();
4261 # ifndef __MINGW64__
4262 # ifndef __MINGW32__
4263 # ifndef CROSS_MINGW64
4264 # ifndef CROSS_MINGW32
4265 sk_init ();
4266 # endif /* ifndef CROSS_MINGW32 */
4267 # endif /* ifndef CROSS_MINGW64 */
4268 # endif /* ifndef __MINGW64__ */
4269 # endif /* ifndef __MINGW32__ */
4270 fnpInit ();
4271 console_init (); // must come after fnpInit due to libuv initiailization
4272 /* mpc_init (); */
4273 scu_init ();
4274 cpu_init ();
4275 rdr_init ();
4276 pun_init ();
4277 prt_init ();
4278 urp_init ();
4279 # ifndef __MINGW64__
4280 # ifndef __MINGW32__
4281 # ifndef CROSS_MINGW64
4282 # ifndef CROSS_MINGW32
4283 absi_init ();
4284 # endif /* CROSS_MINGW32 */
4285 # endif /* CROSS_MINGW64 */
4286 # endif /* ifndef __MINGW32__ */
4287 # endif /* ifndef __MINGW64__ */
4288 set_default_base_system (0, NULL);
4289 # ifdef PANEL
4290 panelScraperInit ();
4291 # endif /* ifdef PANEL */
4292 #endif
4293 #if defined(THREADZ) || defined(LOCKLESS)
4294 initThreadz ();
4295 #endif /* if defined(THREADZ) || defined(LOCKLESS) */
4296 }
4297
4298 #ifdef TESTING
4299 static struct pr_table
4300 {
4301 char * alias; // pr alias
4302 int n; // number alias represents ....
4303 } _prtab[] =
4304 {
4305 {"pr0", 0}, ///< pr0 - 7
4306 {"pr1", 1},
4307 {"pr2", 2},
4308 {"pr3", 3},
4309 {"pr4", 4},
4310 {"pr5", 5},
4311 {"pr6", 6},
4312 {"pr7", 7},
4313
4314 {"pr[0]", 0}, ///< pr0 - 7
4315 {"pr[1]", 1},
4316 {"pr[2]", 2},
4317 {"pr[3]", 3},
4318 {"pr[4]", 4},
4319 {"pr[5]", 5},
4320 {"pr[6]", 6},
4321 {"pr[7]", 7},
4322
4323 // See: https://multicians.org/pg/mvm.html
4324 {"ap", 0},
4325 {"ab", 1},
4326 {"bp", 2},
4327 {"bb", 3},
4328 {"lp", 4},
4329 {"lb", 5},
4330 {"sp", 6},
4331 {"sb", 7},
4332 {0, 0}
4333 };
4334
4335 # ifndef SCUMEM
getAddress(int segno,int offset)4336 static int getAddress(int segno, int offset)
4337 {
4338 // XXX Do we need to 1st check SDWAM for segment entry?
4339
4340 // get address of in-core segment descriptor word from DSBR
4341 sdw0_s *s = fetchSDW ((word15) segno);
4342
4343 return (s->ADDR + (word18) offset) & 0xffffff; // keep to 24-bits
4344 }
4345 # endif // !SCUMEM
parse_addr(UNUSED DEVICE * dptr,const char * cptr,const char ** optr)4346 static t_addr parse_addr (UNUSED DEVICE * dptr, const char *cptr,
4347 const char **optr)
4348 {
4349 # ifdef SCUMEM
4350 return 0;
4351 # else
4352 // a segment reference?
4353 if (strchr(cptr, '|'))
4354 {
4355 static char addspec[256];
4356 strcpy(addspec, cptr);
4357
4358 *strchr(addspec, '|') = ' ';
4359
4360 char seg[256], off[256];
4361 int params = sscanf(addspec, "%s %s", seg, off);
4362 if (params != 2)
4363 {
4364 sim_warn("parse_addr(): illegal number of parameters\n");
4365 *optr = cptr; // signal error
4366 return 0;
4367 }
4368
4369 // determine if segment is numeric or symbolic...
4370 char *endp;
4371 word18 PRoffset = 0; // offset from PR[n] register (if any)
4372 int segno = (int)strtoll(seg, &endp, 8);
4373 if (endp == seg)
4374 {
4375 // not numeric...
4376 // 1st, see if it's a PR or alias thereof
4377 struct pr_table *prt = _prtab;
4378 while (prt->alias)
4379 {
4380 if (strcasecmp(seg, prt->alias) == 0)
4381 {
4382 segno = cpu.PR[prt->n].SNR;
4383 PRoffset = cpu.PR[prt->n].WORDNO;
4384 break;
4385 }
4386
4387 prt += 1;
4388 }
4389
4390 if (!prt->alias) // not a PR or alias
4391 {
4392 return 0;
4393 }
4394 }
4395
4396 // determine if offset is numeric or symbolic entry point/segdef...
4397 uint offset = (uint)strtoll(off, &endp, 8);
4398 if (endp == off)
4399 {
4400 // not numeric...
4401 return 0;
4402 }
4403
4404 // if we get here then seg contains a segment# and offset.
4405 // So, fetch the actual address given the segment & offset ...
4406 // ... and return this absolute, 24-bit address
4407
4408 word24 abs_addr = (word24) getAddress(segno, (int) (offset + PRoffset));
4409
4410 // TODO: only luckily does this work FixMe
4411 *optr = endp; //cptr + strlen(cptr);
4412
4413 return abs_addr;
4414 }
4415 else
4416 {
4417 // a PR or alias thereof
4418 int segno = 0;
4419 word24 offset = 0;
4420 struct pr_table *prt = _prtab;
4421 while (prt->alias)
4422 {
4423 if (strncasecmp(cptr, prt->alias, strlen(prt->alias)) == 0)
4424 {
4425 segno = cpu.PR[prt->n].SNR;
4426 offset = cpu.PR[prt->n].WORDNO;
4427 break;
4428 }
4429
4430 prt += 1;
4431 }
4432 if (prt->alias) // a PR or alias
4433 {
4434 word24 abs_addr = (word24) getAddress(segno, (int) offset);
4435 *optr = cptr + strlen(prt->alias);
4436
4437 return abs_addr;
4438 }
4439 }
4440
4441 // No, determine absolute address given by cptr
4442 return (t_addr)strtol(cptr, (char **) optr, 8);
4443 # endif // !SCUMEM
4444 }
4445 #endif // TESTING
4446
4447 #ifdef TESTING
fprint_addr(FILE * stream,UNUSED DEVICE * dptr,t_addr simh_addr)4448 static void fprint_addr (FILE * stream, UNUSED DEVICE * dptr, t_addr simh_addr)
4449 {
4450 fprintf(stream, "%06o", simh_addr);
4451 }
4452 #endif // TESTING
4453
4454 // This is part of the simh interface
4455 // Based on the switch variable, symbolically output to stream ofile the data in
4456 // array val at the specified addr in unit uptr.
4457 // simh "fprint_sym" – Based on the switch variable, symbolically output to
4458 // stream ofile the data in array val at the specified addr in unit uptr.
4459
fprint_sym(UNUSED FILE * ofile,UNUSED t_addr addr,UNUSED t_value * val,UNUSED UNIT * uptr,int32 UNUSED sw)4460 t_stat fprint_sym (UNUSED FILE * ofile, UNUSED t_addr addr,
4461 UNUSED t_value *val, UNUSED UNIT *uptr, int32 UNUSED sw)
4462 {
4463 #ifdef TESTING
4464 // XXX Bug: assumes single cpu
4465 // XXX CAC: This seems rather bogus; deciding the output format based on the
4466 // address of the UNIT? Would it be better to use sim_unit.u3 (or some such
4467 // as a word width?
4468
4469 if (!((uint) sw & SWMASK ('M')))
4470 return SCPE_ARG;
4471
4472 if (uptr == &cpu_dev.units[0])
4473 {
4474 word36 word1 = *val;
4475 char buf[256];
4476 // get base syntax
4477 char *d = disassemble(buf, word1);
4478
4479 fprintf(ofile, "%s", d);
4480
4481 // decode instruction
4482 DCDstruct ci;
4483 DCDstruct * p = & ci;
4484 decode_instruction (word1, p);
4485
4486 // MW EIS?
4487 if (p->info->ndes > 1)
4488 {
4489 // Yup, just output word values (for now)
4490
4491 // XXX Need to complete MW EIS support in disassemble()
4492
4493 for(uint n = 0 ; n < p->info->ndes; n += 1)
4494 fprintf(ofile, " %012"PRIo64"", val[n + 1]);
4495
4496 return (t_stat) -p->info->ndes;
4497 }
4498
4499 return SCPE_OK;
4500
4501 //fprintf(ofile, "%012"PRIo64"", *val);
4502 //return SCPE_OK;
4503 }
4504 #endif
4505 return SCPE_ARG;
4506 }
4507
4508 // This is part of the simh interface
4509 // – Based on the switch variable, parse character string cptr for a
4510 // symbolic value val at the specified addr in unit uptr.
4511
parse_sym(UNUSED const char * cptr,UNUSED t_addr addr,UNUSED UNIT * uptr,UNUSED t_value * val,UNUSED int32 sswitch)4512 t_stat parse_sym (UNUSED const char * cptr, UNUSED t_addr addr,
4513 UNUSED UNIT * uptr, UNUSED t_value * val, UNUSED int32 sswitch)
4514 {
4515 return SCPE_ARG;
4516 }
4517
4518 // from MM
4519
4520 sysinfo_t sys_opts;
4521
sys_show_config(UNUSED FILE * st,UNUSED UNIT * uptr,UNUSED int val,UNUSED const void * desc)4522 static t_stat sys_show_config (UNUSED FILE * st, UNUSED UNIT * uptr,
4523 UNUSED int val, UNUSED const void * desc)
4524 {
4525 sim_msg ("IOM connect time: %d\n",
4526 sys_opts.iom_times.connect);
4527 return SCPE_OK;
4528 }
4529
4530 static config_value_list_t cfg_timing_list[] =
4531 {
4532 { "disable", -1 },
4533 { NULL, 0 }
4534 };
4535
4536 bool breakEnable = false;
4537
sys_set_break(UNUSED UNIT * uptr,int32 value,UNUSED const char * cptr,UNUSED void * desc)4538 static t_stat sys_set_break (UNUSED UNIT * uptr, int32 value,
4539 UNUSED const char * cptr, UNUSED void * desc)
4540 {
4541 breakEnable = !! value;
4542 return SCPE_OK;
4543 }
4544
sys_show_break(UNUSED FILE * st,UNUSED UNIT * uptr,UNUSED int val,UNUSED const void * desc)4545 static t_stat sys_show_break (UNUSED FILE * st, UNUSED UNIT * uptr,
4546 UNUSED int val, UNUSED const void * desc)
4547 {
4548 sim_msg ("BREAK %s\r\n", breakEnable ? "ON" : "OFF" );
4549 return SCPE_OK;
4550 }
4551
4552 static config_value_list_t cfg_on_off [] =
4553 {
4554 { "off", 0 },
4555 { "on", 1 },
4556 { "disable", 0 },
4557 { "enable", 1 },
4558 { NULL, 0 }
4559 };
4560
4561 static config_list_t sys_config_list[] =
4562 {
4563 { "connect_time", -1, 100000, cfg_timing_list },
4564 { "color", 0, 1, cfg_on_off },
4565 { NULL, 0, 0, NULL }
4566 };
4567
sys_set_config(UNUSED UNIT * uptr,UNUSED int32 value,const char * cptr,UNUSED void * desc)4568 static t_stat sys_set_config (UNUSED UNIT * uptr, UNUSED int32 value,
4569 const char * cptr, UNUSED void * desc)
4570 {
4571 config_state_t cfg_state = { NULL, NULL };
4572
4573 for (;;)
4574 {
4575 int64_t v;
4576 int rc = cfg_parse ("sys_set_config", cptr, sys_config_list, & cfg_state,
4577 & v);
4578 if (rc == -1) // done
4579 {
4580 break;
4581 }
4582 if (rc == -2) // error
4583 {
4584 cfg_parse_done (& cfg_state);
4585 return SCPE_ARG;
4586 }
4587
4588 const char * p = sys_config_list[rc].name;
4589 if (strcmp (p, "connect_time") == 0)
4590 sys_opts.iom_times.connect = (int) v;
4591 else if (strcmp (p, "color") == 0)
4592 sys_opts.no_color = ! v;
4593 else
4594 {
4595 sim_msg ("error: sys_set_config: invalid cfg_parse rc <%d>\n", rc);
4596 cfg_parse_done (& cfg_state);
4597 return SCPE_ARG;
4598 }
4599 } // process statements
4600 cfg_parse_done (& cfg_state);
4601 return SCPE_OK;
4602 }
4603
4604
4605 static MTAB sys_mod[] =
4606 {
4607 {
4608 MTAB_dev_value, /* mask */
4609 0, /* match */
4610 (char *) "CONFIG", /* print string */
4611 (char *) "CONFIG", /* match string */
4612 sys_set_config, /* validation routine */
4613 sys_show_config, /* display routine */
4614 NULL, /* value descriptor */
4615 NULL, /* help */
4616 },
4617 {
4618 MTAB_dev_novalue, /* mask */
4619 1, /* match */
4620 (char *) "BREAK", /* print string */
4621 (char *) "BREAK", /* match string */
4622 sys_set_break, /* validation routine */
4623 sys_show_break, /* display routine */
4624 NULL, /* value descriptor */
4625 NULL, /* help */
4626 },
4627 {
4628 MTAB_dev_novalue, /* mask */
4629 0, /* match */
4630 (char *) "NOBREAK", /* print string */
4631 (char *) "NOBREAK", /* match string */
4632 sys_set_break, /* validation routine */
4633 sys_show_break, /* display routine */
4634 NULL, /* value descriptor */
4635 NULL, /* help */
4636 },
4637 MTAB_eol
4638 };
4639
4640
sys_reset(UNUSED DEVICE * dptr)4641 static t_stat sys_reset (UNUSED DEVICE * dptr)
4642 {
4643 return SCPE_OK;
4644 }
4645
4646 static DEVICE sys_dev = {
4647 "SYS", /* name */
4648 NULL, /* units */
4649 NULL, /* registers */
4650 sys_mod, /* modifiers */
4651 0, /* #units */
4652 8, /* address radix */
4653 PASIZE, /* address width */
4654 1, /* address increment */
4655 8, /* data radix */
4656 36, /* data width */
4657 NULL, /* examine routine */
4658 NULL, /* deposit routine */
4659 & sys_reset, /* reset routine */
4660 NULL, /* boot routine */
4661 NULL, /* attach routine */
4662 NULL, /* detach routine */
4663 NULL, /* context */
4664 0, /* flags */
4665 0, /* debug control flags */
4666 0, /* debug flag names */
4667 NULL, /* memory size change */
4668 NULL, /* logical name */
4669 NULL, /* help */
4670 NULL, /* attach_help */
4671 NULL, /* help_ctx */
4672 NULL, /* description */
4673 NULL
4674 };
4675
4676
4677 // This is part of the simh interface
4678 DEVICE * sim_devices[] =
4679 {
4680 & cpu_dev, // dev[0] is special to simh; it is the 'default device'
4681 & iom_dev,
4682 & tape_dev,
4683 #ifndef __MINGW64__
4684 # ifndef __MINGW32__
4685 # ifndef CROSS_MINGW32
4686 # ifndef CROSS_MINGW64
4687 & skc_dev,
4688 # endif /* ifndef CROSS_MINGW64 */
4689 # endif /* ifndef CROSS_MINGW32 */
4690 # endif /* ifndef __MINGW32__ */
4691 #endif /* ifndef __MINGW64__ */
4692 & mtp_dev,
4693 & fnp_dev,
4694 & dsk_dev,
4695 & ipc_dev,
4696 & msp_dev,
4697 & scu_dev,
4698 /* & mpc_dev, */
4699 & opc_dev,
4700 & sys_dev,
4701 & urp_dev,
4702 & rdr_dev,
4703 & pun_dev,
4704 & prt_dev,
4705 #ifndef __MINGW64__
4706 # ifndef __MINGW32__
4707 # ifndef CROSS_MINGW32
4708 # ifndef CROSS_MINGW64
4709 & absi_dev,
4710 # endif /* ifndef CROSS_MINGW64 */
4711 # endif /* ifndef CROSS_MINGW32 */
4712 # endif /* ifndef __MINGW32__ */
4713 #endif /* ifndef __MINGW64__ */
4714 NULL
4715 };
4716
4717
4718 #ifdef PERF_STRIP
dps8_init_strip(void)4719 void dps8_init_strip (void)
4720 {
4721 dps8_init ();
4722 }
4723 #endif
4724
4725
4726