cd33ca11f58328ee3e5f26d7fbc86f33f820a858
[riscv-isa-sim.git] / riscv / cachesim.cc
1 #include "cachesim.h"
2 #include "common.h"
3 #include <cstdlib>
4 #include <iostream>
5 #include <iomanip>
6
7 cache_sim_t::cache_sim_t(size_t _sets, size_t _ways, size_t _linesz, const char* _name)
8 : sets(_sets), ways(_ways), linesz(_linesz), name(_name)
9 {
10 init();
11 }
12
13 static void help()
14 {
15 std::cerr << "Cache configurations must be of the form" << std::endl;
16 std::cerr << " sets:ways:blocksize" << std::endl;
17 std::cerr << "where sets, ways, and blocksize are positive integers, with" << std::endl;
18 std::cerr << "sets and blocksize both powers of two and blocksize at least 8." << std::endl;
19 exit(1);
20 }
21
22 cache_sim_t* cache_sim_t::construct(const char* config, const char* name)
23 {
24 const char* wp = strchr(config, ':');
25 if (!wp++) help();
26 const char* bp = strchr(wp, ':');
27 if (!bp++) help();
28
29 size_t sets = atoi(std::string(config, wp).c_str());
30 size_t ways = atoi(std::string(wp, bp).c_str());
31 size_t linesz = atoi(bp);
32
33 if (ways > 4 /* empirical */ && sets == 1)
34 return new fa_cache_sim_t(ways, linesz, name);
35 return new cache_sim_t(sets, ways, linesz, name);
36 }
37
38 void cache_sim_t::init()
39 {
40 if(sets == 0 || (sets & (sets-1)))
41 help();
42 if(linesz < 8 || (linesz & (linesz-1)))
43 help();
44
45 idx_shift = 0;
46 for (size_t x = linesz; x; x >>= 1)
47 idx_shift++;
48
49 tags = new uint64_t[sets*ways]();
50 read_accesses = 0;
51 read_misses = 0;
52 bytes_read = 0;
53 write_accesses = 0;
54 write_misses = 0;
55 bytes_written = 0;
56 writebacks = 0;
57
58 miss_handler = NULL;
59 }
60
61 cache_sim_t::cache_sim_t(const cache_sim_t& rhs)
62 : sets(rhs.sets), ways(rhs.ways), linesz(rhs.linesz),
63 idx_shift(rhs.idx_shift), name(rhs.name)
64 {
65 tags = new uint64_t[sets*ways];
66 memcpy(tags, rhs.tags, sets*ways*sizeof(uint64_t));
67 }
68
69 cache_sim_t::~cache_sim_t()
70 {
71 print_stats();
72 delete [] tags;
73 }
74
75 void cache_sim_t::print_stats()
76 {
77 if(read_accesses + write_accesses == 0)
78 return;
79
80 float mr = 100.0f*(read_misses+write_misses)/(read_accesses+write_accesses);
81
82 std::cout << std::setprecision(3) << std::fixed;
83 std::cout << name << " ";
84 std::cout << "Bytes Read: " << bytes_read << std::endl;
85 std::cout << name << " ";
86 std::cout << "Bytes Written: " << bytes_written << std::endl;
87 std::cout << name << " ";
88 std::cout << "Read Accesses: " << read_accesses << std::endl;
89 std::cout << name << " ";
90 std::cout << "Write Accesses: " << write_accesses << std::endl;
91 std::cout << name << " ";
92 std::cout << "Read Misses: " << read_misses << std::endl;
93 std::cout << name << " ";
94 std::cout << "Write Misses: " << write_misses << std::endl;
95 std::cout << name << " ";
96 std::cout << "Writebacks: " << writebacks << std::endl;
97 std::cout << name << " ";
98 std::cout << "Miss Rate: " << mr << '%' << std::endl;
99 }
100
101 uint64_t* cache_sim_t::check_tag(uint64_t addr)
102 {
103 size_t idx = (addr >> idx_shift) & (sets-1);
104 size_t tag = (addr >> idx_shift) | VALID;
105
106 for (size_t i = 0; i < ways; i++)
107 if (tag == (tags[idx*ways + i] & ~DIRTY))
108 return &tags[idx*ways + i];
109
110 return NULL;
111 }
112
113 uint64_t cache_sim_t::victimize(uint64_t addr)
114 {
115 size_t idx = (addr >> idx_shift) & (sets-1);
116 size_t way = lfsr.next() % ways;
117 uint64_t victim = tags[idx*ways + way];
118 tags[idx*ways + way] = (addr >> idx_shift) | VALID;
119 return victim;
120 }
121
122 void cache_sim_t::access(uint64_t addr, size_t bytes, bool store)
123 {
124 store ? write_accesses++ : read_accesses++;
125 (store ? bytes_written : bytes_read) += bytes;
126
127 uint64_t* hit_way = check_tag(addr);
128 if (likely(hit_way != NULL))
129 {
130 if (store)
131 *hit_way |= DIRTY;
132 return;
133 }
134
135 store ? write_misses++ : read_misses++;
136
137 uint64_t victim = victimize(addr);
138
139 if ((victim & (VALID | DIRTY)) == (VALID | DIRTY))
140 {
141 uint64_t dirty_addr = (victim & ~(VALID | DIRTY)) << idx_shift;
142 if (miss_handler)
143 miss_handler->access(dirty_addr, linesz, true);
144 writebacks++;
145 }
146
147 if (miss_handler)
148 miss_handler->access(addr & ~(linesz-1), linesz, false);
149
150 if (store)
151 *check_tag(addr) |= DIRTY;
152 }
153
154 fa_cache_sim_t::fa_cache_sim_t(size_t ways, size_t linesz, const char* name)
155 : cache_sim_t(1, ways, linesz, name)
156 {
157 }
158
159 uint64_t* fa_cache_sim_t::check_tag(uint64_t addr)
160 {
161 auto it = tags.find(addr >> idx_shift);
162 return it == tags.end() ? NULL : &it->second;
163 }
164
165 uint64_t fa_cache_sim_t::victimize(uint64_t addr)
166 {
167 uint64_t old_tag = 0;
168 if (tags.size() == ways)
169 {
170 auto it = tags.begin();
171 std::advance(it, lfsr.next() % ways);
172 old_tag = it->second;
173 tags.erase(it);
174 }
175 tags[addr >> idx_shift] = (addr >> idx_shift) | VALID;
176 return old_tag;
177 }