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