gem5 v24.0.0.0
Loading...
Searching...
No Matches
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
61namespace gem5
62{
63
64SMMUv3BaseCache::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
73int
74SMMUv3BaseCache::decodePolicyName(const std::string &policy_name)
75{
76 if (policy_name == "rr") {
78 } else if (policy_name == "rand") {
80 } else if (policy_name == "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
146 .flags(pdf);
147}
148
149/*
150 * SMMUTLB
151 */
152
153SMMUTLB::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
183const SMMUTLB::Entry*
184SMMUTLB::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
217const SMMUTLB::Entry*
218SMMUTLB::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
244void
245SMMUTLB::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
265void
266SMMUTLB::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
278void
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
293void
294SMMUTLB::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
309void
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
322void
323SMMUTLB::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
337void
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
352void
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
363size_t
365{
366 return (va >> 12) % sets.size();
367}
368
369size_t
370SMMUTLB::pickSetIdx(uint32_t sid, uint32_t ssid) const
371{
372 return (sid^ssid) % sets.size();
373}
374
375size_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 =
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:
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
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
434ARMArchTLB::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
463const ARMArchTLB::Entry *
464ARMArchTLB::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
496void
497ARMArchTLB::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
517void
518ARMArchTLB::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
533void
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
548void
549ARMArchTLB::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
563void
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
578void
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
589size_t
590ARMArchTLB::pickSetIdx(Addr va, uint16_t asid, uint16_t vmid) const
591{
592 return ((va >> 12) ^ asid ^ vmid) % sets.size();
593}
594
595size_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) {
616
618 return random.random<size_t>(0, associativity-1);
619
621 return lru_idx;
622
623 default:
624 panic("Unknown replacement policy %d\n", replacementPolicy);
625 }
626
627}
628
629/*
630 * IPACache
631 */
632
633IPACache::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
662const IPACache::Entry*
663IPACache::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
695void
696IPACache::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
715void
716IPACache::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
728void
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
743void
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
758void
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
769size_t
770IPACache::pickSetIdx(Addr va, uint16_t vmid) const
771{
772 return ((va >> 12) ^ vmid) % sets.size();
773}
774
775size_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) {
796
798 return random.random<size_t>(0, associativity-1);
799
801 return lru_idx;
802
803 default:
804 panic("Unknown replacement policy %d\n", replacementPolicy);
805 }
806
807}
808
809/*
810 * ConfigCache
811 */
812
813ConfigCache::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
842const ConfigCache::Entry *
843ConfigCache::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
874void
875ConfigCache::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
894void
895ConfigCache::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
907void
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
922void
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
933size_t
934ConfigCache::pickSetIdx(uint32_t sid, uint32_t ssid) const
935{
936 return (sid^ssid) % sets.size();
937}
938
939size_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) {
960
962 return random.random<size_t>(0, associativity-1);
963
965 return lru_idx;
966
967 default:
968 panic("Unknown replacement policy %d\n", replacementPolicy);
969 }
970
971}
972
973/*
974 * WalkCache
975 */
976
977WalkCache::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
1017 sets.resize(num_sets, set);
1018}
1019
1020const 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
1061void
1062WalkCache::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
1090void
1091WalkCache::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
1109void
1110WalkCache::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
1127void
1128WalkCache::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
1142void
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
1157void
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
1168size_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
1196size_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
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
1247 .flags(pdf);
1250 .flags(pdf);
1253 .flags(pdf);
1256 .flags(pdf);
1257
1258 for (int s = 0; s < 2; s++) {
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(),
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(),
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(),
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)
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.
Derived & flags(Flags _flags)
Set the flags and marks this stat to print at the end of simulation.
A formula for statistics that is calculated when printed.
Statistics container.
Definition group.hh:93
Derived & init(size_type _x, size_type _y)
#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 That function will either use a builtin ...
Definition bitfield.hh:369
#define panic(...)
This implements a cprintf based panic() function.
Definition logging.hh:188
#define fatal(...)
This implements a cprintf based fatal() function.
Definition logging.hh:200
Bitfield< 4 > s
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
Bitfield< 8 > va
Bitfield< 5 > l
Bitfield< 20 > level
Definition intmessage.hh:51
const FlagsType pdf
Print the percent of the total that this entry represents.
Definition info.hh:61
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
Definition binary32.hh:36
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition types.hh:147
@ SMMU_CACHE_REPL_LRU
@ SMMU_CACHE_REPL_RANDOM
@ SMMU_CACHE_REPL_ROUND_ROBIN
std::string csprintf(const char *format, const Args &...args)
Definition cprintf.hh:161
statistics::Formula & simSeconds
Definition stats.cc:45
#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:48

Generated on Tue Jun 18 2024 16:24:03 for gem5 by doxygen 1.11.0