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