From eaef9348431ea331ecf118aefc21246dbcf2c998 Mon Sep 17 00:00:00 2001 From: Julian Blake Kongslie Date: Sat, 15 Oct 2022 14:03:28 -0700 Subject: Add memory implementation as well; reorg. --- arbiter.h | 55 ------------------------------ infra/arbiter.h | 55 ++++++++++++++++++++++++++++++ infra/pipetrace.cpp | 9 +++++ infra/pipetrace.h | 37 +++++++++++++++++++++ infra/port.h | 45 +++++++++++++++++++++++++ infra/queue.h | 29 ++++++++++++++++ infra/sim.cpp | 9 +++++ infra/sim.h | 38 +++++++++++++++++++++ infra/stat.h | 35 +++++++++++++++++++ memory/dram.h | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++ memory/line.h | 15 +++++++++ pipetrace.cpp | 9 ----- pipetrace.h | 37 --------------------- port.h | 45 ------------------------- queue.h | 29 ---------------- sim.cpp | 9 ----- sim.h | 38 --------------------- stat.h | 35 ------------------- 18 files changed, 368 insertions(+), 257 deletions(-) delete mode 100644 arbiter.h create mode 100644 infra/arbiter.h create mode 100644 infra/pipetrace.cpp create mode 100644 infra/pipetrace.h create mode 100644 infra/port.h create mode 100644 infra/queue.h create mode 100644 infra/sim.cpp create mode 100644 infra/sim.h create mode 100644 infra/stat.h create mode 100644 memory/dram.h create mode 100644 memory/line.h delete mode 100644 pipetrace.cpp delete mode 100644 pipetrace.h delete mode 100644 port.h delete mode 100644 queue.h delete mode 100644 sim.cpp delete mode 100644 sim.h delete mode 100644 stat.h diff --git a/arbiter.h b/arbiter.h deleted file mode 100644 index 79a9920..0000000 --- a/arbiter.h +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once - -#include -#include - -#include "infra/sim.h" - -namespace infra { - template struct priority_arbiter : public sim { - std::array, peers> peerp; - port *outp = nullptr; - - void clock() { - for (unsigned int i = 0; i < peers; ++i) { - if (outp->can_write() && peerp[i].can_read()) - outp->write(peerp[i].read()); - } - } - }; - - template struct round_robin_arbiter : public sim { - std::array, peers> peerp; - port *outp = nullptr; - unsigned int initial = 0; - - void clock() { - bool initially_empty = outp->can_write(); - for (unsigned int i = initial; i < peers; ++i) { - if (outp->can_write() && peerp[i].can_read()) - outp->write(peerp[i].read()); - } - for (unsigned int i = 0; i < initial; ++i) { - if (outp->can_write() && peerp[i].can_read()) - outp->write(peerp[i].read()); - } - if (initially_empty && !outp->can_write()) - if (++initial == peers) - initial = 0; - } - }; - - template struct shared_bus : public sim { - std::array, peers> peerp; - port *outp = nullptr; - - void clock() { - for (unsigned int i = 0; i < peers; ++i) { - if (peerp[i].can_read()) { - assert(outp->can_write()); - outp->write(peerp[i].read()); - } - } - } - }; -} diff --git a/infra/arbiter.h b/infra/arbiter.h new file mode 100644 index 0000000..79a9920 --- /dev/null +++ b/infra/arbiter.h @@ -0,0 +1,55 @@ +#pragma once + +#include +#include + +#include "infra/sim.h" + +namespace infra { + template struct priority_arbiter : public sim { + std::array, peers> peerp; + port *outp = nullptr; + + void clock() { + for (unsigned int i = 0; i < peers; ++i) { + if (outp->can_write() && peerp[i].can_read()) + outp->write(peerp[i].read()); + } + } + }; + + template struct round_robin_arbiter : public sim { + std::array, peers> peerp; + port *outp = nullptr; + unsigned int initial = 0; + + void clock() { + bool initially_empty = outp->can_write(); + for (unsigned int i = initial; i < peers; ++i) { + if (outp->can_write() && peerp[i].can_read()) + outp->write(peerp[i].read()); + } + for (unsigned int i = 0; i < initial; ++i) { + if (outp->can_write() && peerp[i].can_read()) + outp->write(peerp[i].read()); + } + if (initially_empty && !outp->can_write()) + if (++initial == peers) + initial = 0; + } + }; + + template struct shared_bus : public sim { + std::array, peers> peerp; + port *outp = nullptr; + + void clock() { + for (unsigned int i = 0; i < peers; ++i) { + if (peerp[i].can_read()) { + assert(outp->can_write()); + outp->write(peerp[i].read()); + } + } + } + }; +} diff --git a/infra/pipetrace.cpp b/infra/pipetrace.cpp new file mode 100644 index 0000000..e6642ef --- /dev/null +++ b/infra/pipetrace.cpp @@ -0,0 +1,9 @@ +#include +#include + +#include "infra/pipetrace.h" + +namespace infra { + std::ostream *pt::ptfile = nullptr; + std::uint64_t pt::next_record = 0; +} diff --git a/infra/pipetrace.h b/infra/pipetrace.h new file mode 100644 index 0000000..656b9b9 --- /dev/null +++ b/infra/pipetrace.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include +#include +#include + +namespace infra { + struct transaction { + std::uint64_t record = ~(std::uint64_t)0; + }; + + struct pt { + static std::ostream *ptfile; + + static std::uint64_t next_record; + + static transaction toplevel() { + transaction t; + t.record = next_record++; + return t; + } + + static transaction child(const transaction &p) { + transaction t; + t.record = next_record++; + if (ptfile) + *ptfile << fmt::format("{} parent {}\n", t.record, p.record); + return t; + } + + static void event(const transaction &t, const char *event, std::uint64_t time, const std::string &data) { + if (ptfile) + *ptfile << fmt::format("@{} {} {} {}\n", time, t.record, event, data); + } + }; +} diff --git a/infra/port.h b/infra/port.h new file mode 100644 index 0000000..06a3aa5 --- /dev/null +++ b/infra/port.h @@ -0,0 +1,45 @@ +#pragma once + +#include +#include +#include + +#include "infra/sim.h" + +namespace infra { + template struct port : public sim { + std::optional consumer_side; + std::optional producer_side; + + bool can_read() { return consumer_side.has_value(); } + bool can_write() { return !producer_side.has_value(); } + + T read() { + assert(can_read()); + auto x = std::move(*consumer_side); + consumer_side.reset(); + return x; + } + + const T & peek() { + assert(can_read()); + return *consumer_side; + } + + void discard() { + consumer_side.reset(); + } + + void write(T &&x) { + assert(can_write()); + producer_side = std::move(x); + } + + void unclock() { + if (!consumer_side && producer_side) { + consumer_side = std::move(*producer_side); + producer_side.reset(); + } + } + }; +} diff --git a/infra/queue.h b/infra/queue.h new file mode 100644 index 0000000..1e490bc --- /dev/null +++ b/infra/queue.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include +#include + +#include "infra/port.h" +#include "infra/sim.h" + +namespace infra { + template struct queue : public sim { + port input; + port *output = nullptr; + std::deque elements; + + void clock() { + if (input.can_read() && elements.size() < size) { + auto x = input.read(); + elements.emplace_back(std::move(x)); + } + if (output->can_write() && !elements.empty()) { + auto &x = elements.front(); + output->write(std::move(x)); + elements.pop_front(); + } + } + }; +} diff --git a/infra/sim.cpp b/infra/sim.cpp new file mode 100644 index 0000000..21acc8c --- /dev/null +++ b/infra/sim.cpp @@ -0,0 +1,9 @@ +#include +#include + +#include "infra/sim.h" + +namespace infra { + std::vector sim::sims; + std::uint64_t sim::now = 0; +} diff --git a/infra/sim.h b/infra/sim.h new file mode 100644 index 0000000..185916a --- /dev/null +++ b/infra/sim.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include +#include + +#include "infra/pipetrace.h" + +namespace infra { + struct sim { + virtual void clock() {} + virtual void unclock() {} + + static std::vector sims; + + static std::uint64_t now; + + sim() { + sims.emplace_back(this); + } + + virtual ~sim() { + std::erase(sims, this); + } + + static void advance() { + for (auto &s : sims) + s->clock(); + for (auto &s : sims) + s->unclock(); + ++now; + } + + void pte(const transaction &t, const char *event, const std::string &data) { + pt::event(t, event, now, data); + } + }; +} diff --git a/infra/stat.h b/infra/stat.h new file mode 100644 index 0000000..f1ca75a --- /dev/null +++ b/infra/stat.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include + +#include "infra/sim.h" + +namespace infra { + struct stat : public sim { + std::string name; + std::uint64_t numerator = 0; + std::uint64_t denominator = 0; + + stat(std::string name) + : name(std::move(name)) + { } + + ~stat() { + fmt::print("# {} {}\n", name, (double)numerator/(double)denominator); + } + + void unclock() { + ++denominator; + } + + stat & operator++() { + ++numerator; + return *this; + } + + stat & operator++(int) { + return operator++(); + } + }; +} diff --git a/memory/dram.h b/memory/dram.h new file mode 100644 index 0000000..f59c7a6 --- /dev/null +++ b/memory/dram.h @@ -0,0 +1,96 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#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 page; + + std::map 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 mask; + bool write = false; + infra::port *responsep = nullptr; + }; + + infra::port 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(p->second[line].data()), LINE_BYTES)) + return; + } + } + }; +} diff --git a/memory/line.h b/memory/line.h new file mode 100644 index 0000000..3377ec8 --- /dev/null +++ b/memory/line.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +#include "infra/port.h" +#include "infra/sim.h" + +namespace memory { + constexpr std::uint64_t LINE_BYTES_LOG2 = 4; + constexpr std::uint64_t LINE_BYTES = 1 << LINE_BYTES_LOG2; + constexpr std::uint64_t LINE_BYTE_OFFSET_MASK = LINE_BYTES - 1; + + typedef std::array line; +} diff --git a/pipetrace.cpp b/pipetrace.cpp deleted file mode 100644 index e6642ef..0000000 --- a/pipetrace.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include -#include - -#include "infra/pipetrace.h" - -namespace infra { - std::ostream *pt::ptfile = nullptr; - std::uint64_t pt::next_record = 0; -} diff --git a/pipetrace.h b/pipetrace.h deleted file mode 100644 index 656b9b9..0000000 --- a/pipetrace.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace infra { - struct transaction { - std::uint64_t record = ~(std::uint64_t)0; - }; - - struct pt { - static std::ostream *ptfile; - - static std::uint64_t next_record; - - static transaction toplevel() { - transaction t; - t.record = next_record++; - return t; - } - - static transaction child(const transaction &p) { - transaction t; - t.record = next_record++; - if (ptfile) - *ptfile << fmt::format("{} parent {}\n", t.record, p.record); - return t; - } - - static void event(const transaction &t, const char *event, std::uint64_t time, const std::string &data) { - if (ptfile) - *ptfile << fmt::format("@{} {} {} {}\n", time, t.record, event, data); - } - }; -} diff --git a/port.h b/port.h deleted file mode 100644 index 06a3aa5..0000000 --- a/port.h +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "infra/sim.h" - -namespace infra { - template struct port : public sim { - std::optional consumer_side; - std::optional producer_side; - - bool can_read() { return consumer_side.has_value(); } - bool can_write() { return !producer_side.has_value(); } - - T read() { - assert(can_read()); - auto x = std::move(*consumer_side); - consumer_side.reset(); - return x; - } - - const T & peek() { - assert(can_read()); - return *consumer_side; - } - - void discard() { - consumer_side.reset(); - } - - void write(T &&x) { - assert(can_write()); - producer_side = std::move(x); - } - - void unclock() { - if (!consumer_side && producer_side) { - consumer_side = std::move(*producer_side); - producer_side.reset(); - } - } - }; -} diff --git a/queue.h b/queue.h deleted file mode 100644 index 1e490bc..0000000 --- a/queue.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "infra/port.h" -#include "infra/sim.h" - -namespace infra { - template struct queue : public sim { - port input; - port *output = nullptr; - std::deque elements; - - void clock() { - if (input.can_read() && elements.size() < size) { - auto x = input.read(); - elements.emplace_back(std::move(x)); - } - if (output->can_write() && !elements.empty()) { - auto &x = elements.front(); - output->write(std::move(x)); - elements.pop_front(); - } - } - }; -} diff --git a/sim.cpp b/sim.cpp deleted file mode 100644 index 21acc8c..0000000 --- a/sim.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include -#include - -#include "infra/sim.h" - -namespace infra { - std::vector sim::sims; - std::uint64_t sim::now = 0; -} diff --git a/sim.h b/sim.h deleted file mode 100644 index 185916a..0000000 --- a/sim.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "infra/pipetrace.h" - -namespace infra { - struct sim { - virtual void clock() {} - virtual void unclock() {} - - static std::vector sims; - - static std::uint64_t now; - - sim() { - sims.emplace_back(this); - } - - virtual ~sim() { - std::erase(sims, this); - } - - static void advance() { - for (auto &s : sims) - s->clock(); - for (auto &s : sims) - s->unclock(); - ++now; - } - - void pte(const transaction &t, const char *event, const std::string &data) { - pt::event(t, event, now, data); - } - }; -} diff --git a/stat.h b/stat.h deleted file mode 100644 index f1ca75a..0000000 --- a/stat.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include -#include - -#include "infra/sim.h" - -namespace infra { - struct stat : public sim { - std::string name; - std::uint64_t numerator = 0; - std::uint64_t denominator = 0; - - stat(std::string name) - : name(std::move(name)) - { } - - ~stat() { - fmt::print("# {} {}\n", name, (double)numerator/(double)denominator); - } - - void unclock() { - ++denominator; - } - - stat & operator++() { - ++numerator; - return *this; - } - - stat & operator++(int) { - return operator++(); - } - }; -} -- cgit v1.2.3