gem5  v22.1.0.0
smmu_v3_caches.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014, 2018-2019, 2021 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 
39 
40 #include <numeric>
41 
42 #include "base/bitfield.hh"
43 #include "base/intmath.hh"
44 #include "base/logging.hh"
45 #include "sim/stats.hh"
46 
47 
48 // taken from hex expansion of pi
49 #define SMMUTLB_SEED 0xEA752DFE
50 #define ARMARCHTLB_SEED 0x8B021FA1
51 #define IPACACHE_SEED 0xE5A0CC0F
52 #define CONFIGCACHE_SEED 0xB56F74E8
53 #define WALKCACHE_SEED 0x18ACF3D6
54 
55 /*
56  * BaseCache
57  *
58  * TODO: move more code into this base class to reduce duplication.
59  */
60 
61 namespace gem5
62 {
63 
64 SMMUv3BaseCache::SMMUv3BaseCache(const std::string &policy_name, uint32_t seed,
65  statistics::Group *parent, const std::string &name)
66  : replacementPolicy(decodePolicyName(policy_name)),
67  nextToReplace(0),
68  random(seed),
69  useStamp(0),
70  baseCacheStats(parent, name)
71 {}
72 
73 int
74 SMMUv3BaseCache::decodePolicyName(const std::string &policy_name)
75 {
76  if (policy_name == "rr") {
78  } else if (policy_name == "rand") {
80  } else if (policy_name == "lru") {
81  return SMMU_CACHE_REPL_LRU;
82  } else {
83  panic("Unknown cache replacement policy '%s'\n", policy_name);
84  }
85 }
86 
89  statistics::Group *parent, const std::string &name)
90  : statistics::Group(parent, name.c_str()),
91  ADD_STAT(averageLookups, statistics::units::Rate<
92  statistics::units::Count, statistics::units::Second>::get(),
93  "Average number lookups per second"),
94  ADD_STAT(totalLookups, statistics::units::Count::get(),
95  "Total number of lookups"),
96  ADD_STAT(averageMisses, statistics::units::Rate<
97  statistics::units::Count, statistics::units::Second>::get(),
98  "Average number misses per second"),
99  ADD_STAT(totalMisses, statistics::units::Count::get(),
100  "Total number of misses"),
101  ADD_STAT(averageUpdates, statistics::units::Rate<
102  statistics::units::Count, statistics::units::Second>::get(),
103  "Average number updates per second"),
104  ADD_STAT(totalUpdates, statistics::units::Count::get(),
105  "Total number of updates"),
106  ADD_STAT(averageHitRate, statistics::units::Ratio::get(), "Average hit rate"),
107  ADD_STAT(insertions, statistics::units::Count::get(),
108  "Number of insertions (not replacements)")
109 {
110  using namespace statistics;
111 
112 
114  .flags(pdf);
115 
117  .flags(pdf);
118 
120 
121 
123  .flags(pdf);
124 
126  .flags(pdf);
127 
129 
130 
132  .flags(pdf);
133 
135  .flags(pdf);
136 
138 
139 
141  .flags(pdf);
142 
144 
145  insertions
146  .flags(pdf);
147 }
148 
149 /*
150  * SMMUTLB
151  */
152 
153 SMMUTLB::SMMUTLB(unsigned numEntries, unsigned _associativity,
154  const std::string &policy, statistics::Group *parent,
155  const std::string &name)
156 :
157  SMMUv3BaseCache(policy, SMMUTLB_SEED, parent, name),
158  associativity(_associativity)
159 {
160  if (associativity == 0)
161  associativity = numEntries; // fully associative
162 
163  if (numEntries == 0)
164  fatal("SMMUTLB must have at least one entry\n");
165 
166  if (associativity > numEntries)
167  fatal("SMMUTLB associativity cannot be higher than "
168  "its number of entries\n");
169 
170  unsigned num_sets = numEntries / associativity;
171 
172  if (num_sets*associativity != numEntries)
173  fatal("Number of SMMUTLB entries must be divisible "
174  "by its associativity\n");
175 
176  Entry e;
177  e.valid = false;
178 
180  sets.resize(num_sets, set);
181 }
182 
183 const SMMUTLB::Entry*
184 SMMUTLB::lookup(uint32_t sid, uint32_t ssid,
185  Addr va, bool updStats)
186 {
187  const Entry *result = NULL;
188 
189  Set &set = sets[pickSetIdx(va)];
190 
191  for (size_t i = 0; i < set.size(); i++) {
192  const Entry &e = set[i];
193 
194  if (e.valid && (e.va & e.vaMask) == (va & e.vaMask) &&
195  e.sid==sid && e.ssid==ssid)
196  {
197  if (result != NULL)
198  panic("SMMUTLB: duplicate entry found!\n");
199 
200  result = &e;
201  break;
202  }
203  }
204 
205  if (updStats) {
206  if (result)
207  result->lastUsed = useStamp++;
208 
210  if (result == NULL)
212  }
213 
214  return result;
215 }
216 
217 const SMMUTLB::Entry*
218 SMMUTLB::lookupAnyVA(uint32_t sid, uint32_t ssid, bool updStats)
219 {
220  const Entry *result = NULL;
221 
222  for (size_t s = 0; s < sets.size(); s++) {
223  Set &set = sets[s];
224 
225  for (size_t i = 0; i < set.size(); i++) {
226  const Entry &e = set[i];
227 
228  if (e.valid && e.sid==sid && e.ssid==ssid) {
229  result = &e;
230  break;
231  }
232  }
233  }
234 
235  if (updStats) {
237  if (result == NULL)
239  }
240 
241  return result;
242 }
243 
244 void
245 SMMUTLB::store(const Entry &incoming, AllocPolicy alloc)
246 {
247  if (!incoming.valid)
248  panic("Tried to store an invalid entry\n");
249 
250  incoming.lastUsed = 0;
251 
252  const Entry *existing =
253  lookup(incoming.sid, incoming.ssid, incoming.va, false);
254 
255  if (existing) {
256  *const_cast<Entry *> (existing) = incoming;
257  } else {
258  Set &set = sets[pickSetIdx(incoming.va)];
259  set[pickEntryIdxToReplace(set, alloc)] = incoming;
260  }
261 
263 }
264 
265 void
266 SMMUTLB::invalidateSSID(uint32_t sid, uint32_t ssid)
267 {
268  Set &set = sets[pickSetIdx(sid, ssid)];
269 
270  for (size_t i = 0; i < set.size(); i++) {
271  Entry &e = set[i];
272 
273  if (e.sid == sid && e.ssid == ssid)
274  e.valid = false;
275  }
276 }
277 
278 void
280 {
281  for (size_t s = 0; s < sets.size(); s++) {
282  Set &set = sets[s];
283 
284  for (size_t i = 0; i < set.size(); i++) {
285  Entry &e = set[i];
286 
287  if (e.sid == sid)
288  e.valid = false;
289  }
290  }
291 }
292 
293 void
294 SMMUTLB::invalidateVA(Addr va, uint16_t asid, uint16_t vmid)
295 {
296  Set &set = sets[pickSetIdx(va)];
297 
298  for (size_t i = 0; i < set.size(); i++) {
299  Entry &e = set[i];
300 
301  if ((e.va & e.vaMask) == (va & e.vaMask) &&
302  e.asid==asid && e.vmid==vmid)
303  {
304  e.valid = false;
305  }
306  }
307 }
308 
309 void
311 {
312  Set &set = sets[pickSetIdx(va)];
313 
314  for (size_t i = 0; i < set.size(); i++) {
315  Entry &e = set[i];
316 
317  if ((e.va & e.vaMask) == (va & e.vaMask) && e.vmid==vmid)
318  e.valid = false;
319  }
320 }
321 
322 void
323 SMMUTLB::invalidateASID(uint16_t asid, uint16_t vmid)
324 {
325  for (size_t s = 0; s < sets.size(); s++) {
326  Set &set = sets[s];
327 
328  for (size_t i = 0; i < set.size(); i++) {
329  Entry &e = set[i];
330 
331  if (e.asid==asid && e.vmid==vmid)
332  e.valid = false;
333  }
334  }
335 }
336 
337 void
339 {
340  for (size_t s = 0; s < sets.size(); s++) {
341  Set &set = sets[s];
342 
343  for (size_t i = 0; i < set.size(); i++) {
344  Entry &e = set[i];
345 
346  if (e.vmid == vmid)
347  e.valid = false;
348  }
349  }
350 }
351 
352 void
354 {
355  for (size_t s = 0; s < sets.size(); s++) {
356  Set &set = sets[s];
357 
358  for (size_t i = 0; i < set.size(); i++)
359  set[i].valid = false;
360  }
361 }
362 
363 size_t
365 {
366  return (va >> 12) % sets.size();
367 }
368 
369 size_t
370 SMMUTLB::pickSetIdx(uint32_t sid, uint32_t ssid) const
371 {
372  return (sid^ssid) % sets.size();
373 }
374 
375 size_t
377 {
378  if (alloc == ALLOC_LAST_WAY)
379  return associativity - 1;
380 
381  uint32_t lru_tick = UINT32_MAX;
382  size_t lru_idx = 0;
383  size_t max_idx =
384  alloc==ALLOC_ANY_BUT_LAST_WAY ?
385  set.size()-1 : set.size();
386 
387  for (size_t i = 0; i < max_idx; i++) {
388  if (!set[i].valid) {
390  return i;
391  }
392 
393  if (set[i].lastUsed < lru_tick) {
394  lru_idx = i;
395  lru_tick = set[i].lastUsed;
396  }
397  }
398 
399  switch (replacementPolicy) {
401  switch (alloc) {
402  case ALLOC_ANY_WAY:
403  return nextToReplace = ((nextToReplace+1) % associativity);
405  return nextToReplace = ((nextToReplace+1) % (associativity-1));
406  default:
407  panic("Unknown allocation mode %d\n", alloc);
408  }
409 
411  switch (alloc) {
412  case ALLOC_ANY_WAY:
413  return random.random<size_t>(0, associativity-1);
415  return random.random<size_t>(0, associativity-2);
416  default:
417  panic("Unknown allocation mode %d\n", alloc);
418  }
419 
420  case SMMU_CACHE_REPL_LRU:
421  return lru_idx;
422 
423  default:
424  panic("Unknown replacement policy %d\n", replacementPolicy);
425  }
426 }
427 
428 
429 
430 /*
431  * ARMArchTLB
432  */
433 
434 ARMArchTLB::ARMArchTLB(unsigned numEntries, unsigned _associativity,
435  const std::string &policy, statistics::Group *parent)
436 :
437  SMMUv3BaseCache(policy, ARMARCHTLB_SEED, parent, "tlb"),
438  associativity(_associativity)
439 {
440  if (associativity == 0)
441  associativity = numEntries; // fully associative
442 
443  if (numEntries == 0)
444  fatal("ARMArchTLB must have at least one entry\n");
445 
446  if (associativity > numEntries)
447  fatal("ARMArchTLB associativity cannot be higher than "
448  "its number of entries\n");
449 
450  unsigned num_sets = numEntries / associativity;
451 
452  if (num_sets*associativity != numEntries)
453  fatal("Number of ARMArchTLB entries must be divisible "
454  "by its associativity\n");
455 
456  Entry e;
457  e.valid = false;
458 
460  sets.resize(num_sets, set);
461 }
462 
463 const ARMArchTLB::Entry *
464 ARMArchTLB::lookup(Addr va, uint16_t asid, uint16_t vmid, bool updStats)
465 {
466  const Entry *result = NULL;
467 
468  Set &set = sets[pickSetIdx(va, asid, vmid)];
469 
470  for (size_t i = 0; i < set.size(); i++) {
471  const Entry &e = set[i];
472 
473  if (e.valid && (e.va & e.vaMask) == (va & e.vaMask) &&
474  e.asid==asid && e.vmid==vmid)
475  {
476  if (result != NULL)
477  panic("ARMArchTLB: duplicate entry found!\n");
478 
479  result = &e;
480  break;
481  }
482  }
483 
484  if (updStats) {
485  if (result)
486  result->lastUsed = useStamp++;
487 
489  if (result == NULL)
491  }
492 
493  return result;
494 }
495 
496 void
497 ARMArchTLB::store(const Entry &incoming)
498 {
499  if (!incoming.valid)
500  panic("Tried to store an invalid entry\n");
501 
502  incoming.lastUsed = 0;
503 
504  const Entry *existing =
505  lookup(incoming.va, incoming.asid, incoming.vmid, false);
506 
507  if (existing) {
508  *const_cast<Entry *> (existing) = incoming;
509  } else {
510  Set &set = sets[pickSetIdx(incoming.va, incoming.asid, incoming.vmid)];
511  set[pickEntryIdxToReplace(set)] = incoming;
512  }
513 
515 }
516 
517 void
518 ARMArchTLB::invalidateVA(Addr va, uint16_t asid, uint16_t vmid)
519 {
520  Set &set = sets[pickSetIdx(va, asid, vmid)];
521 
522  for (size_t i = 0; i < set.size(); i++) {
523  Entry &e = set[i];
524 
525  if ((e.va & e.vaMask) == (va & e.vaMask) &&
526  e.asid==asid && e.vmid==vmid)
527  {
528  e.valid = false;
529  }
530  }
531 }
532 
533 void
535 {
536  for (size_t s = 0; s < sets.size(); s++) {
537  Set &set = sets[s];
538 
539  for (size_t i = 0; i < set.size(); i++) {
540  Entry &e = set[i];
541 
542  if ((e.va & e.vaMask) == (va & e.vaMask) && e.vmid==vmid)
543  e.valid = false;
544  }
545  }
546 }
547 
548 void
549 ARMArchTLB::invalidateASID(uint16_t asid, uint16_t vmid)
550 {
551  for (size_t s = 0; s < sets.size(); s++) {
552  Set &set = sets[s];
553 
554  for (size_t i = 0; i < set.size(); i++) {
555  Entry &e = set[i];
556 
557  if (e.asid==asid && e.vmid==vmid)
558  e.valid = false;
559  }
560  }
561 }
562 
563 void
565 {
566  for (size_t s = 0; s < sets.size(); s++) {
567  Set &set = sets[s];
568 
569  for (size_t i = 0; i < set.size(); i++) {
570  Entry &e = set[i];
571 
572  if (e.vmid == vmid)
573  e.valid = false;
574  }
575  }
576 }
577 
578 void
580 {
581  for (size_t s = 0; s < sets.size(); s++) {
582  Set &set = sets[s];
583 
584  for (size_t i = 0; i < set.size(); i++)
585  set[i].valid = false;
586  }
587 }
588 
589 size_t
590 ARMArchTLB::pickSetIdx(Addr va, uint16_t asid, uint16_t vmid) const
591 {
592  return ((va >> 12) ^ asid ^ vmid) % sets.size();
593 }
594 
595 size_t
597 {
598  size_t lru_idx = 0;
599  uint32_t lru_tick = UINT32_MAX;
600 
601  for (size_t i = 0; i < set.size(); i++) {
602  if (!set[i].valid) {
604  return i;
605  }
606 
607  if (set[i].lastUsed < lru_tick) {
608  lru_idx = i;
609  lru_tick = set[i].lastUsed;
610  }
611  }
612 
613  switch (replacementPolicy) {
615  return nextToReplace = ((nextToReplace+1) % associativity);
616 
618  return random.random<size_t>(0, associativity-1);
619 
620  case SMMU_CACHE_REPL_LRU:
621  return lru_idx;
622 
623  default:
624  panic("Unknown replacement policy %d\n", replacementPolicy);
625  }
626 
627 }
628 
629 /*
630  * IPACache
631  */
632 
633 IPACache::IPACache(unsigned numEntries, unsigned _associativity,
634  const std::string &policy, statistics::Group *parent)
635 :
636  SMMUv3BaseCache(policy, IPACACHE_SEED, parent, "ipa"),
637  associativity(_associativity)
638 {
639  if (associativity == 0)
640  associativity = numEntries; // fully associative
641 
642  if (numEntries == 0)
643  fatal("IPACache must have at least one entry\n");
644 
645  if (associativity > numEntries)
646  fatal("IPACache associativity cannot be higher than "
647  "its number of entries\n");
648 
649  unsigned num_sets = numEntries / associativity;
650 
651  if (num_sets*associativity != numEntries)
652  fatal("Number of IPACache entries must be divisible "
653  "by its associativity\n");
654 
655  Entry e;
656  e.valid = false;
657 
659  sets.resize(num_sets, set);
660 }
661 
662 const IPACache::Entry*
663 IPACache::lookup(Addr ipa, uint16_t vmid, bool updStats)
664 {
665  const Entry *result = NULL;
666 
667  Set &set = sets[pickSetIdx(ipa, vmid)];
668 
669  for (size_t i = 0; i < set.size(); i++) {
670  const Entry &e = set[i];
671 
672  if (e.valid && (e.ipa & e.ipaMask) == (ipa & e.ipaMask) &&
673  e.vmid==vmid)
674  {
675  if (result != NULL)
676  panic("IPACache: duplicate entry found!\n");
677 
678  result = &e;
679  break;
680  }
681  }
682 
683  if (updStats) {
684  if (result)
685  result->lastUsed = useStamp++;
686 
688  if (result == NULL)
690  }
691 
692  return result;
693 }
694 
695 void
696 IPACache::store(const Entry &incoming)
697 {
698  if (!incoming.valid)
699  panic("Tried to store an invalid entry\n");
700 
701  incoming.lastUsed = 0;
702 
703  const Entry *existing = lookup(incoming.ipa, incoming.vmid, false);
704 
705  if (existing) {
706  *const_cast<Entry *> (existing) = incoming;
707  } else {
708  Set &set = sets[pickSetIdx(incoming.ipa, incoming.vmid)];
709  set[pickEntryIdxToReplace(set)] = incoming;
710  }
711 
713 }
714 
715 void
716 IPACache::invalidateIPA(Addr ipa, uint16_t vmid)
717 {
718  Set &set = sets[pickSetIdx(ipa, vmid)];
719 
720  for (size_t i = 0; i < set.size(); i++) {
721  Entry &e = set[i];
722 
723  if ((e.ipa & e.ipaMask) == (ipa & e.ipaMask) && e.vmid==vmid)
724  e.valid = false;
725  }
726 }
727 
728 void
730 {
731  for (size_t s = 0; s < sets.size(); s++) {
732  Set &set = sets[s];
733 
734  for (size_t i = 0; i < set.size(); i++) {
735  Entry &e = set[i];
736 
737  if ((e.ipa & e.ipaMask) == (ipa & e.ipaMask))
738  e.valid = false;
739  }
740  }
741 }
742 
743 void
745 {
746  for (size_t s = 0; s < sets.size(); s++) {
747  Set &set = sets[s];
748 
749  for (size_t i = 0; i < set.size(); i++) {
750  Entry &e = set[i];
751 
752  if (e.vmid == vmid)
753  e.valid = false;
754  }
755  }
756 }
757 
758 void
760 {
761  for (size_t s = 0; s < sets.size(); s++) {
762  Set &set = sets[s];
763 
764  for (size_t i = 0; i < set.size(); i++)
765  set[i].valid = false;
766  }
767 }
768 
769 size_t
770 IPACache::pickSetIdx(Addr va, uint16_t vmid) const
771 {
772  return ((va >> 12) ^ vmid) % sets.size();
773 }
774 
775 size_t
777 {
778  size_t lru_idx = 0;
779  uint32_t lru_tick = UINT32_MAX;
780 
781  for (size_t i = 0; i < set.size(); i++) {
782  if (!set[i].valid) {
784  return i;
785  }
786 
787  if (set[i].lastUsed < lru_tick) {
788  lru_idx = i;
789  lru_tick = set[i].lastUsed;
790  }
791  }
792 
793  switch (replacementPolicy) {
795  return nextToReplace = ((nextToReplace+1) % associativity);
796 
798  return random.random<size_t>(0, associativity-1);
799 
800  case SMMU_CACHE_REPL_LRU:
801  return lru_idx;
802 
803  default:
804  panic("Unknown replacement policy %d\n", replacementPolicy);
805  }
806 
807 }
808 
809 /*
810  * ConfigCache
811  */
812 
813 ConfigCache::ConfigCache(unsigned numEntries, unsigned _associativity,
814  const std::string &policy, statistics::Group *parent)
815 :
816  SMMUv3BaseCache(policy, CONFIGCACHE_SEED, parent, "cfg"),
817  associativity(_associativity)
818 {
819  if (associativity == 0)
820  associativity = numEntries; // fully associative
821 
822  if (numEntries == 0)
823  fatal("ConfigCache must have at least one entry\n");
824 
825  if (associativity > numEntries)
826  fatal("ConfigCache associativity cannot be higher than "
827  "its number of entries\n");
828 
829  unsigned num_sets = numEntries / associativity;
830 
831  if (num_sets*associativity != numEntries)
832  fatal("Number of ConfigCache entries must be divisible "
833  "by its associativity\n");
834 
835  Entry e;
836  e.valid = false;
837 
839  sets.resize(num_sets, set);
840 }
841 
842 const ConfigCache::Entry *
843 ConfigCache::lookup(uint32_t sid, uint32_t ssid, bool updStats)
844 {
845  const Entry *result = NULL;
846 
847  Set &set = sets[pickSetIdx(sid, ssid)];
848 
849  for (size_t i = 0; i < set.size(); i++) {
850  const Entry &e = set[i];
851 
852  if (e.valid && e.sid==sid && e.ssid==ssid)
853  {
854  if (result != NULL)
855  panic("ConfigCache: duplicate entry found!\n");
856 
857  result = &e;
858  break;
859  }
860  }
861 
862  if (updStats) {
863  if (result)
864  result->lastUsed = useStamp++;
865 
867  if (result == NULL)
869  }
870 
871  return result;
872 }
873 
874 void
875 ConfigCache::store(const Entry &incoming)
876 {
877  if (!incoming.valid)
878  panic("Tried to store an invalid entry\n");
879 
880  incoming.lastUsed = 0;
881 
882  const Entry *existing = lookup(incoming.sid, incoming.ssid, false);
883 
884  if (existing) {
885  *const_cast<Entry *> (existing) = incoming;
886  } else {
887  Set &set = sets[pickSetIdx(incoming.sid, incoming.ssid)];
888  set[pickEntryIdxToReplace(set)] = incoming;
889  }
890 
892 }
893 
894 void
895 ConfigCache::invalidateSSID(uint32_t sid, uint32_t ssid)
896 {
897  Set &set = sets[pickSetIdx(sid, ssid)];
898 
899  for (size_t i = 0; i < set.size(); i++) {
900  Entry &e = set[i];
901 
902  if (e.sid==sid && e.ssid==ssid)
903  e.valid = false;
904  }
905 }
906 
907 void
909 {
910  for (size_t s = 0; s < sets.size(); s++) {
911  Set &set = sets[s];
912 
913  for (size_t i = 0; i < set.size(); i++) {
914  Entry &e = set[i];
915 
916  if (e.sid == sid)
917  e.valid = false;
918  }
919  }
920 }
921 
922 void
924 {
925  for (size_t s = 0; s < sets.size(); s++) {
926  Set &set = sets[s];
927 
928  for (size_t i = 0; i < set.size(); i++)
929  set[i].valid = false;
930  }
931 }
932 
933 size_t
934 ConfigCache::pickSetIdx(uint32_t sid, uint32_t ssid) const
935 {
936  return (sid^ssid) % sets.size();
937 }
938 
939 size_t
941 {
942  size_t lru_idx = 0;
943  uint32_t lru_tick = UINT32_MAX;
944 
945  for (size_t i = 0; i < set.size(); i++) {
946  if (!set[i].valid) {
948  return i;
949  }
950 
951  if (set[i].lastUsed < lru_tick) {
952  lru_idx = i;
953  lru_tick = set[i].lastUsed;
954  }
955  }
956 
957  switch (replacementPolicy) {
959  return nextToReplace = ((nextToReplace+1) % associativity);
960 
962  return random.random<size_t>(0, associativity-1);
963 
964  case SMMU_CACHE_REPL_LRU:
965  return lru_idx;
966 
967  default:
968  panic("Unknown replacement policy %d\n", replacementPolicy);
969  }
970 
971 }
972 
973 /*
974  * WalkCache
975  */
976 
977 WalkCache::WalkCache(const std::array<unsigned, 2*WALK_CACHE_LEVELS> &_sizes,
978  unsigned _associativity, const std::string &policy,
979  statistics::Group *parent) :
980  SMMUv3BaseCache(policy, WALKCACHE_SEED, parent, "walk"),
981  walkCacheStats(&(SMMUv3BaseCache::baseCacheStats)),
982  associativity(_associativity),
983  sizes()
984 {
985  unsigned numEntries = std::accumulate(&_sizes[0],
986  &_sizes[2*WALK_CACHE_LEVELS], 0);
987 
988  if (associativity == 0)
989  associativity = numEntries; // fully associative
990 
991  if (numEntries == 0)
992  fatal("WalkCache must have at least one entry\n");
993 
994  for (size_t i = 0; i < 2*WALK_CACHE_LEVELS; i++){
995  if (_sizes[i] % associativity != 0)
996  fatal("Number of WalkCache entries at each level must be "
997  "divisible by WalkCache associativity\n");
998 
999  sizes[i] = _sizes[i] / associativity;
1000  offsets[i] = i==0 ? 0 : offsets[i-1] + sizes[i-1];
1001  }
1002 
1003  if (associativity > numEntries)
1004  fatal("WalkCache associativity cannot be higher than "
1005  "its number of entries\n");
1006 
1007  unsigned num_sets = numEntries / associativity;
1008 
1009  if (num_sets*associativity != numEntries)
1010  fatal("Number of WalkCache entries must be divisible "
1011  "by its associativity\n");
1012 
1013  Entry e;
1014  e.valid = false;
1015 
1016  Set set(associativity, e);
1017  sets.resize(num_sets, set);
1018 }
1019 
1020 const WalkCache::Entry*
1022  uint16_t asid, uint16_t vmid,
1023  unsigned stage, unsigned level,
1024  bool updStats)
1025 {
1026  const Entry *result = NULL;
1027 
1028  Set &set = sets[pickSetIdx(va, vaMask, stage, level)];
1029 
1030  for (size_t i = 0; i < set.size(); i++) {
1031  const Entry &e = set[i];
1032 
1033  if (e.valid && (e.va & e.vaMask) == (va & e.vaMask) &&
1034  e.asid==asid && e.vmid==vmid && e.stage==stage && e.level==level)
1035  {
1036  if (result != NULL)
1037  panic("WalkCache: duplicate entry found!\n");
1038 
1039  result = &e;
1040  break;
1041  }
1042  }
1043 
1044  if (updStats) {
1045  if (result)
1046  result->lastUsed = useStamp++;
1047 
1049  if (result == NULL)
1051 
1053  if (result == NULL) {
1055  }
1056  }
1057 
1058  return result;
1059 }
1060 
1061 void
1062 WalkCache::store(const Entry &incoming)
1063 {
1064  if (!incoming.valid)
1065  panic("Tried to store an invalid entry\n");
1066 
1067  assert(incoming.stage==1 || incoming.stage==2);
1068  assert(incoming.level<=WALK_CACHE_LEVELS);
1069 
1070  incoming.lastUsed = 0;
1071 
1072  const Entry *existing = lookup(incoming.va, incoming.vaMask,
1073  incoming.asid, incoming.vmid,
1074  incoming.stage, incoming.level, false);
1075 
1076  if (existing) {
1077  *const_cast<Entry *> (existing) = incoming;
1078  } else {
1079  Set &set = sets[pickSetIdx(incoming.va, incoming.vaMask,
1080  incoming.stage, incoming.level)];
1081  set[pickEntryIdxToReplace(set, incoming.stage, incoming.level)] =
1082  incoming;
1083  }
1084 
1087  .totalUpdatesByStageLevel[incoming.stage-1][incoming.level]++;
1088 }
1089 
1090 void
1091 WalkCache::invalidateVA(Addr va, uint16_t asid, uint16_t vmid,
1092  const bool leaf_only)
1093 {
1094  for (size_t s = 0; s < sets.size(); s++) {
1095  Set &set = sets[s];
1096 
1097  for (size_t i = 0; i < set.size(); i++) {
1098  Entry &e = set[i];
1099 
1100  if ((!leaf_only || e.leaf) && (e.va & e.vaMask) == (va & e.vaMask)
1101  && e.asid == asid && e.vmid == vmid)
1102  {
1103  e.valid = false;
1104  }
1105  }
1106  }
1107 }
1108 
1109 void
1110 WalkCache::invalidateVAA(Addr va, uint16_t vmid, const bool leaf_only)
1111 {
1112  for (size_t s = 0; s < sets.size(); s++) {
1113  Set &set = sets[s];
1114 
1115  for (size_t i = 0; i < set.size(); i++) {
1116  Entry &e = set[i];
1117 
1118  if ((!leaf_only || e.leaf) && (e.va & e.vaMask) == (va & e.vaMask)
1119  && e.vmid == vmid)
1120  {
1121  e.valid = false;
1122  }
1123  }
1124  }
1125 }
1126 
1127 void
1128 WalkCache::invalidateASID(uint16_t asid, uint16_t vmid)
1129 {
1130  for (size_t s = 0; s < sets.size(); s++) {
1131  Set &set = sets[s];
1132 
1133  for (size_t i = 0; i < set.size(); i++) {
1134  Entry &e = set[i];
1135 
1136  if (e.asid==asid && e.vmid==vmid)
1137  e.valid = false;
1138  }
1139  }
1140 }
1141 
1142 void
1144 {
1145  for (size_t s = 0; s < sets.size(); s++) {
1146  Set &set = sets[s];
1147 
1148  for (size_t i = 0; i < set.size(); i++) {
1149  Entry &e = set[i];
1150 
1151  if (e.vmid == vmid)
1152  e.valid = false;
1153  }
1154  }
1155 }
1156 
1157 void
1159 {
1160  for (size_t s = 0; s < sets.size(); s++) {
1161  Set &set = sets[s];
1162 
1163  for (size_t i = 0; i < set.size(); i++)
1164  set[i].valid = false;
1165  }
1166 }
1167 
1168 size_t
1170  unsigned stage, unsigned level) const
1171 {
1172  (void) stage;
1173 
1174  int size, offset;
1175 
1176  switch (stage) {
1177  case 1:
1178  assert (level<=3);
1179  size = sizes[0*WALK_CACHE_LEVELS + level];
1181  break;
1182 
1183  case 2:
1184  assert (level<=3);
1185  size = sizes[1*WALK_CACHE_LEVELS + level];
1187  break;
1188 
1189  default:
1190  panic("bad stage");
1191  }
1192 
1193  return ((va >> findLsbSet(vaMask)) % size) + offset;
1194 }
1195 
1196 size_t
1198  unsigned stage, unsigned level)
1199 {
1200  size_t lru_idx = 0;
1201  uint32_t lru_tick = UINT32_MAX;
1202 
1203  for (size_t i = 0; i < set.size(); i++) {
1204  if (!set[i].valid) {
1207  return i;
1208  }
1209 
1210  if (set[i].lastUsed < lru_tick) {
1211  lru_idx = i;
1212  lru_tick = set[i].lastUsed;
1213  }
1214  }
1215 
1216  switch (replacementPolicy) {
1218  return nextToReplace = ((nextToReplace+1) % associativity);
1219 
1221  return random.random<size_t>(0, associativity-1);
1222 
1223  case SMMU_CACHE_REPL_LRU:
1224  return lru_idx;
1225 
1226  default:
1227  panic("Unknown replacement policy %d\n", replacementPolicy);
1228  }
1229 
1230 }
1231 
1233  : statistics::Group(parent),
1234  ADD_STAT(totalLookupsByStageLevel, statistics::units::Count::get(),
1235  "Total number of lookups"),
1236  ADD_STAT(totalMissesByStageLevel, statistics::units::Count::get(),
1237  "Total number of misses"),
1238  ADD_STAT(totalUpdatesByStageLevel, statistics::units::Count::get(),
1239  "Total number of updates"),
1240  ADD_STAT(insertionsByStageLevel, statistics::units::Count::get(),
1241  "Number of insertions (not replacements)")
1242 {
1243  using namespace statistics;
1244 
1246  .init(2, WALK_CACHE_LEVELS)
1247  .flags(pdf);
1249  .init(2, WALK_CACHE_LEVELS)
1250  .flags(pdf);
1252  .init(2, WALK_CACHE_LEVELS)
1253  .flags(pdf);
1255  .init(2, WALK_CACHE_LEVELS)
1256  .flags(pdf);
1257 
1258  for (int s = 0; s < 2; s++) {
1260  totalMissesByStageLevel.subname(s, csprintf("S%d", s + 1));
1262  insertionsByStageLevel.subname(s, csprintf("S%d", s + 1));
1263 
1264  for (int l = 0; l < WALK_CACHE_LEVELS; l++) {
1269 
1270  auto avg_lookup = new statistics::Formula(
1271  this,
1272  csprintf("averageLookups_S%dL%d", s+1, l).c_str(),
1274  statistics::units::Second>::get(),
1275  "Average number lookups per second");
1276  avg_lookup->flags(pdf);
1277  averageLookupsByStageLevel.push_back(avg_lookup);
1278 
1279  *avg_lookup =
1281 
1282  auto avg_misses = new statistics::Formula(
1283  this,
1284  csprintf("averageMisses_S%dL%d", s+1, l).c_str(),
1286  statistics::units::Second>::get(),
1287  "Average number misses per second");
1288  avg_misses->flags(pdf);
1289  averageMissesByStageLevel.push_back(avg_misses);
1290 
1291  *avg_misses =
1293 
1294  auto avg_updates = new statistics::Formula(
1295  this,
1296  csprintf("averageUpdates_S%dL%d", s+1, l).c_str(),
1298  statistics::units::Second>::get(),
1299  "Average number updates per second");
1300  avg_updates->flags(pdf);
1301  averageUpdatesByStageLevel.push_back(avg_updates);
1302 
1303  *avg_updates =
1305 
1306  auto avg_hitrate = new statistics::Formula(
1307  this,
1308  csprintf("averageHitRate_S%dL%d", s+1, l).c_str(),
1309  statistics::units::Ratio::get(), "Average hit rate");
1310  avg_hitrate->flags(pdf);
1311  averageHitRateByStageLevel.push_back(avg_hitrate);
1312 
1313  *avg_hitrate =
1317 
1318  }
1319  }
1320 }
1321 
1323 {
1324  for (auto avg_lookup : averageLookupsByStageLevel)
1325  delete avg_lookup;
1326 
1327  for (auto avg_miss : averageMissesByStageLevel)
1328  delete avg_miss;
1329 
1330  for (auto avg_update : averageUpdatesByStageLevel)
1331  delete avg_update;
1332 
1333  for (auto avg_hitrate : averageHitRateByStageLevel)
1334  delete avg_hitrate;
1335 }
1336 
1337 } // namespace gem5
void invalidateVAA(Addr va, uint16_t vmid)
size_t pickEntryIdxToReplace(const Set &set)
void invalidateVA(Addr va, uint16_t asid, uint16_t vmid)
void store(const Entry &incoming)
std::vector< Set > sets
size_t pickSetIdx(Addr va, uint16_t asid, uint16_t vmid) const
ARMArchTLB(unsigned numEntries, unsigned _associativity, const std::string &policy, statistics::Group *parent)
void invalidateVMID(uint16_t vmid)
void invalidateASID(uint16_t asid, uint16_t vmid)
const Entry * lookup(Addr va, uint16_t asid, uint16_t vmid, bool updStats=true)
size_t pickSetIdx(uint32_t sid, uint32_t ssid) const
void invalidateSID(uint32_t sid)
const Entry * lookup(uint32_t sid, uint32_t ssid, bool updStats=true)
ConfigCache(unsigned numEntries, unsigned _associativity, const std::string &policy, statistics::Group *parent)
void store(const Entry &incoming)
void invalidateSSID(uint32_t sid, uint32_t ssid)
std::vector< Set > sets
size_t pickEntryIdxToReplace(const Set &set)
void store(const Entry &incoming)
const Entry * lookup(Addr ipa, uint16_t vmid, bool updStats=true)
void invalidateIPAA(Addr ipa)
IPACache(unsigned numEntries, unsigned _associativity, const std::string &policy, statistics::Group *parent)
size_t pickSetIdx(Addr ipa, uint16_t vmid) const
size_t pickEntryIdxToReplace(const Set &set)
std::vector< Set > sets
void invalidateVMID(uint16_t vmid)
void invalidateIPA(Addr ipa, uint16_t vmid)
void invalidateSID(uint32_t sid)
std::vector< Set > sets
SMMUTLB(unsigned numEntries, unsigned _associativity, const std::string &policy, statistics::Group *parent, const std::string &name)
const Entry * lookupAnyVA(uint32_t sid, uint32_t ssid, bool updStats=true)
void invalidateVAA(Addr va, uint16_t vmid)
void invalidateASID(uint16_t asid, uint16_t vmid)
void store(const Entry &incoming, AllocPolicy alloc)
const Entry * lookup(uint32_t sid, uint32_t ssid, Addr va, bool updStats=true)
size_t pickSetIdx(uint32_t sid, uint32_t ssid) const
void invalidateVMID(uint16_t vmid)
size_t pickEntryIdxToReplace(const Set &set, AllocPolicy alloc)
void invalidateVA(Addr va, uint16_t asid, uint16_t vmid)
void invalidateSSID(uint32_t sid, uint32_t ssid)
static int decodePolicyName(const std::string &policy_name)
SMMUv3BaseCache(const std::string &policy_name, uint32_t seed, statistics::Group *parent, const std::string &name)
gem5::SMMUv3BaseCache::SMMUv3BaseCacheStats baseCacheStats
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)
void invalidateVAA(Addr va, uint16_t vmid, const bool leaf_only)
size_t pickEntryIdxToReplace(const Set &set, unsigned stage, unsigned level)
void invalidateVMID(uint16_t vmid)
void invalidateASID(uint16_t asid, uint16_t vmid)
size_t pickSetIdx(Addr va, Addr vaMask, unsigned stage, unsigned level) const
std::array< unsigned, 2 *WALK_CACHE_LEVELS > sizes
gem5::WalkCache::WalkCacheStats walkCacheStats
std::array< unsigned, 2 *WALK_CACHE_LEVELS > offsets
std::vector< Set > sets
void invalidateVA(Addr va, uint16_t asid, uint16_t vmid, const bool leaf_only)
WalkCache(const std::array< unsigned, 2 *WALK_CACHE_LEVELS > &_sizes, unsigned _associativity, const std::string &policy, statistics::Group *parent)
Derived & ysubname(off_type index, const std::string &subname)
Definition: statistics.hh:490
Derived & subname(off_type index, const std::string &name)
Set the subfield name for the given index, and marks this stat to print at the end of simulation.
Definition: statistics.hh:402
Derived & flags(Flags _flags)
Set the flags and marks this stat to print at the end of simulation.
Definition: statistics.hh:358
A formula for statistics that is calculated when printed.
Definition: statistics.hh:2540
Statistics container.
Definition: group.hh:94
Derived & init(size_type _x, size_type _y)
Definition: statistics.hh:1174
static Ratio * get()
Definition: units.hh:312
#define ADD_STAT(n,...)
Convenience macro to add a stat to a statistics group.
Definition: group.hh:75
std::enable_if_t< std::is_integral_v< T >, T > random()
Use the SFINAE idiom to choose an implementation based on whether the type is integral or floating po...
Definition: random.hh:90
constexpr int findLsbSet(uint64_t val)
Returns the bit position of the LSB that is set in the input.
Definition: bitfield.hh:296
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:178
#define fatal(...)
This implements a cprintf based fatal() function.
Definition: logging.hh:190
Bitfield< 7 > i
Definition: misc_types.hh:67
Bitfield< 23, 0 > offset
Definition: types.hh:144
Bitfield< 9 > e
Definition: misc_types.hh:65
Bitfield< 12, 11 > set
Definition: misc_types.hh:709
Bitfield< 8 > va
Definition: misc_types.hh:282
Bitfield< 1 > s
Definition: pagetable.hh:64
Bitfield< 55 > l
Definition: pagetable.hh:54
Bitfield< 20 > level
Definition: intmessage.hh:51
const FlagsType pdf
Print the percent of the total that this entry represents.
Definition: info.hh:62
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:147
std::string csprintf(const char *format, const Args &...args)
Definition: cprintf.hh:161
statistics::Formula & simSeconds
Definition: stats.cc:45
@ SMMU_CACHE_REPL_LRU
@ SMMU_CACHE_REPL_RANDOM
@ SMMU_CACHE_REPL_ROUND_ROBIN
#define SMMUTLB_SEED
#define ARMARCHTLB_SEED
#define WALKCACHE_SEED
#define IPACACHE_SEED
#define CONFIGCACHE_SEED
#define WALK_CACHE_LEVELS
SMMUv3BaseCacheStats(statistics::Group *parent, const std::string &name)
statistics::Vector2d totalLookupsByStageLevel
statistics::Vector2d totalMissesByStageLevel
WalkCacheStats(statistics::Group *parent)
std::vector< statistics::Formula * > averageMissesByStageLevel
statistics::Vector2d insertionsByStageLevel
std::vector< statistics::Formula * > averageHitRateByStageLevel
std::vector< statistics::Formula * > averageUpdatesByStageLevel
std::vector< statistics::Formula * > averageLookupsByStageLevel
statistics::Vector2d totalUpdatesByStageLevel
const std::string & name()
Definition: trace.cc:49

Generated on Wed Dec 21 2022 10:22:33 for gem5 by doxygen 1.9.1