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
1009 { (char *) "ALL", DBG_ALL, NULL },
1010 { NULL, 0, NULL }
1011 };
1012
1013 DEVICE scu_dev =
1014 {
1015 (char *) "SCU",
1016 scu_unit,
1017 NULL,
1018 scu_mod,
1019 N_SCU_UNITS,
1020 10,
1021 8,
1022 1,
1023 8,
1024 8,
1025 NULL,
1026 NULL,
1027 & scu_reset,
1028 NULL,
1029 NULL,
1030 NULL,
1031 NULL,
1032 DEV_DEBUG,
1033 0,
1034 scu_dt,
1035 NULL,
1036 NULL,
1037 NULL,
1038 NULL,
1039 NULL,
1040 NULL,
1041 NULL
1042 };
1043
1044 static void dump_intr_regs (char * ctx, uint scu_unit_idx)
1045 {
1046 scu_t * up = scu + scu_unit_idx;
1047
1048 sim_debug (DBG_DEBUG, & scu_dev,
1049 "%s A: mask %011o enable %o assignment %o\n",
1050 ctx, up -> exec_intr_mask [0], up -> mask_enable [0],
1051 up -> mask_assignment [0]);
1052 sim_debug (DBG_DEBUG, & scu_dev,
1053 "%s B: mask %011o enable %o assignment %o\n",
1054 ctx, up -> exec_intr_mask [1], up -> mask_enable [1],
1055 up -> mask_assignment [1]);
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
1105 void scu_unit_reset (int scu_unit_idx)
1106 {
1107 scu_t * up = scu + scu_unit_idx;
1108 struct config_switches * sw = config_switches + scu_unit_idx;
1109
1110 for (int i = 0; i < N_SCU_PORTS; i ++)
1111 {
1112 up -> port_enable [i] = sw -> port_enable [i];
1113 }
1114
1115 for (int i = 0; i < N_ASSIGNMENTS; i ++)
1116 {
1117 up -> mask_enable [i] = sw -> mask_enable [i];
1118 up -> mask_assignment [i] = sw -> mask_assignment [i];
1119 }
1120 up -> lower_store_size = sw -> lower_store_size;
1121 up -> cyclic = sw -> cyclic;
1122 up -> nea = sw -> nea;
1123 up -> onl = sw -> onl;
1124 up -> interlace = sw -> interlace;
1125 up -> lwr = sw -> lwr;
1126
1127
1128
1129
1130 for (uint port_num = 0; port_num < N_SCU_PORTS; port_num ++)
1131 {
1132 struct ports * portp = & scu [scu_unit_idx].ports [port_num];
1133 if (portp->type != ADEV_IOM)
1134 continue;
1135
1136
1137 iom_unit_reset_idx ((uint) portp->dev_idx);
1138 }
1139
1140
1141
1142
1143
1144 for (int i = 0; i < N_ASSIGNMENTS; i ++)
1145 {
1146
1147 up -> exec_intr_mask [i] = 037777777777;
1148 }
1149 }
1150
1151 t_stat scu_reset (UNUSED DEVICE * dptr)
1152 {
1153
1154
1155 for (int scu_unit_idx = 0; scu_unit_idx < N_SCU_UNITS_MAX; scu_unit_idx ++)
1156 scu_unit_reset (scu_unit_idx);
1157 return SCPE_OK;
1158 }
1159
1160
1161
1162 #if defined(THREADZ) || defined(LOCKLESS)
1163 static pthread_mutex_t clock_lock = PTHREAD_MUTEX_INITIALIZER;
1164 #endif
1165
1166
1167 static uint64 set_SCU_clock (uint scu_unit_idx)
1168 {
1169 #if defined(THREADZ) || defined(LOCKLESS)
1170 pthread_mutex_lock (& clock_lock);
1171 #endif
1172
1173
1174
1175
1176
1177
1178 if (scu [0].steady_clock)
1179 {
1180
1181
1182 #ifdef NEED_128
1183 uint128 big = construct_128 (0, cpu.instrCnt);
1184
1185
1186 big = lshift_128 (big, 2);
1187 if (scu [0].bullet_time)
1188 big = multiply_128 (big, construct_128 (0, 10000u));
1189
1190
1191 uint128 days = construct_128 (0, scu[0].elapsed_days);
1192 days = multiply_128 (days, construct_128 (0, 1000000));
1193 days = multiply_128 (days, construct_128 (0, 60 * 60 * 24));
1194 big = add_128 (big, days);
1195 #else
1196 __uint128_t big = cpu.instrCnt;
1197
1198 big *= 4u;
1199
1200 if (scu [0].bullet_time)
1201 big *= 10000;
1202
1203 big += scu [0].elapsed_days * 1000000llu * 60llu * 60llu * 24llu;
1204 #endif
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214 uint64 UNIX_secs = 631184400;
1215
1216 #ifdef NEED_128
1217 uint64 UNIX_usecs = UNIX_secs * 1000000llu + big.l;
1218 #else
1219 uint64 UNIX_usecs = UNIX_secs * 1000000llu + (uint64) big;
1220 #endif
1221
1222 uint64 Multics_usecs = 2177452800000000llu + UNIX_usecs;
1223
1224
1225
1226 Multics_usecs += (uint64) scu [scu_unit_idx].user_correction;
1227
1228
1229
1230
1231 if (scu [scu_unit_idx].last_time >= Multics_usecs)
1232 {
1233 sim_debug (DBG_TRACE, & scu_dev, "finagle clock\n");
1234 Multics_usecs = scu [scu_unit_idx].last_time + 1;
1235 }
1236 scu [scu_unit_idx].last_time = Multics_usecs;
1237 goto done;
1238 }
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253 struct timeval now;
1254 gettimeofday(& now, NULL);
1255
1256 if (scu [0].y2k)
1257 {
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297 now.tv_sec -= (1491074334 - 733691934);
1298
1299
1300
1301 }
1302 uint64 UNIX_secs = (uint64) now.tv_sec;
1303 uint64 UNIX_usecs = UNIX_secs * 1000000LL + (uint64) now.tv_usec;
1304
1305 static uint64 last_UNIX_usecs = 0;
1306 if ( (!sim_quiet) && (UNIX_usecs < last_UNIX_usecs))
1307 {
1308 if (gtod_warned < 11)
1309 {
1310 sim_warn ("\rHost clock went backwards %llu uS!\r\n",
1311 (unsigned long long)(last_UNIX_usecs - UNIX_usecs));
1312 gtod_warned++;
1313 }
1314 else if (gtod_warned == 11)
1315 {
1316 sim_warn ("\rHost clock went backwards %llu uS! Suppressing further warnings.\r\n",
1317 (unsigned long long)(last_UNIX_usecs - UNIX_usecs));
1318 gtod_warned++;
1319 }
1320 }
1321 last_UNIX_usecs = UNIX_usecs;
1322
1323
1324 uint64 Multics_usecs = 2177452800000000LL + UNIX_usecs;
1325
1326
1327
1328
1329
1330 Multics_usecs += (uint64) scu [scu_unit_idx].user_correction;
1331
1332 if (scu [scu_unit_idx].last_time >= Multics_usecs)
1333 Multics_usecs = scu [scu_unit_idx].last_time + 1;
1334 scu [scu_unit_idx].last_time = Multics_usecs;
1335
1336 done:
1337 #if defined(THREADZ) || defined(LOCKLESS)
1338 pthread_mutex_unlock (& clock_lock);
1339 #endif
1340
1341 return scu [scu_unit_idx].last_time;
1342
1343 }
1344
1345
1346 static char * pcells (uint scu_unit_idx, char * buf)
1347 {
1348 for (uint i = 0; i < N_CELL_INTERRUPTS; i ++)
1349 {
1350 if (scu [scu_unit_idx].cells [i])
1351 buf [i] = '1';
1352 else
1353 buf [i] = '0';
1354 }
1355 buf [N_CELL_INTERRUPTS] = '\0';
1356 return buf;
1357 }
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373 static void deliver_interrupts (uint scu_unit_idx)
1374 {
1375 sim_debug (DBG_DEBUG, & scu_dev, "deliver_interrupts %o\n", scu_unit_idx);
1376 for (uint cpun = 0; cpun < cpu_dev.numunits; cpun ++)
1377 {
1378 cpus[cpun].events.XIP[scu_unit_idx] = false;
1379 }
1380
1381
1382
1383
1384
1385 #ifdef REORDER
1386 for (uint jnum = 0; jnum < N_CELL_INTERRUPTS; jnum ++)
1387 {
1388 static const uint reorder[N_CELL_INTERRUPTS] = {
1389 0, 1, 2, 3, 4, 5, 6, 7,
1390 16, 17, 18, 29, 20, 21, 22, 23,
1391 8, 9, 10, 11, 12, 13, 14, 15,
1392 25, 25, 26, 27, 28, 29, 30, 31 };
1393 uint inum = reorder[jnum];
1394 if (! scu [scu_unit_idx].cells [inum])
1395 continue;
1396 sim_debug (DBG_DEBUG, & scu_dev, "trying to deliver %d\n", inum);
1397 sim_debug (DBG_INTR, & scu_dev,
1398 "scu %u trying to deliver %d\n", scu_unit_idx, inum);
1399
1400 for (uint pima = 0; pima < N_ASSIGNMENTS; pima ++)
1401 {
1402
1403
1404
1405 if (scu [scu_unit_idx].mask_enable [pima] == 0)
1406 continue;
1407 uint mask = scu [scu_unit_idx].exec_intr_mask [pima];
1408 uint port = scu [scu_unit_idx].mask_assignment [pima];
1409
1410
1411
1412
1413 if (scu [scu_unit_idx].ports [port].type != ADEV_CPU)
1414 continue;
1415 if ((mask & (1u << (31 - inum))) != 0)
1416 {
1417 uint sn = 0;
1418 if (scu[scu_unit_idx].ports[port].is_exp)
1419 {
1420 sn = (uint) scu[scu_unit_idx].ports[port].xipmaskval;
1421 if (sn >= N_SCU_SUBPORTS)
1422 {
1423 sim_warn ("XIP mask not set; defaulting to subport 0\n");
1424 sn = 0;
1425 }
1426 }
1427 if (! cables->scu_to_cpu[scu_unit_idx][port][sn].in_use)
1428 {
1429 sim_warn ("bad scu_unit_idx %u\n", scu_unit_idx);
1430 continue;
1431 }
1432 uint cpu_unit_udx = cables->scu_to_cpu[scu_unit_idx][port][sn].cpu_unit_idx;
1433 # if defined(THREADZ) || defined(LOCKLESS)
1434 cpus[cpu_unit_udx].events.XIP[scu_unit_idx] = true;
1435 # ifdef TESTING
1436 HDBGIntrSet (inum, cpu_unit_udx, scu_unit_idx, __func__);
1437 # endif
1438 createCPUThread((uint) cpu_unit_udx);
1439 # ifndef NO_TIMEWAIT
1440 wakeCPU ((uint) cpu_unit_udx);
1441 # endif
1442 sim_debug (DBG_DEBUG, & scu_dev,
1443 "interrupt set for CPU %d SCU %d\n",
1444 cpu_unit_udx, scu_unit_idx);
1445 # else
1446
1447 # ifdef ROUND_ROBIN
1448 cpus[cpu_unit_udx].isRunning = true;
1449 # endif
1450 cpus[cpu_unit_udx].events.XIP[scu_unit_idx] = true;
1451 sim_debug (DBG_DEBUG, & scu_dev, "interrupt set for CPU %d SCU %d\n", cpu_unit_udx, scu_unit_idx);
1452 sim_debug (DBG_INTR, & scu_dev,
1453 "XIP set for SCU %d\n", scu_unit_idx);
1454 # endif
1455 }
1456 }
1457 }
1458 #else
1459 for (uint inum = 0; inum < N_CELL_INTERRUPTS; inum ++)
1460 {
1461 if (! scu [scu_unit_idx].cells [inum])
1462 continue;
1463 sim_debug (DBG_DEBUG, & scu_dev, "trying to deliver %d\n", inum);
1464 sim_debug (DBG_INTR, & scu_dev,
1465 "scu %u trying to deliver %d\n", scu_unit_idx, inum);
1466
1467 for (uint pima = 0; pima < N_ASSIGNMENTS; pima ++)
1468 {
1469
1470
1471
1472 if (scu [scu_unit_idx].mask_enable [pima] == 0)
1473 continue;
1474 uint mask = scu [scu_unit_idx].exec_intr_mask [pima];
1475 uint port = scu [scu_unit_idx].mask_assignment [pima];
1476
1477
1478
1479
1480 if (scu [scu_unit_idx].ports [port].type != ADEV_CPU)
1481 continue;
1482 if ((mask & (1u << (31 - inum))) != 0)
1483 {
1484 uint sn = 0;
1485 if (scu[scu_unit_idx].ports[port].is_exp)
1486 {
1487 sn = (uint) scu[scu_unit_idx].ports[port].xipmaskval;
1488 if (sn >= N_SCU_SUBPORTS)
1489 {
1490 sim_warn ("XIP mask not set; defaulting to subport 0\n");
1491 sn = 0;
1492 }
1493 }
1494 if (! cables->scu_to_cpu[scu_unit_idx][port][sn].in_use)
1495 {
1496 sim_warn ("bad scu_unit_idx %u\n", scu_unit_idx);
1497 continue;
1498 }
1499 uint cpu_unit_udx = cables->scu_to_cpu[scu_unit_idx][port][sn].cpu_unit_idx;
1500 # if defined(THREADZ) || defined(LOCKLESS)
1501 cpus[cpu_unit_udx].events.XIP[scu_unit_idx] = true;
1502 # ifdef TESTING
1503 HDBGIntrSet (inum, cpu_unit_udx, scu_unit_idx, __func__);
1504 # endif
1505 createCPUThread((uint) cpu_unit_udx);
1506 # ifndef NO_TIMEWAIT
1507 wakeCPU ((uint) cpu_unit_udx);
1508 # endif
1509 sim_debug (DBG_DEBUG, & scu_dev,
1510 "interrupt set for CPU %d SCU %d\n",
1511 cpu_unit_udx, scu_unit_idx);
1512 # else
1513
1514 # ifdef ROUND_ROBIN
1515 cpus[cpu_unit_udx].isRunning = true;
1516 # endif
1517 cpus[cpu_unit_udx].events.XIP[scu_unit_idx] = true;
1518 sim_debug (DBG_DEBUG, & scu_dev, "interrupt set for CPU %d SCU %d\n", cpu_unit_udx, scu_unit_idx);
1519 sim_debug (DBG_INTR, & scu_dev,
1520 "XIP set for SCU %d\n", scu_unit_idx);
1521 # endif
1522 }
1523 }
1524 }
1525 #endif
1526 }
1527
1528 t_stat scu_smic (uint scu_unit_idx, uint UNUSED cpu_unit_udx,
1529 uint UNUSED cpu_port_num, word36 rega)
1530 {
1531 #if defined(THREADZ) || defined(LOCKLESS)
1532 lock_scu ();
1533 #endif
1534
1535
1536 if (getbits36_1 (rega, 35))
1537 {
1538 for (uint i = 0; i < 16; i ++)
1539 {
1540 if (getbits36_1 (rega, i))
1541 scu [scu_unit_idx].cells [i + 16] = 1;
1542 }
1543 char pcellb [N_CELL_INTERRUPTS + 1];
1544 sim_debug (DBG_TRACE, & scu_dev,
1545 "SMIC low: Unit %u Cells: %s\n",
1546 scu_unit_idx, pcells (scu_unit_idx, pcellb));
1547 }
1548 else
1549 {
1550 for (uint i = 0; i < 16; i ++)
1551 {
1552 if (getbits36_1 (rega, i))
1553 scu [scu_unit_idx].cells [i] = 1;
1554 }
1555 char pcellb [N_CELL_INTERRUPTS + 1];
1556 sim_debug (DBG_TRACE, & scu_dev,
1557 "SMIC high: Unit %d Cells: %s\n",
1558 scu_unit_idx, pcells (scu_unit_idx, pcellb));
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 dump_intr_regs ("smic", scu_unit_idx);
1586 deliver_interrupts (scu_unit_idx);
1587 #if defined(THREADZ) || defined(LOCKLESS)
1588 unlock_scu ();
1589 #endif
1590 return SCPE_OK;
1591 }
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622 t_stat scu_sscr (uint scu_unit_idx, UNUSED uint cpu_unit_udx,
1623 UNUSED uint cpu_port_num, word18 addr,
1624 word36 rega, word36 regq)
1625 {
1626 sim_debug (DBG_DEBUG, & scu_dev, "sscr SCU unit %o\n", scu_unit_idx);
1627
1628
1629
1630 if (scu_unit_idx >= scu_dev.numunits)
1631 {
1632
1633 sim_warn ("%s: scu_unit_idx out of range %d\n",
1634 __func__, scu_unit_idx);
1635 return SCPE_OK;
1636 }
1637
1638
1639
1640
1641 uint function = (addr >> 3) & 07;
1642
1643
1644
1645 if (config_switches [scu_unit_idx].mode != MODE_PROGRAM)
1646 {
1647 sim_warn ("%s: SCU mode is 'MANUAL', not 'PROGRAM' -- sscr "
1648 "not allowed to set switches.\n",
1649 __func__);
1650
1651
1652 return SCPE_OK;
1653 }
1654
1655
1656
1657 switch (function)
1658 {
1659 case 00000:
1660 {
1661 #if defined(THREADZ) || defined(LOCKLESS)
1662 lock_scu ();
1663 #endif
1664 scu [scu_unit_idx].id = (word4) getbits36_4 (regq, 50 - 36);
1665 scu [scu_unit_idx].mode_reg = getbits36_18 (regq, 54 - 36);
1666 #if defined(THREADZ) || defined(LOCKLESS)
1667 unlock_scu ();
1668 #endif
1669 }
1670 break;
1671
1672 case 00001:
1673
1674 {
1675 sim_debug (DBG_DEBUG, & scu_dev,
1676 "sscr 1 %d A: %012"PRIo64" Q: %012"PRIo64"\n",
1677 scu_unit_idx, rega, regq);
1678 #if defined(THREADZ) || defined(LOCKLESS)
1679 lock_scu ();
1680 #endif
1681 scu_t * up = scu + scu_unit_idx;
1682 for (int maskab = 0; maskab < 2; maskab ++)
1683 {
1684 word9 mask = ((maskab ? regq : rega) >> 27) & 0777;
1685 if (mask & 01)
1686 {
1687 up -> mask_enable [maskab] = 0;
1688 sim_debug (DBG_DEBUG, & scu_dev,
1689 "sscr %u mask disable %d\n",
1690 scu_unit_idx, maskab);
1691 }
1692 else
1693 {
1694 up -> mask_enable [maskab] = 1;
1695 sim_debug (DBG_DEBUG, & scu_dev,
1696 "sscr %u mask enable %d\n",
1697 scu_unit_idx, maskab);
1698 for (int pn = 0; pn < N_SCU_PORTS; pn ++)
1699 {
1700 if ((2 << (N_SCU_PORTS - 1 - pn)) & mask)
1701 {
1702 up -> mask_assignment [maskab] = (uint) pn;
1703 break;
1704 }
1705 }
1706
1707 }
1708 sim_debug (DBG_INTR, & scu_dev,
1709 "SCU%u SSCR1 mask %c enable set to %u assigned to "
1710 "port %u\n",
1711 scu_unit_idx, 'a' + maskab, up->mask_enable[maskab],
1712 up->mask_assignment[maskab]);
1713 }
1714
1715
1716
1717
1718
1719 up -> lower_store_size = (rega >> 24) & 07;
1720 up -> cyclic = (regq >> 8) & 0177;
1721 up -> nea = (rega >> 6) & 0377;
1722 up -> onl = (rega >> 20) & 017;
1723 up -> interlace = (rega >> 5) & 1;
1724 up -> lwr = (rega >> 4) & 1;
1725 up -> port_enable [0] = (rega >> 3) & 01;
1726 up -> port_enable [1] = (rega >> 2) & 01;
1727 up -> port_enable [2] = (rega >> 1) & 01;
1728 up -> port_enable [3] = (rega >> 0) & 01;
1729 up -> port_enable [4] = (regq >> 3) & 01;
1730 up -> port_enable [5] = (regq >> 2) & 01;
1731 up -> port_enable [6] = (regq >> 1) & 01;
1732 up -> port_enable [7] = (regq >> 0) & 01;
1733
1734 #if defined(THREADZ) || defined(LOCKLESS)
1735 unlock_scu ();
1736 #endif
1737
1738
1739 break;
1740 }
1741
1742 case 00002:
1743
1744
1745
1746
1747
1748
1749
1750 {
1751 #if defined(THREADZ) || defined(LOCKLESS)
1752 lock_scu ();
1753 #endif
1754 uint port_num = (addr >> 6) & 07;
1755 sim_debug (DBG_DEBUG, & scu_dev, "Set mask register port %d to "
1756 "%012"PRIo64",%012"PRIo64"\n",
1757 port_num, rega, regq);
1758
1759
1760 int mask_num = -1;
1761 uint n_masks_found = 0;
1762 for (int p = 0; p < N_ASSIGNMENTS; p ++)
1763 {
1764
1765 if (scu [scu_unit_idx].mask_enable [p] == 0)
1766 continue;
1767
1768 if (scu [scu_unit_idx ].mask_assignment [p] == port_num)
1769 {
1770 if (n_masks_found == 0)
1771 mask_num = p;
1772 n_masks_found ++;
1773 }
1774 }
1775
1776 if (! n_masks_found)
1777 {
1778
1779 sim_debug (DBG_WARN, & scu_dev,
1780 "%s: No masks assigned to cpu on port %d\n",
1781 __func__, port_num);
1782 #if defined(THREADZ) || defined(LOCKLESS)
1783 unlock_scu ();
1784 #endif
1785 return SCPE_OK;
1786 }
1787
1788 if (n_masks_found > 1)
1789 {
1790
1791 sim_debug (DBG_WARN, & scu_dev,
1792 "%s: Multiple masks assigned to cpu on port %d\n",
1793 __func__, port_num);
1794 }
1795
1796
1797
1798 scu [scu_unit_idx].exec_intr_mask [mask_num] = 0;
1799 scu [scu_unit_idx].exec_intr_mask [mask_num] |=
1800 ((word32) getbits36_16(rega, 0) << 16);
1801 scu [scu_unit_idx].exec_intr_mask [mask_num] |=
1802 getbits36_16(regq, 0);
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812 sim_debug (DBG_TRACE, & scu_dev,
1813 "SSCR Set mask unit %u port %u mask_num %u "
1814 "mask 0x%08x\n",
1815 scu_unit_idx, port_num, mask_num,
1816 scu [scu_unit_idx].exec_intr_mask [mask_num]);
1817 dump_intr_regs ("sscr set mask", scu_unit_idx);
1818 scu [scu_unit_idx].mask_enable [mask_num] = 1;
1819 sim_debug (DBG_INTR, & scu_dev,
1820 "SCU%u SSCR2 exec_intr mask %c set to 0x%08x"
1821 " and enabled.\n",
1822 scu_unit_idx, 'a' + mask_num,
1823 scu[scu_unit_idx].exec_intr_mask[mask_num]);
1824
1825 deliver_interrupts (scu_unit_idx);
1826 #if defined(THREADZ) || defined(LOCKLESS)
1827 unlock_scu ();
1828 #endif
1829 }
1830 break;
1831
1832 case 00003:
1833 {
1834 #if defined(THREADZ) || defined(LOCKLESS)
1835 lock_scu ();
1836 #endif
1837 for (uint i = 0; i < 16; i ++)
1838 {
1839 scu [scu_unit_idx].cells [i] =
1840 getbits36_1 (rega, i) ? 1 : 0;
1841 scu [scu_unit_idx].cells [i + 16] =
1842 getbits36_1 (regq, i) ? 1 : 0;
1843 }
1844 char pcellb [N_CELL_INTERRUPTS + 1];
1845 sim_debug (DBG_TRACE, & scu_dev,
1846 "SSCR Set int. cells: Unit %u Cells: %s\n",
1847 scu_unit_idx, pcells (scu_unit_idx, pcellb));
1848 sim_debug (DBG_INTR, & scu_dev,
1849 "SCU%u SSCR3 Set int. cells %s\n",
1850 scu_unit_idx, pcells (scu_unit_idx, pcellb));
1851 dump_intr_regs ("sscr set interrupt cells", scu_unit_idx);
1852 deliver_interrupts (scu_unit_idx);
1853 #if defined(THREADZ) || defined(LOCKLESS)
1854 unlock_scu ();
1855 #endif
1856 }
1857 break;
1858
1859 case 00004:
1860 case 00005:
1861 {
1862
1863 word16 b0_15 = (word16) getbits36_16 (cpu.rA, 20);
1864 word36 b16_51 = cpu.rQ;
1865 uint64 new_clk = (((uint64) b0_15) << 36) | b16_51;
1866 #if defined(THREADZ) || defined(LOCKLESS)
1867 lock_scu ();
1868 #endif
1869 scu [scu_unit_idx].user_correction =
1870 (int64) (new_clk - set_SCU_clock (scu_unit_idx));
1871 #if defined(THREADZ) || defined(LOCKLESS)
1872 unlock_scu ();
1873 #endif
1874
1875 }
1876 break;
1877
1878 case 00006:
1879 case 00007:
1880
1881
1882
1883 sim_warn ("sscr set unit mode register\n");
1884
1885 return SCPE_OK;
1886
1887 default:
1888 sim_warn ("sscr unhandled code\n");
1889
1890 return SCPE_OK;
1891
1892 }
1893 return SCPE_OK;
1894 }
1895
1896 t_stat scu_rscr (uint scu_unit_idx, uint cpu_unit_udx, word18 addr,
1897 word36 * rega, word36 * regq)
1898 {
1899
1900
1901 if (scu_unit_idx >= scu_dev.numunits)
1902 {
1903 sim_warn ("%s: scu_unit_idx out of range %d\n",
1904 __func__, scu_unit_idx);
1905 return SCPE_OK;
1906 }
1907
1908
1909
1910
1911 uint function = (addr >> 3) & 07;
1912
1913
1914
1915
1916
1917 switch (function)
1918 {
1919 case 00000:
1920 {
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932 * rega = 0;
1933
1934 * regq = 0;
1935 #if defined(THREADZ) || defined(LOCKLESS)
1936 lock_scu ();
1937 #endif
1938 putbits36_4 (regq, 50 - 36, scu [scu_unit_idx].id);
1939 putbits36_18 (regq, 54 - 36, scu [scu_unit_idx].mode_reg);
1940 #if defined(THREADZ) || defined(LOCKLESS)
1941 unlock_scu ();
1942 #endif
1943 break;
1944 }
1945
1946 case 00001:
1947 {
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978 sim_debug (DBG_DEBUG, & scu_dev, "rscr 1 %d\n", scu_unit_idx);
1979 #if defined(THREADZ) || defined(LOCKLESS)
1980 lock_scu ();
1981 #endif
1982 scu_t * up = scu + scu_unit_idx;
1983 word9 maskab [2];
1984 for (int i = 0; i < 2; i ++)
1985 {
1986 if (up -> mask_enable [i])
1987 {
1988 maskab [i] = (2 << (N_SCU_PORTS - 1 -
1989 up -> mask_assignment [i])) & 0777;
1990 }
1991 else
1992 maskab [i] = 0001;
1993 }
1994
1995 int scu_port_num = -1;
1996
1997
1998 for (int pn = 0; pn < N_SCU_PORTS; pn ++)
1999 {
2000 for (int sn = 0; sn < N_SCU_SUBPORTS; sn ++)
2001 {
2002 if (cables->scu_to_cpu[scu_unit_idx][pn][sn].in_use &&
2003 cables->scu_to_cpu[scu_unit_idx][pn][sn].cpu_unit_idx ==
2004 cpu_unit_udx)
2005 {
2006 scu_port_num = pn;
2007 goto gotit;
2008 }
2009 }
2010 }
2011 gotit:;
2012 if (scu_port_num < 0)
2013 {
2014 #if defined(THREADZ) || defined(LOCKLESS)
2015 unlock_scu ();
2016 #endif
2017 sim_warn ("%s: can't find cpu port in the snarl of cables; "
2018 "scu_unit_no %d, cpu_unit_udx %d\n",
2019 __func__, scu_unit_idx, cpu_unit_udx);
2020 return SCPE_OK;
2021 }
2022
2023
2024 word36 a, q;
2025
2026 a = 0;
2027
2028 putbits36_9 (& a, 0, maskab [0]);
2029 putbits36_3 (& a, 9, (word3) up -> lower_store_size);
2030 putbits36_4 (& a, 12, (word4) up -> onl);
2031 putbits36_4 (& a, 16, (word4) scu_port_num);
2032 putbits36_1 (& a, 21, (word1) config_switches[scu_unit_idx].mode);
2033 putbits36_8 (& a, 22, (word8) up -> nea);
2034 putbits36_1 (& a, 30, (word1) up -> interlace);
2035 putbits36_1 (& a, 31, (word1) up -> lwr);
2036
2037
2038
2039
2040
2041 putbits36_1 (& a, 32, (word1) up -> port_enable [0]);
2042 putbits36_1 (& a, 33, (word1) up -> port_enable [1]);
2043 putbits36_1 (& a, 34, (word1) up -> port_enable [2]);
2044 putbits36_1 (& a, 35, (word1) up -> port_enable [3]);
2045 * rega = a;
2046
2047 q = 0;
2048 putbits36_9 (& q, 0, maskab [1]);
2049
2050 putbits36_7 (& q, 57-36, (word7) up -> cyclic & MASK7);
2051
2052
2053 putbits36_1 (& q, 32, (word1) up -> port_enable [4]);
2054 putbits36_1 (& q, 33, (word1) up -> port_enable [5]);
2055 putbits36_1 (& q, 34, (word1) up -> port_enable [6]);
2056 putbits36_1 (& q, 35, (word1) up -> port_enable [7]);
2057 * regq = q;
2058
2059 #if defined(THREADZ) || defined(LOCKLESS)
2060 unlock_scu ();
2061 #endif
2062 sim_debug (DBG_DEBUG, & scu_dev,
2063 "rscr 1 %d A: %012"PRIo64" Q: %012"PRIo64"\n",
2064 scu_unit_idx, * rega, * regq);
2065 break;
2066 }
2067
2068 case 00002:
2069 {
2070 uint port_num = (addr >> 6) & MASK3;
2071 #if defined(THREADZ) || defined(LOCKLESS)
2072 lock_scu ();
2073 #endif
2074 scu_t * up = scu + scu_unit_idx;
2075 uint mask_contents = 0;
2076 if (up -> mask_assignment [0] == port_num)
2077 {
2078 mask_contents = up -> exec_intr_mask [0];
2079 }
2080 else if (up -> mask_assignment [1] == port_num)
2081 {
2082 mask_contents = up -> exec_intr_mask [1];
2083 }
2084 mask_contents &= MASK32;
2085
2086 * rega = 0;
2087 putbits36 (rega, 0, 16, (mask_contents >> 16) & MASK16);
2088 putbits36 (rega, 32, 1, up -> port_enable [0]);
2089 putbits36 (rega, 33, 1, up -> port_enable [1]);
2090 putbits36 (rega, 34, 1, up -> port_enable [2]);
2091 putbits36 (rega, 35, 1, up -> port_enable [3]);
2092
2093 * regq = 0;
2094 putbits36 (rega, 0, 16, (mask_contents >> 0) & MASK16);
2095 putbits36 (regq, 32, 1, up -> port_enable [4]);
2096 putbits36 (regq, 33, 1, up -> port_enable [5]);
2097 putbits36 (regq, 34, 1, up -> port_enable [6]);
2098 putbits36 (regq, 35, 1, up -> port_enable [7]);
2099
2100 #if defined(THREADZ) || defined(LOCKLESS)
2101 unlock_scu ();
2102 #endif
2103 sim_debug (DBG_TRACE, & scu_dev,
2104 "RSCR mask unit %u port %u assigns %u %u mask 0x%08x\n",
2105 scu_unit_idx, port_num, up -> mask_assignment [0],
2106 up -> mask_assignment [1],
2107 mask_contents);
2108 }
2109 break;
2110
2111 case 00003:
2112 {
2113 #if defined(THREADZ) || defined(LOCKLESS)
2114 lock_scu ();
2115 #endif
2116 scu_t * up = scu + scu_unit_idx;
2117
2118
2119 for (uint i = 0; i < N_CELL_INTERRUPTS; i ++)
2120 {
2121 word1 cell = up -> cells [i] ? 1 : 0;
2122 if (i < 16)
2123 putbits36_1 (rega, i, cell);
2124 else
2125 putbits36_1 (regq, i - 16, cell);
2126 }
2127 #if defined(THREADZ) || defined(LOCKLESS)
2128 unlock_scu ();
2129 #endif
2130 }
2131 break;
2132
2133 case 00004:
2134 case 00005:
2135 {
2136 uint64 clk = set_SCU_clock (scu_unit_idx);
2137 cpu.rQ = clk & 0777777777777;
2138 cpu.rA = (clk >> 36) & 0177777;
2139 #ifdef TESTING
2140 HDBGRegAW ("rscr get clock");
2141 HDBGRegQW ("rscr get clock");
2142 #endif
2143 }
2144 break;
2145
2146 case 00006:
2147 case 00007:
2148 {
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
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 * rega = 0;
2197 * regq = 0;
2198 }
2199 break;
2200
2201 default:
2202 sim_warn ("rscr %o\n", function);
2203 return SCPE_OK;
2204 }
2205 return SCPE_OK;
2206 }
2207
2208
2209
2210
2211
2212 int scu_cioc (uint cpu_unit_udx, uint scu_unit_idx, uint scu_port_num,
2213 uint expander_command, uint sub_mask)
2214 {
2215
2216
2217
2218 sim_debug (DBG_DEBUG, & scu_dev,
2219 "scu_cioc: Connect from %o sent to "
2220 "unit %o port %o exp %o mask %03o\n",
2221 cpu_unit_udx, scu_unit_idx, scu_port_num,
2222 expander_command, sub_mask);
2223
2224 #if defined(THREADZ) || defined(LOCKLESS)
2225 lock_scu ();
2226 #endif
2227 struct ports * portp = & scu [scu_unit_idx].ports [scu_port_num];
2228
2229 int rc = 0;
2230 if (! scu [scu_unit_idx].port_enable [scu_port_num])
2231 {
2232 sim_debug (DBG_ERR, & scu_dev,
2233 "scu_cioc: Connect sent to disabled port; dropping\n");
2234 sim_debug (DBG_ERR, & scu_dev,
2235 "scu_cioc: scu_unit_idx %u scu_port_num %u\n",
2236 scu_unit_idx, scu_port_num);
2237 rc = 1;
2238 goto done;
2239 }
2240
2241 if (expander_command == 1)
2242 {
2243 for (uint i = 0; i < N_SCU_SUBPORTS; i++)
2244 {
2245 portp->subport_enables [i] = !! (sub_mask & (0200u >> i));
2246 }
2247 goto done;
2248 }
2249
2250 if (expander_command == 2)
2251 {
2252 int cnt = 0;
2253 int val = -1;
2254 for (uint i = 0; i < N_SCU_SUBPORTS; i++)
2255 {
2256 portp->xipmask [i] = !! (sub_mask & (0200u >> i));
2257 if (portp->xipmask [i])
2258 {
2259 val = (int) i;
2260 cnt ++;
2261 }
2262 }
2263 if (cnt > 1)
2264 {
2265 sim_warn ("xip mask cnt > 1\n");
2266 val = -1;
2267 }
2268 portp->xipmaskval = val;
2269 goto done;
2270 }
2271
2272 if (portp -> type == ADEV_IOM)
2273 {
2274 int iom_unit_idx = portp->dev_idx;
2275 #if defined(THREADZ) || defined(LOCKLESS)
2276 unlock_scu ();
2277 # if !defined(IO_ASYNC_PAYLOAD_CHAN) && !defined(IO_ASYNC_PAYLOAD_CHAN_THREAD)
2278 lock_iom ();
2279 lock_libuv ();
2280 # endif
2281 iom_interrupt (scu_unit_idx, (uint) iom_unit_idx);
2282 # if !defined(IO_ASYNC_PAYLOAD_CHAN) && !defined(IO_ASYNC_PAYLOAD_CHAN_THREAD)
2283 unlock_libuv ();
2284 unlock_iom ();
2285 # endif
2286 return 0;
2287 #else
2288 if (sys_opts.iom_times.connect <= 0)
2289 {
2290 iom_interrupt (scu_unit_idx, (uint) iom_unit_idx);
2291 goto done;
2292 }
2293 else
2294 {
2295
2296
2297
2298 sim_debug (DBG_INFO, & scu_dev,
2299 "scu_cioc: Queuing an IOM in %d cycles "
2300 "(for the connect channel)\n",
2301 sys_opts.iom_times.connect);
2302
2303 iom_dev.units[iom_unit_idx].u3 = (int32) scu_unit_idx;
2304 iom_dev.units[iom_unit_idx].u4 = (int32) iom_unit_idx;
2305 int rc;
2306 if ((rc = sim_activate (& iom_dev.units [iom_unit_idx],
2307 sys_opts.iom_times.connect)) != SCPE_OK)
2308 {
2309 sim_warn ("sim_activate failed (%d)\n", rc);
2310 goto done;
2311 }
2312 goto done;
2313 }
2314 #endif
2315 }
2316 else if (portp -> type == ADEV_CPU)
2317 {
2318
2319
2320
2321 if (portp->is_exp)
2322 {
2323 for (uint sn = 0; sn < N_SCU_SUBPORTS; sn ++)
2324 {
2325 if (portp->subport_enables[sn])
2326 {
2327 if (! cables->
2328 scu_to_cpu[scu_unit_idx][scu_port_num][sn].in_use)
2329 {
2330 sim_warn ("Can't find CPU to interrupt\n");
2331 continue;
2332 }
2333 uint cpu_unit_udx = cables->
2334 scu_to_cpu[scu_unit_idx][scu_port_num][sn].cpu_unit_idx;
2335 setG7fault ((uint) cpu_unit_udx, FAULT_CON, fst_zero);
2336 }
2337 }
2338 }
2339 else
2340 {
2341 if (! cables->scu_to_cpu[scu_unit_idx][scu_port_num][0].in_use)
2342 {
2343 sim_warn ("Can't find CPU to interrupt\n");
2344 rc = 1;
2345 goto done;
2346 }
2347 uint cpu_unit_udx =
2348 cables->scu_to_cpu[scu_unit_idx][scu_port_num][0].cpu_unit_idx;
2349 setG7fault ((uint) cpu_unit_udx, FAULT_CON, fst_zero);
2350 }
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373 goto done;
2374 }
2375 else
2376 {
2377 sim_debug (DBG_ERR, & scu_dev,
2378 "scu_cioc: Connect sent to not-an-IOM or CPU; dropping\n");
2379 rc = 1;
2380 goto done;
2381 }
2382 done:
2383 #if defined(THREADZ) || defined(LOCKLESS)
2384 unlock_scu ();
2385 #endif
2386 return rc;
2387 }
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399 int scu_set_interrupt (uint scu_unit_idx, uint inum)
2400 {
2401 const char* moi = "SCU::interrupt";
2402
2403 if (inum >= N_CELL_INTERRUPTS)
2404 {
2405 sim_debug (DBG_WARN, & scu_dev,
2406 "%s: Bad interrupt number %d\n", moi, inum);
2407 return 1;
2408 }
2409
2410 #if defined(THREADZ) || defined(LOCKLESS)
2411 lock_scu ();
2412 #endif
2413 scu [scu_unit_idx].cells [inum] = 1;
2414 dump_intr_regs ("scu_set_interrupt", scu_unit_idx);
2415 deliver_interrupts (scu_unit_idx);
2416 #if defined(THREADZ) || defined(LOCKLESS)
2417 unlock_scu ();
2418 #endif
2419 return 0;
2420 }
2421
2422
2423
2424
2425
2426
2427
2428 uint scu_get_highest_intr (uint scu_unit_idx)
2429 {
2430 #if defined(THREADZ) || defined(LOCKLESS)
2431 lock_scu ();
2432 #endif
2433
2434 for (int inum = 0; inum < N_CELL_INTERRUPTS; inum ++)
2435 {
2436 for (uint pima = 0; pima < N_ASSIGNMENTS; pima ++)
2437 {
2438 if (scu [scu_unit_idx].mask_enable [pima] == 0)
2439 continue;
2440 uint mask = scu [scu_unit_idx].exec_intr_mask [pima];
2441 uint port = scu [scu_unit_idx].mask_assignment [pima];
2442
2443
2444 if (scu[scu_unit_idx].ports[port].type != ADEV_CPU ||
2445 cpus[current_running_cpu_idx].scu_port[scu_unit_idx] != port)
2446 continue;
2447 if (scu [scu_unit_idx].cells [inum] &&
2448 (mask & (1u << (31 - inum))) != 0)
2449 {
2450 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]);
2451 scu [scu_unit_idx].cells [inum] = false;
2452 dump_intr_regs ("scu_get_highest_intr", scu_unit_idx);
2453 deliver_interrupts (scu_unit_idx);
2454 #if defined(THREADZ) || defined(LOCKLESS)
2455 unlock_scu ();
2456 #endif
2457 return (uint) inum * 2;
2458 }
2459 }
2460 }
2461 #if defined(THREADZ) || defined(LOCKLESS)
2462 unlock_scu ();
2463 #endif
2464 return 1;
2465 }
2466
2467 t_stat scu_reset_unit (UNIT * uptr, UNUSED int32 value,
2468 UNUSED const char * cptr,
2469 UNUSED void * desc)
2470 {
2471 uint scu_unit_idx = (uint) (uptr - scu_unit);
2472 scu_unit_reset ((int) scu_unit_idx);
2473 return SCPE_OK;
2474 }
2475
2476 void scu_init (void)
2477 {
2478
2479
2480 for (int u = 0; u < N_SCU_UNITS_MAX; u ++)
2481 {
2482 for (int p = 0; p < N_SCU_PORTS; p ++)
2483 {
2484 for (int s = 0; s < N_SCU_SUBPORTS; s ++)
2485 {
2486 scu[u].ports[p].dev_port[s] = -1;
2487 scu[u].ports[p].subport_enables[s] = false;
2488 scu[u].ports[p].xipmask[s] = false;
2489
2490 scu[u].ports[p].xipmaskval = N_SCU_SUBPORTS;
2491 }
2492 scu[u].ports[p].type = ADEV_NONE;
2493 scu[u].ports[p].is_exp = false;
2494 }
2495
2496
2497
2498
2499 scu [u].id = 02l;
2500 scu [u].mode_reg = 0;
2501 scu [u].elapsed_days = 0;
2502 }
2503
2504 }
2505
2506 t_stat scu_rmcm (uint scu_unit_idx, uint cpu_unit_udx, word36 * rega,
2507 word36 * regq)
2508 {
2509 scu_t * up = scu + scu_unit_idx;
2510
2511
2512 * rega = 0;
2513 * regq = 0;
2514
2515
2516
2517 int scu_port_num = -1;
2518
2519
2520 for (int pn = 0; pn < N_SCU_PORTS; pn ++)
2521 {
2522 for (int sn = 0; sn < N_SCU_SUBPORTS; sn ++)
2523 {
2524 if (cables->scu_to_cpu[scu_unit_idx][pn][sn].in_use &&
2525 cables->scu_to_cpu[scu_unit_idx][pn][sn].cpu_unit_idx ==
2526 cpu_unit_udx)
2527 {
2528 scu_port_num = pn;
2529 goto gotit;
2530 }
2531 }
2532 }
2533
2534 gotit:;
2535
2536
2537
2538 if (scu_port_num < 0)
2539 {
2540 sim_warn ("%s: can't find cpu port in the snarl of cables; "
2541 "scu_unit_no %d, cpu_unit_udx %d\n",
2542 __func__, scu_unit_idx, cpu_unit_udx);
2543 sim_debug (DBG_ERR, & scu_dev,
2544 "%s: can't find cpu port in the snarl of cables; "
2545 "scu_unit_no %d, cpu_unit_udx %d\n",
2546 __func__, scu_unit_idx, cpu_unit_udx);
2547
2548 return SCPE_OK;
2549 }
2550
2551
2552
2553
2554
2555
2556
2557
2558 sim_debug (DBG_TRACE, & scu_dev, "rmcm selected scu port %u\n",
2559 scu_port_num);
2560 #if defined(THREADZ) || defined(LOCKLESS)
2561 lock_scu ();
2562 #endif
2563 uint mask_contents = 0;
2564 if (up -> mask_assignment [0] == (uint) scu_port_num)
2565 {
2566 mask_contents = up -> exec_intr_mask [0];
2567 sim_debug (DBG_TRACE, & scu_dev, "rmcm got mask %011o from pima A\n",
2568 mask_contents);
2569 }
2570 else if (up -> mask_assignment [1] == (uint) scu_port_num)
2571 {
2572 mask_contents = up -> exec_intr_mask [1];
2573 sim_debug (DBG_TRACE, & scu_dev, "rmcm got mask %011o from pima B\n",
2574 mask_contents);
2575 }
2576 mask_contents &= MASK32;
2577
2578 * rega = 0;
2579 putbits36_16 (rega, 0, (mask_contents >> 16) & MASK16);
2580 putbits36_1 (rega, 32, (word1) up -> port_enable [0]);
2581 putbits36_1 (rega, 33, (word1) up -> port_enable [1]);
2582 putbits36_1 (rega, 34, (word1) up -> port_enable [2]);
2583 putbits36_1 (rega, 35, (word1) up -> port_enable [3]);
2584
2585 * regq = 0;
2586 putbits36_16 (regq, 0, (mask_contents >> 0) & MASK16);
2587 putbits36_1 (regq, 32, (word1) up -> port_enable [4]);
2588 putbits36_1 (regq, 33, (word1) up -> port_enable [5]);
2589 putbits36_1 (regq, 34, (word1) up -> port_enable [6]);
2590 putbits36_1 (regq, 35, (word1) up -> port_enable [7]);
2591
2592 #if defined(THREADZ) || defined(LOCKLESS)
2593 unlock_scu ();
2594 #endif
2595 sim_debug (DBG_TRACE, & scu_dev,
2596 "RMCM returns %012"PRIo64" %012"PRIo64"\n",
2597 * rega, * regq);
2598 dump_intr_regs ("rmcm", scu_unit_idx);
2599 return SCPE_OK;
2600 }
2601
2602 t_stat scu_smcm (uint scu_unit_idx, uint cpu_unit_udx, word36 rega, word36 regq)
2603 {
2604 sim_debug (DBG_TRACE, & scu_dev,
2605 "SMCM SCU unit %d CPU unit %d A %012"PRIo64" Q %012"PRIo64"\n",
2606 scu_unit_idx, cpu_unit_udx, rega, regq);
2607
2608 scu_t * up = scu + scu_unit_idx;
2609
2610
2611
2612 int scu_port_num = -1;
2613
2614
2615 for (int pn = 0; pn < N_SCU_PORTS; pn ++)
2616 {
2617 for (int sn = 0; sn < N_SCU_SUBPORTS; sn ++)
2618 {
2619 if (cables->scu_to_cpu[scu_unit_idx][pn][sn].in_use &&
2620 cables->scu_to_cpu[scu_unit_idx][pn][sn].cpu_unit_idx ==
2621 cpu_unit_udx)
2622 {
2623 scu_port_num = pn;
2624 goto gotit;
2625 }
2626 }
2627 }
2628 gotit:;
2629
2630
2631
2632 if (scu_port_num < 0)
2633 {
2634 sim_warn ("%s: can't find cpu port in the snarl of cables; "
2635 "scu_unit_no %d, cpu_unit_udx %d\n",
2636 __func__, scu_unit_idx, cpu_unit_udx);
2637 return SCPE_OK;
2638 }
2639
2640 sim_debug (DBG_TRACE, & scu_dev, "SMCM SCU port num %d\n", scu_port_num);
2641
2642
2643
2644
2645
2646
2647
2648
2649 uint imask =
2650 ((uint) getbits36_16(rega, 0) << 16) |
2651 ((uint) getbits36_16(regq, 0) << 0);
2652 #if defined(THREADZ) || defined(LOCKLESS)
2653 lock_scu ();
2654 #endif
2655 if (up -> mask_assignment [0] == (uint) scu_port_num)
2656 {
2657 up -> exec_intr_mask [0] = imask;
2658 sim_debug (DBG_TRACE, & scu_dev, "SMCM intr mask 0 set to %011o\n",
2659 imask);
2660 }
2661 else if (up -> mask_assignment [1] == (uint) scu_port_num)
2662 {
2663 up -> exec_intr_mask [1] = imask;
2664 sim_debug (DBG_TRACE, & scu_dev, "SMCM intr mask 1 set to %011o\n",
2665 imask);
2666 }
2667
2668 scu [scu_unit_idx].port_enable [0] = (uint) getbits36_1 (rega, 32);
2669 scu [scu_unit_idx].port_enable [1] = (uint) getbits36_1 (rega, 33);
2670 scu [scu_unit_idx].port_enable [2] = (uint) getbits36_1 (rega, 34);
2671 scu [scu_unit_idx].port_enable [3] = (uint) getbits36_1 (rega, 35);
2672 scu [scu_unit_idx].port_enable [4] = (uint) getbits36_1 (regq, 32);
2673 scu [scu_unit_idx].port_enable [5] = (uint) getbits36_1 (regq, 33);
2674 scu [scu_unit_idx].port_enable [6] = (uint) getbits36_1 (regq, 34);
2675 scu [scu_unit_idx].port_enable [7] = (uint) getbits36_1 (regq, 35);
2676
2677 dump_intr_regs ("smcm", scu_unit_idx);
2678 deliver_interrupts (scu_unit_idx);
2679 #if defined(THREADZ) || defined(LOCKLESS)
2680 unlock_scu ();
2681 #endif
2682
2683 return SCPE_OK;
2684 }