From 82cc71261d3d32012d33d3bebe56ca5e3b0bcdbd Mon Sep 17 00:00:00 2001 From: Julian Blake Kongslie Date: Sun, 2 Oct 2022 15:32:49 -0700 Subject: Initial commit. --- infra/arbiter.h | 42 ++++++++++++++++++++++++++++++++++++++++++ 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 +++++++++++++++++++++++++++++++++++ 8 files changed, 244 insertions(+) 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 (limited to 'infra') diff --git a/infra/arbiter.h b/infra/arbiter.h new file mode 100644 index 0000000..5dd1647 --- /dev/null +++ b/infra/arbiter.h @@ -0,0 +1,42 @@ +#pragma once + +#include +#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; + } + }; +} 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++(); + } + }; +} -- cgit v1.2.3