diff options
| -rw-r--r-- | infra/arbiter.h | 31 | ||||
| -rw-r--r-- | memory/cache.h | 96 | ||||
| -rw-r--r-- | memory/dram.h | 50 | ||||
| -rw-r--r-- | memory/line.h | 4 |
4 files changed, 153 insertions, 28 deletions
diff --git a/infra/arbiter.h b/infra/arbiter.h index 79a9920..63ddbd6 100644 --- a/infra/arbiter.h +++ b/infra/arbiter.h | |||
| @@ -3,53 +3,40 @@ | |||
| 3 | #include <array> | 3 | #include <array> |
| 4 | #include <cassert> | 4 | #include <cassert> |
| 5 | 5 | ||
| 6 | #include "infra/port.h" | ||
| 6 | #include "infra/sim.h" | 7 | #include "infra/sim.h" |
| 7 | 8 | ||
| 8 | namespace infra { | 9 | namespace infra { |
| 9 | template<typename T, unsigned int peers> struct priority_arbiter : public sim { | 10 | template<typename T, unsigned int peers> struct priority_arbiter : public sim { |
| 10 | std::array<port<T>, peers> peerp; | 11 | std::array<port<T> *, peers> peerp; |
| 11 | port<T> *outp = nullptr; | 12 | port<T> *outp = nullptr; |
| 12 | 13 | ||
| 13 | void clock() { | 14 | void clock() { |
| 14 | for (unsigned int i = 0; i < peers; ++i) { | 15 | for (unsigned int i = 0; i < peers; ++i) { |
| 15 | if (outp->can_write() && peerp[i].can_read()) | 16 | if (outp->can_write() && peerp[i]->can_read()) |
| 16 | outp->write(peerp[i].read()); | 17 | outp->write(peerp[i]->read()); |
| 17 | } | 18 | } |
| 18 | } | 19 | } |
| 19 | }; | 20 | }; |
| 20 | 21 | ||
| 21 | template<typename T, unsigned int peers> struct round_robin_arbiter : public sim { | 22 | template<typename T, unsigned int peers> struct round_robin_arbiter : public sim { |
| 22 | std::array<port<T>, peers> peerp; | 23 | std::array<port<T> *, peers> peerp; |
| 23 | port<T> *outp = nullptr; | 24 | port<T> *outp = nullptr; |
| 24 | unsigned int initial = 0; | 25 | unsigned int initial = 0; |
| 25 | 26 | ||
| 26 | void clock() { | 27 | void clock() { |
| 27 | bool initially_empty = outp->can_write(); | 28 | bool initially_empty = outp->can_write(); |
| 28 | for (unsigned int i = initial; i < peers; ++i) { | 29 | for (unsigned int i = initial; i < peers; ++i) { |
| 29 | if (outp->can_write() && peerp[i].can_read()) | 30 | if (outp->can_write() && peerp[i]->can_read()) |
| 30 | outp->write(peerp[i].read()); | 31 | outp->write(peerp[i]->read()); |
| 31 | } | 32 | } |
| 32 | for (unsigned int i = 0; i < initial; ++i) { | 33 | for (unsigned int i = 0; i < initial; ++i) { |
| 33 | if (outp->can_write() && peerp[i].can_read()) | 34 | if (outp->can_write() && peerp[i]->can_read()) |
| 34 | outp->write(peerp[i].read()); | 35 | outp->write(peerp[i]->read()); |
| 35 | } | 36 | } |
| 36 | if (initially_empty && !outp->can_write()) | 37 | if (initially_empty && !outp->can_write()) |
| 37 | if (++initial == peers) | 38 | if (++initial == peers) |
| 38 | initial = 0; | 39 | initial = 0; |
| 39 | } | 40 | } |
| 40 | }; | 41 | }; |
| 41 | |||
| 42 | template<typename T, unsigned int peers> struct shared_bus : public sim { | ||
| 43 | std::array<port<T>, peers> peerp; | ||
| 44 | port<T> *outp = nullptr; | ||
| 45 | |||
| 46 | void clock() { | ||
| 47 | for (unsigned int i = 0; i < peers; ++i) { | ||
| 48 | if (peerp[i].can_read()) { | ||
| 49 | assert(outp->can_write()); | ||
| 50 | outp->write(peerp[i].read()); | ||
| 51 | } | ||
| 52 | } | ||
| 53 | } | ||
| 54 | }; | ||
| 55 | } | 42 | } |
diff --git a/memory/cache.h b/memory/cache.h new file mode 100644 index 0000000..8554910 --- /dev/null +++ b/memory/cache.h | |||
| @@ -0,0 +1,96 @@ | |||
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include <array> | ||
| 4 | #include <cstdint> | ||
| 5 | |||
| 6 | #include "memory/dram.h" | ||
| 7 | #include "memory/line.h" | ||
| 8 | |||
| 9 | namespace memory { | ||
| 10 | template<unsigned int SETS_LOG2, unsigned int WAYS> struct inline_cache { | ||
| 11 | static constexpr std::uint64_t SETS = 1 << SETS_LOG2; | ||
| 12 | static constexpr std::uint64_t LINE_SET_OFFSET_MASK = SETS - 1; | ||
| 13 | |||
| 14 | std::uint64_t last_serial = 0; | ||
| 15 | |||
| 16 | struct tag { | ||
| 17 | std::uint64_t serial = 0; | ||
| 18 | std::uint64_t line_address; | ||
| 19 | infra::transaction transaction; | ||
| 20 | }; | ||
| 21 | |||
| 22 | typedef std::array<tag, WAYS> set_tags; | ||
| 23 | typedef std::array<line, WAYS> set_data; | ||
| 24 | |||
| 25 | std::array<set_tags, SETS> tags; | ||
| 26 | std::array<set_data, SETS> data; | ||
| 27 | |||
| 28 | void handle_response(const dram::response &r) { | ||
| 29 | auto set_address = r.line_address & LINE_SET_OFFSET_MASK; | ||
| 30 | auto &stags = tags[set_address]; | ||
| 31 | auto &sdata = data[set_address]; | ||
| 32 | for (unsigned int i = 0; i < WAYS; ++i) { | ||
| 33 | auto &stag = stags[i]; | ||
| 34 | if (stag.serial && stag.line_address == r.line_address) { | ||
| 35 | handle_response(r, stag, sdata[i]); | ||
| 36 | return; | ||
| 37 | } | ||
| 38 | } | ||
| 39 | std::uint64_t min_serial = ~(std::uint64_t)0; | ||
| 40 | unsigned int victim; | ||
| 41 | for (unsigned int i = 0; i < WAYS; ++i) { | ||
| 42 | auto &stag = stags[i]; | ||
| 43 | if (stag.serial < min_serial) { | ||
| 44 | min_serial = stag.serial; | ||
| 45 | victim = i; | ||
| 46 | } | ||
| 47 | } | ||
| 48 | handle_response(r, stags[victim], sdata[victim]); | ||
| 49 | } | ||
| 50 | |||
| 51 | void handle_response(const dram::response &r, tag &t, line &d) { | ||
| 52 | t.serial = ++last_serial; | ||
| 53 | t.line_address = r.line_address; | ||
| 54 | t.transaction = r.transaction; | ||
| 55 | d = r.data; | ||
| 56 | } | ||
| 57 | |||
| 58 | std::optional<tag> probe(std::uint64_t address) { | ||
| 59 | auto line_address = address >> LINE_BYTES_LOG2; | ||
| 60 | auto set_address = line_address & LINE_SET_OFFSET_MASK; | ||
| 61 | auto &stags = tags[set_address]; | ||
| 62 | for (unsigned int i = 0; i < WAYS; ++i) { | ||
| 63 | auto &stag = stags[i]; | ||
| 64 | if (stag.serial && stag.line_address == line_address) | ||
| 65 | return stag; | ||
| 66 | } | ||
| 67 | return {}; | ||
| 68 | } | ||
| 69 | |||
| 70 | std::optional<tag> fetchline(line &dst, std::uint64_t address) { | ||
| 71 | auto line_address = address >> LINE_BYTES_LOG2; | ||
| 72 | auto set_address = line_address & LINE_SET_OFFSET_MASK; | ||
| 73 | auto &stags = tags[set_address]; | ||
| 74 | auto &sdata = data[set_address]; | ||
| 75 | for (unsigned int i = 0; i < WAYS; ++i) { | ||
| 76 | auto &stag = stags[i]; | ||
| 77 | if (stag.serial && stag.line_address == line_address) { | ||
| 78 | stag.serial = ++last_serial; | ||
| 79 | dst = sdata[i]; | ||
| 80 | return stag; | ||
| 81 | } | ||
| 82 | } | ||
| 83 | return {}; | ||
| 84 | } | ||
| 85 | |||
| 86 | std::optional<tag> fetch(unsigned int &dst, std::uint64_t address) { | ||
| 87 | line data; | ||
| 88 | if (auto tag = fetchline(data, address); tag.has_value()) { | ||
| 89 | auto line_offset = address & LINE_BYTE_OFFSET_MASK; | ||
| 90 | dst = data[line_offset]; | ||
| 91 | return tag; | ||
| 92 | } | ||
| 93 | return {}; | ||
| 94 | } | ||
| 95 | }; | ||
| 96 | } | ||
diff --git a/memory/dram.h b/memory/dram.h index f59c7a6..31aea12 100644 --- a/memory/dram.h +++ b/memory/dram.h | |||
| @@ -21,6 +21,8 @@ namespace memory { | |||
| 21 | 21 | ||
| 22 | typedef std::array<line, PAGE_LINES> page; | 22 | typedef std::array<line, PAGE_LINES> page; |
| 23 | 23 | ||
| 24 | const unsigned int latency; | ||
| 25 | |||
| 24 | std::map<std::uint64_t, page> image; | 26 | std::map<std::uint64_t, page> image; |
| 25 | 27 | ||
| 26 | struct response { | 28 | struct response { |
| @@ -38,11 +40,26 @@ namespace memory { | |||
| 38 | infra::port<response> *responsep = nullptr; | 40 | infra::port<response> *responsep = nullptr; |
| 39 | }; | 41 | }; |
| 40 | 42 | ||
| 41 | infra::port<command> commandp; | 43 | infra::port<command> *commandp = nullptr; |
| 44 | |||
| 45 | unsigned int progress = 0; | ||
| 46 | std::optional<command> current_command; | ||
| 47 | |||
| 48 | dram(unsigned int latency=0) | ||
| 49 | : latency(latency) | ||
| 50 | { } | ||
| 42 | 51 | ||
| 43 | void clock() { | 52 | void clock() { |
| 44 | if (commandp.can_read()) { | 53 | if (!current_command.has_value() && commandp->can_read()) { |
| 45 | const auto &c = commandp.peek(); | 54 | current_command = commandp->read(); |
| 55 | progress = latency; | ||
| 56 | } | ||
| 57 | if (current_command.has_value()) { | ||
| 58 | if (progress) { | ||
| 59 | --progress; | ||
| 60 | return; | ||
| 61 | } | ||
| 62 | const auto &c = *current_command; | ||
| 46 | if (!c.responsep || c.responsep->can_write()) { | 63 | if (!c.responsep || c.responsep->can_write()) { |
| 47 | auto page_address = c.line_address >> PAGE_LINES_LOG2; | 64 | auto page_address = c.line_address >> PAGE_LINES_LOG2; |
| 48 | auto page_line = c.line_address & PAGE_LINE_OFFSET_MASK; | 65 | auto page_line = c.line_address & PAGE_LINE_OFFSET_MASK; |
| @@ -76,7 +93,7 @@ namespace memory { | |||
| 76 | c.responsep->write(std::move(r)); | 93 | c.responsep->write(std::move(r)); |
| 77 | } | 94 | } |
| 78 | } | 95 | } |
| 79 | commandp.discard(); | 96 | current_command.reset(); |
| 80 | } | 97 | } |
| 81 | } | 98 | } |
| 82 | } | 99 | } |
| @@ -92,5 +109,30 @@ namespace memory { | |||
| 92 | return; | 109 | return; |
| 93 | } | 110 | } |
| 94 | } | 111 | } |
| 112 | |||
| 113 | unsigned int fetch(std::uint64_t address) const { | ||
| 114 | auto page_address = address >> PAGE_LINES_LOG2; | ||
| 115 | if (auto i = image.find(page_address); i != image.end()) { | ||
| 116 | auto &page = i->second; | ||
| 117 | auto line_address = (address & PAGE_LINE_OFFSET_MASK) >> LINE_BYTES_LOG2; | ||
| 118 | auto &line = page[line_address]; | ||
| 119 | auto word_address = address & LINE_BYTE_OFFSET_MASK; | ||
| 120 | return line[word_address]; | ||
| 121 | } | ||
| 122 | return 0; | ||
| 123 | } | ||
| 124 | |||
| 125 | void store(std::uint64_t address, unsigned int value) { | ||
| 126 | auto page_address = address >> PAGE_LINES_LOG2; | ||
| 127 | auto [p, emplaced] = image.try_emplace(page_address); | ||
| 128 | auto &page = p->second; | ||
| 129 | if (emplaced) | ||
| 130 | for (unsigned int i = 0; i < PAGE_LINES; ++i) | ||
| 131 | page[i].fill(0); | ||
| 132 | auto line_address = (address & PAGE_LINE_OFFSET_MASK) >> LINE_BYTES_LOG2; | ||
| 133 | auto &line = page[line_address]; | ||
| 134 | auto word_address = address & LINE_BYTE_OFFSET_MASK; | ||
| 135 | line[word_address] = value; | ||
| 136 | } | ||
| 95 | }; | 137 | }; |
| 96 | } | 138 | } |
diff --git a/memory/line.h b/memory/line.h index 3377ec8..82b85f5 100644 --- a/memory/line.h +++ b/memory/line.h | |||
| @@ -7,9 +7,9 @@ | |||
| 7 | #include "infra/sim.h" | 7 | #include "infra/sim.h" |
| 8 | 8 | ||
| 9 | namespace memory { | 9 | namespace memory { |
| 10 | constexpr std::uint64_t LINE_BYTES_LOG2 = 4; | 10 | constexpr std::uint64_t LINE_BYTES_LOG2 = 2; |
| 11 | constexpr std::uint64_t LINE_BYTES = 1 << LINE_BYTES_LOG2; | 11 | constexpr std::uint64_t LINE_BYTES = 1 << LINE_BYTES_LOG2; |
| 12 | constexpr std::uint64_t LINE_BYTE_OFFSET_MASK = LINE_BYTES - 1; | 12 | constexpr std::uint64_t LINE_BYTE_OFFSET_MASK = LINE_BYTES - 1; |
| 13 | 13 | ||
| 14 | typedef std::array<std::uint8_t, LINE_BYTES> line; | 14 | typedef std::array<unsigned int, LINE_BYTES> line; |
| 15 | } | 15 | } |
