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
95
96
|
#pragma once
#include <array>
#include <cstdint>
#include <cstring>
#include <istream>
#include <map>
#include <string>
#include <utility>
#include "memory/line.h"
namespace memory {
struct dram : public infra::sim {
static constexpr std::uint64_t PAGE_LINES_LOG2 = 20 - LINE_BYTES_LOG2;
static constexpr std::uint64_t PAGE_LINES = 1 << PAGE_LINES_LOG2;
static constexpr std::uint64_t PAGE_LINE_OFFSET_MASK = PAGE_LINES - 1;
static constexpr std::uint64_t PAGE_BYTES_LOG2 = PAGE_LINES_LOG2 + LINE_BYTES_LOG2;
static constexpr std::uint64_t PAGE_BYTES = 1 << PAGE_BYTES_LOG2;
static constexpr std::uint64_t PAGE_BYTE_OFFSET_MASK = PAGE_BYTES - 1;
typedef std::array<line, PAGE_LINES> page;
std::map<std::uint64_t, page> image;
struct response {
infra::transaction transaction;
std::uint64_t line_address;
line data;
};
struct command {
infra::transaction transaction;
std::uint64_t line_address;
line data;
std::array<bool, LINE_BYTES> mask;
bool write = false;
infra::port<response> *responsep = nullptr;
};
infra::port<command> commandp;
void clock() {
if (commandp.can_read()) {
const auto &c = commandp.peek();
if (!c.responsep || c.responsep->can_write()) {
auto page_address = c.line_address >> PAGE_LINES_LOG2;
auto page_line = c.line_address & PAGE_LINE_OFFSET_MASK;
if (c.write) {
pte(c.transaction, "s", fmt::format("store {:x}-{:x}", page_address, page_line));
if (c.responsep) {
response r;
r.transaction = c.transaction;
r.line_address = c.line_address;
r.data = c.data;
c.responsep->write(std::move(r));
}
auto [p, emplaced] = image.try_emplace(page_address);
if (emplaced)
for (unsigned int i = 0; i < PAGE_LINES; ++i)
p->second[i].fill(0);
auto &l = p->second[page_line];
for (unsigned int i = 0; i < LINE_BYTES; ++i)
if (c.mask[i])
l[i] = c.data[i];
} else {
pte(c.transaction, "f", fmt::format("fill {:x}-{:x}", page_address, page_line));
if (c.responsep) {
response r;
r.transaction = c.transaction;
r.line_address = c.line_address;
if (auto p = image.find(page_address); p != image.end())
r.data = p->second[page_line];
else
r.data.fill(0);
c.responsep->write(std::move(r));
}
}
commandp.discard();
}
}
}
void load(std::istream &fh) {
for (unsigned int page = 0; ; ++page) {
auto [p, emplaced] = image.try_emplace(page);
if (emplaced)
for (unsigned int i = 0; i < PAGE_LINES; ++i)
p->second[i].fill(0);
for (unsigned int line = 0; line < PAGE_LINES; ++line)
if (!fh.read(reinterpret_cast<char *>(p->second[line].data()), LINE_BYTES))
return;
}
}
};
}
|