mirror of https://github.com/YosysHQ/yosys.git
cxxrtl: preserve interior memory pointers across reset.
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.
This commit is contained in:
parent
7c9e498662
commit
55c9fb3b18
|
@ -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() {}
|
||||
|
|
|
@ -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";
|
||||
|
|
Loading…
Reference in New Issue