diff options
Diffstat (limited to 'backends/cxxrtl/cxxrtl.h')
-rw-r--r-- | backends/cxxrtl/cxxrtl.h | 75 |
1 files changed, 67 insertions, 8 deletions
diff --git a/backends/cxxrtl/cxxrtl.h b/backends/cxxrtl/cxxrtl.h index 593c31c28..701510b7f 100644 --- a/backends/cxxrtl/cxxrtl.h +++ b/backends/cxxrtl/cxxrtl.h @@ -28,7 +28,9 @@ #include <type_traits> #include <tuple> #include <vector> +#include <map> #include <algorithm> +#include <memory> #include <sstream> // The cxxrtl support library implements compile time specialized arbitrary width arithmetics, as well as provides @@ -604,12 +606,15 @@ struct memory { auto _ = {std::move(std::begin(init.data), std::end(init.data), data.begin() + init.offset)...}; } - value<Width> &operator [](size_t index) { + // An operator for direct memory reads. May be used at any time during the simulation. + const value<Width> &operator [](size_t index) const { assert(index < data.size()); return data[index]; } - const value<Width> &operator [](size_t index) const { + // An operator for direct memory writes. May only be used before the simulation is started. If used + // after the simulation is started, the design may malfunction. + value<Width> &operator [](size_t index) { assert(index < data.size()); return data[index]; } @@ -636,13 +641,15 @@ struct memory { void update(size_t index, const value<Width> &val, const value<Width> &mask, int priority = 0) { assert(index < data.size()); - write_queue.emplace_back(write { index, val, mask, priority }); + // Queue up the write while keeping the queue sorted by priority. + write_queue.insert( + std::upper_bound(write_queue.begin(), write_queue.end(), priority, + [](const int a, const write& b) { return a < b.priority; }), + write { index, val, mask, priority }); } bool commit() { bool changed = false; - std::sort(write_queue.begin(), write_queue.end(), - [](const write &a, const write &b) { return a.priority < b.priority; }); for (const write &entry : write_queue) { value<Width> elem = data[entry.index]; elem = elem.update(entry.val, entry.mask); @@ -654,6 +661,57 @@ struct memory { } }; +struct metadata { + const enum { + MISSING = 0, + UINT = 1, + SINT = 2, + STRING = 3, + DOUBLE = 4, + } value_type; + + // In debug mode, using the wrong .as_*() function will assert. + // In release mode, using the wrong .as_*() function will safely return a default value. + union { + const unsigned uint_value = 0; + const signed sint_value; + }; + const std::string string_value = ""; + const double double_value = 0.0; + + metadata() : value_type(MISSING) {} + metadata(unsigned value) : value_type(UINT), uint_value(value) {} + metadata(signed value) : value_type(SINT), sint_value(value) {} + metadata(const std::string &value) : value_type(STRING), string_value(value) {} + metadata(const char *value) : value_type(STRING), string_value(value) {} + metadata(double value) : value_type(DOUBLE), double_value(value) {} + + metadata(const metadata &) = default; + metadata &operator=(const metadata &) = delete; + + unsigned as_uint() const { + assert(value_type == UINT); + return uint_value; + } + + signed as_sint() const { + assert(value_type == SINT); + return sint_value; + } + + const std::string &as_string() const { + assert(value_type == STRING); + return string_value; + } + + double as_double() const { + assert(value_type == DOUBLE); + return double_value; + } +}; + +typedef std::map<std::string, metadata> metadata_map; + struct module { module() {} virtual ~module() {} @@ -661,15 +719,16 @@ struct module { module(const module &) = delete; module &operator=(const module &) = delete; - virtual void eval() = 0; + virtual bool eval() = 0; virtual bool commit() = 0; size_t step() { size_t deltas = 0; + bool converged = false; do { - eval(); + converged = eval(); deltas++; - } while (commit()); + } while (commit() && !converged); return deltas; } }; |