add I$/D$/L2$ simulators
[riscv-isa-sim.git] / riscv / cachesim.cc
1 #include "cachesim.h"
2 #include <cstdlib>
3 #include <iostream>
4 #include <iomanip>
5
6 cache_sim_t::cache_sim_t(size_t _sets, size_t _ways, size_t _linesz, const char* _name)
7 : sets(_sets), ways(_ways), linesz(_linesz), name(_name)
8 {
9 init();
10 }
11
12 static void help()
13 {
14 std::cerr << "Cache configurations must be of the form" << std::endl;
15 std::cerr << " sets:ways:blocksize" << std::endl;
16 std::cerr << "where sets, ways, and blocksize are positive integers, with" << std::endl;
17 std::cerr << "sets and blocksize both powers of two and blocksize at least 8." << std::endl;
18 exit(1);
19 }
20
21 cache_sim_t::cache_sim_t(const char* config, const char* _name)
22 : name(_name)
23 {
24 const char* wp = strchr(config, ':');
25 if (!wp++) help();
26 const char* bp = strchr(wp, ':');
27 if (!bp++) help();
28
29 sets = atoi(std::string(config, wp).c_str());
30 ways = atoi(std::string(wp, bp).c_str());
31 linesz = atoi(bp);
32
33 init();
34 }
35
36 void cache_sim_t::init()
37 {
38 if(sets == 0 || (sets & (sets-1)))
39 help();
40 if(linesz < 8 || (linesz & (linesz-1)))
41 help();
42
43 idx_shift = 0;
44 for (size_t x = linesz; x; x >>= 1)
45 idx_shift++;
46
47 tags = new uint64_t[sets*ways]();
48 read_accesses = 0;
49 read_misses = 0;
50 bytes_read = 0;
51 write_accesses = 0;
52 write_misses = 0;
53 bytes_written = 0;
54 writebacks = 0;
55
56 miss_handler = NULL;
57 }
58
59 cache_sim_t::cache_sim_t(const cache_sim_t& rhs)
60 : sets(rhs.sets), ways(rhs.ways), linesz(rhs.linesz),
61 idx_shift(rhs.idx_shift), name(rhs.name)
62 {
63 tags = new uint64_t[sets*ways];
64 memcpy(tags, rhs.tags, sets*ways*sizeof(uint64_t));
65 }
66
67 cache_sim_t::~cache_sim_t()
68 {
69 print_stats();
70 delete [] tags;
71 }
72
73 void cache_sim_t::print_stats()
74 {
75 if(read_accesses + write_accesses == 0)
76 return;
77
78 float mr = 100.0f*(read_misses+write_misses)/(read_accesses+write_accesses);
79
80 std::cout << std::setprecision(3) << std::fixed;
81 std::cout << name << " ";
82 std::cout << "Bytes Read: " << bytes_read << std::endl;
83 std::cout << name << " ";
84 std::cout << "Bytes Written: " << bytes_written << std::endl;
85 std::cout << name << " ";
86 std::cout << "Read Accesses: " << read_accesses << std::endl;
87 std::cout << name << " ";
88 std::cout << "Write Accesses: " << write_accesses << std::endl;
89 std::cout << name << " ";
90 std::cout << "Read Misses: " << read_misses << std::endl;
91 std::cout << name << " ";
92 std::cout << "Write Misses: " << write_misses << std::endl;
93 std::cout << name << " ";
94 std::cout << "Writebacks: " << writebacks << std::endl;
95 std::cout << name << " ";
96 std::cout << "Miss Rate: " << mr << '%' << std::endl;
97 }
98
99 void cache_sim_t::access(uint64_t addr, size_t bytes, bool store)
100 {
101 store ? write_accesses++ : read_accesses++;
102 (store ? bytes_written : bytes_read) += bytes;
103
104 size_t idx = (addr >> idx_shift) & (sets-1);
105 size_t tag = (addr >> idx_shift) | VALID;
106 size_t* set_tags = &tags[idx*ways];
107
108 for(size_t i = 0; i < ways; i++)
109 {
110 if(tag == (set_tags[i] & ~DIRTY)) // hit
111 {
112 if(store)
113 set_tags[i] |= DIRTY;
114 return;
115 }
116 }
117
118 store ? write_misses++ : read_misses++;
119
120 size_t way = lfsr.next() % ways;
121 if((set_tags[way] & (VALID | DIRTY)) == (VALID | DIRTY))
122 {
123 uint64_t dirty_addr = (set_tags[way] & ~(VALID | DIRTY)) << idx_shift;
124 if (miss_handler) miss_handler->access(dirty_addr, linesz, true);
125 writebacks++;
126 }
127 if (miss_handler) miss_handler->access(addr & ~(linesz-1), linesz, false);
128 set_tags[way] = tag | (store ? DIRTY : 0);
129 }