diff options
author | Catherine <whitequark@whitequark.org> | 2021-12-12 01:23:03 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-12-12 01:23:03 +0000 |
commit | bdc6ba019ca12a3f3d4cfb1a4d64652538b7c5ef (patch) | |
tree | cf4c21921a6fb1824a5339df131e3c2b29031218 | |
parent | 6a7253b46e82d6243c9f3c70de5dfaee8853471e (diff) | |
parent | 55c9fb3b18cee0e2171486f9d4dfbd9b9e106354 (diff) | |
download | yosys-bdc6ba019ca12a3f3d4cfb1a4d64652538b7c5ef.tar.gz yosys-bdc6ba019ca12a3f3d4cfb1a4d64652538b7c5ef.tar.bz2 yosys-bdc6ba019ca12a3f3d4cfb1a4d64652538b7c5ef.zip |
Merge pull request #3105 from whitequark/cxxrtl-reset-memories-2
cxxrtl: preserve interior memory pointers across reset
-rw-r--r-- | backends/cxxrtl/cxxrtl.h | 50 | ||||
-rw-r--r-- | backends/cxxrtl/cxxrtl_backend.cc | 138 |
2 files changed, 80 insertions, 108 deletions
diff --git a/backends/cxxrtl/cxxrtl.h b/backends/cxxrtl/cxxrtl.h index 4552a0125..3e1357498 100644 --- a/backends/cxxrtl/cxxrtl.h +++ b/backends/cxxrtl/cxxrtl.h @@ -722,50 +722,32 @@ std::ostream &operator<<(std::ostream &os, const wire<Bits> &val) { template<size_t Width> struct memory { - std::vector<value<Width>> data; + const size_t depth; + std::unique_ptr<value<Width>[]> data; - size_t depth() const { - return data.size(); - } - - memory() = delete; - explicit memory(size_t depth) : data(depth) {} + explicit memory(size_t depth) : depth(depth), data(new value<Width>[depth]) {} memory(const memory<Width> &) = delete; memory<Width> &operator=(const memory<Width> &) = delete; memory(memory<Width> &&) = default; - memory<Width> &operator=(memory<Width> &&) = default; - - // The only way to get the compiler to put the initializer in .rodata and do not copy it on stack is to stuff it - // into a plain array. You'd think an std::initializer_list would work here, but it doesn't, because you can't - // construct an initializer_list in a constexpr (or something) and so if you try to do that the whole thing is - // first copied on the stack (probably overflowing it) and then again into `data`. - template<size_t Size> - struct init { - size_t offset; - value<Width> data[Size]; - }; - - template<size_t... InitSize> - explicit memory(size_t depth, const init<InitSize> &...init) : data(depth) { - data.resize(depth); - // This utterly reprehensible construct is the most reasonable way to apply a function to every element - // of a parameter pack, if the elements all have different types and so cannot be cast to an initializer list. - auto _ = {std::move(std::begin(init.data), std::end(init.data), data.begin() + init.offset)...}; - (void)_; + memory<Width> &operator=(memory<Width> &&other) { + assert(depth == other.depth); + data = std::move(other.data); + write_queue = std::move(other.write_queue); + return *this; } // 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()); + assert(index < depth); return data[index]; } // 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()); + assert(index < depth); return data[index]; } @@ -790,7 +772,7 @@ struct memory { std::vector<write> write_queue; void update(size_t index, const value<Width> &val, const value<Width> &mask, int priority = 0) { - assert(index < data.size()); + assert(index < depth); // Queue up the write while keeping the queue sorted by priority. write_queue.insert( std::upper_bound(write_queue.begin(), write_queue.end(), priority, @@ -947,9 +929,9 @@ struct debug_item : ::cxxrtl_object { flags = 0; width = Width; lsb_at = 0; - depth = item.data.size(); + depth = item.depth; zero_at = zero_offset; - curr = item.data.empty() ? nullptr : item.data[0].data; + curr = item.data ? item.data[0].data : nullptr; next = nullptr; outline = nullptr; } @@ -1051,9 +1033,9 @@ struct debug_items { } }; -// Tag class to disambiguate module move constructor and module constructor that takes black boxes -// out of another instance of the module. -struct adopt {}; +// Tag class to disambiguate the default constructor used by the toplevel module that calls reset(), +// and the constructor of interior modules that should not call it. +struct interior {}; struct module { module() {} diff --git a/backends/cxxrtl/cxxrtl_backend.cc b/backends/cxxrtl/cxxrtl_backend.cc index ff28c20b3..6623e025e 100644 --- a/backends/cxxrtl/cxxrtl_backend.cc +++ b/backends/cxxrtl/cxxrtl_backend.cc @@ -934,11 +934,6 @@ struct CxxrtlWorker { f << "}"; } - void dump_const_init(const RTLIL::Const &data) - { - dump_const_init(data, data.size()); - } - void dump_const(const RTLIL::Const &data, int width, int offset = 0, bool fixed_width = false) { f << "value<" << width << ">"; @@ -1785,20 +1780,10 @@ struct CxxrtlWorker { } else { f << "<" << wire->width << ">"; } - f << " " << mangle(wire); - if (wire_init.count(wire)) { - f << " "; - dump_const_init(wire_init.at(wire)); - } - f << ";\n"; + f << " " << mangle(wire) << ";\n"; if (edge_wires[wire]) { if (!wire_type.is_buffered()) { - f << indent << "value<" << wire->width << "> prev_" << mangle(wire); - if (wire_init.count(wire)) { - f << " "; - dump_const_init(wire_init.at(wire)); - } - f << ";\n"; + f << indent << "value<" << wire->width << "> prev_" << mangle(wire) << ";\n"; } for (auto edge_type : edge_types) { if (edge_type.first.wire == wire) { @@ -1848,38 +1833,65 @@ struct CxxrtlWorker { f << "value<" << wire->width << "> " << mangle(wire) << ";\n"; } - void dump_memory(Mem *mem) + void dump_reset_method(RTLIL::Module *module) { - dump_attrs(mem); - f << indent << "memory<" << mem->width << "> " << mangle(mem) - << " { " << mem->size << "u"; - if (!GetSize(mem->inits)) { - f << " };\n"; - } else { - f << ",\n"; - inc_indent(); - for (auto &init : mem->inits) { + int mem_init_idx = 0; + inc_indent(); + for (auto wire : module->wires()) { + if (!wire_init.count(wire)) continue; + + f << indent << mangle(wire) << " = "; + if (wire_types[wire].is_buffered()) { + f << "wire<" << wire->width << ">"; + } else { + f << "value<" << wire->width << ">"; + } + dump_const_init(wire_init.at(wire), wire->width); + f << ";\n"; + + if (edge_wires[wire] && !wire_types[wire].is_buffered()) { + f << indent << "prev_" << mangle(wire) << " = "; + dump_const(wire_init.at(wire), wire->width); + f << ";\n"; + } + } + for (auto &mem : mod_memories[module]) { + for (auto &init : mem.inits) { if (init.removed) continue; dump_attrs(&init); - int words = GetSize(init.data) / mem->width; - f << indent << "memory<" << mem->width << ">::init<" << words << "> { " - << stringf("%#x", init.addr.as_int()) << ", {"; + int words = GetSize(init.data) / mem.width; + f << indent << "static const value<" << mem.width << "> "; + f << "mem_init_" << ++mem_init_idx << "[" << words << "] {"; inc_indent(); for (int n = 0; n < words; n++) { if (n % 4 == 0) f << "\n" << indent; else f << " "; - dump_const(init.data, mem->width, n * mem->width, /*fixed_width=*/true); + dump_const(init.data, mem.width, n * mem.width, /*fixed_width=*/true); f << ","; } dec_indent(); - f << "\n" << indent << "}},\n"; + f << "\n"; + f << indent << "};\n"; + f << indent << "std::copy(std::begin(mem_init_" << mem_init_idx << "), "; + f << "std::end(mem_init_" << mem_init_idx << "), "; + f << "&" << mangle(&mem) << ".data[" << stringf("%#x", init.addr.as_int()) << "]);\n"; } - dec_indent(); - f << indent << "};\n"; - } + } + for (auto cell : module->cells()) { + if (is_internal_cell(cell->type)) + continue; + f << indent << mangle(cell); + RTLIL::Module *cell_module = module->design->module(cell->type); + if (cell_module->get_bool_attribute(ID(cxxrtl_blackbox))) { + f << "->reset();\n"; + } else { + f << ".reset();\n"; + } + } + dec_indent(); } void dump_eval_method(RTLIL::Module *module) @@ -2200,6 +2212,10 @@ struct CxxrtlWorker { dump_wire(wire, /*is_local=*/false); } f << "\n"; + f << indent << "void reset() override {\n"; + dump_reset_method(module); + f << indent << "}\n"; + f << "\n"; f << indent << "bool eval() override {\n"; dump_eval_method(module); f << indent << "}\n"; @@ -2248,7 +2264,9 @@ struct CxxrtlWorker { dump_debug_wire(wire, /*is_local=*/false); bool has_memories = false; for (auto &mem : mod_memories[module]) { - dump_memory(&mem); + dump_attrs(&mem); + f << indent << "memory<" << mem.width << "> " << mangle(&mem) + << " { " << mem.size << "u };\n"; has_memories = true; } if (has_memories) @@ -2269,52 +2287,20 @@ struct CxxrtlWorker { dump_metadata_map(cell->attributes); f << ");\n"; } else { - f << indent << mangle(cell_module) << " " << mangle(cell) << ";\n"; + f << indent << mangle(cell_module) << " " << mangle(cell) << " {interior()};\n"; } has_cells = true; } if (has_cells) f << "\n"; - f << indent << mangle(module) << "() {}\n"; - if (has_cells) { - f << indent << mangle(module) << "(adopt, " << mangle(module) << " other) :\n"; - bool first = true; - for (auto cell : module->cells()) { - if (is_internal_cell(cell->type)) - continue; - if (first) { - first = false; - } else { - f << ",\n"; - } - RTLIL::Module *cell_module = module->design->module(cell->type); - if (cell_module->get_bool_attribute(ID(cxxrtl_blackbox))) { - f << indent << " " << mangle(cell) << "(std::move(other." << mangle(cell) << "))"; - } else { - f << indent << " " << mangle(cell) << "(adopt {}, std::move(other." << mangle(cell) << "))"; - } - } - f << " {\n"; - inc_indent(); - for (auto cell : module->cells()) { - if (is_internal_cell(cell->type)) - continue; - RTLIL::Module *cell_module = module->design->module(cell->type); - if (cell_module->get_bool_attribute(ID(cxxrtl_blackbox))) - f << indent << mangle(cell) << "->reset();\n"; - } - dec_indent(); - f << indent << "}\n"; - } else { - f << indent << mangle(module) << "(adopt, " << mangle(module) << " other) {}\n"; - } - f << "\n"; - f << indent << "void reset() override {\n"; + f << indent << mangle(module) << "(interior) {}\n"; + f << indent << mangle(module) << "() {\n"; inc_indent(); - f << indent << "*this = " << mangle(module) << "(adopt {}, std::move(*this));\n"; + f << indent << "reset();\n"; dec_indent(); - f << indent << "}\n"; + f << indent << "};\n"; f << "\n"; + f << indent << "void reset() override;\n"; f << indent << "bool eval() override;\n"; f << indent << "bool commit() override;\n"; if (debug_info) { @@ -2341,6 +2327,10 @@ struct CxxrtlWorker { { if (module->get_bool_attribute(ID(cxxrtl_blackbox))) return; + f << indent << "void " << mangle(module) << "::reset() {\n"; + dump_reset_method(module); + f << indent << "}\n"; + f << "\n"; f << indent << "bool " << mangle(module) << "::eval() {\n"; dump_eval_method(module); f << indent << "}\n"; |