This source file includes following definitions.
- lruLoaded
- lruNewer
- lruVictim
- main
- columnOf
- keyOf
- levelOf
- levelMask
- findLevel
- dirRead
- dirWrite
- dirInvalidate
- dirFill
- cacheLocksInit
- cacheLock
- cacheUnlock
- cacheOn
- bypass
- sinceInstr
- pendingClears
- startClear
- cacheable
- takeFetch
- realAddress
- cacheAddr
- absKeyOfReal
- purgeOne
- cachePurgeOthers
- cacheStoreNotifyOn
- cacheStoreBadParity
- cachePurgeAllOn
- cacheInvalidate
- cacheReset
- cacheCpuReset
- cacheConfigured
- cacheConfigChanged
- cacheUpdateAnyOn
- cacheClearStarted
- cacheStats
- cacheDirWord
- dumpMode
- dumpRead
- dirReadout
- badWordsAt
- parityBits
- cacheParityFault
- cacheParity
- blockCacheable
- readThrough
- ccheck
- readWord
- readAndClear
- cache_read_lock_on
- cache_read_on
- cache_read2_on
- cache_readN_on
- cache_writeN_on
- cache_write2_on
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 #define PAR_CACHE 04000u
46 #define PAR_CACHE_STR 01000u
47 #define PAR_CACHE_BLK 02000u
48 #define FR_CPAR_DIR (((word36) 1) << (35 - 32))
49
50 #if defined(SELF_TEST)
51 # include <stdio.h>
52 # include <stdint.h>
53 # include <stdbool.h>
54 typedef unsigned int uint;
55 # define N_LEVELS 4
56 #else
57 # include <sched.h>
58 # include "dps8.h"
59 # include "dps8_cpu.h"
60 # include "dps8_faults.h"
61 # include "dps8_iom.h"
62 # include "dps8_cable.h"
63 # include "dps8_cache.h"
64 #endif
65
66
67
68
69
70
71
72
73
74
75
76 static const uint8_t pairBit[N_LEVELS][N_LEVELS] = {
77 { 0, 040, 020, 010 },
78 { 0, 0, 04, 02 },
79 { 0, 0, 0, 01 },
80 { 0, 0, 0, 0 },
81 };
82
83
84 static uint8_t lruLoaded (uint8_t lru, uint level) {
85 for (uint j = level + 1; j < N_LEVELS; j ++)
86 lru |= pairBit[level][j];
87 for (uint i = 0; i < level; i ++)
88 lru &= (uint8_t) ~pairBit[i][level];
89 return lru;
90 }
91
92
93 static bool lruNewer (uint8_t lru, uint a, uint b) {
94 return a < b ? (lru & pairBit[a][b]) != 0 : (lru & pairBit[b][a]) == 0;
95 }
96
97
98 static uint lruVictim (uint8_t lru, uint mask) {
99 for (uint l = 0; l < N_LEVELS; l ++) {
100 if (! (mask & (1u << l)))
101 continue;
102 bool oldest = true;
103 for (uint m = 0; m < N_LEVELS; m ++)
104 if (m != l && (mask & (1u << m)) && ! lruNewer (lru, m, l)) {
105 oldest = false;
106 break;
107 }
108 if (oldest)
109 return l;
110 }
111 for (uint l = 0; l < N_LEVELS; l ++)
112 if (mask & (1u << l))
113 return l;
114 return 0;
115 }
116
117 #if defined(SELF_TEST)
118
119 int main (void) {
120 int fails = 0;
121
122 static const uint8_t want[N_LEVELS] = { 070, 036, 013, 000 };
123 uint8_t lru = 0;
124 for (uint l = 0; l < N_LEVELS; l ++) {
125 lru = lruLoaded (lru, l);
126 if (lru != want[l]) {
127 printf ("load %u: %02o, expected %02o\n", l, lru, want[l]);
128 fails ++;
129 }
130 }
131
132 for (uint n = 0; n < 8; n ++) {
133 uint v = lruVictim (lru, 017);
134 if (v != n % 4) {
135 printf ("victim %u: %u, expected %u\n", n, v, n % 4);
136 fails ++;
137 }
138 lru = lruLoaded (lru, v);
139 }
140
141 lru = 0;
142 uint v1 = lruVictim (lru, 014); lru = lruLoaded (lru, v1);
143 uint v2 = lruVictim (lru, 014); lru = lruLoaded (lru, v2);
144 uint v3 = lruVictim (lru, 014);
145 if (v1 != 2 || v2 != 3 || v3 != 2) {
146 printf ("CSH2 victims %u %u %u, expected 2 3 2\n", v1, v2, v3);
147 fails ++;
148 }
149
150
151 lru = lruLoaded (0, 0);
152 if (lru != 070 || lruVictim (lru, 003) != 1) {
153 printf ("CSH1 only: %02o victim %u, expected 70 1\n", lru, lruVictim (lru, 003));
154 fails ++;
155 }
156 printf ("%s\n", fails ? "FAIL" : "pass");
157 return fails != 0;
158 }
159
160 #else
161
162 # define L68 cpu.tweaks.l68_mode
163
164
165
166
167
168
169
170 static inline uint columnOf (cpu_state_t * cpup, word24 address) {
171 return L68 ? (address >> 2) % L68_N_COLUMNS : (address >> 2) % DPS8_N_COLUMNS;
172 }
173
174 static inline word24 keyOf (cpu_state_t * cpup, word24 address) {
175 return L68 ? address >> 9 : address >> 11;
176 }
177
178
179 static inline uint levelOf (cpu_state_t * cpup, word24 address) {
180 return L68 ? (address >> 9) & 3 : (address >> 11) & 3;
181 }
182
183
184 static inline uint levelMask (cpu_state_t * cpup) {
185 return (cpu.CMR.csh1_on ? 003u : 0u) | (cpu.CMR.csh2_on ? 014u : 0u);
186 }
187
188
189
190
191
192
193 static int findLevel (cpu_state_t * cpup, word24 address, uint mask) {
194 uint col = columnOf (cpup, address);
195 word24 key = keyOf (cpup, address);
196 for (uint l = 0; l < N_LEVELS; l ++) {
197 directory * e = & cpu.directories[col][l];
198 if ((mask & (1u << l)) && e->FE && ! e->badParity && e->key == key)
199 return (int) l;
200 }
201 return -1;
202 }
203
204
205
206
207
208
209 static bool dirRead (cpu_state_t * cpup, word24 address, uint mask, word36 * data, bool * bad) {
210 cpu.cacheProbes ++;
211 uint col = columnOf (cpup, address);
212 for (uint l = 0; l < N_LEVELS; l ++) {
213 directory * e = & cpu.directories[col][l];
214 if ((mask & (1u << l)) && e->FE && e->badParity)
215 cpu.faultRegister[0] |= FR_CPAR_DIR;
216 }
217 int l = findLevel (cpup, address, mask);
218 if (l < 0)
219 return false;
220 cpu.cacheHits ++;
221 directory * e = & cpu.directories[col][l];
222 * data = e->block[address % BLOCK_SZ];
223 * bad = (e->badWord >> (address % BLOCK_SZ)) & 1;
224 return true;
225 }
226
227
228
229
230
231
232
233 static void dirWrite (cpu_state_t * cpup, word24 address, word36 data) {
234 int l = findLevel (cpup, address, levelMask (cpup));
235 if (l >= 0) {
236 directory * e = & cpu.directories[columnOf (cpup, address)][l];
237 e->block[address % BLOCK_SZ] = data;
238 e->badWord &= (uint8_t) ~(1u << (address % BLOCK_SZ));
239 }
240 }
241
242
243
244 static void dirInvalidate (cpu_state_t * cpup, word24 address) {
245 int l = findLevel (cpup, address, 017);
246 if (l >= 0)
247 cpu.directories[columnOf (cpup, address)][l].FE = false;
248 }
249
250
251
252
253
254
255 static void dirFill (cpu_state_t * cpup, word24 address, word24 cpuAddr,
256 const word36 block[BLOCK_SZ], uint mask, int half) {
257 if (! mask)
258 return;
259 uint col = columnOf (cpup, address);
260 int found = findLevel (cpup, address, mask);
261 uint lvl;
262 if (found >= 0) {
263 lvl = (uint) found;
264 } else {
265 lvl = N_LEVELS;
266 for (uint l = 0; l < N_LEVELS; l ++)
267 if ((mask & (1u << l)) && ! cpu.directories[col][l].FE) {
268 lvl = l;
269 break;
270 }
271 if (lvl == N_LEVELS)
272 lvl = lruVictim (cpu.cacheLRU[col], mask);
273 }
274 directory * e = & cpu.directories[col][lvl];
275 for (uint w = 0; w < BLOCK_SZ; w ++)
276 if (half < 0 || (int) (w / 2) == half)
277 e->block[w] = block[w];
278 e->key = keyOf (cpup, address);
279 e->dirAddr = (word13) (keyOf (cpup, cpuAddr) & 017777);
280 e->FE = true;
281 e->badParity = false;
282 e->badWord = 0;
283 cpu.cacheLRU[col] = lruLoaded (cpu.cacheLRU[col], lvl);
284
285
286
287
288 if (mask == 003 && cpu.directories[col][0].FE && cpu.directories[col][1].FE)
289 cpu.cacheLRU[col] &= pairBit[0][1];
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 # if defined(THREADZ) || defined(LOCKLESS)
322 # include <pthread.h>
323 static pthread_mutex_t cacheLocks [N_CPU_UNITS_MAX];
324 static pthread_once_t cacheLocksOnce = PTHREAD_ONCE_INIT;
325 static void cacheLocksInit (void) {
326 for (uint i = 0; i < N_CPU_UNITS_MAX; i ++)
327 pthread_mutex_init (& cacheLocks[i], NULL);
328 }
329 static inline void cacheLock (cpu_state_t * cpup) {
330 (void) pthread_once (& cacheLocksOnce, cacheLocksInit);
331 pthread_mutex_lock (& cacheLocks[cpup - cpus]);
332 }
333 static inline void cacheUnlock (cpu_state_t * cpup) {
334 pthread_mutex_unlock (& cacheLocks[cpup - cpus]);
335 }
336 # else
337 # define cacheLock(cpup) (void) (cpup)
338 # define cacheUnlock(cpup) (void) (cpup)
339 # endif
340
341
342
343 static uint32_t purgeCount [N_CPU_UNITS_MAX] [DPS8_N_COLUMNS];
344
345
346
347 static inline bool cacheOn (cpu_state_t * cpup) {
348 return cpu.switches.enable_cache && cpu.tweaks.enable_wam;
349 }
350
351
352
353
354
355
356
357
358
359
360
361
362
363 static bool bypass (cpu_state_t * cpup) {
364 if (cpu.currentInstruction.opcode10 == 0015)
365 return true;
366 if (get_addr_mode (cpup) == APPEND_mode && cpu.SDW && ! cpu.SDW->C &&
367 (L68 || ! cpu.CMR.bypass_cache))
368 return true;
369 return false;
370 }
371
372
373
374 static inline unsigned long long sinceInstr (cpu_state_t * cpup, unsigned long long start) {
375 return cpu.instrCnt >= start ? cpu.instrCnt - start : ~0ULL;
376 }
377
378
379
380
381
382
383
384 # define CACHE_CLEAR_INSTRUCTIONS 128
385
386
387
388
389
390
391
392
393 # define CACHE_CLEAR_DELAY 2
394
395
396 static void pendingClears (cpu_state_t * cpup, bool all) {
397 cacheLock (cpup);
398 uint n = 0;
399 while (n < cpu.cachePendN &&
400 (all || sinceInstr (cpup, cpu.cachePendAt[n]) >= CACHE_CLEAR_DELAY)) {
401 int l = findLevel (cpup, cpu.cachePendAddr[n], levelMask (cpup));
402 if (l >= 0)
403 cpu.directories[columnOf (cpup, cpu.cachePendAddr[n])][l].FE = false;
404 n ++;
405 }
406 for (uint i = n; i < cpu.cachePendN; i ++) {
407 cpu.cachePendAddr[i - n] = cpu.cachePendAddr[i];
408 cpu.cachePendAt[i - n] = cpu.cachePendAt[i];
409 }
410 cpu.cachePendN -= n;
411 cacheUnlock (cpup);
412 }
413
414 # if defined(LOCKLESS)
415
416
417 static void startClear (cpu_state_t * cpup, word24 addr) {
418 if (cpu.cachePendN == CACHE_PENDING_CLEARS)
419 pendingClears (cpup, true);
420 cacheLock (cpup);
421 cpu.cachePendAddr[cpu.cachePendN] = addr;
422 cpu.cachePendAt[cpu.cachePendN] = cpu.instrCnt;
423 cpu.cachePendN ++;
424 cacheUnlock (cpup);
425 }
426 # endif
427
428
429
430 static bool cacheable (cpu_state_t * cpup, bool fetch) {
431 if (cpu.cacheClearing) {
432 if (sinceInstr (cpup, cpu.cacheClearStart) < CACHE_CLEAR_INSTRUCTIONS)
433 return false;
434 cpu.cacheClearing = false;
435 }
436 if (! cacheOn (cpup) || ! levelMask (cpup))
437 return false;
438 if (fetch ? ! cpu.CMR.inst_on : (L68 && ! cpu.CMR.opnd_on))
439 return false;
440 return ! bypass (cpup);
441 }
442
443
444
445 static void cacheParityFault (cpu_state_t * cpup, uint bits, const char * why);
446
447 static inline bool takeFetch (cpu_state_t * cpup) {
448 bool fetch = cpu.cacheFetch;
449 cpu.cacheFetch = false;
450 if (cpu.cachePendN)
451 pendingClears (cpup, false);
452 if (cpu.cacheParPending) {
453 uint bits = cpu.cacheParPending;
454 cpu.cacheParPending = 0;
455 cacheParityFault (cpup, bits, "cache block load parity");
456 }
457 return fetch;
458 }
459
460
461
462 static inline word24 realAddress (cpu_state_t * cpup, word24 addr) {
463 word24 real = addr;
464 SC_MAP_ADDR (addr, real);
465 return real;
466 }
467
468
469
470
471
472
473
474
475
476
477
478
479 # define ABS_KEY ((word24) 1 << 24)
480
481
482 static inline word24 cacheAddr (cpu_state_t * cpup, word24 addr, word24 real) {
483 if (cpu.sc_fine && sc_fine_interlaced (cpup, addr))
484 return addr | ABS_KEY;
485 return real;
486 }
487
488
489
490 static inline bool absKeyOfReal (cpu_state_t * cpup, word24 real, word24 * caddr) {
491 word24 a;
492 if (! cpu.sc_fine || ! sc_fine_unmap (cpup, real, & a))
493 return false;
494 * caddr = a | ABS_KEY;
495 return true;
496 }
497
498
499 static void purgeOne (cpu_state_t * cpup, word24 addr) {
500 if (! cacheOn (cpup))
501 return;
502 word24 caddr;
503 bool fine = absKeyOfReal (cpup, addr, & caddr);
504 cacheLock (cpup);
505 dirInvalidate (cpup, addr);
506 purgeCount[cpup - cpus][columnOf (cpup, addr)] ++;
507 if (fine) {
508 dirInvalidate (cpup, caddr);
509 purgeCount[cpup - cpus][columnOf (cpup, caddr)] ++;
510 }
511 cacheUnlock (cpup);
512 }
513
514
515
516
517 void cachePurgeOthers (cpu_state_t * cpup, word24 addr) {
518 uint self = (uint) (cpup - cpus);
519 for (uint i = 0; i < cpu_dev.numunits && i < N_CPU_UNITS_MAX; i ++)
520 if (i != self)
521 purgeOne (& cpus[i], addr);
522 }
523
524
525
526
527
528 void cacheStoreNotifyOn (cpu_state_t * cpup, word24 addr, word36 data) {
529 if (cacheOn (cpup)) {
530 word24 caddr;
531 bool fine = absKeyOfReal (cpup, addr, & caddr);
532 cacheLock (cpup);
533 dirWrite (cpup, addr, data);
534 if (fine)
535 dirWrite (cpup, caddr, data);
536 cacheUnlock (cpup);
537 }
538 cachePurgeOthers (cpup, addr);
539 }
540
541
542
543
544
545
546
547 void cacheStoreBadParity (cpu_state_t * cpup, word24 addr) {
548 if (! cacheOn (cpup))
549 return;
550 word24 caddr = cacheAddr (cpup, addr, realAddress (cpup, addr));
551 cacheLock (cpup);
552 int l = findLevel (cpup, caddr, levelMask (cpup));
553 if (l >= 0)
554 cpu.directories[columnOf (cpup, caddr)][l].badWord |= (uint8_t) (1u << (caddr % BLOCK_SZ));
555 cacheUnlock (cpup);
556 }
557
558
559
560 void cachePurgeAllOn (word24 addr) {
561 for (uint i = 0; i < cpu_dev.numunits && i < N_CPU_UNITS_MAX; i ++)
562 purgeOne (& cpus[i], addr);
563 }
564
565
566
567
568
569 void cacheInvalidate (cpu_state_t * cpup, word24 addr) {
570 if (! cacheOn (cpup))
571 return;
572 word24 caddr = cacheAddr (cpup, addr, realAddress (cpup, addr));
573 cacheLock (cpup);
574 dirInvalidate (cpup, caddr);
575 cacheUnlock (cpup);
576 }
577
578
579
580
581 void cacheReset (cpu_state_t * cpup) {
582 cacheLock (cpup);
583 for (uint c = 0; c < N_COLUMNS; c ++) {
584 for (uint l = 0; l < N_LEVELS; l ++) {
585 cpu.directories[c][l].FE = false;
586 cpu.directories[c][l].badParity = false;
587 cpu.directories[c][l].badWord = 0;
588 cpu.directories[c][l].key = 0;
589 cpu.directories[c][l].dirAddr = 0;
590 }
591 cpu.cacheLRU[c] = 0;
592 }
593 cpu.cachePendN = 0;
594 cacheUnlock (cpup);
595 }
596
597
598
599
600
601 void cacheCpuReset (cpu_state_t * cpup) {
602 cacheReset (cpup);
603 cpu.cacheParPending = 0;
604 cpu.cacheFetch = false;
605 cpu.cacheDirReadout = false;
606 cpu.cacheClearing = false;
607 cpu.cacheClearStart = 0;
608 }
609
610
611 bool cacheConfigured (cpu_state_t * cpup) {
612 return cacheOn (cpup);
613 }
614
615
616
617
618
619
620 void cacheConfigChanged (cpu_state_t * cpup, bool was) {
621 if (cacheOn (cpup) != was)
622 cacheReset (cpup);
623 cacheUpdateAnyOn ();
624 }
625
626
627
628
629
630 # if defined(THREADZ) || defined(LOCKLESS)
631 atomic_bool cacheAnyOn = false;
632 # else
633 bool cacheAnyOn = false;
634 # endif
635
636 void cacheUpdateAnyOn (void) {
637 bool on = false;
638 for (uint i = 0; i < N_CPU_UNITS_MAX; i ++)
639 if (cacheOn (& cpus[i]))
640 on = true;
641 if (on && ! CACHE_ANY_ON ())
642 for (uint i = 0; i < N_CPU_UNITS_MAX; i ++) {
643 cpus[i].cacheFetch = false;
644 cpus[i].cacheDirReadout = false;
645 }
646 # if defined(THREADZ) || defined(LOCKLESS)
647 atomic_store_explicit (& cacheAnyOn, on, memory_order_relaxed);
648 # else
649 cacheAnyOn = on;
650 # endif
651 }
652
653 void cacheClearStarted (cpu_state_t * cpup) {
654 cpu.cacheClearing = true;
655 cpu.cacheClearStart = cpu.instrCnt;
656 }
657
658 void cacheStats (uint cpuNo) {
659 (void)fflush(stdout);
660 (void)fflush(stderr);
661 sim_msg ("\r\n| Cache Probes: %15llu |\r\n", (unsigned long long) cpus[cpuNo].cacheProbes);
662 sim_msg ("| Cache Hits: %15llu |\r\n", (unsigned long long) cpus[cpuNo].cacheHits);
663 sim_msg ("+---------------------------------+");
664 (void)fflush(stdout);
665 (void)fflush(stderr);
666 }
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681 word36 cacheDirWord (cpu_state_t * cpup, word24 y) {
682 if (! cacheOn (cpup))
683 return 0;
684 if (cpu.cachePendN)
685 pendingClears (cpup, false);
686 uint col = columnOf (cpup, y);
687 uint lvl = levelOf (cpup, y);
688 bool dup = (y >> 1) & 1;
689 cacheLock (cpup);
690 directory * e = & cpu.directories[col][lvl];
691 word36 w = ((word36) (e->dirAddr & 017777)) << (35 - 12);
692 if (e->FE)
693 w |= ((word36) 1) << (35 - 16);
694 if (! dup) {
695 if (e->badParity)
696 w |= ((word36) 1) << (35 - 15);
697 w |= ((word36) (cpu.cacheLRU[col] & 077)) << (35 - 30);
698 }
699 cacheUnlock (cpup);
700 return w;
701 }
702
703
704
705
706
707
708
709 static bool dumpMode (cpu_state_t * cpup, bool fetch) {
710 return ! fetch && cpu.CMR.csh_reg && cacheOn (cpup) &&
711 cpu.currentInstruction.opcode10 == 0237;
712 }
713
714 static void dumpRead (cpu_state_t * cpup, word24 y, word36 * even, word36 * odd) {
715 uint col = columnOf (cpup, y);
716 uint lvl = levelOf (cpup, y);
717 uint pair = (y >> 1) & 1;
718 cacheLock (cpup);
719 * even = cpu.directories[col][lvl].block[pair * 2];
720 * odd = cpu.directories[col][lvl].block[pair * 2 + 1];
721 cacheUnlock (cpup);
722 }
723
724
725 static inline void dirReadout (cpu_state_t * cpup, word24 y, word36 * odd) {
726 if (cpu.cacheDirReadout) {
727 cpu.cacheDirReadout = false;
728 * odd |= cacheDirWord (cpup, y);
729 }
730 }
731
732
733
734
735
736
737
738
739
740 # if defined(CCHECK)
741 static int inconsCnt = 32;
742 # endif
743
744
745
746
747
748
749
750 static uint badWordsAt (cpu_state_t * cpup, word24 blk) {
751 if (! nBadParity || ! cpu.tweaks.tandd_mode)
752 return 0;
753 uint bad = 0;
754 for (uint w = 0; w < BLOCK_SZ; w ++)
755 if (bad_parity_marked (blk + w))
756 bad |= 1u << w;
757 return bad;
758 }
759
760
761
762
763 static uint parityBits (uint bad, uint w, uint readw) {
764 bool upper = (bad >> w) & 1, lower = (bad >> (w + 1)) & 1;
765 if (readw & 1)
766 upper = lower = true;
767 return (upper ? 0100u : 0u) | (lower ? 0200u : 0u);
768 }
769
770
771
772
773
774
775 static void cacheParityFault (cpu_state_t * cpup, uint bits, const char * why) {
776 cpu.CMR.csh1_on = 0;
777 cpu.CMR.csh2_on = 0;
778 cpu.cacheFetch = false;
779 doFault (FAULT_PAR, (_fault_subtype) {.bits=bits | PAR_CACHE}, why);
780 }
781
782 static void cacheParity (cpu_state_t * cpup, uint bits, const char * why) {
783 SETF (cpu.cu.IR, I_PERR);
784 if (! TST_I_PMASK)
785 cacheParityFault (cpup, bits, why);
786 }
787
788
789
790
791
792
793
794 static bool blockCacheable (cpu_state_t * cpup, word24 blk, word24 realBlk) {
795 if (! cpu.sc_fine)
796 return true;
797 if (realBlk % BLOCK_SZ)
798 return false;
799 for (uint w = 1; w < BLOCK_SZ; w ++)
800 if (realAddress (cpup, blk + w) != realBlk + w)
801 return false;
802 return true;
803 }
804
805
806
807 static void readThrough (cpu_state_t * cpup, word24 addr, word36 * data, uint mask,
808 const char * ctx) {
809 (void) ctx;
810 word24 real = realAddress (cpup, addr);
811 word24 caddr = cacheAddr (cpup, addr, real);
812 uint col = columnOf (cpup, caddr);
813 bool bad = false;
814 cacheLock (cpup);
815 bool hit = dirRead (cpup, caddr, mask, data, & bad);
816 uint32_t count = purgeCount[cpup - cpus][col];
817 cacheUnlock (cpup);
818 if (hit) {
819 # if !defined(SPEED)
820
821
822 if (ctx)
823 cpu_watch_read (cpup, real, * data, ctx);
824 # endif
825
826 if (bad)
827 cacheParity (cpup, parityBits (1u << (addr % BLOCK_SZ), (addr % BLOCK_SZ) & ~1u,
828 addr % BLOCK_SZ) | PAR_CACHE_STR, "cache storage parity");
829 return;
830 }
831
832
833
834
835
836
837
838 word24 blk = BLK_ADDR (addr);
839 uint req = (addr % BLOCK_SZ) & 2;
840 uint badWords = badWordsAt (cpup, blk);
841 word36 block[BLOCK_SZ];
842 if (badWords) {
843
844
845 word18 ir = cpu.cu.IR;
846 SETF (cpu.cu.IR, I_PMASK);
847 core_readN (cpup, blk, block, BLOCK_SZ, __func__);
848 cpu.cu.IR = ir;
849 SETF (cpu.cu.IR, I_PERR);
850 if (! (badWords & (3u << req)) && (badWords & (3u << (req ^ 2))) && ! TST_I_PMASK)
851 cpu.cacheParPending = parityBits (badWords, req ^ 2, req ^ 2) | PAR_CACHE_BLK;
852 } else {
853 core_readN (cpup, blk, block, BLOCK_SZ, __func__);
854 }
855 * data = block[addr % BLOCK_SZ];
856
857 word24 cblk = BLK_ADDR (caddr) | (caddr & ABS_KEY);
858 bool keep = (caddr & ABS_KEY) || blockCacheable (cpup, blk, realAddress (cpup, blk));
859
860
861
862
863 int half = -1;
864 if (cpu.currentInstruction.opcode10 == 0674 && cpu.currentInstruction.tag == 02 &&
865 ((* data >> (35 - 19)) & 3) == 0)
866 half = (int) ((addr % BLOCK_SZ) / 2);
867 cacheLock (cpup);
868
869
870 for (int retry = 0; retry < 4 && purgeCount[cpup - cpus][col] != count; retry ++) {
871 count = purgeCount[cpup - cpus][col];
872 cacheUnlock (cpup);
873 if (badWords) {
874 word18 ir = cpu.cu.IR;
875 SETF (cpu.cu.IR, I_PMASK);
876 core_readN (cpup, blk, block, BLOCK_SZ, __func__);
877 cpu.cu.IR = ir;
878 } else {
879 core_readN (cpup, blk, block, BLOCK_SZ, __func__);
880 }
881 cacheLock (cpup);
882 }
883 if (keep && purgeCount[cpup - cpus][col] == count) {
884 dirFill (cpup, cblk, blk, block, mask, half);
885
886
887 if (cpu.MR.separ || badWords) {
888 for (uint l = 0; l < N_LEVELS; l ++) {
889 directory * e = & cpu.directories[col][l];
890 if (e->FE && ! e->badParity && e->key == keyOf (cpup, cblk)) {
891 e->badParity = cpu.MR.separ;
892 e->badWord = (uint8_t) badWords;
893 }
894 }
895 }
896 }
897 cacheUnlock (cpup);
898 if (badWords & (3u << req))
899 cacheParity (cpup, parityBits (badWords, req, addr % BLOCK_SZ), "block load parity");
900 }
901
902 # if defined(CCHECK)
903
904
905
906
907 static void ccheck (cpu_state_t * cpup, word24 addr, word36 data, uint mask, const char * who) {
908 word36 w0, w1, c1;
909 if (nBadParity && cpu.tweaks.tandd_mode)
910 return;
911 core_read (cpup, addr, & w0, __func__);
912 if (w0 == data)
913 return;
914
915
916
917
918
919 for (int i = 0; i < 1000; i ++) {
920 sched_yield ();
921 readThrough (cpup, addr, & c1, mask, NULL);
922 core_read (cpup, addr, & w1, __func__);
923 if (c1 == w1 || w1 != w0 || c1 != data)
924 return;
925 }
926 if (inconsCnt > 0) {
927 inconsCnt --;
928 sim_warn ("%s inconsistent %08o core: %012llo cache: %012llo\r\n", who, addr, w0, data);
929 # if defined(TESTING)
930 hdbgNote (__func__, "%s inconsistent %08o core: %012llo cache: %012llo\r\n", who, addr, w0, data);
931 # endif
932 }
933 }
934 # endif
935
936
937 static void readWord (cpu_state_t * cpup, word24 addr, word36 * data, bool fetch, const char * ctx) {
938 if (! cacheable (cpup, fetch)) {
939 core_read (cpup, addr, data, ctx);
940 return;
941 }
942 uint mask = levelMask (cpup);
943 readThrough (cpup, addr, data, mask, ctx);
944 # if defined(CCHECK)
945 ccheck (cpup, addr, * data, mask, ctx);
946 # endif
947 }
948
949 # if defined(LOCKLESS)
950
951
952
953
954
955 static bool readAndClear (cpu_state_t * cpup) {
956 switch (cpu.currentInstruction.opcode10) {
957 case 0034:
958 case 0032:
959 case 0214:
960 case 0354:
961 case 0654:
962 return true;
963 default:
964 return false;
965 }
966 }
967
968 int cache_read_lock_on (cpu_state_t * cpup, word24 addr, word36 *data, const char * ctx) {
969 (void) takeFetch (cpup);
970 if (! cacheOn (cpup))
971 return core_read_lock (cpup, addr, data, ctx);
972 if (readAndClear (cpup)) {
973 int r = core_read_lock (cpup, addr, data, ctx);
974 startClear (cpup, cacheAddr (cpup, addr, realAddress (cpup, addr)));
975 return r;
976 }
977 if (! cacheable (cpup, false))
978 return core_read_lock (cpup, addr, data, ctx);
979
980
981
982
983 word36 w;
984 int rc = core_read_lock (cpup, addr, & w, ctx);
985 readThrough (cpup, addr, data, levelMask (cpup), ctx);
986 # if defined(CCHECK)
987 if (w != * data && inconsCnt > 0) {
988 inconsCnt --;
989 sim_warn ("cache_read_lock inconsistent %08o core: %012llo cache: %012llo\r\n", addr, w, *data);
990 }
991 # endif
992 return rc;
993 }
994 # endif
995
996
997
998
999
1000
1001 int cache_read_on (cpu_state_t * cpup, word24 addr, word36 *data, const char * ctx) {
1002 bool fetch = takeFetch (cpup);
1003 readWord (cpup, addr, data, fetch, ctx);
1004 return 0;
1005 }
1006
1007
1008 int cache_read2_on (cpu_state_t * cpup, word24 addr, word36 *even, word36 *odd, const char * ctx) {
1009 bool fetch = takeFetch (cpup);
1010 addr &= (word24) ~1;
1011 if (dumpMode (cpup, fetch)) {
1012 dumpRead (cpup, addr, even, odd);
1013 return 0;
1014 }
1015 if (! cacheable (cpup, fetch))
1016 return core_read2 (cpup, addr, even, odd, ctx);
1017 readWord (cpup, addr, even, fetch, ctx);
1018 readWord (cpup, addr + 1, odd, fetch, ctx);
1019 return 0;
1020 }
1021
1022
1023 void cache_readN_on (cpu_state_t * cpup, word24 addr, word36 * data, uint n, UNUSED const char * ctx) {
1024 bool fetch = takeFetch (cpup);
1025 if (n == 2 && dumpMode (cpup, fetch)) {
1026 dumpRead (cpup, addr & (word24) ~1, data, data + 1);
1027 return;
1028 }
1029 if (! cacheable (cpup, fetch)) {
1030 core_readN (cpup, addr, data, n, ctx);
1031 return;
1032 }
1033 for (uint i = 0; i < n; i ++)
1034 readWord (cpup, addr + i, data + i, fetch, ctx);
1035 }
1036
1037
1038 void cache_writeN_on (cpu_state_t * cpup, word24 addr, word36 * data, uint n, UNUSED const char * ctx) {
1039 if (n == 2)
1040 dirReadout (cpup, addr, data + 1);
1041 for (uint i = 0; i < n; i ++)
1042 (void) cache_write (cpup, addr + i, data[i], ctx);
1043 }
1044
1045
1046 int cache_write2_on (cpu_state_t * cpup, word24 addr, word36 even, word36 odd, const char * ctx) {
1047 dirReadout (cpup, addr, & odd);
1048 return core_write2 (cpup, addr, even, odd, ctx);
1049 }
1050
1051 #endif