This source file includes following definitions.
- scu_set_state
- 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_set_state (UNUSED UNIT * uptr, UNUSED int32 value,
606 const char * cptr, UNUSED void * desc)
607 {
608 sim_printf("Cannot modify STATE; try SET SCUn CONFIG%s%s.\r\n",
609 cptr ? "=" : "", cptr ? cptr : "");
610 return SCPE_ARG;
611 }
612
613 static t_stat scu_show_nunits (UNUSED FILE * st, UNUSED UNIT * uptr,
614 UNUSED int val, const UNUSED void * desc)
615 {
616 sim_printf("Number of SCU units in system is %d\r\n", scu_dev.numunits);
617 return SCPE_OK;
618 }
619
620 static t_stat scu_set_nunits (UNUSED UNIT * uptr, UNUSED int32 value,
621 const char * cptr, UNUSED void * desc)
622 {
623 if (! cptr)
624 return SCPE_ARG;
625 int n = atoi (cptr);
626 if (n < 1 || n > N_SCU_UNITS_MAX)
627 return SCPE_ARG;
628 scu_dev.numunits = (uint) n;
629 return SCPE_OK;
630 }
631
632 static t_stat scu_show_state (UNUSED FILE * st, UNIT *uptr, UNUSED int val,
633 UNUSED const void * desc)
634 {
635 #if defined(TESTING)
636 cpu_state_t * cpup = _cpup;
637 #endif
638 long scu_unit_idx = UNIT_NUM (uptr);
639 if (scu_unit_idx < 0 || scu_unit_idx >= (int) scu_dev.numunits)
640 {
641 sim_debug (DBG_ERR, & scu_dev,
642 "scu_show_state: Invalid unit number %ld\r\n",
643 (long) scu_unit_idx);
644 sim_printf ("error: Invalid unit number %ld\r\n", (long) scu_unit_idx);
645 return SCPE_ARG;
646 }
647
648 sim_printf ("SCU unit number %ld\r\n", (long) scu_unit_idx);
649 scu_t * scup = scu + scu_unit_idx;
650 sim_printf (" Mode %s\r\n",
651 config_switches[scu_unit_idx].mode ? "PROGRAM" : "MANUAL");
652
653 for (int i = 0; i < N_SCU_PORTS; i ++)
654 {
655 struct ports * pp = scup -> ports + i;
656
657 sim_printf (" Port %d %s dev_idx %d dev_port %d type %s\r\n",
658 i, scup->port_enable[i] ? "ENABLE " : "DISABLE",
659 pp->dev_idx, pp->dev_port[XXX_TEMP_SCU_SUBPORT],
660 pp->type == ADEV_NONE ? "NONE" :
661 pp->type == ADEV_CPU ? "CPU" :
662 pp->type == ADEV_IOM ? "IOM" :
663 "<enum broken>");
664 }
665 for (int i = 0; i < N_ASSIGNMENTS; i ++)
666 {
667
668
669 sim_printf (" Cell %c\r\n", 'A' + i);
670 sim_printf (" exec_intr_mask %012o\r\n",
671 scup -> exec_intr_mask [i]);
672 sim_printf (" mask_enable %s\r\n",
673 scup -> mask_enable [i] ? "ENABLE" : "DISABLE");
674 sim_printf (" mask_assignment %d\r\n",
675 scup -> mask_assignment [i]);
676 sim_printf (" cells ");
677 for (int j = 0; j < N_CELL_INTERRUPTS; j ++)
678 sim_printf("%d", scup -> cells [j]);
679 sim_printf ("\r\n");
680 }
681 sim_printf("Lower store size: %d\r\n", scup -> lower_store_size);
682 sim_printf("Cyclic: %03o\r\n", scup -> cyclic);
683 sim_printf("NEA: %03o\r\n", scup -> nea);
684 sim_printf("Online: %02o\r\n", scup -> onl);
685 sim_printf("Interlace: %o\r\n", scup -> interlace);
686 sim_printf("Lower: %o\r\n", scup -> lwr);
687 sim_printf("ID: %o\r\n", scup -> id);
688 sim_printf("mode_reg: %06o\r\n", scup -> mode_reg);
689 sim_printf("Elapsed days: %d\r\n", scup -> elapsed_days);
690 sim_printf("Steady clock: %d\r\n", scup -> steady_clock);
691 sim_printf("Bullet time: %d\r\n", scup -> bullet_time);
692 sim_printf("Clock delta: %lld\r\n", (long long)scup -> clock_delta);
693 return SCPE_OK;
694 }
695
696 static t_stat scu_show_config (UNUSED FILE * st, UNUSED UNIT * uptr,
697 UNUSED int val, UNUSED const void * desc)
698 {
699 #if defined(TESTING)
700 cpu_state_t * cpup = _cpup;
701 #endif
702 static const char * map [N_SCU_PORTS] =
703 {
704 "0", "1", "2", "3", "4", "5", "6", "7"
705 };
706 long scu_unit_idx = UNIT_NUM (uptr);
707 if (scu_unit_idx < 0 || scu_unit_idx >= (int) scu_dev.numunits)
708 {
709 sim_debug (DBG_ERR, & scu_dev,
710 "scu_show_config: Invalid unit number %ld\r\n",
711 (long) scu_unit_idx);
712 sim_printf ("error: Invalid unit number %ld\r\n", (long) scu_unit_idx);
713 return SCPE_ARG;
714 }
715
716 sim_printf ("SCU unit number %ld\r\n", (long) scu_unit_idx);
717
718 struct config_switches * sw = config_switches + scu_unit_idx;
719
720 const char * mode = "<out of range>";
721 switch (sw -> mode)
722 {
723 case MODE_PROGRAM:
724 mode = "Program";
725 break;
726 case MODE_MANUAL:
727 mode = "Manual";
728 break;
729 }
730
731 sim_printf ("Mode: %s\r\n", mode);
732 sim_printf ("Port Enable: ");
733 for (int i = 0; i < N_SCU_PORTS; i ++)
734 sim_printf (" %3o", sw -> port_enable [i]);
735 sim_printf ("\r\n");
736 for (int i = 0; i < N_ASSIGNMENTS; i ++)
737 {
738 sim_printf ("Mask %c: %s\r\n",
739 'A' + i,
740 sw->mask_enable[i] ? (map[sw->mask_assignment[i]]) : "Off");
741 }
742 sim_printf ("Lower Store Size: %o\r\n", sw -> lower_store_size);
743 sim_printf ("Cyclic: %03o\r\n", sw -> cyclic);
744 sim_printf ("Non-existent address: %03o\r\n", sw -> nea);
745
746 return SCPE_OK;
747 }
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772 static config_value_list_t cfg_mode_list [] =
773 {
774 { "manual", 0 },
775 { "program", 1 },
776 { NULL, 0 }
777 };
778
779 static config_value_list_t cfg_mask_list [] =
780 {
781 { "off", -1 },
782 { NULL, 0 }
783 };
784
785 static config_value_list_t cfg_able_list [] =
786 {
787 { "disable", 0 },
788 { "enable", 1 },
789 { NULL, 0 }
790 };
791
792 static config_value_list_t cfg_size_list [] =
793 {
794 { "32", 0 },
795 { "64", 1 },
796 { "128", 2 },
797 { "256", 3 },
798 { "512", 4 },
799 { "1024", 5 },
800 { "2048", 6 },
801 { "4096", 7 },
802 { "32K", 0 },
803 { "64K", 1 },
804 { "128K", 2 },
805 { "256K", 3 },
806 { "512K", 4 },
807 { "1024K", 5 },
808 { "2048K", 6 },
809 { "4096K", 7 },
810 { "1M", 5 },
811 { "2M", 6 },
812 { "4M", 7 },
813 { NULL, 0 }
814 };
815
816 static config_value_list_t cfg_on_off [] =
817 {
818 { "off", 0 },
819 { "on", 1 },
820 { "disable", 0 },
821 { "enable", 1 },
822 { NULL, 0 }
823 };
824
825 static config_list_t scu_config_list [] =
826 {
827 { "mode", 1, 0, cfg_mode_list },
828 { "maska", 0, N_SCU_PORTS - 1, cfg_mask_list },
829 { "maskb", 0, N_SCU_PORTS - 1, cfg_mask_list },
830 { "port0", 1, 0, cfg_able_list },
831 { "port1", 1, 0, cfg_able_list },
832 { "port2", 1, 0, cfg_able_list },
833 { "port3", 1, 0, cfg_able_list },
834 { "port4", 1, 0, cfg_able_list },
835 { "port5", 1, 0, cfg_able_list },
836 { "port6", 1, 0, cfg_able_list },
837 { "port7", 1, 0, cfg_able_list },
838 { "lwrstoresize", 0, 7, cfg_size_list },
839 { "cyclic", 0, 0177, NULL },
840 { "nea", 0, 0377, NULL },
841
842 { "onl", 0, 017, NULL },
843 { "int", 0, 1, NULL },
844 { "lwr", 0, 1, NULL },
845
846
847
848 { "elapsed_days", 0, 20000, NULL },
849 { "steady_clock", 0, 1, cfg_on_off },
850 { "bullet_time", 0, 1, cfg_on_off },
851 { "clock_delta", -2147483648, 2147483647, NULL },
852 { NULL, 0, 0, NULL }
853 };
854
855 static t_stat scu_set_config (UNIT * uptr, UNUSED int32 value,
856 const char * cptr, UNUSED void * desc)
857 {
858 #if defined(TESTING)
859 cpu_state_t * cpup = _cpup;
860 #endif
861 long scu_unit_idx = UNIT_NUM (uptr);
862 if (scu_unit_idx < 0 || scu_unit_idx >= (int) scu_dev.numunits)
863 {
864 sim_debug (DBG_ERR, & scu_dev,
865 "scu_set_config: Invalid unit number %ld\r\n", (long) scu_unit_idx);
866 sim_printf ("error: scu_set_config: Invalid unit number %ld\r\n",
867 (long) scu_unit_idx);
868 return SCPE_ARG;
869 }
870
871 struct config_switches * sw = config_switches + scu_unit_idx;
872
873 config_state_t cfg_state = { NULL, NULL };
874
875 for (;;)
876 {
877 int64_t v;
878 int rc = cfg_parse ("scu_set_config", cptr, scu_config_list,
879 & cfg_state, & v);
880 if (rc == -1)
881 break;
882
883 if (rc == -2)
884 {
885 cfg_parse_done (& cfg_state);
886 return SCPE_ARG;
887 }
888
889 const char * p = scu_config_list [rc].name;
890 if (strcmp (p, "mode") == 0)
891 sw -> mode = (uint) v;
892 else if (strcmp (p, "maska") == 0)
893 {
894 if (v == -1)
895 sw -> mask_enable [0] = false;
896 else
897 {
898 sw -> mask_enable [0] = true;
899 sw -> mask_assignment [0] = (uint) v;
900 }
901 }
902 else if (strcmp (p, "maskb") == 0)
903 {
904 if (v == -1)
905 sw -> mask_enable [1] = false;
906 else
907 {
908 sw -> mask_enable [1] = true;
909 sw -> mask_assignment [1] = (uint) v;
910 }
911 }
912 else if (strcmp (p, "port0") == 0)
913 sw -> port_enable [0] = (uint) v;
914 else if (strcmp (p, "port1") == 0)
915 sw -> port_enable [1] = (uint) v;
916 else if (strcmp (p, "port2") == 0)
917 sw -> port_enable [2] = (uint) v;
918 else if (strcmp (p, "port3") == 0)
919 sw -> port_enable [3] = (uint) v;
920 else if (strcmp (p, "port4") == 0)
921 sw -> port_enable [4] = (uint) v;
922 else if (strcmp (p, "port5") == 0)
923 sw -> port_enable [5] = (uint) v;
924 else if (strcmp (p, "port6") == 0)
925 sw -> port_enable [6] = (uint) v;
926 else if (strcmp (p, "port7") == 0)
927 sw -> port_enable [7] = (uint) v;
928 else if (strcmp (p, "lwrstoresize") == 0)
929 sw -> lower_store_size = (uint) v;
930 else if (strcmp (p, "cyclic") == 0)
931 sw -> cyclic = (uint) v;
932 else if (strcmp (p, "nea") == 0)
933 sw -> nea = (uint) v;
934 else if (strcmp (p, "onl") == 0)
935 sw -> onl = (uint) v;
936 else if (strcmp (p, "int") == 0)
937 sw -> interlace = (uint) v;
938 else if (strcmp (p, "lwr") == 0)
939 sw -> lwr = (uint) v;
940 else if (strcmp (p, "elapsed_days") == 0)
941 scu [scu_unit_idx].elapsed_days = (uint) v;
942 else if (strcmp (p, "steady_clock") == 0)
943 scu [scu_unit_idx].steady_clock = (uint) v;
944 else if (strcmp (p, "bullet_time") == 0)
945 scu [scu_unit_idx].bullet_time = (uint) v;
946 else if (strcmp (p, "clock_delta") == 0)
947 scu [scu_unit_idx].clock_delta = (int64_t) v;
948 else
949 {
950 sim_printf ("error: scu_set_config: invalid cfg_parse rc <%d>\r\n",
951 rc);
952 cfg_parse_done (& cfg_state);
953 return SCPE_ARG;
954 }
955 }
956 cfg_parse_done (& cfg_state);
957 return SCPE_OK;
958 }
959
960 static MTAB scu_mod [] =
961 {
962 {
963 MTAB_XTD | MTAB_VUN | \
964 MTAB_NMO | MTAB_VALR,
965 0,
966 (char *) "CONFIG",
967 (char *) "CONFIG",
968 scu_set_config,
969 scu_show_config,
970 NULL,
971 NULL
972 },
973 {
974 MTAB_XTD | MTAB_VDV | \
975 MTAB_NMO | MTAB_VALR,
976 0,
977 (char *) "NUNITS",
978 (char *) "NUNITS",
979 scu_set_nunits,
980 scu_show_nunits,
981 (char *) "Number of SCU units in the system",
982 NULL
983 },
984 {
985 MTAB_XTD | MTAB_VUN | \
986 MTAB_NMO | MTAB_VALR,
987 0,
988 (char *) "STATE",
989 (char *) "STATE",
990 scu_set_state,
991 scu_show_state,
992 (char *) "SCU unit internal state",
993 NULL
994 },
995 {
996 MTAB_XTD | MTAB_VUN | \
997 MTAB_NMO | MTAB_VALR,
998 0,
999 (char *) "RESET",
1000 (char *) "RESET",
1001 scu_reset_unit,
1002 NULL,
1003 (char *) "reset SCU unit",
1004 NULL
1005 },
1006 {
1007 0, 0, NULL, NULL, NULL, NULL, NULL, NULL
1008 }
1009 };
1010
1011
1012
1013 static DEBTAB scu_dt [] =
1014 {
1015 { (char *) "TRACE", DBG_TRACE, NULL },
1016 { (char *) "NOTIFY", DBG_NOTIFY, NULL },
1017 { (char *) "INFO", DBG_INFO, NULL },
1018 { (char *) "ERR", DBG_ERR, NULL },
1019 { (char *) "WARN", DBG_WARN, NULL },
1020 { (char *) "DEBUG", DBG_DEBUG, NULL },
1021 { (char *) "INTR", DBG_INTR, NULL },
1022 { (char *) "ALL", DBG_ALL, NULL },
1023 { NULL, 0, NULL }
1024 };
1025
1026 DEVICE scu_dev =
1027 {
1028 (char *) "SCU",
1029 scu_unit,
1030 NULL,
1031 scu_mod,
1032 N_SCU_UNITS,
1033 10,
1034 8,
1035 1,
1036 8,
1037 8,
1038 NULL,
1039 NULL,
1040 & scu_reset,
1041 NULL,
1042 NULL,
1043 NULL,
1044 NULL,
1045 DEV_DEBUG,
1046 0,
1047 scu_dt,
1048 NULL,
1049 NULL,
1050 NULL,
1051 NULL,
1052 NULL,
1053 NULL,
1054 NULL
1055 };
1056
1057 static void dump_intr_regs (char * ctx, uint scu_unit_idx)
1058 {
1059 #if defined(TESTING)
1060 scu_t * up = scu + scu_unit_idx;
1061 cpu_state_t * cpup = _cpup;
1062
1063 sim_debug (DBG_DEBUG, & scu_dev,
1064 "%s A: mask %011o enable %o assignment %o\r\n",
1065 ctx, up -> exec_intr_mask [0], up -> mask_enable [0],
1066 up -> mask_assignment [0]);
1067 sim_debug (DBG_DEBUG, & scu_dev,
1068 "%s B: mask %011o enable %o assignment %o\r\n",
1069 ctx, up -> exec_intr_mask [1], up -> mask_enable [1],
1070 up -> mask_assignment [1]);
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
1111
1112
1113
1114
1115
1116
1117
1118 #endif
1119 }
1120
1121 void scu_unit_reset (int scu_unit_idx)
1122 {
1123 scu_t * up = scu + scu_unit_idx;
1124 struct config_switches * sw = config_switches + scu_unit_idx;
1125
1126 for (int i = 0; i < N_SCU_PORTS; i ++)
1127 {
1128 up -> port_enable [i] = sw -> port_enable [i];
1129 }
1130
1131 for (int i = 0; i < N_ASSIGNMENTS; i ++)
1132 {
1133 up -> mask_enable [i] = sw -> mask_enable [i];
1134 up -> mask_assignment [i] = sw -> mask_assignment [i];
1135 }
1136 up -> lower_store_size = sw -> lower_store_size;
1137 up -> cyclic = sw -> cyclic;
1138 up -> nea = sw -> nea;
1139 up -> onl = sw -> onl;
1140 up -> interlace = sw -> interlace;
1141 up -> lwr = sw -> lwr;
1142
1143
1144
1145
1146 for (uint port_num = 0; port_num < N_SCU_PORTS; port_num ++)
1147 {
1148 struct ports * portp = & scu [scu_unit_idx].ports [port_num];
1149 if (portp->type != ADEV_IOM)
1150 continue;
1151
1152
1153 iom_unit_reset_idx ((uint) portp->dev_idx);
1154 }
1155
1156
1157
1158
1159
1160 for (int i = 0; i < N_ASSIGNMENTS; i ++)
1161 {
1162
1163 up -> exec_intr_mask [i] = 037777777777;
1164 }
1165 }
1166
1167 t_stat scu_reset (UNUSED DEVICE * dptr)
1168 {
1169
1170
1171 for (int scu_unit_idx = 0; scu_unit_idx < N_SCU_UNITS_MAX; scu_unit_idx ++)
1172 scu_unit_reset (scu_unit_idx);
1173 return SCPE_OK;
1174 }
1175
1176
1177
1178 #if defined(THREADZ) || defined(LOCKLESS)
1179 static pthread_mutex_t clock_lock = PTHREAD_MUTEX_INITIALIZER;
1180 #endif
1181
1182
1183 static uint64 set_SCU_clock (cpu_state_t * cpup, uint scu_unit_idx)
1184 {
1185 #if defined(THREADZ) || defined(LOCKLESS)
1186 pthread_mutex_lock (& clock_lock);
1187 #endif
1188
1189
1190
1191
1192
1193
1194 if (scu [0].steady_clock)
1195 {
1196
1197
1198 #if defined(NEED_128)
1199 uint128 big = construct_128 (0, cpu.instrCnt);
1200
1201
1202 big = lshift_128 (big, 2);
1203 if (scu [0].bullet_time)
1204 big = multiply_128 (big, construct_128 (0, 10000u));
1205
1206
1207 uint128 days = construct_128 (0, scu[0].elapsed_days);
1208 days = multiply_128 (days, construct_128 (0, 1000000));
1209 days = multiply_128 (days, construct_128 (0, 60 * 60 * 24));
1210 big = add_128 (big, days);
1211 #else
1212 __uint128_t big = cpu.instrCnt;
1213
1214 big *= 4u;
1215
1216 if (scu [0].bullet_time)
1217 big *= 10000;
1218
1219 big += scu [0].elapsed_days * 1000000llu * 60llu * 60llu * 24llu;
1220 #endif
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234 uint64 UNIX_secs = (uint64)time(NULL);
1235
1236 #if defined(NEED_128)
1237 uint64 UNIX_usecs = UNIX_secs * 1000000llu + big.l;
1238 #else
1239 uint64 UNIX_usecs = UNIX_secs * 1000000llu + (uint64) big;
1240 #endif
1241
1242 uint64 Multics_usecs = 2177452800000000llu + UNIX_usecs;
1243
1244
1245
1246 Multics_usecs += (uint64) scu [scu_unit_idx].user_correction;
1247
1248
1249
1250
1251 if (scu [scu_unit_idx].last_time >= Multics_usecs)
1252 {
1253 sim_debug (DBG_TRACE, & scu_dev, "finagle clock\r\n");
1254 Multics_usecs = scu [scu_unit_idx].last_time + 1;
1255 }
1256 scu [scu_unit_idx].last_time = Multics_usecs;
1257 goto done;
1258 }
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271 struct timeval now;
1272 gettimeofday(& now, NULL);
1273
1274 if (scu [scu_unit_idx].clock_delta)
1275 now.tv_sec += scu [scu_unit_idx].clock_delta;
1276
1277 uint64 UNIX_secs = (uint64) now.tv_sec;
1278 uint64 UNIX_usecs = UNIX_secs * 1000000LL + (uint64) now.tv_usec;
1279
1280 static uint64 last_UNIX_usecs = 0;
1281 if ( (!sim_quiet) && (UNIX_usecs < last_UNIX_usecs))
1282 {
1283 if (gtod_warned < 11)
1284 {
1285 sim_warn ("\rHost clock went backwards %llu uS!\r\n",
1286 (unsigned long long)(last_UNIX_usecs - UNIX_usecs));
1287 gtod_warned++;
1288 }
1289 else if (gtod_warned == 11)
1290 {
1291 sim_warn ("\rHost clock went backwards %llu uS! Suppressing further warnings.\r\n",
1292 (unsigned long long)(last_UNIX_usecs - UNIX_usecs));
1293 gtod_warned++;
1294 }
1295 }
1296 last_UNIX_usecs = UNIX_usecs;
1297
1298
1299 uint64 Multics_usecs = 2177452800000000LL + UNIX_usecs;
1300
1301
1302
1303 Multics_usecs += (uint64) scu [scu_unit_idx].user_correction;
1304
1305 if (scu [scu_unit_idx].last_time >= Multics_usecs)
1306 Multics_usecs = scu [scu_unit_idx].last_time + 1;
1307 scu [scu_unit_idx].last_time = Multics_usecs;
1308
1309 done:
1310 #if defined(THREADZ) || defined(LOCKLESS)
1311 pthread_mutex_unlock (& clock_lock);
1312 #endif
1313
1314 return scu [scu_unit_idx].last_time;
1315 }
1316
1317
1318 static char * pcells (uint scu_unit_idx, char * buf)
1319 {
1320 for (uint i = 0; i < N_CELL_INTERRUPTS; i ++)
1321 {
1322 if (scu [scu_unit_idx].cells [i])
1323 buf [i] = '1';
1324 else
1325 buf [i] = '0';
1326 }
1327 buf [N_CELL_INTERRUPTS] = '\0';
1328 return buf;
1329 }
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345 static void deliver_interrupts (cpu_state_t * cpup, uint scu_unit_idx)
1346 {
1347 #if defined(TESTING)
1348 {
1349 cpu_state_t * cpup = _cpup;
1350 sim_debug (DBG_DEBUG, & scu_dev, "deliver_interrupts %o\r\n", scu_unit_idx);
1351 }
1352 #endif
1353 #if defined(THREADZ) || defined(LOCKLESS)
1354 atomic_thread_fence (memory_order_seq_cst);
1355 #endif
1356 for (uint cpun = 0; cpun < cpu_dev.numunits; cpun ++)
1357 {
1358 cpus[cpun].events.XIP[scu_unit_idx] = false;
1359 }
1360
1361
1362
1363
1364
1365 #if defined(REORDER)
1366 for (uint jnum = 0; jnum < N_CELL_INTERRUPTS; jnum ++)
1367 {
1368 static const uint reorder[N_CELL_INTERRUPTS] = {
1369 0, 1, 2, 3, 4, 5, 6, 7,
1370 16, 17, 18, 29, 20, 21, 22, 23,
1371 8, 9, 10, 11, 12, 13, 14, 15,
1372 25, 25, 26, 27, 28, 29, 30, 31 };
1373 uint inum = reorder[jnum];
1374 if (! scu [scu_unit_idx].cells [inum])
1375 continue;
1376 sim_debug (DBG_DEBUG, & scu_dev, "trying to deliver %d\r\n", inum);
1377 sim_debug (DBG_INTR, & scu_dev,
1378 "scu %u trying to deliver %d\r\n", scu_unit_idx, inum);
1379
1380 for (uint pima = 0; pima < N_ASSIGNMENTS; pima ++)
1381 {
1382
1383
1384
1385 if (scu [scu_unit_idx].mask_enable [pima] == 0)
1386 continue;
1387 uint mask = scu [scu_unit_idx].exec_intr_mask [pima];
1388 uint port = scu [scu_unit_idx].mask_assignment [pima];
1389
1390
1391
1392
1393 if (scu [scu_unit_idx].ports [port].type != ADEV_CPU)
1394 continue;
1395 if ((mask & (1u << (31 - inum))) != 0)
1396 {
1397 uint sn = 0;
1398 if (scu[scu_unit_idx].ports[port].is_exp)
1399 {
1400 sn = (uint) scu[scu_unit_idx].ports[port].xipmaskval;
1401 if (sn >= N_SCU_SUBPORTS)
1402 {
1403 sim_warn ("XIP mask not set; defaulting to subport 0\r\n");
1404 sn = 0;
1405 }
1406 }
1407 if (! cables->scu_to_cpu[scu_unit_idx][port][sn].in_use)
1408 {
1409 sim_warn ("bad scu_unit_idx %u\r\n", scu_unit_idx);
1410 continue;
1411 }
1412 uint cpu_unit_udx = cables->scu_to_cpu[scu_unit_idx][port][sn].cpu_unit_idx;
1413 # if defined(THREADZ) || defined(LOCKLESS)
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424 if ((! sys.sys_opts.nosync) && cpup && (! cpus[cpu_unit_udx].inMultics)) {
1425
1426 # ifdef SYNCTEST
1427 sim_printf ("CPU %c becomes clock master\r\n", 'A' + cpu_unit_udx);
1428 # endif
1429 becomeClockMaster (cpu_unit_udx);
1430
1431 cpu.syncClockModePoll = 0;
1432 cpu.syncClockModeCache = true;
1433 __asm volatile ("");
1434 atomic_thread_fence (memory_order_seq_cst);
1435 }
1436 cpus[cpu_unit_udx].events.XIP[scu_unit_idx] = true;
1437 # if defined(TESTING)
1438 HDBGIntrSet (inum, cpu_unit_udx, scu_unit_idx, __func__);
1439 # endif
1440 createCPUThread((uint) cpu_unit_udx);
1441 # if !defined(NO_TIMEWAIT)
1442 wakeCPU ((uint) cpu_unit_udx);
1443 # endif
1444 sim_debug (DBG_DEBUG, & scu_dev,
1445 "interrupt set for CPU %d SCU %d\r\n",
1446 cpu_unit_udx, scu_unit_idx);
1447 # else
1448 cpus[cpu_unit_udx].events.XIP[scu_unit_idx] = true;
1449 sim_debug (DBG_DEBUG, & scu_dev, "interrupt set for CPU %d SCU %d\r\n", cpu_unit_udx, scu_unit_idx);
1450 sim_debug (DBG_INTR, & scu_dev,
1451 "XIP set for SCU %d\r\n", scu_unit_idx);
1452 # endif
1453 }
1454 }
1455 }
1456 #else
1457 for (uint inum = 0; inum < N_CELL_INTERRUPTS; inum ++)
1458 {
1459 if (! scu [scu_unit_idx].cells [inum])
1460 continue;
1461 sim_debug (DBG_DEBUG, & scu_dev, "trying to deliver %d\r\n", inum);
1462 sim_debug (DBG_INTR, & scu_dev,
1463 "scu %u trying to deliver %d\r\n", scu_unit_idx, inum);
1464
1465 for (uint pima = 0; pima < N_ASSIGNMENTS; pima ++)
1466 {
1467
1468
1469
1470 if (scu [scu_unit_idx].mask_enable [pima] == 0)
1471 continue;
1472 uint mask = scu [scu_unit_idx].exec_intr_mask [pima];
1473 uint port = scu [scu_unit_idx].mask_assignment [pima];
1474
1475
1476
1477
1478 if (scu [scu_unit_idx].ports [port].type != ADEV_CPU)
1479 continue;
1480 if ((mask & (1u << (31 - inum))) != 0)
1481 {
1482 uint sn = 0;
1483 if (scu[scu_unit_idx].ports[port].is_exp)
1484 {
1485 sn = (uint) scu[scu_unit_idx].ports[port].xipmaskval;
1486 if (sn >= N_SCU_SUBPORTS)
1487 {
1488 sim_warn ("XIP mask not set; defaulting to subport 0\r\n");
1489 sn = 0;
1490 }
1491 }
1492 if (! cables->scu_to_cpu[scu_unit_idx][port][sn].in_use)
1493 {
1494 sim_warn ("bad scu_unit_idx %u\r\n", scu_unit_idx);
1495 continue;
1496 }
1497 uint cpu_unit_udx = cables->scu_to_cpu[scu_unit_idx][port][sn].cpu_unit_idx;
1498 # if defined(THREADZ) || defined(LOCKLESS)
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509 if ((! sys_opts.nosync) && cpup && (! cpus[cpu_unit_udx].inMultics)) {
1510
1511 # ifdef SYNCTEST
1512 sim_printf ("CPU %c becomes clock master\r\n", 'A' + cpu_unit_udx);
1513 # endif
1514 becomeClockMaster (cpu_unit_udx);
1515 }
1516 cpus[cpu_unit_udx].events.XIP[scu_unit_idx] = true;
1517 # if defined(TESTING)
1518 HDBGIntrSet (inum, cpu_unit_udx, scu_unit_idx, __func__);
1519 # endif
1520 # ifdef SYNCTEST
1521 if (cpus[cpu_unit_udx].rcfDelete) sim_printf ("Poking CPU %c in rcfDelete\r\n", 'A' + cpu_unit_udx);
1522 # endif
1523 createCPUThread((uint) cpu_unit_udx);
1524 # if !defined(NO_TIMEWAIT)
1525 wakeCPU ((uint) cpu_unit_udx);
1526 # endif
1527 sim_debug (DBG_DEBUG, & scu_dev,
1528 "interrupt set for CPU %d SCU %d\r\n",
1529 cpu_unit_udx, scu_unit_idx);
1530 # else
1531 cpus[cpu_unit_udx].events.XIP[scu_unit_idx] = true;
1532 sim_debug (DBG_DEBUG, & scu_dev, "interrupt set for CPU %d SCU %d\r\n", cpu_unit_udx, scu_unit_idx);
1533 sim_debug (DBG_INTR, & scu_dev,
1534 "XIP set for SCU %d\r\n", scu_unit_idx);
1535 # endif
1536 }
1537 }
1538 }
1539 #endif
1540 }
1541
1542 t_stat scu_smic (cpu_state_t * cpup, uint scu_unit_idx, uint UNUSED cpu_unit_udx,
1543 uint UNUSED cpu_port_num, word36 rega)
1544 {
1545 #if defined(THREADZ) || defined(LOCKLESS)
1546 lock_scu ();
1547 #endif
1548
1549
1550 if (getbits36_1 (rega, 35))
1551 {
1552 for (uint i = 0; i < 16; i ++)
1553 {
1554 if (getbits36_1 (rega, i))
1555 scu [scu_unit_idx].cells [i + 16] = 1;
1556 }
1557 char pcellb [N_CELL_INTERRUPTS + 1];
1558 sim_debug (DBG_TRACE, & scu_dev,
1559 "SMIC low: Unit %u Cells: %s\r\n",
1560 scu_unit_idx, pcells (scu_unit_idx, pcellb));
1561 }
1562 else
1563 {
1564 for (uint i = 0; i < 16; i ++)
1565 {
1566 if (getbits36_1 (rega, i))
1567 scu [scu_unit_idx].cells [i] = 1;
1568 }
1569 char pcellb [N_CELL_INTERRUPTS + 1];
1570 sim_debug (DBG_TRACE, & scu_dev,
1571 "SMIC high: Unit %d Cells: %s\r\n",
1572 scu_unit_idx, pcells (scu_unit_idx, pcellb));
1573 }
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599 dump_intr_regs ("smic", scu_unit_idx);
1600 deliver_interrupts (cpup, scu_unit_idx);
1601 #if defined(THREADZ) || defined(LOCKLESS)
1602 unlock_scu ();
1603 #endif
1604 return SCPE_OK;
1605 }
1606
1607
1608
1609
1610
1611
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 t_stat scu_sscr (cpu_state_t * cpup, uint scu_unit_idx, UNUSED uint cpu_unit_udx,
1637 UNUSED uint cpu_port_num, word18 addr,
1638 word36 rega, word36 regq)
1639 {
1640 sim_debug (DBG_DEBUG, & scu_dev, "sscr SCU unit %o\r\n", scu_unit_idx);
1641
1642
1643
1644 if (scu_unit_idx >= scu_dev.numunits)
1645 {
1646
1647 sim_warn ("%s: scu_unit_idx out of range %d\r\n",
1648 __func__, scu_unit_idx);
1649 return SCPE_OK;
1650 }
1651
1652
1653
1654
1655 uint function = (addr >> 3) & 07;
1656
1657
1658
1659 if (config_switches [scu_unit_idx].mode != MODE_PROGRAM)
1660 {
1661 sim_warn ("%s: SCU mode is 'MANUAL', not 'PROGRAM' -- sscr "
1662 "not allowed to set switches.\r\n",
1663 __func__);
1664
1665
1666 return SCPE_OK;
1667 }
1668
1669
1670
1671 switch (function)
1672 {
1673 case 00000:
1674 {
1675 #if defined(THREADZ) || defined(LOCKLESS)
1676 lock_scu ();
1677 #endif
1678 scu [scu_unit_idx].id = (word4) getbits36_4 (regq, 50 - 36);
1679 scu [scu_unit_idx].mode_reg = getbits36_18 (regq, 54 - 36);
1680 #if defined(THREADZ) || defined(LOCKLESS)
1681 unlock_scu ();
1682 #endif
1683 }
1684 break;
1685
1686 case 00001:
1687
1688 {
1689 sim_debug (DBG_DEBUG, & scu_dev,
1690 "sscr 1 %d A: %012"PRIo64" Q: %012"PRIo64"\r\n",
1691 scu_unit_idx, rega, regq);
1692 #if defined(THREADZ) || defined(LOCKLESS)
1693 lock_scu ();
1694 #endif
1695 scu_t * up = scu + scu_unit_idx;
1696 for (int maskab = 0; maskab < 2; maskab ++)
1697 {
1698 word9 mask = ((maskab ? regq : rega) >> 27) & 0777;
1699 if (mask & 01)
1700 {
1701 up -> mask_enable [maskab] = 0;
1702 sim_debug (DBG_DEBUG, & scu_dev,
1703 "sscr %u mask disable %d\r\n",
1704 scu_unit_idx, maskab);
1705 }
1706 else
1707 {
1708 up -> mask_enable [maskab] = 1;
1709 sim_debug (DBG_DEBUG, & scu_dev,
1710 "sscr %u mask enable %d\r\n",
1711 scu_unit_idx, maskab);
1712 for (int pn = 0; pn < N_SCU_PORTS; pn ++)
1713 {
1714 if ((2 << (N_SCU_PORTS - 1 - pn)) & mask)
1715 {
1716 up -> mask_assignment [maskab] = (uint) pn;
1717 break;
1718 }
1719 }
1720
1721 }
1722 sim_debug (DBG_INTR, & scu_dev,
1723 "SCU%u SSCR1 mask %c enable set to %u assigned to "
1724 "port %u\r\n",
1725 scu_unit_idx, 'a' + maskab, up->mask_enable[maskab],
1726 up->mask_assignment[maskab]);
1727 }
1728
1729
1730
1731
1732
1733 up -> lower_store_size = (rega >> 24) & 07;
1734 up -> cyclic = (regq >> 8) & 0177;
1735 up -> nea = (rega >> 6) & 0377;
1736 up -> onl = (rega >> 20) & 017;
1737 up -> interlace = (rega >> 5) & 1;
1738 up -> lwr = (rega >> 4) & 1;
1739 up -> port_enable [0] = (rega >> 3) & 01;
1740 up -> port_enable [1] = (rega >> 2) & 01;
1741 up -> port_enable [2] = (rega >> 1) & 01;
1742 up -> port_enable [3] = (rega >> 0) & 01;
1743 up -> port_enable [4] = (regq >> 3) & 01;
1744 up -> port_enable [5] = (regq >> 2) & 01;
1745 up -> port_enable [6] = (regq >> 1) & 01;
1746 up -> port_enable [7] = (regq >> 0) & 01;
1747
1748 #if defined(THREADZ) || defined(LOCKLESS)
1749 unlock_scu ();
1750 #endif
1751
1752
1753 break;
1754 }
1755
1756 case 00002:
1757
1758
1759
1760
1761
1762
1763
1764 {
1765 #if defined(THREADZ) || defined(LOCKLESS)
1766 lock_scu ();
1767 #endif
1768 uint port_num = (addr >> 6) & 07;
1769 sim_debug (DBG_DEBUG, & scu_dev, "Set mask register port %d to "
1770 "%012"PRIo64",%012"PRIo64"\r\n",
1771 port_num, rega, regq);
1772
1773
1774 int mask_num = -1;
1775 uint n_masks_found = 0;
1776 for (int p = 0; p < N_ASSIGNMENTS; p ++)
1777 {
1778
1779 if (scu [scu_unit_idx].mask_enable [p] == 0)
1780 continue;
1781
1782 if (scu [scu_unit_idx ].mask_assignment [p] == port_num)
1783 {
1784 if (n_masks_found == 0)
1785 mask_num = p;
1786 n_masks_found ++;
1787 }
1788 }
1789
1790 if (! n_masks_found)
1791 {
1792
1793 sim_debug (DBG_WARN, & scu_dev,
1794 "%s: No masks assigned to cpu on port %d\r\n",
1795 __func__, port_num);
1796 #if defined(THREADZ) || defined(LOCKLESS)
1797 unlock_scu ();
1798 #endif
1799 return SCPE_OK;
1800 }
1801
1802 if (n_masks_found > 1)
1803 {
1804
1805 sim_debug (DBG_WARN, & scu_dev,
1806 "%s: Multiple masks assigned to cpu on port %d\r\n",
1807 __func__, port_num);
1808 }
1809
1810
1811
1812 scu [scu_unit_idx].exec_intr_mask [mask_num] = 0;
1813 scu [scu_unit_idx].exec_intr_mask [mask_num] |=
1814 ((word32) getbits36_16(rega, 0) << 16);
1815 scu [scu_unit_idx].exec_intr_mask [mask_num] |=
1816 getbits36_16(regq, 0);
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826 sim_debug (DBG_TRACE, & scu_dev,
1827 "SSCR Set mask unit %u port %u mask_num %u "
1828 "mask 0x%08x\r\n",
1829 scu_unit_idx, port_num, mask_num,
1830 scu [scu_unit_idx].exec_intr_mask [mask_num]);
1831 dump_intr_regs ("sscr set mask", scu_unit_idx);
1832 scu [scu_unit_idx].mask_enable [mask_num] = 1;
1833 sim_debug (DBG_INTR, & scu_dev,
1834 "SCU%u SSCR2 exec_intr mask %c set to 0x%08x"
1835 " and enabled.\r\n",
1836 scu_unit_idx, 'a' + mask_num,
1837 scu[scu_unit_idx].exec_intr_mask[mask_num]);
1838
1839 deliver_interrupts (cpup, scu_unit_idx);
1840 #if defined(THREADZ) || defined(LOCKLESS)
1841 unlock_scu ();
1842 #endif
1843 }
1844 break;
1845
1846 case 00003:
1847 {
1848 #if defined(THREADZ) || defined(LOCKLESS)
1849 lock_scu ();
1850 #endif
1851 for (uint i = 0; i < 16; i ++)
1852 {
1853 scu [scu_unit_idx].cells [i] =
1854 getbits36_1 (rega, i) ? 1 : 0;
1855 scu [scu_unit_idx].cells [i + 16] =
1856 getbits36_1 (regq, i) ? 1 : 0;
1857 }
1858 char pcellb [N_CELL_INTERRUPTS + 1];
1859 sim_debug (DBG_TRACE, & scu_dev,
1860 "SSCR Set int. cells: Unit %u Cells: %s\r\n",
1861 scu_unit_idx, pcells (scu_unit_idx, pcellb));
1862 sim_debug (DBG_INTR, & scu_dev,
1863 "SCU%u SSCR3 Set int. cells %s\r\n",
1864 scu_unit_idx, pcells (scu_unit_idx, pcellb));
1865 dump_intr_regs ("sscr set interrupt cells", scu_unit_idx);
1866 deliver_interrupts (NULL, scu_unit_idx);
1867 #if defined(THREADZ) || defined(LOCKLESS)
1868 unlock_scu ();
1869 #endif
1870 }
1871 break;
1872
1873 case 00004:
1874 case 00005:
1875 {
1876
1877 word16 b0_15 = (word16) getbits36_16 (cpu.rA, 20);
1878 word36 b16_51 = cpu.rQ;
1879 uint64 new_clk = (((uint64) b0_15) << 36) | b16_51;
1880 #if defined(THREADZ) || defined(LOCKLESS)
1881 lock_scu ();
1882 #endif
1883 scu [scu_unit_idx].user_correction =
1884 (int64) (new_clk - set_SCU_clock (cpup, scu_unit_idx));
1885 #if defined(THREADZ) || defined(LOCKLESS)
1886 unlock_scu ();
1887 #endif
1888
1889 }
1890 break;
1891
1892 case 00006:
1893 case 00007:
1894
1895
1896 sim_warn ("sscr set unit mode register\r\n");
1897
1898 return SCPE_OK;
1899
1900 default:
1901 sim_warn ("sscr unhandled code\r\n");
1902
1903 return SCPE_OK;
1904
1905 }
1906 return SCPE_OK;
1907 }
1908
1909 t_stat scu_rscr (cpu_state_t * cpup, uint scu_unit_idx, uint cpu_unit_udx, word18 addr,
1910 word36 * rega, word36 * regq)
1911 {
1912
1913
1914 if (scu_unit_idx >= scu_dev.numunits)
1915 {
1916 sim_warn ("%s: scu_unit_idx out of range %d\r\n",
1917 __func__, scu_unit_idx);
1918 return SCPE_OK;
1919 }
1920
1921
1922
1923
1924 uint function = (addr >> 3) & 07;
1925
1926
1927
1928
1929
1930 switch (function)
1931 {
1932 case 00000:
1933 {
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945 * rega = 0;
1946
1947 * regq = 0;
1948 #if defined(THREADZ) || defined(LOCKLESS)
1949 lock_scu ();
1950 #endif
1951 putbits36_4 (regq, 50 - 36, scu [scu_unit_idx].id);
1952 putbits36_18 (regq, 54 - 36, scu [scu_unit_idx].mode_reg);
1953 #if defined(THREADZ) || defined(LOCKLESS)
1954 unlock_scu ();
1955 #endif
1956 break;
1957 }
1958
1959 case 00001:
1960 {
1961
1962
1963
1964
1965
1966
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 sim_debug (DBG_DEBUG, & scu_dev, "rscr 1 %d\r\n", scu_unit_idx);
1992 #if defined(THREADZ) || defined(LOCKLESS)
1993 lock_scu ();
1994 #endif
1995 scu_t * up = scu + scu_unit_idx;
1996 word9 maskab [2];
1997 for (int i = 0; i < 2; i ++)
1998 {
1999 if (up -> mask_enable [i])
2000 {
2001 maskab [i] = (2 << (N_SCU_PORTS - 1 -
2002 up -> mask_assignment [i])) & 0777;
2003 }
2004 else
2005 maskab [i] = 0001;
2006 }
2007
2008 int scu_port_num = -1;
2009
2010
2011 for (int pn = 0; pn < N_SCU_PORTS; pn ++)
2012 {
2013 for (int sn = 0; sn < N_SCU_SUBPORTS; sn ++)
2014 {
2015 if (cables->scu_to_cpu[scu_unit_idx][pn][sn].in_use &&
2016 cables->scu_to_cpu[scu_unit_idx][pn][sn].cpu_unit_idx ==
2017 cpu_unit_udx)
2018 {
2019 scu_port_num = pn;
2020 goto gotit;
2021 }
2022 }
2023 }
2024 gotit:;
2025 if (scu_port_num < 0)
2026 {
2027 #if defined(THREADZ) || defined(LOCKLESS)
2028 unlock_scu ();
2029 #endif
2030 sim_warn ("%s: can't find cpu port in the snarl of cables; "
2031 "scu_unit_no %d, cpu_unit_udx %d\r\n",
2032 __func__, scu_unit_idx, cpu_unit_udx);
2033 return SCPE_OK;
2034 }
2035
2036
2037 word36 a, q;
2038
2039 a = 0;
2040
2041 putbits36_9 (& a, 0, maskab [0]);
2042 putbits36_3 (& a, 9, (word3) up -> lower_store_size);
2043 putbits36_4 (& a, 12, (word4) up -> onl);
2044 putbits36_4 (& a, 16, (word4) scu_port_num);
2045 putbits36_1 (& a, 21, (word1) config_switches[scu_unit_idx].mode);
2046 putbits36_8 (& a, 22, (word8) up -> nea);
2047 putbits36_1 (& a, 30, (word1) up -> interlace);
2048 putbits36_1 (& a, 31, (word1) up -> lwr);
2049
2050
2051
2052
2053
2054 putbits36_1 (& a, 32, (word1) up -> port_enable [0]);
2055 putbits36_1 (& a, 33, (word1) up -> port_enable [1]);
2056 putbits36_1 (& a, 34, (word1) up -> port_enable [2]);
2057 putbits36_1 (& a, 35, (word1) up -> port_enable [3]);
2058 * rega = a;
2059
2060 q = 0;
2061 putbits36_9 (& q, 0, maskab [1]);
2062
2063 putbits36_7 (& q, 57-36, (word7) up -> cyclic & MASK7);
2064
2065
2066 putbits36_1 (& q, 32, (word1) up -> port_enable [4]);
2067 putbits36_1 (& q, 33, (word1) up -> port_enable [5]);
2068 putbits36_1 (& q, 34, (word1) up -> port_enable [6]);
2069 putbits36_1 (& q, 35, (word1) up -> port_enable [7]);
2070 * regq = q;
2071
2072 #if defined(THREADZ) || defined(LOCKLESS)
2073 unlock_scu ();
2074 #endif
2075 sim_debug (DBG_DEBUG, & scu_dev,
2076 "rscr 1 %d A: %012"PRIo64" Q: %012"PRIo64"\r\n",
2077 scu_unit_idx, * rega, * regq);
2078 break;
2079 }
2080
2081 case 00002:
2082 {
2083 uint port_num = (addr >> 6) & MASK3;
2084 #if defined(THREADZ) || defined(LOCKLESS)
2085 lock_scu ();
2086 #endif
2087 scu_t * up = scu + scu_unit_idx;
2088 uint mask_contents = 0;
2089 if (up -> mask_assignment [0] == port_num)
2090 {
2091 mask_contents = up -> exec_intr_mask [0];
2092 }
2093 else if (up -> mask_assignment [1] == port_num)
2094 {
2095 mask_contents = up -> exec_intr_mask [1];
2096 }
2097 mask_contents &= MASK32;
2098
2099 * rega = 0;
2100 putbits36 (rega, 0, 16, (mask_contents >> 16) & MASK16);
2101 putbits36 (rega, 32, 1, up -> port_enable [0]);
2102 putbits36 (rega, 33, 1, up -> port_enable [1]);
2103 putbits36 (rega, 34, 1, up -> port_enable [2]);
2104 putbits36 (rega, 35, 1, up -> port_enable [3]);
2105
2106 * regq = 0;
2107 putbits36 (rega, 0, 16, (mask_contents >> 0) & MASK16);
2108 putbits36 (regq, 32, 1, up -> port_enable [4]);
2109 putbits36 (regq, 33, 1, up -> port_enable [5]);
2110 putbits36 (regq, 34, 1, up -> port_enable [6]);
2111 putbits36 (regq, 35, 1, up -> port_enable [7]);
2112
2113 #if defined(THREADZ) || defined(LOCKLESS)
2114 unlock_scu ();
2115 #endif
2116 sim_debug (DBG_TRACE, & scu_dev,
2117 "RSCR mask unit %u port %u assigns %u %u mask 0x%08x\r\n",
2118 scu_unit_idx, port_num, up -> mask_assignment [0],
2119 up -> mask_assignment [1],
2120 mask_contents);
2121 }
2122 break;
2123
2124 case 00003:
2125 {
2126 #if defined(THREADZ) || defined(LOCKLESS)
2127 lock_scu ();
2128 #endif
2129 scu_t * up = scu + scu_unit_idx;
2130
2131
2132 for (uint i = 0; i < N_CELL_INTERRUPTS; i ++)
2133 {
2134 word1 cell = up -> cells [i] ? 1 : 0;
2135 if (i < 16)
2136 putbits36_1 (rega, i, cell);
2137 else
2138 putbits36_1 (regq, i - 16, cell);
2139 }
2140 #if defined(THREADZ) || defined(LOCKLESS)
2141 unlock_scu ();
2142 #endif
2143 }
2144 break;
2145
2146 case 00004:
2147 case 00005:
2148 {
2149 uint64 clk = set_SCU_clock (cpup, scu_unit_idx);
2150 cpu.rQ = clk & 0777777777777;
2151 cpu.rA = (clk >> 36) & 0177777;
2152 #if defined(TESTING)
2153 HDBGRegAW ("rscr get clock");
2154 HDBGRegQW ("rscr get clock");
2155 #endif
2156 }
2157 break;
2158
2159 case 00006:
2160 case 00007:
2161 {
2162
2163
2164
2165
2166
2167
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 * rega = 0;
2210 * regq = 0;
2211 }
2212 break;
2213
2214 default:
2215 sim_warn ("rscr %o\r\n", function);
2216 return SCPE_OK;
2217 }
2218 return SCPE_OK;
2219 }
2220
2221
2222
2223
2224
2225 int scu_cioc (uint cpu_unit_udx, uint scu_unit_idx, uint scu_port_num,
2226 uint expander_command, uint sub_mask)
2227 {
2228
2229
2230
2231 #if defined(TESTING)
2232 cpu_state_t * cpup = _cpup;
2233 sim_debug (DBG_DEBUG, & scu_dev,
2234 "scu_cioc: Connect from %o sent to "
2235 "unit %o port %o exp %o mask %03o\r\n",
2236 cpu_unit_udx, scu_unit_idx, scu_port_num,
2237 expander_command, sub_mask);
2238 #endif
2239 #if defined(THREADZ) || defined(LOCKLESS)
2240 lock_scu ();
2241 #endif
2242 struct ports * portp = & scu [scu_unit_idx].ports [scu_port_num];
2243
2244 int rc = 0;
2245 if (! scu [scu_unit_idx].port_enable [scu_port_num])
2246 {
2247 sim_debug (DBG_ERR, & scu_dev,
2248 "scu_cioc: Connect sent to disabled port; dropping\r\n");
2249 sim_debug (DBG_ERR, & scu_dev,
2250 "scu_cioc: scu_unit_idx %u scu_port_num %u\r\n",
2251 scu_unit_idx, scu_port_num);
2252 rc = 1;
2253 goto done;
2254 }
2255
2256 if (expander_command == 1)
2257 {
2258 for (uint i = 0; i < N_SCU_SUBPORTS; i++)
2259 {
2260 portp->subport_enables [i] = !! (sub_mask & (0200u >> i));
2261 }
2262 goto done;
2263 }
2264
2265 if (expander_command == 2)
2266 {
2267 int cnt = 0;
2268 int val = -1;
2269 for (uint i = 0; i < N_SCU_SUBPORTS; i++)
2270 {
2271 portp->xipmask [i] = !! (sub_mask & (0200u >> i));
2272 if (portp->xipmask [i])
2273 {
2274 val = (int) i;
2275 cnt ++;
2276 }
2277 }
2278 if (cnt > 1)
2279 {
2280 sim_warn ("xip mask cnt > 1\r\n");
2281 val = -1;
2282 }
2283 portp->xipmaskval = val;
2284 goto done;
2285 }
2286
2287 if (portp -> type == ADEV_IOM)
2288 {
2289 int iom_unit_idx = portp->dev_idx;
2290 #if defined(THREADZ) || defined(LOCKLESS)
2291 unlock_scu ();
2292 # if !defined(IO_ASYNC_PAYLOAD_CHAN) && !defined(IO_ASYNC_PAYLOAD_CHAN_THREAD)
2293 lock_iom ();
2294 lock_libuv ();
2295 # endif
2296 iom_interrupt (scu_unit_idx, (uint) iom_unit_idx);
2297 # if !defined(IO_ASYNC_PAYLOAD_CHAN) && !defined(IO_ASYNC_PAYLOAD_CHAN_THREAD)
2298 unlock_libuv ();
2299 unlock_iom ();
2300 # endif
2301 return 0;
2302 #else
2303 if (sys_opts.iom_times.connect <= 0)
2304 {
2305 iom_interrupt (scu_unit_idx, (uint) iom_unit_idx);
2306 goto done;
2307 }
2308 else
2309 {
2310
2311
2312
2313 sim_debug (DBG_INFO, & scu_dev,
2314 "scu_cioc: Queuing an IOM in %d cycles "
2315 "(for the connect channel)\r\n",
2316 sys_opts.iom_times.connect);
2317
2318 iom_dev.units[iom_unit_idx].u3 = (int32) scu_unit_idx;
2319 iom_dev.units[iom_unit_idx].u4 = (int32) iom_unit_idx;
2320 int rc;
2321 if ((rc = sim_activate (& iom_dev.units [iom_unit_idx],
2322 sys_opts.iom_times.connect)) != SCPE_OK)
2323 {
2324 sim_warn ("sim_activate failed (%d)\r\n", rc);
2325 goto done;
2326 }
2327 goto done;
2328 }
2329 #endif
2330 }
2331 else if (portp -> type == ADEV_CPU)
2332 {
2333
2334
2335 if (portp->is_exp)
2336 {
2337 for (uint sn = 0; sn < N_SCU_SUBPORTS; sn ++)
2338 {
2339 if (portp->subport_enables[sn])
2340 {
2341 if (! cables->
2342 scu_to_cpu[scu_unit_idx][scu_port_num][sn].in_use)
2343 {
2344 sim_warn ("Can't find CPU to interrupt\r\n");
2345 continue;
2346 }
2347 uint cpu_unit_udx = cables->
2348 scu_to_cpu[scu_unit_idx][scu_port_num][sn].cpu_unit_idx;
2349 setG7fault ((uint) cpu_unit_udx, FAULT_CON);
2350 }
2351 }
2352 }
2353 else
2354 {
2355 if (! cables->scu_to_cpu[scu_unit_idx][scu_port_num][0].in_use)
2356 {
2357 sim_warn ("Can't find CPU to interrupt\r\n");
2358 rc = 1;
2359 goto done;
2360 }
2361 uint cpu_unit_udx =
2362 cables->scu_to_cpu[scu_unit_idx][scu_port_num][0].cpu_unit_idx;
2363 setG7fault ((uint) cpu_unit_udx, FAULT_CON);
2364 }
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387 goto done;
2388 }
2389 else
2390 {
2391 sim_debug (DBG_ERR, & scu_dev,
2392 "scu_cioc: Connect sent to not-an-IOM or CPU; dropping\r\n");
2393 rc = 1;
2394 goto done;
2395 }
2396 done:
2397 #if defined(THREADZ) || defined(LOCKLESS)
2398 unlock_scu ();
2399 #endif
2400 return rc;
2401 }
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413 int scu_set_interrupt (uint scu_unit_idx, uint inum)
2414 {
2415 #if defined(TESTING)
2416 cpu_state_t * cpup = _cpup;
2417 #endif
2418 const char* moi = "SCU::interrupt";
2419
2420 if (inum >= N_CELL_INTERRUPTS)
2421 {
2422 sim_debug (DBG_WARN, & scu_dev,
2423 "%s: Bad interrupt number %d\r\n", moi, inum);
2424 return 1;
2425 }
2426
2427 #if defined(THREADZ) || defined(LOCKLESS)
2428 lock_scu ();
2429 #endif
2430 scu [scu_unit_idx].cells [inum] = 1;
2431 dump_intr_regs ("scu_set_interrupt", scu_unit_idx);
2432 deliver_interrupts (NULL, scu_unit_idx);
2433 #if defined(THREADZ) || defined(LOCKLESS)
2434 unlock_scu ();
2435 #endif
2436 return 0;
2437 }
2438
2439
2440
2441
2442
2443
2444
2445 uint scu_get_highest_intr (uint scu_unit_idx)
2446 {
2447 #if defined(TESTING)
2448 cpu_state_t * cpup = _cpup;
2449 #endif
2450 #if defined(THREADZ) || defined(LOCKLESS)
2451 lock_scu ();
2452 #endif
2453
2454 for (int inum = 0; inum < N_CELL_INTERRUPTS; inum ++)
2455 {
2456 for (uint pima = 0; pima < N_ASSIGNMENTS; pima ++)
2457 {
2458 if (scu [scu_unit_idx].mask_enable [pima] == 0)
2459 continue;
2460 uint mask = scu [scu_unit_idx].exec_intr_mask [pima];
2461 uint port = scu [scu_unit_idx].mask_assignment [pima];
2462
2463
2464 if (scu[scu_unit_idx].ports[port].type != ADEV_CPU ||
2465 cpus[current_running_cpu_idx].scu_port[scu_unit_idx] != port)
2466 continue;
2467 if (scu [scu_unit_idx].cells [inum] &&
2468 (mask & (1u << (31 - inum))) != 0)
2469 {
2470 sim_debug (DBG_TRACE, & scu_dev,
2471 "scu_get_highest_intr inum %d pima %u mask 0%011o port %u cells 0%011o\r\n",
2472 inum, pima, mask, port, scu [scu_unit_idx].cells [inum]);
2473 scu [scu_unit_idx].cells [inum] = false;
2474 dump_intr_regs ("scu_get_highest_intr", scu_unit_idx);
2475 deliver_interrupts (NULL, scu_unit_idx);
2476 #if defined(THREADZ) || defined(LOCKLESS)
2477 unlock_scu ();
2478 #endif
2479 return (uint) inum * 2;
2480 }
2481 }
2482 }
2483 #if defined(THREADZ) || defined(LOCKLESS)
2484 unlock_scu ();
2485 #endif
2486 return 1;
2487 }
2488
2489 t_stat scu_reset_unit (UNIT * uptr, UNUSED int32 value,
2490 UNUSED const char * cptr,
2491 UNUSED void * desc)
2492 {
2493 uint scu_unit_idx = (uint) (uptr - scu_unit);
2494 scu_unit_reset ((int) scu_unit_idx);
2495 return SCPE_OK;
2496 }
2497
2498 void scu_init (void)
2499 {
2500
2501
2502 for (int u = 0; u < N_SCU_UNITS_MAX; u ++)
2503 {
2504 for (int p = 0; p < N_SCU_PORTS; p ++)
2505 {
2506 for (int s = 0; s < N_SCU_SUBPORTS; s ++)
2507 {
2508 scu[u].ports[p].dev_port[s] = -1;
2509 scu[u].ports[p].subport_enables[s] = false;
2510 scu[u].ports[p].xipmask[s] = false;
2511
2512 scu[u].ports[p].xipmaskval = N_SCU_SUBPORTS;
2513 }
2514 scu[u].ports[p].type = ADEV_NONE;
2515 scu[u].ports[p].is_exp = false;
2516 }
2517
2518
2519
2520
2521 scu [u].id = 02l;
2522 scu [u].mode_reg = 0;
2523 scu [u].elapsed_days = 0;
2524 }
2525
2526 }
2527
2528 t_stat scu_rmcm (uint scu_unit_idx, uint cpu_unit_udx, word36 * rega,
2529 word36 * regq)
2530 {
2531 #if defined(TESTING)
2532 cpu_state_t * cpup = _cpup;
2533 #endif
2534 scu_t * up = scu + scu_unit_idx;
2535
2536
2537 * rega = 0;
2538 * regq = 0;
2539
2540
2541
2542 int scu_port_num = -1;
2543
2544
2545 for (int pn = 0; pn < N_SCU_PORTS; pn ++)
2546 {
2547 for (int sn = 0; sn < N_SCU_SUBPORTS; sn ++)
2548 {
2549 if (cables->scu_to_cpu[scu_unit_idx][pn][sn].in_use &&
2550 cables->scu_to_cpu[scu_unit_idx][pn][sn].cpu_unit_idx ==
2551 cpu_unit_udx)
2552 {
2553 scu_port_num = pn;
2554 goto gotit;
2555 }
2556 }
2557 }
2558
2559 gotit:;
2560
2561
2562
2563 if (scu_port_num < 0)
2564 {
2565 sim_warn ("%s: can't find cpu port in the snarl of cables; "
2566 "scu_unit_no %d, cpu_unit_udx %d\r\n",
2567 __func__, scu_unit_idx, cpu_unit_udx);
2568 sim_debug (DBG_ERR, & scu_dev,
2569 "%s: can't find cpu port in the snarl of cables; "
2570 "scu_unit_no %d, cpu_unit_udx %d\r\n",
2571 __func__, scu_unit_idx, cpu_unit_udx);
2572
2573 return SCPE_OK;
2574 }
2575
2576
2577
2578
2579
2580
2581
2582
2583 sim_debug (DBG_TRACE, & scu_dev, "rmcm selected scu port %u\r\n",
2584 scu_port_num);
2585 #if defined(THREADZ) || defined(LOCKLESS)
2586 lock_scu ();
2587 #endif
2588 uint mask_contents = 0;
2589 if (up -> mask_assignment [0] == (uint) scu_port_num)
2590 {
2591 mask_contents = up -> exec_intr_mask [0];
2592 sim_debug (DBG_TRACE, & scu_dev, "rmcm got mask %011o from pima A\r\n",
2593 mask_contents);
2594 }
2595 else if (up -> mask_assignment [1] == (uint) scu_port_num)
2596 {
2597 mask_contents = up -> exec_intr_mask [1];
2598 sim_debug (DBG_TRACE, & scu_dev, "rmcm got mask %011o from pima B\r\n",
2599 mask_contents);
2600 }
2601 mask_contents &= MASK32;
2602
2603 * rega = 0;
2604 putbits36_16 (rega, 0, (mask_contents >> 16) & MASK16);
2605 putbits36_1 (rega, 32, (word1) up -> port_enable [0]);
2606 putbits36_1 (rega, 33, (word1) up -> port_enable [1]);
2607 putbits36_1 (rega, 34, (word1) up -> port_enable [2]);
2608 putbits36_1 (rega, 35, (word1) up -> port_enable [3]);
2609
2610 * regq = 0;
2611 putbits36_16 (regq, 0, (mask_contents >> 0) & MASK16);
2612 putbits36_1 (regq, 32, (word1) up -> port_enable [4]);
2613 putbits36_1 (regq, 33, (word1) up -> port_enable [5]);
2614 putbits36_1 (regq, 34, (word1) up -> port_enable [6]);
2615 putbits36_1 (regq, 35, (word1) up -> port_enable [7]);
2616
2617 #if defined(THREADZ) || defined(LOCKLESS)
2618 unlock_scu ();
2619 #endif
2620 sim_debug (DBG_TRACE, & scu_dev,
2621 "RMCM returns %012"PRIo64" %012"PRIo64"\r\n",
2622 * rega, * regq);
2623 dump_intr_regs ("rmcm", scu_unit_idx);
2624 return SCPE_OK;
2625 }
2626
2627 t_stat scu_smcm (uint scu_unit_idx, uint cpu_unit_udx, word36 rega, word36 regq)
2628 {
2629 #if defined(TESTING)
2630 cpu_state_t * cpup = _cpup;
2631 #endif
2632 sim_debug (DBG_TRACE, & scu_dev,
2633 "SMCM SCU unit %d CPU unit %d A %012"PRIo64" Q %012"PRIo64"\r\n",
2634 scu_unit_idx, cpu_unit_udx, rega, regq);
2635
2636 scu_t * up = scu + scu_unit_idx;
2637
2638
2639
2640 int scu_port_num = -1;
2641
2642
2643 for (int pn = 0; pn < N_SCU_PORTS; pn ++)
2644 {
2645 for (int sn = 0; sn < N_SCU_SUBPORTS; sn ++)
2646 {
2647 if (cables->scu_to_cpu[scu_unit_idx][pn][sn].in_use &&
2648 cables->scu_to_cpu[scu_unit_idx][pn][sn].cpu_unit_idx ==
2649 cpu_unit_udx)
2650 {
2651 scu_port_num = pn;
2652 goto gotit;
2653 }
2654 }
2655 }
2656 gotit:;
2657
2658
2659
2660 if (scu_port_num < 0)
2661 {
2662 sim_warn ("%s: can't find cpu port in the snarl of cables; "
2663 "scu_unit_no %d, cpu_unit_udx %d\r\n",
2664 __func__, scu_unit_idx, cpu_unit_udx);
2665 return SCPE_OK;
2666 }
2667
2668 sim_debug (DBG_TRACE, & scu_dev, "SMCM SCU port num %d\r\n", scu_port_num);
2669
2670
2671
2672
2673
2674
2675
2676
2677 uint imask =
2678 ((uint) getbits36_16(rega, 0) << 16) |
2679 ((uint) getbits36_16(regq, 0) << 0);
2680 #if defined(THREADZ) || defined(LOCKLESS)
2681 lock_scu ();
2682 #endif
2683 if (up -> mask_assignment [0] == (uint) scu_port_num)
2684 {
2685 up -> exec_intr_mask [0] = imask;
2686 sim_debug (DBG_TRACE, & scu_dev, "SMCM intr mask 0 set to %011o\r\n",
2687 imask);
2688 }
2689 else if (up -> mask_assignment [1] == (uint) scu_port_num)
2690 {
2691 up -> exec_intr_mask [1] = imask;
2692 sim_debug (DBG_TRACE, & scu_dev, "SMCM intr mask 1 set to %011o\r\n",
2693 imask);
2694 }
2695
2696 scu [scu_unit_idx].port_enable [0] = (uint) getbits36_1 (rega, 32);
2697 scu [scu_unit_idx].port_enable [1] = (uint) getbits36_1 (rega, 33);
2698 scu [scu_unit_idx].port_enable [2] = (uint) getbits36_1 (rega, 34);
2699 scu [scu_unit_idx].port_enable [3] = (uint) getbits36_1 (rega, 35);
2700 scu [scu_unit_idx].port_enable [4] = (uint) getbits36_1 (regq, 32);
2701 scu [scu_unit_idx].port_enable [5] = (uint) getbits36_1 (regq, 33);
2702 scu [scu_unit_idx].port_enable [6] = (uint) getbits36_1 (regq, 34);
2703 scu [scu_unit_idx].port_enable [7] = (uint) getbits36_1 (regq, 35);
2704
2705 dump_intr_regs ("smcm", scu_unit_idx);
2706 deliver_interrupts (NULL, scu_unit_idx);
2707 #if defined(THREADZ) || defined(LOCKLESS)
2708 unlock_scu ();
2709 #endif
2710
2711 return SCPE_OK;
2712 }