This source file includes following definitions.
- scu_show_nunits
- scu_set_nunits
- scu_show_state
- scu_show_config
- scu_set_config
- dump_intr_regs
- scu_unit_reset
- scu_reset
- set_SCU_clock
- pcells
- deliver_interrupts
- scu_smic
- scu_sscr
- scu_rscr
- scu_cioc
- scu_set_interrupt
- scu_get_highest_intr
- scu_reset_unit
- scu_init
- scu_rmcm
- scu_smcm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543 #include <sys/time.h>
544 #include "dps8.h"
545 #include "dps8_sys.h"
546 #include "dps8_iom.h"
547 #include "dps8_cable.h"
548 #include "dps8_cpu.h"
549 #include "dps8_faults.h"
550 #include "dps8_scu.h"
551 #include "dps8_utils.h"
552 #if defined(THREADZ) || defined(LOCKLESS)
553 # include "threadz.h"
554 #endif
555
556 #define DBG_CTR 1
557
558 scu_t scu [N_SCU_UNITS_MAX];
559
560 #define N_SCU_UNITS 1
561
562 static UNIT scu_unit [N_SCU_UNITS_MAX] = {
563 #if defined(NO_C_ELLIPSIS)
564 { UDATA (NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
565 { UDATA (NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
566 { UDATA (NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
567 { UDATA (NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
568 { UDATA (NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
569 { UDATA (NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
570 { UDATA (NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
571 { UDATA (NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL }
572 #else
573 [0 ... N_SCU_UNITS_MAX-1] = {
574 UDATA (NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL
575 }
576 #endif
577 };
578
579 #define UNIT_NUM(uptr) ((uptr) - scu_unit)
580
581
582
583
584
585 static struct config_switches
586 {
587 uint mode;
588 uint port_enable [N_SCU_PORTS];
589 uint mask_enable [N_ASSIGNMENTS];
590 uint mask_assignment [N_ASSIGNMENTS];
591 uint lower_store_size;
592 uint cyclic;
593 uint nea;
594 uint onl;
595 uint interlace;
596 uint lwr;
597 } config_switches [N_SCU_UNITS_MAX];
598
599 enum { MODE_MANUAL = 0, MODE_PROGRAM = 1 };
600
601 unsigned int gtod_warned = 0;
602
603
604
605 static t_stat scu_show_nunits (UNUSED FILE * st, UNUSED UNIT * uptr,
606 UNUSED int val, const UNUSED void * desc)
607 {
608 sim_printf("Number of SCU units in system is %d\n", scu_dev.numunits);
609 return SCPE_OK;
610 }
611
612 static t_stat scu_set_nunits (UNUSED UNIT * uptr, UNUSED int32 value,
613 const char * cptr, UNUSED void * desc)
614 {
615 if (! cptr)
616 return SCPE_ARG;
617 int n = atoi (cptr);
618 if (n < 1 || n > N_SCU_UNITS_MAX)
619 return SCPE_ARG;
620 scu_dev.numunits = (uint) n;
621 return SCPE_OK;
622 }
623
624 static t_stat scu_show_state (UNUSED FILE * st, UNIT *uptr, UNUSED int val,
625 UNUSED const void * desc)
626 {
627 #if defined(TESTING)
628 cpu_state_t * cpup = _cpup;
629 #endif
630 long scu_unit_idx = UNIT_NUM (uptr);
631 if (scu_unit_idx < 0 || scu_unit_idx >= (int) scu_dev.numunits)
632 {
633 sim_debug (DBG_ERR, & scu_dev,
634 "scu_show_state: Invalid unit number %ld\n",
635 (long) scu_unit_idx);
636 sim_printf ("error: Invalid unit number %ld\n", (long) scu_unit_idx);
637 return SCPE_ARG;
638 }
639
640 sim_printf ("SCU unit number %ld\n", (long) scu_unit_idx);
641 scu_t * scup = scu + scu_unit_idx;
642 sim_printf (" Mode %s\n",
643 config_switches[scu_unit_idx].mode ? "PROGRAM" : "MANUAL");
644
645 for (int i = 0; i < N_SCU_PORTS; i ++)
646 {
647 struct ports * pp = scup -> ports + i;
648
649 sim_printf (" Port %d %s dev_idx %d dev_port %d type %s\n",
650 i, scup->port_enable[i] ? "ENABLE " : "DISABLE",
651 pp->dev_idx, pp->dev_port[XXX_TEMP_SCU_SUBPORT],
652 pp->type == ADEV_NONE ? "NONE" :
653 pp->type == ADEV_CPU ? "CPU" :
654 pp->type == ADEV_IOM ? "IOM" :
655 "<enum broken>");
656 }
657 for (int i = 0; i < N_ASSIGNMENTS; i ++)
658 {
659
660
661 sim_printf (" Cell %c\n", 'A' + i);
662 sim_printf (" exec_intr_mask %012o\n",
663 scup -> exec_intr_mask [i]);
664 sim_printf (" mask_enable %s\n",
665 scup -> mask_enable [i] ? "ENABLE" : "DISABLE");
666 sim_printf (" mask_assignment %d\n",
667 scup -> mask_assignment [i]);
668 sim_printf (" cells ");
669 for (int j = 0; j < N_CELL_INTERRUPTS; j ++)
670 sim_printf("%d", scup -> cells [j]);
671 sim_printf ("\n");
672 }
673 sim_printf("Lower store size: %d\n", scup -> lower_store_size);
674 sim_printf("Cyclic: %03o\n", scup -> cyclic);
675 sim_printf("NEA: %03o\n", scup -> nea);
676 sim_printf("Online: %02o\n", scup -> onl);
677 sim_printf("Interlace: %o\n", scup -> interlace);
678 sim_printf("Lower: %o\n", scup -> lwr);
679 sim_printf("ID: %o\n", scup -> id);
680 sim_printf("mode_reg: %06o\n", scup -> mode_reg);
681 sim_printf("Elapsed days: %d\n", scup -> elapsed_days);
682 sim_printf("Steady clock: %d\n", scup -> steady_clock);
683 sim_printf("Bullet time: %d\n", scup -> bullet_time);
684 sim_printf("Y2K enabled: %d\n", scup -> y2k);
685 return SCPE_OK;
686 }
687
688 static t_stat scu_show_config (UNUSED FILE * st, UNUSED UNIT * uptr,
689 UNUSED int val, UNUSED const void * desc)
690 {
691 #if defined(TESTING)
692 cpu_state_t * cpup = _cpup;
693 #endif
694 static const char * map [N_SCU_PORTS] =
695 {
696 "0", "1", "2", "3", "4", "5", "6", "7"
697 };
698 long scu_unit_idx = UNIT_NUM (uptr);
699 if (scu_unit_idx < 0 || scu_unit_idx >= (int) scu_dev.numunits)
700 {
701 sim_debug (DBG_ERR, & scu_dev,
702 "scu_show_config: Invalid unit number %ld\n",
703 (long) scu_unit_idx);
704 sim_printf ("error: Invalid unit number %ld\n", (long) scu_unit_idx);
705 return SCPE_ARG;
706 }
707
708 sim_printf ("SCU unit number %ld\n", (long) scu_unit_idx);
709
710 struct config_switches * sw = config_switches + scu_unit_idx;
711
712 const char * mode = "<out of range>";
713 switch (sw -> mode)
714 {
715 case MODE_PROGRAM:
716 mode = "Program";
717 break;
718 case MODE_MANUAL:
719 mode = "Manual";
720 break;
721 }
722
723 sim_printf ("Mode: %s\n", mode);
724 sim_printf ("Port Enable: ");
725 for (int i = 0; i < N_SCU_PORTS; i ++)
726 sim_printf (" %3o", sw -> port_enable [i]);
727 sim_printf ("\n");
728 for (int i = 0; i < N_ASSIGNMENTS; i ++)
729 {
730 sim_printf ("Mask %c: %s\n",
731 'A' + i,
732 sw->mask_enable[i] ? (map[sw->mask_assignment[i]]) : "Off");
733 }
734 sim_printf ("Lower Store Size: %o\n", sw -> lower_store_size);
735 sim_printf ("Cyclic: %03o\n", sw -> cyclic);
736 sim_printf ("Non-existent address: %03o\n", sw -> nea);
737
738 return SCPE_OK;
739 }
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764 static config_value_list_t cfg_mode_list [] =
765 {
766 { "manual", 0 },
767 { "program", 1 },
768 { NULL, 0 }
769 };
770
771 static config_value_list_t cfg_mask_list [] =
772 {
773 { "off", -1 },
774 { NULL, 0 }
775 };
776
777 static config_value_list_t cfg_able_list [] =
778 {
779 { "disable", 0 },
780 { "enable", 1 },
781 { NULL, 0 }
782 };
783
784 static config_value_list_t cfg_size_list [] =
785 {
786 { "32", 0 },
787 { "64", 1 },
788 { "128", 2 },
789 { "256", 3 },
790 { "512", 4 },
791 { "1024", 5 },
792 { "2048", 6 },
793 { "4096", 7 },
794 { "32K", 0 },
795 { "64K", 1 },
796 { "128K", 2 },
797 { "256K", 3 },
798 { "512K", 4 },
799 { "1024K", 5 },
800 { "2048K", 6 },
801 { "4096K", 7 },
802 { "1M", 5 },
803 { "2M", 6 },
804 { "4M", 7 },
805 { NULL, 0 }
806 };
807
808 static config_value_list_t cfg_on_off [] =
809 {
810 { "off", 0 },
811 { "on", 1 },
812 { "disable", 0 },
813 { "enable", 1 },
814 { NULL, 0 }
815 };
816
817 static config_list_t scu_config_list [] =
818 {
819 { "mode", 1, 0, cfg_mode_list },
820 { "maska", 0, N_SCU_PORTS - 1, cfg_mask_list },
821 { "maskb", 0, N_SCU_PORTS - 1, cfg_mask_list },
822 { "port0", 1, 0, cfg_able_list },
823 { "port1", 1, 0, cfg_able_list },
824 { "port2", 1, 0, cfg_able_list },
825 { "port3", 1, 0, cfg_able_list },
826 { "port4", 1, 0, cfg_able_list },
827 { "port5", 1, 0, cfg_able_list },
828 { "port6", 1, 0, cfg_able_list },
829 { "port7", 1, 0, cfg_able_list },
830 { "lwrstoresize", 0, 7, cfg_size_list },
831 { "cyclic", 0, 0177, NULL },
832 { "nea", 0, 0377, NULL },
833
834 { "onl", 0, 017, NULL },
835 { "int", 0, 1, NULL },
836 { "lwr", 0, 1, NULL },
837
838
839
840 { "elapsed_days", 0, 20000, NULL },
841 { "steady_clock", 0, 1, cfg_on_off },
842 { "bullet_time", 0, 1, cfg_on_off },
843 { "y2k", 0, 1, cfg_on_off },
844 { NULL, 0, 0, NULL }
845 };
846
847 static t_stat scu_set_config (UNIT * uptr, UNUSED int32 value,
848 const char * cptr, UNUSED void * desc)
849 {
850 #if defined(TESTING)
851 cpu_state_t * cpup = _cpup;
852 #endif
853 long scu_unit_idx = UNIT_NUM (uptr);
854 if (scu_unit_idx < 0 || scu_unit_idx >= (int) scu_dev.numunits)
855 {
856 sim_debug (DBG_ERR, & scu_dev,
857 "scu_set_config: Invalid unit number %ld\n", (long) scu_unit_idx);
858 sim_printf ("error: scu_set_config: Invalid unit number %ld\n",
859 (long) scu_unit_idx);
860 return SCPE_ARG;
861 }
862
863 struct config_switches * sw = config_switches + scu_unit_idx;
864
865 config_state_t cfg_state = { NULL, NULL };
866
867 for (;;)
868 {
869 int64_t v;
870 int rc = cfg_parse ("scu_set_config", cptr, scu_config_list,
871 & cfg_state, & v);
872 if (rc == -1)
873 break;
874
875 if (rc == -2)
876 {
877 cfg_parse_done (& cfg_state);
878 return SCPE_ARG;
879 }
880
881 const char * p = scu_config_list [rc].name;
882 if (strcmp (p, "mode") == 0)
883 sw -> mode = (uint) v;
884 else if (strcmp (p, "maska") == 0)
885 {
886 if (v == -1)
887 sw -> mask_enable [0] = false;
888 else
889 {
890 sw -> mask_enable [0] = true;
891 sw -> mask_assignment [0] = (uint) v;
892 }
893 }
894 else if (strcmp (p, "maskb") == 0)
895 {
896 if (v == -1)
897 sw -> mask_enable [1] = false;
898 else
899 {
900 sw -> mask_enable [1] = true;
901 sw -> mask_assignment [1] = (uint) v;
902 }
903 }
904 else if (strcmp (p, "port0") == 0)
905 sw -> port_enable [0] = (uint) v;
906 else if (strcmp (p, "port1") == 0)
907 sw -> port_enable [1] = (uint) v;
908 else if (strcmp (p, "port2") == 0)
909 sw -> port_enable [2] = (uint) v;
910 else if (strcmp (p, "port3") == 0)
911 sw -> port_enable [3] = (uint) v;
912 else if (strcmp (p, "port4") == 0)
913 sw -> port_enable [4] = (uint) v;
914 else if (strcmp (p, "port5") == 0)
915 sw -> port_enable [5] = (uint) v;
916 else if (strcmp (p, "port6") == 0)
917 sw -> port_enable [6] = (uint) v;
918 else if (strcmp (p, "port7") == 0)
919 sw -> port_enable [7] = (uint) v;
920 else if (strcmp (p, "lwrstoresize") == 0)
921 sw -> lower_store_size = (uint) v;
922 else if (strcmp (p, "cyclic") == 0)
923 sw -> cyclic = (uint) v;
924 else if (strcmp (p, "nea") == 0)
925 sw -> nea = (uint) v;
926 else if (strcmp (p, "onl") == 0)
927 sw -> onl = (uint) v;
928 else if (strcmp (p, "int") == 0)
929 sw -> interlace = (uint) v;
930 else if (strcmp (p, "lwr") == 0)
931 sw -> lwr = (uint) v;
932 else if (strcmp (p, "elapsed_days") == 0)
933 scu [scu_unit_idx].elapsed_days = (uint) v;
934 else if (strcmp (p, "steady_clock") == 0)
935 scu [scu_unit_idx].steady_clock = (uint) v;
936 else if (strcmp (p, "bullet_time") == 0)
937 scu [scu_unit_idx].bullet_time = (uint) v;
938 else if (strcmp (p, "y2k") == 0)
939 scu [scu_unit_idx].y2k = (uint) v;
940 else
941 {
942 sim_printf ("error: scu_set_config: invalid cfg_parse rc <%d>\n",
943 rc);
944 cfg_parse_done (& cfg_state);
945 return SCPE_ARG;
946 }
947 }
948 cfg_parse_done (& cfg_state);
949 return SCPE_OK;
950 }
951
952 static MTAB scu_mod [] =
953 {
954 {
955 MTAB_XTD | MTAB_VUN | \
956 MTAB_NMO | MTAB_VALR,
957 0,
958 (char *) "CONFIG",
959 (char *) "CONFIG",
960 scu_set_config,
961 scu_show_config,
962 NULL,
963 NULL
964 },
965 {
966 MTAB_XTD | MTAB_VDV | \
967 MTAB_NMO | MTAB_VALR,
968 0,
969 (char *) "NUNITS",
970 (char *) "NUNITS",
971 scu_set_nunits,
972 scu_show_nunits,
973 (char *) "Number of SCU units in the system",
974 NULL
975 },
976 {
977 MTAB_XTD | MTAB_VUN | \
978 MTAB_NMO | MTAB_VALR,
979 0,
980 (char *) "STATE",
981 (char *) "STATE",
982 NULL,
983 scu_show_state,
984 (char *) "SCU unit internal state",
985 NULL
986 },
987 {
988 MTAB_XTD | MTAB_VUN | \
989 MTAB_NMO | MTAB_VALR,
990 0,
991 (char *) "RESET",
992 (char *) "RESET",
993 scu_reset_unit,
994 NULL,
995 (char *) "reset SCU unit",
996 NULL
997 },
998 {
999 0, 0, NULL, NULL, NULL, NULL, NULL, NULL
1000 }
1001 };
1002
1003
1004
1005 static DEBTAB scu_dt [] =
1006 {
1007 { (char *) "TRACE", DBG_TRACE, NULL },
1008 { (char *) "NOTIFY", DBG_NOTIFY, NULL },
1009 { (char *) "INFO", DBG_INFO, NULL },
1010 { (char *) "ERR", DBG_ERR, NULL },
1011 { (char *) "WARN", DBG_WARN, NULL },
1012 { (char *) "DEBUG", DBG_DEBUG, NULL },
1013 { (char *) "INTR", DBG_INTR, NULL },
1014 { (char *) "ALL", DBG_ALL, NULL },
1015 { NULL, 0, NULL }
1016 };
1017
1018 DEVICE scu_dev =
1019 {
1020 (char *) "SCU",
1021 scu_unit,
1022 NULL,
1023 scu_mod,
1024 N_SCU_UNITS,
1025 10,
1026 8,
1027 1,
1028 8,
1029 8,
1030 NULL,
1031 NULL,
1032 & scu_reset,
1033 NULL,
1034 NULL,
1035 NULL,
1036 NULL,
1037 DEV_DEBUG,
1038 0,
1039 scu_dt,
1040 NULL,
1041 NULL,
1042 NULL,
1043 NULL,
1044 NULL,
1045 NULL,
1046 NULL
1047 };
1048
1049 static void dump_intr_regs (char * ctx, uint scu_unit_idx)
1050 {
1051 #if defined(TESTING)
1052 scu_t * up = scu + scu_unit_idx;
1053 cpu_state_t * cpup = _cpup;
1054
1055 sim_debug (DBG_DEBUG, & scu_dev,
1056 "%s A: mask %011o enable %o assignment %o\n",
1057 ctx, up -> exec_intr_mask [0], up -> mask_enable [0],
1058 up -> mask_assignment [0]);
1059 sim_debug (DBG_DEBUG, & scu_dev,
1060 "%s B: mask %011o enable %o assignment %o\n",
1061 ctx, up -> exec_intr_mask [1], up -> mask_enable [1],
1062 up -> mask_assignment [1]);
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110 #endif
1111 }
1112
1113 void scu_unit_reset (int scu_unit_idx)
1114 {
1115 scu_t * up = scu + scu_unit_idx;
1116 struct config_switches * sw = config_switches + scu_unit_idx;
1117
1118 for (int i = 0; i < N_SCU_PORTS; i ++)
1119 {
1120 up -> port_enable [i] = sw -> port_enable [i];
1121 }
1122
1123 for (int i = 0; i < N_ASSIGNMENTS; i ++)
1124 {
1125 up -> mask_enable [i] = sw -> mask_enable [i];
1126 up -> mask_assignment [i] = sw -> mask_assignment [i];
1127 }
1128 up -> lower_store_size = sw -> lower_store_size;
1129 up -> cyclic = sw -> cyclic;
1130 up -> nea = sw -> nea;
1131 up -> onl = sw -> onl;
1132 up -> interlace = sw -> interlace;
1133 up -> lwr = sw -> lwr;
1134
1135
1136
1137
1138 for (uint port_num = 0; port_num < N_SCU_PORTS; port_num ++)
1139 {
1140 struct ports * portp = & scu [scu_unit_idx].ports [port_num];
1141 if (portp->type != ADEV_IOM)
1142 continue;
1143
1144
1145 iom_unit_reset_idx ((uint) portp->dev_idx);
1146 }
1147
1148
1149
1150
1151
1152 for (int i = 0; i < N_ASSIGNMENTS; i ++)
1153 {
1154
1155 up -> exec_intr_mask [i] = 037777777777;
1156 }
1157 }
1158
1159 t_stat scu_reset (UNUSED DEVICE * dptr)
1160 {
1161
1162
1163 for (int scu_unit_idx = 0; scu_unit_idx < N_SCU_UNITS_MAX; scu_unit_idx ++)
1164 scu_unit_reset (scu_unit_idx);
1165 return SCPE_OK;
1166 }
1167
1168
1169
1170 #if defined(THREADZ) || defined(LOCKLESS)
1171 static pthread_mutex_t clock_lock = PTHREAD_MUTEX_INITIALIZER;
1172 #endif
1173
1174
1175 static uint64 set_SCU_clock (cpu_state_t * cpup, uint scu_unit_idx)
1176 {
1177 #if defined(THREADZ) || defined(LOCKLESS)
1178 pthread_mutex_lock (& clock_lock);
1179 #endif
1180
1181
1182
1183
1184
1185
1186 if (scu [0].steady_clock)
1187 {
1188
1189
1190 #if defined(NEED_128)
1191 uint128 big = construct_128 (0, cpu.instrCnt);
1192
1193
1194 big = lshift_128 (big, 2);
1195 if (scu [0].bullet_time)
1196 big = multiply_128 (big, construct_128 (0, 10000u));
1197
1198
1199 uint128 days = construct_128 (0, scu[0].elapsed_days);
1200 days = multiply_128 (days, construct_128 (0, 1000000));
1201 days = multiply_128 (days, construct_128 (0, 60 * 60 * 24));
1202 big = add_128 (big, days);
1203 #else
1204 __uint128_t big = cpu.instrCnt;
1205
1206 big *= 4u;
1207
1208 if (scu [0].bullet_time)
1209 big *= 10000;
1210
1211 big += scu [0].elapsed_days * 1000000llu * 60llu * 60llu * 24llu;
1212 #endif
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226 uint64 UNIX_secs = (uint64)time(NULL);
1227
1228 #if defined(NEED_128)
1229 uint64 UNIX_usecs = UNIX_secs * 1000000llu + big.l;
1230 #else
1231 uint64 UNIX_usecs = UNIX_secs * 1000000llu + (uint64) big;
1232 #endif
1233
1234 uint64 Multics_usecs = 2177452800000000llu + UNIX_usecs;
1235
1236
1237
1238 Multics_usecs += (uint64) scu [scu_unit_idx].user_correction;
1239
1240
1241
1242
1243 if (scu [scu_unit_idx].last_time >= Multics_usecs)
1244 {
1245 sim_debug (DBG_TRACE, & scu_dev, "finagle clock\n");
1246 Multics_usecs = scu [scu_unit_idx].last_time + 1;
1247 }
1248 scu [scu_unit_idx].last_time = Multics_usecs;
1249 goto done;
1250 }
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263 struct timeval now;
1264 gettimeofday(& now, NULL);
1265
1266 if (scu [0].y2k)
1267 {
1268
1269
1270
1271
1272 now.tv_sec -= (1685451324 - 738766524);
1273 }
1274 uint64 UNIX_secs = (uint64) now.tv_sec;
1275 uint64 UNIX_usecs = UNIX_secs * 1000000LL + (uint64) now.tv_usec;
1276
1277 static uint64 last_UNIX_usecs = 0;
1278 if ( (!sim_quiet) && (UNIX_usecs < last_UNIX_usecs))
1279 {
1280 if (gtod_warned < 11)
1281 {
1282 sim_warn ("\rHost clock went backwards %llu uS!\r\n",
1283 (unsigned long long)(last_UNIX_usecs - UNIX_usecs));
1284 gtod_warned++;
1285 }
1286 else if (gtod_warned == 11)
1287 {
1288 sim_warn ("\rHost clock went backwards %llu uS! Suppressing further warnings.\r\n",
1289 (unsigned long long)(last_UNIX_usecs - UNIX_usecs));
1290 gtod_warned++;
1291 }
1292 }
1293 last_UNIX_usecs = UNIX_usecs;
1294
1295
1296 uint64 Multics_usecs = 2177452800000000LL + UNIX_usecs;
1297
1298
1299
1300
1301
1302 Multics_usecs += (uint64) scu [scu_unit_idx].user_correction;
1303
1304 if (scu [scu_unit_idx].last_time >= Multics_usecs)
1305 Multics_usecs = scu [scu_unit_idx].last_time + 1;
1306 scu [scu_unit_idx].last_time = Multics_usecs;
1307
1308 done:
1309 #if defined(THREADZ) || defined(LOCKLESS)
1310 pthread_mutex_unlock (& clock_lock);
1311 #endif
1312
1313 return scu [scu_unit_idx].last_time;
1314 }
1315
1316
1317 static char * pcells (uint scu_unit_idx, char * buf)
1318 {
1319 for (uint i = 0; i < N_CELL_INTERRUPTS; i ++)
1320 {
1321 if (scu [scu_unit_idx].cells [i])
1322 buf [i] = '1';
1323 else
1324 buf [i] = '0';
1325 }
1326 buf [N_CELL_INTERRUPTS] = '\0';
1327 return buf;
1328 }
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344 static void deliver_interrupts (cpu_state_t * cpup, uint scu_unit_idx)
1345 {
1346 #if defined(TESTING)
1347 {
1348 cpu_state_t * cpup = _cpup;
1349 sim_debug (DBG_DEBUG, & scu_dev, "deliver_interrupts %o\n", scu_unit_idx);
1350 }
1351 #endif
1352 #if defined(THREADZ) || defined(LOCKLESS)
1353 atomic_thread_fence (memory_order_seq_cst);
1354 #endif
1355 for (uint cpun = 0; cpun < cpu_dev.numunits; cpun ++)
1356 {
1357 cpus[cpun].events.XIP[scu_unit_idx] = false;
1358 }
1359
1360
1361
1362
1363
1364 #if defined(REORDER)
1365 for (uint jnum = 0; jnum < N_CELL_INTERRUPTS; jnum ++)
1366 {
1367 static const uint reorder[N_CELL_INTERRUPTS] = {
1368 0, 1, 2, 3, 4, 5, 6, 7,
1369 16, 17, 18, 29, 20, 21, 22, 23,
1370 8, 9, 10, 11, 12, 13, 14, 15,
1371 25, 25, 26, 27, 28, 29, 30, 31 };
1372 uint inum = reorder[jnum];
1373 if (! scu [scu_unit_idx].cells [inum])
1374 continue;
1375 sim_debug (DBG_DEBUG, & scu_dev, "trying to deliver %d\n", inum);
1376 sim_debug (DBG_INTR, & scu_dev,
1377 "scu %u trying to deliver %d\n", scu_unit_idx, inum);
1378
1379 for (uint pima = 0; pima < N_ASSIGNMENTS; pima ++)
1380 {
1381
1382
1383
1384 if (scu [scu_unit_idx].mask_enable [pima] == 0)
1385 continue;
1386 uint mask = scu [scu_unit_idx].exec_intr_mask [pima];
1387 uint port = scu [scu_unit_idx].mask_assignment [pima];
1388
1389
1390
1391
1392 if (scu [scu_unit_idx].ports [port].type != ADEV_CPU)
1393 continue;
1394 if ((mask & (1u << (31 - inum))) != 0)
1395 {
1396 uint sn = 0;
1397 if (scu[scu_unit_idx].ports[port].is_exp)
1398 {
1399 sn = (uint) scu[scu_unit_idx].ports[port].xipmaskval;
1400 if (sn >= N_SCU_SUBPORTS)
1401 {
1402 sim_warn ("XIP mask not set; defaulting to subport 0\n");
1403 sn = 0;
1404 }
1405 }
1406 if (! cables->scu_to_cpu[scu_unit_idx][port][sn].in_use)
1407 {
1408 sim_warn ("bad scu_unit_idx %u\n", scu_unit_idx);
1409 continue;
1410 }
1411 uint cpu_unit_udx = cables->scu_to_cpu[scu_unit_idx][port][sn].cpu_unit_idx;
1412 # if defined(THREADZ) || defined(LOCKLESS)
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423 if ((! sys.sys_opts.nosync) && cpup && (! cpus[cpu_unit_udx].inMultics)) {
1424
1425 # ifdef SYNCTEST
1426 sim_printf ("CPU %c becomes clock master\n", 'A' + cpu_unit_udx);
1427 # endif
1428 becomeClockMaster (cpu_unit_udx);
1429
1430 cpu.syncClockModePoll = 0;
1431 cpu.syncClockModeCache = true;
1432 __asm volatile ("");
1433 atomic_thread_fence (memory_order_seq_cst);
1434 }
1435 cpus[cpu_unit_udx].events.XIP[scu_unit_idx] = true;
1436 # if defined(TESTING)
1437 HDBGIntrSet (inum, cpu_unit_udx, scu_unit_idx, __func__);
1438 # endif
1439 createCPUThread((uint) cpu_unit_udx);
1440 # if !defined(NO_TIMEWAIT)
1441 wakeCPU ((uint) cpu_unit_udx);
1442 # endif
1443 sim_debug (DBG_DEBUG, & scu_dev,
1444 "interrupt set for CPU %d SCU %d\n",
1445 cpu_unit_udx, scu_unit_idx);
1446 # else
1447
1448 # if defined(ROUND_ROBIN)
1449 cpus[cpu_unit_udx].isRunning = true;
1450 # endif
1451 cpus[cpu_unit_udx].events.XIP[scu_unit_idx] = true;
1452 sim_debug (DBG_DEBUG, & scu_dev, "interrupt set for CPU %d SCU %d\n", cpu_unit_udx, scu_unit_idx);
1453 sim_debug (DBG_INTR, & scu_dev,
1454 "XIP set for SCU %d\n", scu_unit_idx);
1455 # endif
1456 }
1457 }
1458 }
1459 #else
1460 for (uint inum = 0; inum < N_CELL_INTERRUPTS; inum ++)
1461 {
1462 if (! scu [scu_unit_idx].cells [inum])
1463 continue;
1464 sim_debug (DBG_DEBUG, & scu_dev, "trying to deliver %d\n", inum);
1465 sim_debug (DBG_INTR, & scu_dev,
1466 "scu %u trying to deliver %d\n", scu_unit_idx, inum);
1467
1468 for (uint pima = 0; pima < N_ASSIGNMENTS; pima ++)
1469 {
1470
1471
1472
1473 if (scu [scu_unit_idx].mask_enable [pima] == 0)
1474 continue;
1475 uint mask = scu [scu_unit_idx].exec_intr_mask [pima];
1476 uint port = scu [scu_unit_idx].mask_assignment [pima];
1477
1478
1479
1480
1481 if (scu [scu_unit_idx].ports [port].type != ADEV_CPU)
1482 continue;
1483 if ((mask & (1u << (31 - inum))) != 0)
1484 {
1485 uint sn = 0;
1486 if (scu[scu_unit_idx].ports[port].is_exp)
1487 {
1488 sn = (uint) scu[scu_unit_idx].ports[port].xipmaskval;
1489 if (sn >= N_SCU_SUBPORTS)
1490 {
1491 sim_warn ("XIP mask not set; defaulting to subport 0\n");
1492 sn = 0;
1493 }
1494 }
1495 if (! cables->scu_to_cpu[scu_unit_idx][port][sn].in_use)
1496 {
1497 sim_warn ("bad scu_unit_idx %u\n", scu_unit_idx);
1498 continue;
1499 }
1500 uint cpu_unit_udx = cables->scu_to_cpu[scu_unit_idx][port][sn].cpu_unit_idx;
1501 # if defined(THREADZ) || defined(LOCKLESS)
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512 if ((! sys_opts.nosync) && cpup && (! cpus[cpu_unit_udx].inMultics)) {
1513
1514 # ifdef SYNCTEST
1515 sim_printf ("CPU %c becomes clock master\n", 'A' + cpu_unit_udx);
1516 # endif
1517 becomeClockMaster (cpu_unit_udx);
1518 }
1519 cpus[cpu_unit_udx].events.XIP[scu_unit_idx] = true;
1520 # if defined(TESTING)
1521 HDBGIntrSet (inum, cpu_unit_udx, scu_unit_idx, __func__);
1522 # endif
1523 # ifdef SYNCTEST
1524 if (cpus[cpu_unit_udx].rcfDelete) sim_printf ("Poking CPU %c in rcfDelete\n", 'A' + cpu_unit_udx);
1525 # endif
1526 createCPUThread((uint) cpu_unit_udx);
1527 # if !defined(NO_TIMEWAIT)
1528 wakeCPU ((uint) cpu_unit_udx);
1529 # endif
1530 sim_debug (DBG_DEBUG, & scu_dev,
1531 "interrupt set for CPU %d SCU %d\n",
1532 cpu_unit_udx, scu_unit_idx);
1533 # else
1534
1535 # if defined(ROUND_ROBIN)
1536 cpus[cpu_unit_udx].isRunning = true;
1537 # endif
1538 cpus[cpu_unit_udx].events.XIP[scu_unit_idx] = true;
1539 sim_debug (DBG_DEBUG, & scu_dev, "interrupt set for CPU %d SCU %d\n", cpu_unit_udx, scu_unit_idx);
1540 sim_debug (DBG_INTR, & scu_dev,
1541 "XIP set for SCU %d\n", scu_unit_idx);
1542 # endif
1543 }
1544 }
1545 }
1546 #endif
1547 }
1548
1549 t_stat scu_smic (cpu_state_t * cpup, uint scu_unit_idx, uint UNUSED cpu_unit_udx,
1550 uint UNUSED cpu_port_num, word36 rega)
1551 {
1552 #if defined(THREADZ) || defined(LOCKLESS)
1553 lock_scu ();
1554 #endif
1555
1556
1557 if (getbits36_1 (rega, 35))
1558 {
1559 for (uint i = 0; i < 16; i ++)
1560 {
1561 if (getbits36_1 (rega, i))
1562 scu [scu_unit_idx].cells [i + 16] = 1;
1563 }
1564 char pcellb [N_CELL_INTERRUPTS + 1];
1565 sim_debug (DBG_TRACE, & scu_dev,
1566 "SMIC low: Unit %u Cells: %s\n",
1567 scu_unit_idx, pcells (scu_unit_idx, pcellb));
1568 }
1569 else
1570 {
1571 for (uint i = 0; i < 16; i ++)
1572 {
1573 if (getbits36_1 (rega, i))
1574 scu [scu_unit_idx].cells [i] = 1;
1575 }
1576 char pcellb [N_CELL_INTERRUPTS + 1];
1577 sim_debug (DBG_TRACE, & scu_dev,
1578 "SMIC high: Unit %d Cells: %s\n",
1579 scu_unit_idx, pcells (scu_unit_idx, pcellb));
1580 }
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606 dump_intr_regs ("smic", scu_unit_idx);
1607 deliver_interrupts (cpup, scu_unit_idx);
1608 #if defined(THREADZ) || defined(LOCKLESS)
1609 unlock_scu ();
1610 #endif
1611 return SCPE_OK;
1612 }
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643 t_stat scu_sscr (cpu_state_t * cpup, uint scu_unit_idx, UNUSED uint cpu_unit_udx,
1644 UNUSED uint cpu_port_num, word18 addr,
1645 word36 rega, word36 regq)
1646 {
1647 sim_debug (DBG_DEBUG, & scu_dev, "sscr SCU unit %o\n", scu_unit_idx);
1648
1649
1650
1651 if (scu_unit_idx >= scu_dev.numunits)
1652 {
1653
1654 sim_warn ("%s: scu_unit_idx out of range %d\n",
1655 __func__, scu_unit_idx);
1656 return SCPE_OK;
1657 }
1658
1659
1660
1661
1662 uint function = (addr >> 3) & 07;
1663
1664
1665
1666 if (config_switches [scu_unit_idx].mode != MODE_PROGRAM)
1667 {
1668 sim_warn ("%s: SCU mode is 'MANUAL', not 'PROGRAM' -- sscr "
1669 "not allowed to set switches.\n",
1670 __func__);
1671
1672
1673 return SCPE_OK;
1674 }
1675
1676
1677
1678 switch (function)
1679 {
1680 case 00000:
1681 {
1682 #if defined(THREADZ) || defined(LOCKLESS)
1683 lock_scu ();
1684 #endif
1685 scu [scu_unit_idx].id = (word4) getbits36_4 (regq, 50 - 36);
1686 scu [scu_unit_idx].mode_reg = getbits36_18 (regq, 54 - 36);
1687 #if defined(THREADZ) || defined(LOCKLESS)
1688 unlock_scu ();
1689 #endif
1690 }
1691 break;
1692
1693 case 00001:
1694
1695 {
1696 sim_debug (DBG_DEBUG, & scu_dev,
1697 "sscr 1 %d A: %012"PRIo64" Q: %012"PRIo64"\n",
1698 scu_unit_idx, rega, regq);
1699 #if defined(THREADZ) || defined(LOCKLESS)
1700 lock_scu ();
1701 #endif
1702 scu_t * up = scu + scu_unit_idx;
1703 for (int maskab = 0; maskab < 2; maskab ++)
1704 {
1705 word9 mask = ((maskab ? regq : rega) >> 27) & 0777;
1706 if (mask & 01)
1707 {
1708 up -> mask_enable [maskab] = 0;
1709 sim_debug (DBG_DEBUG, & scu_dev,
1710 "sscr %u mask disable %d\n",
1711 scu_unit_idx, maskab);
1712 }
1713 else
1714 {
1715 up -> mask_enable [maskab] = 1;
1716 sim_debug (DBG_DEBUG, & scu_dev,
1717 "sscr %u mask enable %d\n",
1718 scu_unit_idx, maskab);
1719 for (int pn = 0; pn < N_SCU_PORTS; pn ++)
1720 {
1721 if ((2 << (N_SCU_PORTS - 1 - pn)) & mask)
1722 {
1723 up -> mask_assignment [maskab] = (uint) pn;
1724 break;
1725 }
1726 }
1727
1728 }
1729 sim_debug (DBG_INTR, & scu_dev,
1730 "SCU%u SSCR1 mask %c enable set to %u assigned to "
1731 "port %u\n",
1732 scu_unit_idx, 'a' + maskab, up->mask_enable[maskab],
1733 up->mask_assignment[maskab]);
1734 }
1735
1736
1737
1738
1739
1740 up -> lower_store_size = (rega >> 24) & 07;
1741 up -> cyclic = (regq >> 8) & 0177;
1742 up -> nea = (rega >> 6) & 0377;
1743 up -> onl = (rega >> 20) & 017;
1744 up -> interlace = (rega >> 5) & 1;
1745 up -> lwr = (rega >> 4) & 1;
1746 up -> port_enable [0] = (rega >> 3) & 01;
1747 up -> port_enable [1] = (rega >> 2) & 01;
1748 up -> port_enable [2] = (rega >> 1) & 01;
1749 up -> port_enable [3] = (rega >> 0) & 01;
1750 up -> port_enable [4] = (regq >> 3) & 01;
1751 up -> port_enable [5] = (regq >> 2) & 01;
1752 up -> port_enable [6] = (regq >> 1) & 01;
1753 up -> port_enable [7] = (regq >> 0) & 01;
1754
1755 #if defined(THREADZ) || defined(LOCKLESS)
1756 unlock_scu ();
1757 #endif
1758
1759
1760 break;
1761 }
1762
1763 case 00002:
1764
1765
1766
1767
1768
1769
1770
1771 {
1772 #if defined(THREADZ) || defined(LOCKLESS)
1773 lock_scu ();
1774 #endif
1775 uint port_num = (addr >> 6) & 07;
1776 sim_debug (DBG_DEBUG, & scu_dev, "Set mask register port %d to "
1777 "%012"PRIo64",%012"PRIo64"\n",
1778 port_num, rega, regq);
1779
1780
1781 int mask_num = -1;
1782 uint n_masks_found = 0;
1783 for (int p = 0; p < N_ASSIGNMENTS; p ++)
1784 {
1785
1786 if (scu [scu_unit_idx].mask_enable [p] == 0)
1787 continue;
1788
1789 if (scu [scu_unit_idx ].mask_assignment [p] == port_num)
1790 {
1791 if (n_masks_found == 0)
1792 mask_num = p;
1793 n_masks_found ++;
1794 }
1795 }
1796
1797 if (! n_masks_found)
1798 {
1799
1800 sim_debug (DBG_WARN, & scu_dev,
1801 "%s: No masks assigned to cpu on port %d\n",
1802 __func__, port_num);
1803 #if defined(THREADZ) || defined(LOCKLESS)
1804 unlock_scu ();
1805 #endif
1806 return SCPE_OK;
1807 }
1808
1809 if (n_masks_found > 1)
1810 {
1811
1812 sim_debug (DBG_WARN, & scu_dev,
1813 "%s: Multiple masks assigned to cpu on port %d\n",
1814 __func__, port_num);
1815 }
1816
1817
1818
1819 scu [scu_unit_idx].exec_intr_mask [mask_num] = 0;
1820 scu [scu_unit_idx].exec_intr_mask [mask_num] |=
1821 ((word32) getbits36_16(rega, 0) << 16);
1822 scu [scu_unit_idx].exec_intr_mask [mask_num] |=
1823 getbits36_16(regq, 0);
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833 sim_debug (DBG_TRACE, & scu_dev,
1834 "SSCR Set mask unit %u port %u mask_num %u "
1835 "mask 0x%08x\n",
1836 scu_unit_idx, port_num, mask_num,
1837 scu [scu_unit_idx].exec_intr_mask [mask_num]);
1838 dump_intr_regs ("sscr set mask", scu_unit_idx);
1839 scu [scu_unit_idx].mask_enable [mask_num] = 1;
1840 sim_debug (DBG_INTR, & scu_dev,
1841 "SCU%u SSCR2 exec_intr mask %c set to 0x%08x"
1842 " and enabled.\n",
1843 scu_unit_idx, 'a' + mask_num,
1844 scu[scu_unit_idx].exec_intr_mask[mask_num]);
1845
1846 deliver_interrupts (cpup, scu_unit_idx);
1847 #if defined(THREADZ) || defined(LOCKLESS)
1848 unlock_scu ();
1849 #endif
1850 }
1851 break;
1852
1853 case 00003:
1854 {
1855 #if defined(THREADZ) || defined(LOCKLESS)
1856 lock_scu ();
1857 #endif
1858 for (uint i = 0; i < 16; i ++)
1859 {
1860 scu [scu_unit_idx].cells [i] =
1861 getbits36_1 (rega, i) ? 1 : 0;
1862 scu [scu_unit_idx].cells [i + 16] =
1863 getbits36_1 (regq, i) ? 1 : 0;
1864 }
1865 char pcellb [N_CELL_INTERRUPTS + 1];
1866 sim_debug (DBG_TRACE, & scu_dev,
1867 "SSCR Set int. cells: Unit %u Cells: %s\n",
1868 scu_unit_idx, pcells (scu_unit_idx, pcellb));
1869 sim_debug (DBG_INTR, & scu_dev,
1870 "SCU%u SSCR3 Set int. cells %s\n",
1871 scu_unit_idx, pcells (scu_unit_idx, pcellb));
1872 dump_intr_regs ("sscr set interrupt cells", scu_unit_idx);
1873 deliver_interrupts (NULL, scu_unit_idx);
1874 #if defined(THREADZ) || defined(LOCKLESS)
1875 unlock_scu ();
1876 #endif
1877 }
1878 break;
1879
1880 case 00004:
1881 case 00005:
1882 {
1883
1884 word16 b0_15 = (word16) getbits36_16 (cpu.rA, 20);
1885 word36 b16_51 = cpu.rQ;
1886 uint64 new_clk = (((uint64) b0_15) << 36) | b16_51;
1887 #if defined(THREADZ) || defined(LOCKLESS)
1888 lock_scu ();
1889 #endif
1890 scu [scu_unit_idx].user_correction =
1891 (int64) (new_clk - set_SCU_clock (cpup, scu_unit_idx));
1892 #if defined(THREADZ) || defined(LOCKLESS)
1893 unlock_scu ();
1894 #endif
1895
1896 }
1897 break;
1898
1899 case 00006:
1900 case 00007:
1901
1902
1903 sim_warn ("sscr set unit mode register\n");
1904
1905 return SCPE_OK;
1906
1907 default:
1908 sim_warn ("sscr unhandled code\n");
1909
1910 return SCPE_OK;
1911
1912 }
1913 return SCPE_OK;
1914 }
1915
1916 t_stat scu_rscr (cpu_state_t * cpup, uint scu_unit_idx, uint cpu_unit_udx, word18 addr,
1917 word36 * rega, word36 * regq)
1918 {
1919
1920
1921 if (scu_unit_idx >= scu_dev.numunits)
1922 {
1923 sim_warn ("%s: scu_unit_idx out of range %d\n",
1924 __func__, scu_unit_idx);
1925 return SCPE_OK;
1926 }
1927
1928
1929
1930
1931 uint function = (addr >> 3) & 07;
1932
1933
1934
1935
1936
1937 switch (function)
1938 {
1939 case 00000:
1940 {
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952 * rega = 0;
1953
1954 * regq = 0;
1955 #if defined(THREADZ) || defined(LOCKLESS)
1956 lock_scu ();
1957 #endif
1958 putbits36_4 (regq, 50 - 36, scu [scu_unit_idx].id);
1959 putbits36_18 (regq, 54 - 36, scu [scu_unit_idx].mode_reg);
1960 #if defined(THREADZ) || defined(LOCKLESS)
1961 unlock_scu ();
1962 #endif
1963 break;
1964 }
1965
1966 case 00001:
1967 {
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998 sim_debug (DBG_DEBUG, & scu_dev, "rscr 1 %d\n", scu_unit_idx);
1999 #if defined(THREADZ) || defined(LOCKLESS)
2000 lock_scu ();
2001 #endif
2002 scu_t * up = scu + scu_unit_idx;
2003 word9 maskab [2];
2004 for (int i = 0; i < 2; i ++)
2005 {
2006 if (up -> mask_enable [i])
2007 {
2008 maskab [i] = (2 << (N_SCU_PORTS - 1 -
2009 up -> mask_assignment [i])) & 0777;
2010 }
2011 else
2012 maskab [i] = 0001;
2013 }
2014
2015 int scu_port_num = -1;
2016
2017
2018 for (int pn = 0; pn < N_SCU_PORTS; pn ++)
2019 {
2020 for (int sn = 0; sn < N_SCU_SUBPORTS; sn ++)
2021 {
2022 if (cables->scu_to_cpu[scu_unit_idx][pn][sn].in_use &&
2023 cables->scu_to_cpu[scu_unit_idx][pn][sn].cpu_unit_idx ==
2024 cpu_unit_udx)
2025 {
2026 scu_port_num = pn;
2027 goto gotit;
2028 }
2029 }
2030 }
2031 gotit:;
2032 if (scu_port_num < 0)
2033 {
2034 #if defined(THREADZ) || defined(LOCKLESS)
2035 unlock_scu ();
2036 #endif
2037 sim_warn ("%s: can't find cpu port in the snarl of cables; "
2038 "scu_unit_no %d, cpu_unit_udx %d\n",
2039 __func__, scu_unit_idx, cpu_unit_udx);
2040 return SCPE_OK;
2041 }
2042
2043
2044 word36 a, q;
2045
2046 a = 0;
2047
2048 putbits36_9 (& a, 0, maskab [0]);
2049 putbits36_3 (& a, 9, (word3) up -> lower_store_size);
2050 putbits36_4 (& a, 12, (word4) up -> onl);
2051 putbits36_4 (& a, 16, (word4) scu_port_num);
2052 putbits36_1 (& a, 21, (word1) config_switches[scu_unit_idx].mode);
2053 putbits36_8 (& a, 22, (word8) up -> nea);
2054 putbits36_1 (& a, 30, (word1) up -> interlace);
2055 putbits36_1 (& a, 31, (word1) up -> lwr);
2056
2057
2058
2059
2060
2061 putbits36_1 (& a, 32, (word1) up -> port_enable [0]);
2062 putbits36_1 (& a, 33, (word1) up -> port_enable [1]);
2063 putbits36_1 (& a, 34, (word1) up -> port_enable [2]);
2064 putbits36_1 (& a, 35, (word1) up -> port_enable [3]);
2065 * rega = a;
2066
2067 q = 0;
2068 putbits36_9 (& q, 0, maskab [1]);
2069
2070 putbits36_7 (& q, 57-36, (word7) up -> cyclic & MASK7);
2071
2072
2073 putbits36_1 (& q, 32, (word1) up -> port_enable [4]);
2074 putbits36_1 (& q, 33, (word1) up -> port_enable [5]);
2075 putbits36_1 (& q, 34, (word1) up -> port_enable [6]);
2076 putbits36_1 (& q, 35, (word1) up -> port_enable [7]);
2077 * regq = q;
2078
2079 #if defined(THREADZ) || defined(LOCKLESS)
2080 unlock_scu ();
2081 #endif
2082 sim_debug (DBG_DEBUG, & scu_dev,
2083 "rscr 1 %d A: %012"PRIo64" Q: %012"PRIo64"\n",
2084 scu_unit_idx, * rega, * regq);
2085 break;
2086 }
2087
2088 case 00002:
2089 {
2090 uint port_num = (addr >> 6) & MASK3;
2091 #if defined(THREADZ) || defined(LOCKLESS)
2092 lock_scu ();
2093 #endif
2094 scu_t * up = scu + scu_unit_idx;
2095 uint mask_contents = 0;
2096 if (up -> mask_assignment [0] == port_num)
2097 {
2098 mask_contents = up -> exec_intr_mask [0];
2099 }
2100 else if (up -> mask_assignment [1] == port_num)
2101 {
2102 mask_contents = up -> exec_intr_mask [1];
2103 }
2104 mask_contents &= MASK32;
2105
2106 * rega = 0;
2107 putbits36 (rega, 0, 16, (mask_contents >> 16) & MASK16);
2108 putbits36 (rega, 32, 1, up -> port_enable [0]);
2109 putbits36 (rega, 33, 1, up -> port_enable [1]);
2110 putbits36 (rega, 34, 1, up -> port_enable [2]);
2111 putbits36 (rega, 35, 1, up -> port_enable [3]);
2112
2113 * regq = 0;
2114 putbits36 (rega, 0, 16, (mask_contents >> 0) & MASK16);
2115 putbits36 (regq, 32, 1, up -> port_enable [4]);
2116 putbits36 (regq, 33, 1, up -> port_enable [5]);
2117 putbits36 (regq, 34, 1, up -> port_enable [6]);
2118 putbits36 (regq, 35, 1, up -> port_enable [7]);
2119
2120 #if defined(THREADZ) || defined(LOCKLESS)
2121 unlock_scu ();
2122 #endif
2123 sim_debug (DBG_TRACE, & scu_dev,
2124 "RSCR mask unit %u port %u assigns %u %u mask 0x%08x\n",
2125 scu_unit_idx, port_num, up -> mask_assignment [0],
2126 up -> mask_assignment [1],
2127 mask_contents);
2128 }
2129 break;
2130
2131 case 00003:
2132 {
2133 #if defined(THREADZ) || defined(LOCKLESS)
2134 lock_scu ();
2135 #endif
2136 scu_t * up = scu + scu_unit_idx;
2137
2138
2139 for (uint i = 0; i < N_CELL_INTERRUPTS; i ++)
2140 {
2141 word1 cell = up -> cells [i] ? 1 : 0;
2142 if (i < 16)
2143 putbits36_1 (rega, i, cell);
2144 else
2145 putbits36_1 (regq, i - 16, cell);
2146 }
2147 #if defined(THREADZ) || defined(LOCKLESS)
2148 unlock_scu ();
2149 #endif
2150 }
2151 break;
2152
2153 case 00004:
2154 case 00005:
2155 {
2156 uint64 clk = set_SCU_clock (cpup, scu_unit_idx);
2157 cpu.rQ = clk & 0777777777777;
2158 cpu.rA = (clk >> 36) & 0177777;
2159 #if defined(TESTING)
2160 HDBGRegAW ("rscr get clock");
2161 HDBGRegQW ("rscr get clock");
2162 #endif
2163 }
2164 break;
2165
2166 case 00006:
2167 case 00007:
2168 {
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216 * rega = 0;
2217 * regq = 0;
2218 }
2219 break;
2220
2221 default:
2222 sim_warn ("rscr %o\n", function);
2223 return SCPE_OK;
2224 }
2225 return SCPE_OK;
2226 }
2227
2228
2229
2230
2231
2232 int scu_cioc (uint cpu_unit_udx, uint scu_unit_idx, uint scu_port_num,
2233 uint expander_command, uint sub_mask)
2234 {
2235
2236
2237
2238 #if defined(TESTING)
2239 cpu_state_t * cpup = _cpup;
2240 sim_debug (DBG_DEBUG, & scu_dev,
2241 "scu_cioc: Connect from %o sent to "
2242 "unit %o port %o exp %o mask %03o\n",
2243 cpu_unit_udx, scu_unit_idx, scu_port_num,
2244 expander_command, sub_mask);
2245 #endif
2246 #if defined(THREADZ) || defined(LOCKLESS)
2247 lock_scu ();
2248 #endif
2249 struct ports * portp = & scu [scu_unit_idx].ports [scu_port_num];
2250
2251 int rc = 0;
2252 if (! scu [scu_unit_idx].port_enable [scu_port_num])
2253 {
2254 sim_debug (DBG_ERR, & scu_dev,
2255 "scu_cioc: Connect sent to disabled port; dropping\n");
2256 sim_debug (DBG_ERR, & scu_dev,
2257 "scu_cioc: scu_unit_idx %u scu_port_num %u\n",
2258 scu_unit_idx, scu_port_num);
2259 rc = 1;
2260 goto done;
2261 }
2262
2263 if (expander_command == 1)
2264 {
2265 for (uint i = 0; i < N_SCU_SUBPORTS; i++)
2266 {
2267 portp->subport_enables [i] = !! (sub_mask & (0200u >> i));
2268 }
2269 goto done;
2270 }
2271
2272 if (expander_command == 2)
2273 {
2274 int cnt = 0;
2275 int val = -1;
2276 for (uint i = 0; i < N_SCU_SUBPORTS; i++)
2277 {
2278 portp->xipmask [i] = !! (sub_mask & (0200u >> i));
2279 if (portp->xipmask [i])
2280 {
2281 val = (int) i;
2282 cnt ++;
2283 }
2284 }
2285 if (cnt > 1)
2286 {
2287 sim_warn ("xip mask cnt > 1\n");
2288 val = -1;
2289 }
2290 portp->xipmaskval = val;
2291 goto done;
2292 }
2293
2294 if (portp -> type == ADEV_IOM)
2295 {
2296 int iom_unit_idx = portp->dev_idx;
2297 #if defined(THREADZ) || defined(LOCKLESS)
2298 unlock_scu ();
2299 # if !defined(IO_ASYNC_PAYLOAD_CHAN) && !defined(IO_ASYNC_PAYLOAD_CHAN_THREAD)
2300 lock_iom ();
2301 lock_libuv ();
2302 # endif
2303 iom_interrupt (scu_unit_idx, (uint) iom_unit_idx);
2304 # if !defined(IO_ASYNC_PAYLOAD_CHAN) && !defined(IO_ASYNC_PAYLOAD_CHAN_THREAD)
2305 unlock_libuv ();
2306 unlock_iom ();
2307 # endif
2308 return 0;
2309 #else
2310 if (sys_opts.iom_times.connect <= 0)
2311 {
2312 iom_interrupt (scu_unit_idx, (uint) iom_unit_idx);
2313 goto done;
2314 }
2315 else
2316 {
2317
2318
2319
2320 sim_debug (DBG_INFO, & scu_dev,
2321 "scu_cioc: Queuing an IOM in %d cycles "
2322 "(for the connect channel)\n",
2323 sys_opts.iom_times.connect);
2324
2325 iom_dev.units[iom_unit_idx].u3 = (int32) scu_unit_idx;
2326 iom_dev.units[iom_unit_idx].u4 = (int32) iom_unit_idx;
2327 int rc;
2328 if ((rc = sim_activate (& iom_dev.units [iom_unit_idx],
2329 sys_opts.iom_times.connect)) != SCPE_OK)
2330 {
2331 sim_warn ("sim_activate failed (%d)\n", rc);
2332 goto done;
2333 }
2334 goto done;
2335 }
2336 #endif
2337 }
2338 else if (portp -> type == ADEV_CPU)
2339 {
2340
2341
2342 if (portp->is_exp)
2343 {
2344 for (uint sn = 0; sn < N_SCU_SUBPORTS; sn ++)
2345 {
2346 if (portp->subport_enables[sn])
2347 {
2348 if (! cables->
2349 scu_to_cpu[scu_unit_idx][scu_port_num][sn].in_use)
2350 {
2351 sim_warn ("Can't find CPU to interrupt\n");
2352 continue;
2353 }
2354 uint cpu_unit_udx = cables->
2355 scu_to_cpu[scu_unit_idx][scu_port_num][sn].cpu_unit_idx;
2356 setG7fault ((uint) cpu_unit_udx, FAULT_CON);
2357 }
2358 }
2359 }
2360 else
2361 {
2362 if (! cables->scu_to_cpu[scu_unit_idx][scu_port_num][0].in_use)
2363 {
2364 sim_warn ("Can't find CPU to interrupt\n");
2365 rc = 1;
2366 goto done;
2367 }
2368 uint cpu_unit_udx =
2369 cables->scu_to_cpu[scu_unit_idx][scu_port_num][0].cpu_unit_idx;
2370 setG7fault ((uint) cpu_unit_udx, FAULT_CON);
2371 }
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394 goto done;
2395 }
2396 else
2397 {
2398 sim_debug (DBG_ERR, & scu_dev,
2399 "scu_cioc: Connect sent to not-an-IOM or CPU; dropping\n");
2400 rc = 1;
2401 goto done;
2402 }
2403 done:
2404 #if defined(THREADZ) || defined(LOCKLESS)
2405 unlock_scu ();
2406 #endif
2407 return rc;
2408 }
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420 int scu_set_interrupt (uint scu_unit_idx, uint inum)
2421 {
2422 #if defined(TESTING)
2423 cpu_state_t * cpup = _cpup;
2424 #endif
2425 const char* moi = "SCU::interrupt";
2426
2427 if (inum >= N_CELL_INTERRUPTS)
2428 {
2429 sim_debug (DBG_WARN, & scu_dev,
2430 "%s: Bad interrupt number %d\n", moi, inum);
2431 return 1;
2432 }
2433
2434 #if defined(THREADZ) || defined(LOCKLESS)
2435 lock_scu ();
2436 #endif
2437 scu [scu_unit_idx].cells [inum] = 1;
2438 dump_intr_regs ("scu_set_interrupt", scu_unit_idx);
2439 deliver_interrupts (NULL, scu_unit_idx);
2440 #if defined(THREADZ) || defined(LOCKLESS)
2441 unlock_scu ();
2442 #endif
2443 return 0;
2444 }
2445
2446
2447
2448
2449
2450
2451
2452 uint scu_get_highest_intr (uint scu_unit_idx)
2453 {
2454 #if defined(TESTING)
2455 cpu_state_t * cpup = _cpup;
2456 #endif
2457 #if defined(THREADZ) || defined(LOCKLESS)
2458 lock_scu ();
2459 #endif
2460
2461 for (int inum = 0; inum < N_CELL_INTERRUPTS; inum ++)
2462 {
2463 for (uint pima = 0; pima < N_ASSIGNMENTS; pima ++)
2464 {
2465 if (scu [scu_unit_idx].mask_enable [pima] == 0)
2466 continue;
2467 uint mask = scu [scu_unit_idx].exec_intr_mask [pima];
2468 uint port = scu [scu_unit_idx].mask_assignment [pima];
2469
2470
2471 if (scu[scu_unit_idx].ports[port].type != ADEV_CPU ||
2472 cpus[current_running_cpu_idx].scu_port[scu_unit_idx] != port)
2473 continue;
2474 if (scu [scu_unit_idx].cells [inum] &&
2475 (mask & (1u << (31 - inum))) != 0)
2476 {
2477 sim_debug (DBG_TRACE, & scu_dev,
2478 "scu_get_highest_intr inum %d pima %u mask 0%011o port %u cells 0%011o\n",
2479 inum, pima, mask, port, scu [scu_unit_idx].cells [inum]);
2480 scu [scu_unit_idx].cells [inum] = false;
2481 dump_intr_regs ("scu_get_highest_intr", scu_unit_idx);
2482 deliver_interrupts (NULL, scu_unit_idx);
2483 #if defined(THREADZ) || defined(LOCKLESS)
2484 unlock_scu ();
2485 #endif
2486 return (uint) inum * 2;
2487 }
2488 }
2489 }
2490 #if defined(THREADZ) || defined(LOCKLESS)
2491 unlock_scu ();
2492 #endif
2493 return 1;
2494 }
2495
2496 t_stat scu_reset_unit (UNIT * uptr, UNUSED int32 value,
2497 UNUSED const char * cptr,
2498 UNUSED void * desc)
2499 {
2500 uint scu_unit_idx = (uint) (uptr - scu_unit);
2501 scu_unit_reset ((int) scu_unit_idx);
2502 return SCPE_OK;
2503 }
2504
2505 void scu_init (void)
2506 {
2507
2508
2509 for (int u = 0; u < N_SCU_UNITS_MAX; u ++)
2510 {
2511 for (int p = 0; p < N_SCU_PORTS; p ++)
2512 {
2513 for (int s = 0; s < N_SCU_SUBPORTS; s ++)
2514 {
2515 scu[u].ports[p].dev_port[s] = -1;
2516 scu[u].ports[p].subport_enables[s] = false;
2517 scu[u].ports[p].xipmask[s] = false;
2518
2519 scu[u].ports[p].xipmaskval = N_SCU_SUBPORTS;
2520 }
2521 scu[u].ports[p].type = ADEV_NONE;
2522 scu[u].ports[p].is_exp = false;
2523 }
2524
2525
2526
2527
2528 scu [u].id = 02l;
2529 scu [u].mode_reg = 0;
2530 scu [u].elapsed_days = 0;
2531 }
2532
2533 }
2534
2535 t_stat scu_rmcm (uint scu_unit_idx, uint cpu_unit_udx, word36 * rega,
2536 word36 * regq)
2537 {
2538 #if defined(TESTING)
2539 cpu_state_t * cpup = _cpup;
2540 #endif
2541 scu_t * up = scu + scu_unit_idx;
2542
2543
2544 * rega = 0;
2545 * regq = 0;
2546
2547
2548
2549 int scu_port_num = -1;
2550
2551
2552 for (int pn = 0; pn < N_SCU_PORTS; pn ++)
2553 {
2554 for (int sn = 0; sn < N_SCU_SUBPORTS; sn ++)
2555 {
2556 if (cables->scu_to_cpu[scu_unit_idx][pn][sn].in_use &&
2557 cables->scu_to_cpu[scu_unit_idx][pn][sn].cpu_unit_idx ==
2558 cpu_unit_udx)
2559 {
2560 scu_port_num = pn;
2561 goto gotit;
2562 }
2563 }
2564 }
2565
2566 gotit:;
2567
2568
2569
2570 if (scu_port_num < 0)
2571 {
2572 sim_warn ("%s: can't find cpu port in the snarl of cables; "
2573 "scu_unit_no %d, cpu_unit_udx %d\n",
2574 __func__, scu_unit_idx, cpu_unit_udx);
2575 sim_debug (DBG_ERR, & scu_dev,
2576 "%s: can't find cpu port in the snarl of cables; "
2577 "scu_unit_no %d, cpu_unit_udx %d\n",
2578 __func__, scu_unit_idx, cpu_unit_udx);
2579
2580 return SCPE_OK;
2581 }
2582
2583
2584
2585
2586
2587
2588
2589
2590 sim_debug (DBG_TRACE, & scu_dev, "rmcm selected scu port %u\n",
2591 scu_port_num);
2592 #if defined(THREADZ) || defined(LOCKLESS)
2593 lock_scu ();
2594 #endif
2595 uint mask_contents = 0;
2596 if (up -> mask_assignment [0] == (uint) scu_port_num)
2597 {
2598 mask_contents = up -> exec_intr_mask [0];
2599 sim_debug (DBG_TRACE, & scu_dev, "rmcm got mask %011o from pima A\n",
2600 mask_contents);
2601 }
2602 else if (up -> mask_assignment [1] == (uint) scu_port_num)
2603 {
2604 mask_contents = up -> exec_intr_mask [1];
2605 sim_debug (DBG_TRACE, & scu_dev, "rmcm got mask %011o from pima B\n",
2606 mask_contents);
2607 }
2608 mask_contents &= MASK32;
2609
2610 * rega = 0;
2611 putbits36_16 (rega, 0, (mask_contents >> 16) & MASK16);
2612 putbits36_1 (rega, 32, (word1) up -> port_enable [0]);
2613 putbits36_1 (rega, 33, (word1) up -> port_enable [1]);
2614 putbits36_1 (rega, 34, (word1) up -> port_enable [2]);
2615 putbits36_1 (rega, 35, (word1) up -> port_enable [3]);
2616
2617 * regq = 0;
2618 putbits36_16 (regq, 0, (mask_contents >> 0) & MASK16);
2619 putbits36_1 (regq, 32, (word1) up -> port_enable [4]);
2620 putbits36_1 (regq, 33, (word1) up -> port_enable [5]);
2621 putbits36_1 (regq, 34, (word1) up -> port_enable [6]);
2622 putbits36_1 (regq, 35, (word1) up -> port_enable [7]);
2623
2624 #if defined(THREADZ) || defined(LOCKLESS)
2625 unlock_scu ();
2626 #endif
2627 sim_debug (DBG_TRACE, & scu_dev,
2628 "RMCM returns %012"PRIo64" %012"PRIo64"\n",
2629 * rega, * regq);
2630 dump_intr_regs ("rmcm", scu_unit_idx);
2631 return SCPE_OK;
2632 }
2633
2634 t_stat scu_smcm (uint scu_unit_idx, uint cpu_unit_udx, word36 rega, word36 regq)
2635 {
2636 #if defined(TESTING)
2637 cpu_state_t * cpup = _cpup;
2638 #endif
2639 sim_debug (DBG_TRACE, & scu_dev,
2640 "SMCM SCU unit %d CPU unit %d A %012"PRIo64" Q %012"PRIo64"\n",
2641 scu_unit_idx, cpu_unit_udx, rega, regq);
2642
2643 scu_t * up = scu + scu_unit_idx;
2644
2645
2646
2647 int scu_port_num = -1;
2648
2649
2650 for (int pn = 0; pn < N_SCU_PORTS; pn ++)
2651 {
2652 for (int sn = 0; sn < N_SCU_SUBPORTS; sn ++)
2653 {
2654 if (cables->scu_to_cpu[scu_unit_idx][pn][sn].in_use &&
2655 cables->scu_to_cpu[scu_unit_idx][pn][sn].cpu_unit_idx ==
2656 cpu_unit_udx)
2657 {
2658 scu_port_num = pn;
2659 goto gotit;
2660 }
2661 }
2662 }
2663 gotit:;
2664
2665
2666
2667 if (scu_port_num < 0)
2668 {
2669 sim_warn ("%s: can't find cpu port in the snarl of cables; "
2670 "scu_unit_no %d, cpu_unit_udx %d\n",
2671 __func__, scu_unit_idx, cpu_unit_udx);
2672 return SCPE_OK;
2673 }
2674
2675 sim_debug (DBG_TRACE, & scu_dev, "SMCM SCU port num %d\n", scu_port_num);
2676
2677
2678
2679
2680
2681
2682
2683
2684 uint imask =
2685 ((uint) getbits36_16(rega, 0) << 16) |
2686 ((uint) getbits36_16(regq, 0) << 0);
2687 #if defined(THREADZ) || defined(LOCKLESS)
2688 lock_scu ();
2689 #endif
2690 if (up -> mask_assignment [0] == (uint) scu_port_num)
2691 {
2692 up -> exec_intr_mask [0] = imask;
2693 sim_debug (DBG_TRACE, & scu_dev, "SMCM intr mask 0 set to %011o\n",
2694 imask);
2695 }
2696 else if (up -> mask_assignment [1] == (uint) scu_port_num)
2697 {
2698 up -> exec_intr_mask [1] = imask;
2699 sim_debug (DBG_TRACE, & scu_dev, "SMCM intr mask 1 set to %011o\n",
2700 imask);
2701 }
2702
2703 scu [scu_unit_idx].port_enable [0] = (uint) getbits36_1 (rega, 32);
2704 scu [scu_unit_idx].port_enable [1] = (uint) getbits36_1 (rega, 33);
2705 scu [scu_unit_idx].port_enable [2] = (uint) getbits36_1 (rega, 34);
2706 scu [scu_unit_idx].port_enable [3] = (uint) getbits36_1 (rega, 35);
2707 scu [scu_unit_idx].port_enable [4] = (uint) getbits36_1 (regq, 32);
2708 scu [scu_unit_idx].port_enable [5] = (uint) getbits36_1 (regq, 33);
2709 scu [scu_unit_idx].port_enable [6] = (uint) getbits36_1 (regq, 34);
2710 scu [scu_unit_idx].port_enable [7] = (uint) getbits36_1 (regq, 35);
2711
2712 dump_intr_regs ("smcm", scu_unit_idx);
2713 deliver_interrupts (NULL, scu_unit_idx);
2714 #if defined(THREADZ) || defined(LOCKLESS)
2715 unlock_scu ();
2716 #endif
2717
2718 return SCPE_OK;
2719 }