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