cxxrtl: preserve interior memory pointers across reset.
authorCatherine <whitequark@whitequark.org>
Sat, 11 Dec 2021 15:38:43 +0000 (15:38 +0000)
committerCatherine <whitequark@whitequark.org>
Sat, 11 Dec 2021 16:40:06 +0000 (16:40 +0000)
Before this commit, values, wires, and memories with an initializer
were value-initialized in emitted C++ code. After this commit, all
values, wires, and memories are default-initialized, and the default
constructor of generated modules calls the reset() method, which
assigns the members that have an initializer.

backends/cxxrtl/cxxrtl.h
backends/cxxrtl/cxxrtl_backend.cc

index 923146eba3f0509324ff4bb42f5465f1919c5d1e..3e1357498cce15d312f750a781d43431e197365d 100644 (file)
@@ -738,24 +738,6 @@ struct memory {
                return *this;
        }
 
-       // 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) : depth(depth), data(new value<Width>[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[init.offset])...};
-               (void)_;
-       }
-
        // 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 < depth);
@@ -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() {}
index ff28c20b394b083ca246036e860825567d7a12e5..6623e025e9464d31e6d22c0fbe5c574d23cc4ed9 100644 (file)
@@ -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";