forked from chipsalliance/VeeR-ISS
-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathFetchCache.hpp
94 lines (80 loc) · 2.41 KB
/
FetchCache.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include <cassert>
#include <unordered_map>
namespace TT_FETCH_CACHE
{
/// Model an instruction cache.
class FetchCache
{
public:
FetchCache(unsigned lineSize = 64)
: lineSize_(lineSize)
{
assert(lineSize > 0 and (lineSize % 8) == 0);
lineShift_ = std::log2(lineSize);
}
/// Add a line to the cache. Data is obtained by calling fetchMem
/// for the words of the line. Return true on success. Return false
/// if any of the memory reads fails.
bool addLine(uint64_t addr, std::function<bool(uint64_t, uint32_t&)> fetchMem)
{
uint64_t lineNum = addr >> lineShift_;
auto& vec = data_[lineNum];
vec.resize(lineSize_);
bool ok = true;
unsigned words = lineSize_ / 4;
addr = lineNum << lineShift_;
for (unsigned i = 0; i < words; ++i, addr += 4)
{
uint32_t val = 0;
ok = fetchMem(addr, val) and ok;
unsigned j = i * 4;
vec.at(j) = val;
vec.at(j + 1) = val >> 8;
vec.at(j + 2) = val >> 16;
vec.at(j + 3) = val >> 24;
}
return ok;
}
/// Remove from this cashe the line contining the given address.
/// No-op if line is not in cache.
void removeLine(uint64_t addr)
{
uint64_t lineNum = addr >> lineShift_;
data_.erase(lineNum);
}
/// Read into inst the 2-bytes at the given address. Return true on success. Return
/// false if addr is not aligned (even) or if the corresponding line is not in the
/// cache.
bool read(uint64_t addr, uint16_t& inst) const
{
if (addr & 1)
return false; // Addr must be even.
uint64_t lineNum = addr >> lineShift_;
auto iter = data_.find(lineNum);
if (iter == data_.end())
return false;
auto& vec = iter->second;
unsigned byteIx = addr % lineSize_;
inst = vec.at(byteIx) | (uint16_t(vec.at(byteIx + 1)) << 8);
return true;
}
/// Poke byte if given address is in the cache. No-op otherwise.
void poke(uint64_t addr, uint8_t byte)
{
uint64_t lineNum = addr >> lineShift_;
auto iter = data_.find(lineNum);
if (iter == data_.end())
return;
auto& vec = iter->second;
unsigned byteIx = addr % lineSize_;
vec.at(byteIx) = byte;
}
/// Empty fetch cache.
void clear()
{ data_.clear(); }
private:
unsigned lineSize_ = 64;
unsigned lineShift_ = 6;
std::unordered_map< uint64_t, std::vector<uint8_t> > data_;
};
}