gem5  v19.0.0.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
smmu_v3_caches.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014, 2018-2019 ARM Limited
3  * All rights reserved
4  *
5  * The license below extends only to copyright in the software and shall
6  * not be construed as granting a license to any other intellectual
7  * property including but not limited to intellectual property relating
8  * to a hardware implementation of the functionality of the software
9  * licensed hereunder. You may use the software subject to the license
10  * terms below provided that you ensure that this notice is replicated
11  * unmodified and in its entirety in all distributions of the software,
12  * modified or unmodified, in source code or in binary form.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions are
16  * met: redistributions of source code must retain the above copyright
17  * notice, this list of conditions and the following disclaimer;
18  * redistributions in binary form must reproduce the above copyright
19  * notice, this list of conditions and the following disclaimer in the
20  * documentation and/or other materials provided with the distribution;
21  * neither the name of the copyright holders nor the names of its
22  * contributors may be used to endorse or promote products derived from
23  * this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  *
37  * Authors: Stan Czerniawski
38  * Damian Richardson
39  */
40 
42 
43 #include <numeric>
44 
45 #include "base/bitfield.hh"
46 #include "base/intmath.hh"
47 #include "base/logging.hh"
48 #include "sim/stats.hh"
49 
50 
51 // taken from hex expansion of pi
52 #define SMMUTLB_SEED 0xEA752DFE
53 #define ARMARCHTLB_SEED 0x8B021FA1
54 #define IPACACHE_SEED 0xE5A0CC0F
55 #define CONFIGCACHE_SEED 0xB56F74E8
56 #define WALKCACHE_SEED 0x18ACF3D6
57 
58 /*
59  * BaseCache
60  *
61  * TODO: move more code into this base class to reduce duplication.
62  */
63 
64 SMMUv3BaseCache::SMMUv3BaseCache(const std::string &policy_name, uint32_t seed) :
65  replacementPolicy(decodePolicyName(policy_name)),
66  nextToReplace(0),
67  random(seed),
68  useStamp(0)
69 {}
70 
71 int
72 SMMUv3BaseCache::decodePolicyName(const std::string &policy_name)
73 {
74  if (policy_name == "rr") {
76  } else if (policy_name == "rand") {
78  } else if (policy_name == "lru") {
79  return SMMU_CACHE_REPL_LRU;
80  } else {
81  panic("Unknown cache replacement policy '%s'\n", policy_name);
82  }
83 }
84 
85 void
86 SMMUv3BaseCache::regStats(const std::string &name)
87 {
88  using namespace Stats;
89 
90 
92  .name(name + ".averageLookups")
93  .desc("Average number lookups per second")
94  .flags(pdf);
95 
97  .name(name + ".totalLookups")
98  .desc("Total number of lookups")
99  .flags(pdf);
100 
102 
103 
105  .name(name + ".averageMisses")
106  .desc("Average number misses per second")
107  .flags(pdf);
108 
110  .name(name + ".totalMisses")
111  .desc("Total number of misses")
112  .flags(pdf);
113 
115 
116 
118  .name(name + ".averageUpdates")
119  .desc("Average number updates per second")
120  .flags(pdf);
121 
123  .name(name + ".totalUpdates")
124  .desc("Total number of updates")
125  .flags(pdf);
126 
128 
129 
131  .name(name + ".averageHitRate")
132  .desc("Average hit rate")
133  .flags(pdf);
134 
136 
137  insertions
138  .name(name + ".insertions")
139  .desc("Number of insertions (not replacements)")
140  .flags(pdf);
141 }
142 
143 
144 
145 /*
146  * SMMUTLB
147  */
148 
149 SMMUTLB::SMMUTLB(unsigned numEntries, unsigned _associativity,
150  const std::string &policy)
151 :
152  SMMUv3BaseCache(policy, SMMUTLB_SEED),
153  associativity(_associativity)
154 {
155  if (associativity == 0)
156  associativity = numEntries; // fully associative
157 
158  if (numEntries == 0)
159  fatal("SMMUTLB must have at least one entry\n");
160 
161  if (associativity > numEntries)
162  fatal("SMMUTLB associativity cannot be higher than "
163  "its number of entries\n");
164 
165  unsigned num_sets = numEntries / associativity;
166 
167  if (num_sets*associativity != numEntries)
168  fatal("Number of SMMUTLB entries must be divisible "
169  "by its associativity\n");
170 
171  Entry e;
172  e.valid = false;
173 
174  Set set(associativity, e);
175  sets.resize(num_sets, set);
176 }
177 
178 const SMMUTLB::Entry*
179 SMMUTLB::lookup(uint32_t sid, uint32_t ssid,
180  Addr va, bool updStats)
181 {
182  const Entry *result = NULL;
183 
184  Set &set = sets[pickSetIdx(va)];
185 
186  for (size_t i = 0; i < set.size(); i++) {
187  const Entry &e = set[i];
188 
189  if (e.valid && (e.va & e.vaMask) == (va & e.vaMask) &&
190  e.sid==sid && e.ssid==ssid)
191  {
192  if (result != NULL)
193  panic("SMMUTLB: duplicate entry found!\n");
194 
195  result = &e;
196  break;
197  }
198  }
199 
200  if (updStats) {
201  if (result)
202  result->lastUsed = useStamp++;
203 
204  totalLookups++;
205  if (result == NULL)
206  totalMisses++;
207  }
208 
209  return result;
210 }
211 
212 const SMMUTLB::Entry*
213 SMMUTLB::lookupAnyVA(uint32_t sid, uint32_t ssid, bool updStats)
214 {
215  const Entry *result = NULL;
216 
217  for (size_t s = 0; s < sets.size(); s++) {
218  Set &set = sets[s];
219 
220  for (size_t i = 0; i < set.size(); i++) {
221  const Entry &e = set[i];
222 
223  if (e.valid && e.sid==sid && e.ssid==ssid) {
224  result = &e;
225  break;
226  }
227  }
228  }
229 
230  if (updStats) {
231  totalLookups++;
232  if (result == NULL)
233  totalMisses++;
234  }
235 
236  return result;
237 }
238 
239 void
240 SMMUTLB::store(const Entry &incoming, AllocPolicy alloc)
241 {
242  if (!incoming.valid)
243  panic("Tried to store an invalid entry\n");
244 
245  incoming.lastUsed = 0;
246 
247  const Entry *existing =
248  lookup(incoming.sid, incoming.ssid, incoming.va, false);
249 
250  if (existing) {
251  *const_cast<Entry *> (existing) = incoming;
252  } else {
253  Set &set = sets[pickSetIdx(incoming.va)];
254  set[pickEntryIdxToReplace(set, alloc)] = incoming;
255  }
256 
257  totalUpdates++;
258 }
259 
260 void
261 SMMUTLB::invalidateSSID(uint32_t sid, uint32_t ssid)
262 {
263  Set &set = sets[pickSetIdx(sid, ssid)];
264 
265  for (size_t i = 0; i < set.size(); i++) {
266  Entry &e = set[i];
267 
268  if (e.sid == sid && e.ssid == ssid)
269  e.valid = false;
270  }
271 }
272 
273 void
275 {
276  for (size_t s = 0; s < sets.size(); s++) {
277  Set &set = sets[s];
278 
279  for (size_t i = 0; i < set.size(); i++) {
280  Entry &e = set[i];
281 
282  if (e.sid == sid)
283  e.valid = false;
284  }
285  }
286 }
287 
288 void
289 SMMUTLB::invalidateVA(Addr va, uint16_t asid, uint16_t vmid)
290 {
291  Set &set = sets[pickSetIdx(va)];
292 
293  for (size_t i = 0; i < set.size(); i++) {
294  Entry &e = set[i];
295 
296  if ((e.va & e.vaMask) == (va & e.vaMask) &&
297  e.asid==asid && e.vmid==vmid)
298  {
299  e.valid = false;
300  }
301  }
302 }
303 
304 void
306 {
307  Set &set = sets[pickSetIdx(va)];
308 
309  for (size_t i = 0; i < set.size(); i++) {
310  Entry &e = set[i];
311 
312  if ((e.va & e.vaMask) == (va & e.vaMask) && e.vmid==vmid)
313  e.valid = false;
314  }
315 }
316 
317 void
318 SMMUTLB::invalidateASID(uint16_t asid, uint16_t vmid)
319 {
320  for (size_t s = 0; s < sets.size(); s++) {
321  Set &set = sets[s];
322 
323  for (size_t i = 0; i < set.size(); i++) {
324  Entry &e = set[i];
325 
326  if (e.asid==asid && e.vmid==vmid)
327  e.valid = false;
328  }
329  }
330 }
331 
332 void
334 {
335  for (size_t s = 0; s < sets.size(); s++) {
336  Set &set = sets[s];
337 
338  for (size_t i = 0; i < set.size(); i++) {
339  Entry &e = set[i];
340 
341  if (e.vmid == vmid)
342  e.valid = false;
343  }
344  }
345 }
346 
347 void
349 {
350  for (size_t s = 0; s < sets.size(); s++) {
351  Set &set = sets[s];
352 
353  for (size_t i = 0; i < set.size(); i++)
354  set[i].valid = false;
355  }
356 }
357 
358 size_t
360 {
361  return (va >> 12) % sets.size();
362 }
363 
364 size_t
365 SMMUTLB::pickSetIdx(uint32_t sid, uint32_t ssid) const
366 {
367  return (sid^ssid) % sets.size();
368 }
369 
370 size_t
372 {
373  if (alloc == ALLOC_LAST_WAY)
374  return associativity - 1;
375 
376  uint32_t lru_tick = UINT32_MAX;
377  size_t lru_idx = 0;
378  size_t max_idx =
379  alloc==ALLOC_ANY_BUT_LAST_WAY ?
380  set.size()-1 : set.size();
381 
382  for (size_t i = 0; i < max_idx; i++) {
383  if (!set[i].valid) {
384  insertions++;
385  return i;
386  }
387 
388  if (set[i].lastUsed < lru_tick) {
389  lru_idx = i;
390  lru_tick = set[i].lastUsed;
391  }
392  }
393 
394  switch (replacementPolicy) {
396  switch (alloc) {
397  case ALLOC_ANY_WAY:
398  return nextToReplace = ((nextToReplace+1) % associativity);
400  return nextToReplace = ((nextToReplace+1) % (associativity-1));
401  default:
402  panic("Unknown allocation mode %d\n", alloc);
403  }
404 
406  switch (alloc) {
407  case ALLOC_ANY_WAY:
408  return random.random<size_t>(0, associativity-1);
410  return random.random<size_t>(0, associativity-2);
411  default:
412  panic("Unknown allocation mode %d\n", alloc);
413  }
414 
415  case SMMU_CACHE_REPL_LRU:
416  return lru_idx;
417 
418  default:
419  panic("Unknown replacement policy %d\n", replacementPolicy);
420  }
421 }
422 
423 
424 
425 /*
426  * ARMArchTLB
427  */
428 
429 ARMArchTLB::ARMArchTLB(unsigned numEntries, unsigned _associativity,
430  const std::string &policy)
431 :
433  associativity(_associativity)
434 {
435  if (associativity == 0)
436  associativity = numEntries; // fully associative
437 
438  if (numEntries == 0)
439  fatal("ARMArchTLB must have at least one entry\n");
440 
441  if (associativity > numEntries)
442  fatal("ARMArchTLB associativity cannot be higher than "
443  "its number of entries\n");
444 
445  unsigned num_sets = numEntries / associativity;
446 
447  if (num_sets*associativity != numEntries)
448  fatal("Number of ARMArchTLB entries must be divisible "
449  "by its associativity\n");
450 
451  Entry e;
452  e.valid = false;
453 
454  Set set(associativity, e);
455  sets.resize(num_sets, set);
456 }
457 
458 const ARMArchTLB::Entry *
459 ARMArchTLB::lookup(Addr va, uint16_t asid, uint16_t vmid, bool updStats)
460 {
461  const Entry *result = NULL;
462 
463  Set &set = sets[pickSetIdx(va, asid, vmid)];
464 
465  for (size_t i = 0; i < set.size(); i++) {
466  const Entry &e = set[i];
467 
468  if (e.valid && (e.va & e.vaMask) == (va & e.vaMask) &&
469  e.asid==asid && e.vmid==vmid)
470  {
471  if (result != NULL)
472  panic("ARMArchTLB: duplicate entry found!\n");
473 
474  result = &e;
475  break;
476  }
477  }
478 
479  if (updStats) {
480  if (result)
481  result->lastUsed = useStamp++;
482 
483  totalLookups++;
484  if (result == NULL)
485  totalMisses++;
486  }
487 
488  return result;
489 }
490 
491 void
492 ARMArchTLB::store(const Entry &incoming)
493 {
494  if (!incoming.valid)
495  panic("Tried to store an invalid entry\n");
496 
497  incoming.lastUsed = 0;
498 
499  const Entry *existing =
500  lookup(incoming.va, incoming.asid, incoming.vmid, false);
501 
502  if (existing) {
503  *const_cast<Entry *> (existing) = incoming;
504  } else {
505  Set &set = sets[pickSetIdx(incoming.va, incoming.asid, incoming.vmid)];
506  set[pickEntryIdxToReplace(set)] = incoming;
507  }
508 
509  totalUpdates++;
510 }
511 
512 void
513 ARMArchTLB::invalidateVA(Addr va, uint16_t asid, uint16_t vmid)
514 {
515  Set &set = sets[pickSetIdx(va, asid, vmid)];
516 
517  for (size_t i = 0; i < set.size(); i++) {
518  Entry &e = set[i];
519 
520  if ((e.va & e.vaMask) == (va & e.vaMask) &&
521  e.asid==asid && e.vmid==vmid)
522  {
523  e.valid = false;
524  }
525  }
526 }
527 
528 void
530 {
531  for (size_t s = 0; s < sets.size(); s++) {
532  Set &set = sets[s];
533 
534  for (size_t i = 0; i < set.size(); i++) {
535  Entry &e = set[i];
536 
537  if ((e.va & e.vaMask) == (va & e.vaMask) && e.vmid==vmid)
538  e.valid = false;
539  }
540  }
541 }
542 
543 void
544 ARMArchTLB::invalidateASID(uint16_t asid, uint16_t vmid)
545 {
546  for (size_t s = 0; s < sets.size(); s++) {
547  Set &set = sets[s];
548 
549  for (size_t i = 0; i < set.size(); i++) {
550  Entry &e = set[i];
551 
552  if (e.asid==asid && e.vmid==vmid)
553  e.valid = false;
554  }
555  }
556 }
557 
558 void
560 {
561  for (size_t s = 0; s < sets.size(); s++) {
562  Set &set = sets[s];
563 
564  for (size_t i = 0; i < set.size(); i++) {
565  Entry &e = set[i];
566 
567  if (e.vmid == vmid)
568  e.valid = false;
569  }
570  }
571 }
572 
573 void
575 {
576  for (size_t s = 0; s < sets.size(); s++) {
577  Set &set = sets[s];
578 
579  for (size_t i = 0; i < set.size(); i++)
580  set[i].valid = false;
581  }
582 }
583 
584 size_t
585 ARMArchTLB::pickSetIdx(Addr va, uint16_t asid, uint16_t vmid) const
586 {
587  return ((va >> 12) ^ asid ^ vmid) % sets.size();
588 }
589 
590 size_t
592 {
593  size_t lru_idx = 0;
594  uint32_t lru_tick = UINT32_MAX;
595 
596  for (size_t i = 0; i < set.size(); i++) {
597  if (!set[i].valid) {
598  insertions++;
599  return i;
600  }
601 
602  if (set[i].lastUsed < lru_tick) {
603  lru_idx = i;
604  lru_tick = set[i].lastUsed;
605  }
606  }
607 
608  switch (replacementPolicy) {
610  return nextToReplace = ((nextToReplace+1) % associativity);
611 
613  return random.random<size_t>(0, associativity-1);
614 
615  case SMMU_CACHE_REPL_LRU:
616  return lru_idx;
617 
618  default:
619  panic("Unknown replacement policy %d\n", replacementPolicy);
620  }
621 
622 }
623 
624 /*
625  * IPACache
626  */
627 
628 IPACache::IPACache(unsigned numEntries, unsigned _associativity,
629  const std::string &policy)
630 :
632  associativity(_associativity)
633 {
634  if (associativity == 0)
635  associativity = numEntries; // fully associative
636 
637  if (numEntries == 0)
638  fatal("IPACache must have at least one entry\n");
639 
640  if (associativity > numEntries)
641  fatal("IPACache associativity cannot be higher than "
642  "its number of entries\n");
643 
644  unsigned num_sets = numEntries / associativity;
645 
646  if (num_sets*associativity != numEntries)
647  fatal("Number of IPACache entries must be divisible "
648  "by its associativity\n");
649 
650  Entry e;
651  e.valid = false;
652 
653  Set set(associativity, e);
654  sets.resize(num_sets, set);
655 }
656 
657 const IPACache::Entry*
658 IPACache::lookup(Addr ipa, uint16_t vmid, bool updStats)
659 {
660  const Entry *result = NULL;
661 
662  Set &set = sets[pickSetIdx(ipa, vmid)];
663 
664  for (size_t i = 0; i < set.size(); i++) {
665  const Entry &e = set[i];
666 
667  if (e.valid && (e.ipa & e.ipaMask) == (ipa & e.ipaMask) &&
668  e.vmid==vmid)
669  {
670  if (result != NULL)
671  panic("IPACache: duplicate entry found!\n");
672 
673  result = &e;
674  break;
675  }
676  }
677 
678  if (updStats) {
679  if (result)
680  result->lastUsed = useStamp++;
681 
682  totalLookups++;
683  if (result == NULL)
684  totalMisses++;
685  }
686 
687  return result;
688 }
689 
690 void
691 IPACache::store(const Entry &incoming)
692 {
693  if (!incoming.valid)
694  panic("Tried to store an invalid entry\n");
695 
696  incoming.lastUsed = 0;
697 
698  const Entry *existing = lookup(incoming.ipa, incoming.vmid, false);
699 
700  if (existing) {
701  *const_cast<Entry *> (existing) = incoming;
702  } else {
703  Set &set = sets[pickSetIdx(incoming.ipa, incoming.vmid)];
704  set[pickEntryIdxToReplace(set)] = incoming;
705  }
706 
707  totalUpdates++;
708 }
709 
710 void
711 IPACache::invalidateIPA(Addr ipa, uint16_t vmid)
712 {
713  Set &set = sets[pickSetIdx(ipa, vmid)];
714 
715  for (size_t i = 0; i < set.size(); i++) {
716  Entry &e = set[i];
717 
718  if ((e.ipa & e.ipaMask) == (ipa & e.ipaMask) && e.vmid==vmid)
719  e.valid = false;
720  }
721 }
722 
723 void
725 {
726  for (size_t s = 0; s < sets.size(); s++) {
727  Set &set = sets[s];
728 
729  for (size_t i = 0; i < set.size(); i++) {
730  Entry &e = set[i];
731 
732  if ((e.ipa & e.ipaMask) == (ipa & e.ipaMask))
733  e.valid = false;
734  }
735  }
736 }
737 
738 void
740 {
741  for (size_t s = 0; s < sets.size(); s++) {
742  Set &set = sets[s];
743 
744  for (size_t i = 0; i < set.size(); i++) {
745  Entry &e = set[i];
746 
747  if (e.vmid == vmid)
748  e.valid = false;
749  }
750  }
751 }
752 
753 void
755 {
756  for (size_t s = 0; s < sets.size(); s++) {
757  Set &set = sets[s];
758 
759  for (size_t i = 0; i < set.size(); i++)
760  set[i].valid = false;
761  }
762 }
763 
764 size_t
765 IPACache::pickSetIdx(Addr va, uint16_t vmid) const
766 {
767  return ((va >> 12) ^ vmid) % sets.size();
768 }
769 
770 size_t
772 {
773  size_t lru_idx = 0;
774  uint32_t lru_tick = UINT32_MAX;
775 
776  for (size_t i = 0; i < set.size(); i++) {
777  if (!set[i].valid) {
778  insertions++;
779  return i;
780  }
781 
782  if (set[i].lastUsed < lru_tick) {
783  lru_idx = i;
784  lru_tick = set[i].lastUsed;
785  }
786  }
787 
788  switch (replacementPolicy) {
790  return nextToReplace = ((nextToReplace+1) % associativity);
791 
793  return random.random<size_t>(0, associativity-1);
794 
795  case SMMU_CACHE_REPL_LRU:
796  return lru_idx;
797 
798  default:
799  panic("Unknown replacement policy %d\n", replacementPolicy);
800  }
801 
802 }
803 
804 /*
805  * ConfigCache
806  */
807 
808 ConfigCache::ConfigCache(unsigned numEntries, unsigned _associativity,
809  const std::string &policy)
810 :
812  associativity(_associativity)
813 {
814  if (associativity == 0)
815  associativity = numEntries; // fully associative
816 
817  if (numEntries == 0)
818  fatal("ConfigCache must have at least one entry\n");
819 
820  if (associativity > numEntries)
821  fatal("ConfigCache associativity cannot be higher than "
822  "its number of entries\n");
823 
824  unsigned num_sets = numEntries / associativity;
825 
826  if (num_sets*associativity != numEntries)
827  fatal("Number of ConfigCache entries must be divisible "
828  "by its associativity\n");
829 
830  Entry e;
831  e.valid = false;
832 
833  Set set(associativity, e);
834  sets.resize(num_sets, set);
835 }
836 
837 const ConfigCache::Entry *
838 ConfigCache::lookup(uint32_t sid, uint32_t ssid, bool updStats)
839 {
840  const Entry *result = NULL;
841 
842  Set &set = sets[pickSetIdx(sid, ssid)];
843 
844  for (size_t i = 0; i < set.size(); i++) {
845  const Entry &e = set[i];
846 
847  if (e.valid && e.sid==sid && e.ssid==ssid)
848  {
849  if (result != NULL)
850  panic("ConfigCache: duplicate entry found!\n");
851 
852  result = &e;
853  break;
854  }
855  }
856 
857  if (updStats) {
858  if (result)
859  result->lastUsed = useStamp++;
860 
861  totalLookups++;
862  if (result == NULL)
863  totalMisses++;
864  }
865 
866  return result;
867 }
868 
869 void
870 ConfigCache::store(const Entry &incoming)
871 {
872  if (!incoming.valid)
873  panic("Tried to store an invalid entry\n");
874 
875  incoming.lastUsed = 0;
876 
877  const Entry *existing = lookup(incoming.sid, incoming.ssid, false);
878 
879  if (existing) {
880  *const_cast<Entry *> (existing) = incoming;
881  } else {
882  Set &set = sets[pickSetIdx(incoming.sid, incoming.ssid)];
883  set[pickEntryIdxToReplace(set)] = incoming;
884  }
885 
886  totalUpdates++;
887 }
888 
889 void
890 ConfigCache::invalidateSSID(uint32_t sid, uint32_t ssid)
891 {
892  Set &set = sets[pickSetIdx(sid, ssid)];
893 
894  for (size_t i = 0; i < set.size(); i++) {
895  Entry &e = set[i];
896 
897  if (e.sid==sid && e.ssid==ssid)
898  e.valid = false;
899  }
900 }
901 
902 void
904 {
905  for (size_t s = 0; s < sets.size(); s++) {
906  Set &set = sets[s];
907 
908  for (size_t i = 0; i < set.size(); i++) {
909  Entry &e = set[i];
910 
911  if (e.sid == sid)
912  e.valid = false;
913  }
914  }
915 }
916 
917 void
919 {
920  for (size_t s = 0; s < sets.size(); s++) {
921  Set &set = sets[s];
922 
923  for (size_t i = 0; i < set.size(); i++)
924  set[i].valid = false;
925  }
926 }
927 
928 size_t
929 ConfigCache::pickSetIdx(uint32_t sid, uint32_t ssid) const
930 {
931  return (sid^ssid) % sets.size();
932 }
933 
934 size_t
936 {
937  size_t lru_idx = 0;
938  uint32_t lru_tick = UINT32_MAX;
939 
940  for (size_t i = 0; i < set.size(); i++) {
941  if (!set[i].valid) {
942  insertions++;
943  return i;
944  }
945 
946  if (set[i].lastUsed < lru_tick) {
947  lru_idx = i;
948  lru_tick = set[i].lastUsed;
949  }
950  }
951 
952  switch (replacementPolicy) {
954  return nextToReplace = ((nextToReplace+1) % associativity);
955 
957  return random.random<size_t>(0, associativity-1);
958 
959  case SMMU_CACHE_REPL_LRU:
960  return lru_idx;
961 
962  default:
963  panic("Unknown replacement policy %d\n", replacementPolicy);
964  }
965 
966 }
967 
968 /*
969  * WalkCache
970  */
971 
972 WalkCache::WalkCache(const std::array<unsigned, 2*WALK_CACHE_LEVELS> &_sizes,
973  unsigned _associativity, const std::string &policy) :
975  associativity(_associativity),
976  sizes()
977 {
978  unsigned numEntries = std::accumulate(&_sizes[0],
979  &_sizes[2*WALK_CACHE_LEVELS], 0);
980 
981  if (associativity == 0)
982  associativity = numEntries; // fully associative
983 
984  if (numEntries == 0)
985  fatal("WalkCache must have at least one entry\n");
986 
987  for (size_t i = 0; i < 2*WALK_CACHE_LEVELS; i++){
988  if (_sizes[i] % associativity != 0)
989  fatal("Number of WalkCache entries at each level must be "
990  "divisible by WalkCache associativity\n");
991 
992  sizes[i] = _sizes[i] / associativity;
993  offsets[i] = i==0 ? 0 : offsets[i-1] + sizes[i-1];
994  }
995 
996  if (associativity > numEntries)
997  fatal("WalkCache associativity cannot be higher than "
998  "its number of entries\n");
999 
1000  unsigned num_sets = numEntries / associativity;
1001 
1002  if (num_sets*associativity != numEntries)
1003  fatal("Number of WalkCache entries must be divisible "
1004  "by its associativity\n");
1005 
1006  Entry e;
1007  e.valid = false;
1008 
1009  Set set(associativity, e);
1010  sets.resize(num_sets, set);
1011 }
1012 
1013 const WalkCache::Entry*
1015  uint16_t asid, uint16_t vmid,
1016  unsigned stage, unsigned level,
1017  bool updStats)
1018 {
1019  const Entry *result = NULL;
1020 
1021  Set &set = sets[pickSetIdx(va, vaMask, stage, level)];
1022 
1023  for (size_t i = 0; i < set.size(); i++) {
1024  const Entry &e = set[i];
1025 
1026  if (e.valid && (e.va & e.vaMask) == (va & e.vaMask) &&
1027  e.asid==asid && e.vmid==vmid && e.stage==stage && e.level==level)
1028  {
1029  if (result != NULL)
1030  panic("WalkCache: duplicate entry found!\n");
1031 
1032  result = &e;
1033  break;
1034  }
1035  }
1036 
1037  if (updStats) {
1038  if (result)
1039  result->lastUsed = useStamp++;
1040 
1041  totalLookups++;
1042  if (result == NULL)
1043  totalMisses++;
1044 
1045  lookupsByStageLevel[stage-1][level]++;
1046  totalLookupsByStageLevel[stage-1][level]++;
1047  if (result == NULL) {
1048  missesByStageLevel[stage-1][level]++;
1049  totalMissesByStageLevel[stage-1][level]++;
1050  }
1051  }
1052 
1053  return result;
1054 }
1055 
1056 void
1057 WalkCache::store(const Entry &incoming)
1058 {
1059  if (!incoming.valid)
1060  panic("Tried to store an invalid entry\n");
1061 
1062  assert(incoming.stage==1 || incoming.stage==2);
1063  assert(incoming.level<=WALK_CACHE_LEVELS);
1064 
1065  incoming.lastUsed = 0;
1066 
1067  const Entry *existing = lookup(incoming.va, incoming.vaMask,
1068  incoming.asid, incoming.vmid,
1069  incoming.stage, incoming.level, false);
1070 
1071  if (existing) {
1072  *const_cast<Entry *> (existing) = incoming;
1073  } else {
1074  Set &set = sets[pickSetIdx(incoming.va, incoming.vaMask,
1075  incoming.stage, incoming.level)];
1076  set[pickEntryIdxToReplace(set, incoming.stage, incoming.level)] =
1077  incoming;
1078  }
1079 
1080  totalUpdates++;
1081  updatesByStageLevel[incoming.stage-1][incoming.level]++;
1082  totalUpdatesByStageLevel[incoming.stage-1][incoming.level]++;
1083 }
1084 
1085 void
1086 WalkCache::invalidateVA(Addr va, uint16_t asid, uint16_t vmid,
1087  const bool leaf_only)
1088 {
1089  for (size_t s = 0; s < sets.size(); s++) {
1090  Set &set = sets[s];
1091 
1092  for (size_t i = 0; i < set.size(); i++) {
1093  Entry &e = set[i];
1094 
1095  if ((!leaf_only || e.leaf) && (e.va & e.vaMask) == (va & e.vaMask)
1096  && e.asid == asid && e.vmid == vmid)
1097  {
1098  e.valid = false;
1099  }
1100  }
1101  }
1102 }
1103 
1104 void
1105 WalkCache::invalidateVAA(Addr va, uint16_t vmid, const bool leaf_only)
1106 {
1107  for (size_t s = 0; s < sets.size(); s++) {
1108  Set &set = sets[s];
1109 
1110  for (size_t i = 0; i < set.size(); i++) {
1111  Entry &e = set[i];
1112 
1113  if ((!leaf_only || e.leaf) && (e.va & e.vaMask) == (va & e.vaMask)
1114  && e.vmid == vmid)
1115  {
1116  e.valid = false;
1117  }
1118  }
1119  }
1120 }
1121 
1122 void
1123 WalkCache::invalidateASID(uint16_t asid, uint16_t vmid)
1124 {
1125  for (size_t s = 0; s < sets.size(); s++) {
1126  Set &set = sets[s];
1127 
1128  for (size_t i = 0; i < set.size(); i++) {
1129  Entry &e = set[i];
1130 
1131  if (e.asid==asid && e.vmid==vmid)
1132  e.valid = false;
1133  }
1134  }
1135 }
1136 
1137 void
1139 {
1140  for (size_t s = 0; s < sets.size(); s++) {
1141  Set &set = sets[s];
1142 
1143  for (size_t i = 0; i < set.size(); i++) {
1144  Entry &e = set[i];
1145 
1146  if (e.vmid == vmid)
1147  e.valid = false;
1148  }
1149  }
1150 }
1151 
1152 void
1154 {
1155  for (size_t s = 0; s < sets.size(); s++) {
1156  Set &set = sets[s];
1157 
1158  for (size_t i = 0; i < set.size(); i++)
1159  set[i].valid = false;
1160  }
1161 }
1162 
1163 size_t
1165  unsigned stage, unsigned level) const
1166 {
1167  (void) stage;
1168 
1169  int size, offset;
1170 
1171  switch (stage) {
1172  case 1:
1173  assert (level<=3);
1174  size = sizes[0*WALK_CACHE_LEVELS + level];
1175  offset = offsets[0*WALK_CACHE_LEVELS + level];
1176  break;
1177 
1178  case 2:
1179  assert (level<=3);
1180  size = sizes[1*WALK_CACHE_LEVELS + level];
1181  offset = offsets[1*WALK_CACHE_LEVELS + level];
1182  break;
1183 
1184  default:
1185  panic("bad stage");
1186  }
1187 
1188  return ((va >> findLsbSet(vaMask)) % size) + offset;
1189 }
1190 
1191 size_t
1193  unsigned stage, unsigned level)
1194 {
1195  size_t lru_idx = 0;
1196  uint32_t lru_tick = UINT32_MAX;
1197 
1198  for (size_t i = 0; i < set.size(); i++) {
1199  if (!set[i].valid) {
1200  insertions++;
1201  insertionsByStageLevel[stage-1][level]++;
1202  return i;
1203  }
1204 
1205  if (set[i].lastUsed < lru_tick) {
1206  lru_idx = i;
1207  lru_tick = set[i].lastUsed;
1208  }
1209  }
1210 
1211  switch (replacementPolicy) {
1213  return nextToReplace = ((nextToReplace+1) % associativity);
1214 
1216  return random.random<size_t>(0, associativity-1);
1217 
1218  case SMMU_CACHE_REPL_LRU:
1219  return lru_idx;
1220 
1221  default:
1222  panic("Unknown replacement policy %d\n", replacementPolicy);
1223  }
1224 
1225 }
1226 
1227 void
1228 WalkCache::regStats(const std::string &name)
1229 {
1230  using namespace Stats;
1231 
1233 
1234  for (int s = 0; s < 2; s++) {
1235  for (int l = 0; l < WALK_CACHE_LEVELS; l++) {
1237  .name(csprintf("%s.averageLookupsS%dL%d", name, s+1, l))
1238  .desc("Average number lookups per second")
1239  .flags(pdf);
1240 
1242  .name(csprintf("%s.totalLookupsS%dL%d", name, s+1, l))
1243  .desc("Total number of lookups")
1244  .flags(pdf);
1245 
1248 
1249 
1251  .name(csprintf("%s.averageMissesS%dL%d", name, s+1, l))
1252  .desc("Average number misses per second")
1253  .flags(pdf);
1254 
1256  .name(csprintf("%s.totalMissesS%dL%d", name, s+1, l))
1257  .desc("Total number of misses")
1258  .flags(pdf);
1259 
1262 
1263 
1265  .name(csprintf("%s.averageUpdatesS%dL%d", name, s+1, l))
1266  .desc("Average number updates per second")
1267  .flags(pdf);
1268 
1270  .name(csprintf("%s.totalUpdatesS%dL%d", name, s+1, l))
1271  .desc("Total number of updates")
1272  .flags(pdf);
1273 
1276 
1277 
1279  .name(csprintf("%s.averageHitRateS%dL%d", name, s+1, l))
1280  .desc("Average hit rate")
1281  .flags(pdf);
1282 
1287 
1289  .name(csprintf("%s.insertionsS%dL%d", name, s+1, l))
1290  .desc("Number of insertions (not replacements)")
1291  .flags(pdf);
1292  }
1293  }
1294 }
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:167
void invalidateSID(uint32_t sid)
const FlagsType pdf
Print the percent of the total that this entry represents.
Definition: info.hh:53
Stats::Formula averageMissesByStageLevel[2][WALK_CACHE_LEVELS]
#define SMMUTLB_SEED
int findLsbSet(uint64_t val)
Returns the bit position of the LSB that is set in the input.
Definition: bitfield.hh:221
void store(const Entry &incoming, AllocPolicy alloc)
size_t pickSetIdx(Addr ipa, uint16_t vmid) const
Stats::Scalar insertions
std::vector< Set > sets
void invalidateVAA(Addr va, uint16_t vmid, const bool leaf_only)
#define IPACACHE_SEED
#define fatal(...)
This implements a cprintf based fatal() function.
Definition: logging.hh:175
const std::string & name()
Definition: trace.cc:54
Bitfield< 7 > i
const Entry * lookup(uint32_t sid, uint32_t ssid, Addr va, bool updStats=true)
void invalidateVMID(uint16_t vmid)
void invalidateAll()
unsigned int lookupsByStageLevel[2][WALK_CACHE_LEVELS]
const Entry * lookup(Addr ipa, uint16_t vmid, bool updStats=true)
void store(const Entry &incoming)
std::array< unsigned, 2 *WALK_CACHE_LEVELS > offsets
void invalidateVMID(uint16_t vmid)
size_t pickEntryIdxToReplace(const Set &set)
void invalidateASID(uint16_t asid, uint16_t vmid)
void invalidateSSID(uint32_t sid, uint32_t ssid)
Bitfield< 23, 0 > offset
Definition: types.hh:154
void invalidateVA(Addr va, uint16_t asid, uint16_t vmid)
Stats::Formula averageUpdatesByStageLevel[2][WALK_CACHE_LEVELS]
void invalidateVA(Addr va, uint16_t asid, uint16_t vmid, const bool leaf_only)
size_t pickEntryIdxToReplace(const Set &set, AllocPolicy alloc)
Derived & flags(Flags _flags)
Set the flags and marks this stat to print at the end of simulation.
Definition: statistics.hh:336
Stats::Scalar totalMissesByStageLevel[2][WALK_CACHE_LEVELS]
Stats::Formula simSeconds
Definition: stat_control.cc:64
std::vector< Set > sets
void invalidateVAA(Addr va, uint16_t vmid)
size_t associativity
std::enable_if< std::is_integral< T >::value, T >::type random()
Use the SFINAE idiom to choose an implementation based on whether the type is integral or floating po...
Definition: random.hh:83
unsigned int missesByStageLevel[2][WALK_CACHE_LEVELS]
#define WALKCACHE_SEED
void invalidateAll()
Stats::Formula averageLookupsByStageLevel[2][WALK_CACHE_LEVELS]
Stats::Formula averageHitRateByStageLevel[2][WALK_CACHE_LEVELS]
std::array< unsigned, 2 *WALK_CACHE_LEVELS > sizes
std::string csprintf(const char *format, const Args &...args)
Definition: cprintf.hh:162
Bitfield< 4 > s
void invalidateAll()
std::vector< Set > sets
size_t associativity
void invalidateAll()
void invalidateIPAA(Addr ipa)
Stats::Scalar insertionsByStageLevel[2][WALK_CACHE_LEVELS]
void invalidateIPA(Addr ipa, uint16_t vmid)
const Entry * lookup(Addr va, uint16_t asid, uint16_t vmid, bool updStats=true)
void invalidateSID(uint32_t sid)
const Entry * lookupAnyVA(uint32_t sid, uint32_t ssid, bool updStats=true)
#define ARMARCHTLB_SEED
void store(const Entry &incoming)
Stats::Scalar totalUpdates
void invalidateASID(uint16_t asid, uint16_t vmid)
ARMArchTLB(unsigned numEntries, unsigned _associativity, const std::string &policy)
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:142
ConfigCache(unsigned numEntries, unsigned _associativity, const std::string &policy)
void invalidateSSID(uint32_t sid, uint32_t ssid)
#define WALK_CACHE_LEVELS
Bitfield< 8 > va
void store(const Entry &incoming)
Stats::Scalar totalUpdatesByStageLevel[2][WALK_CACHE_LEVELS]
size_t pickSetIdx(uint32_t sid, uint32_t ssid) const
Bitfield< 20 > level
Definition: intmessage.hh:49
size_t associativity
Bitfield< 9 > e
Derived & name(const std::string &name)
Set the name and marks this stat to print at the end of simulation.
Definition: statistics.hh:279
const Entry * lookup(uint32_t sid, uint32_t ssid, bool updStats=true)
Stats::Formula averageHitRate
void invalidateVAA(Addr va, uint16_t vmid)
SMMUTLB(unsigned numEntries, unsigned _associativity, const std::string &policy)
Stats::Formula averageLookups
Stats::Scalar totalLookupsByStageLevel[2][WALK_CACHE_LEVELS]
size_t pickSetIdx(Addr va, uint16_t asid, uint16_t vmid) const
void store(const Entry &incoming)
const Entry * lookup(Addr va, Addr vaMask, uint16_t asid, uint16_t vmid, unsigned stage, unsigned level, bool updStats=true)
static int decodePolicyName(const std::string &policy_name)
void invalidateAll()
std::vector< Set > sets
size_t pickEntryIdxToReplace(const Set &set, unsigned stage, unsigned level)
Stats::Formula averageMisses
SMMUv3BaseCache(const std::string &policy_name, uint32_t seed)
Stats::Scalar totalLookups
void invalidateVMID(uint16_t vmid)
size_t pickEntryIdxToReplace(const Set &set)
Derived & desc(const std::string &_desc)
Set the description and marks this stat to print at the end of simulation.
Definition: statistics.hh:312
std::vector< Set > sets
#define CONFIGCACHE_SEED
void invalidateVA(Addr va, uint16_t asid, uint16_t vmid)
size_t associativity
void regStats(const std::string &name) override
Stats::Formula averageUpdates
Bitfield< 5 > l
virtual void regStats(const std::string &name)
void invalidateVMID(uint16_t vmid)
WalkCache(const std::array< unsigned, 2 *WALK_CACHE_LEVELS > &_sizes, unsigned _associativity, const std::string &policy)
size_t pickSetIdx(Addr va, Addr vaMask, unsigned stage, unsigned level) const
IPACache(unsigned numEntries, unsigned _associativity, const std::string &policy)
size_t associativity
size_t pickSetIdx(uint32_t sid, uint32_t ssid) const
Stats::Scalar totalMisses
void invalidateASID(uint16_t asid, uint16_t vmid)
size_t pickEntryIdxToReplace(const Set &set)
unsigned int updatesByStageLevel[2][WALK_CACHE_LEVELS]

Generated on Fri Feb 28 2020 16:27:00 for gem5 by doxygen 1.8.13