mirror of https://github.com/YosysHQ/yosys.git
cxxrtl: provide a way to perform unobtrusive power-on reset.
Although it is always possible to destroy and recreate the design to simulate a power-on reset, this has two drawbacks: * Black boxes are also destroyed and recreated, which causes them to reacquire their resources, which might be costly and/or erase important state. * Pointers into the design are invalidated and have to be acquired again, which is costly and might be very inconvenient if they are captured elsewhere (especially through the C API).
This commit is contained in:
parent
7b0cfd5c36
commit
5beab5bc17
|
@ -96,9 +96,11 @@ struct value : public expr_base<value<Bits>> {
|
||||||
explicit constexpr value(Init ...init) : data{init...} {}
|
explicit constexpr value(Init ...init) : data{init...} {}
|
||||||
|
|
||||||
value(const value<Bits> &) = default;
|
value(const value<Bits> &) = default;
|
||||||
value(value<Bits> &&) = default;
|
|
||||||
value<Bits> &operator=(const value<Bits> &) = default;
|
value<Bits> &operator=(const value<Bits> &) = default;
|
||||||
|
|
||||||
|
value(value<Bits> &&) = default;
|
||||||
|
value<Bits> &operator=(value<Bits> &&) = default;
|
||||||
|
|
||||||
// A (no-op) helper that forces the cast to value<>.
|
// A (no-op) helper that forces the cast to value<>.
|
||||||
CXXRTL_ALWAYS_INLINE
|
CXXRTL_ALWAYS_INLINE
|
||||||
const value<Bits> &val() const {
|
const value<Bits> &val() const {
|
||||||
|
@ -647,10 +649,16 @@ struct wire {
|
||||||
template<typename... Init>
|
template<typename... Init>
|
||||||
explicit constexpr wire(Init ...init) : curr{init...}, next{init...} {}
|
explicit constexpr wire(Init ...init) : curr{init...}, next{init...} {}
|
||||||
|
|
||||||
|
// Copying and copy-assigning values is natural. If, however, a value is replaced with a wire,
|
||||||
|
// e.g. because a module is built with a different optimization level, then existing code could
|
||||||
|
// unintentionally copy a wire instead, which would create a subtle but serious bug. To make sure
|
||||||
|
// this doesn't happen, prohibit copying and copy-assigning wires.
|
||||||
wire(const wire<Bits> &) = delete;
|
wire(const wire<Bits> &) = delete;
|
||||||
wire(wire<Bits> &&) = default;
|
|
||||||
wire<Bits> &operator=(const wire<Bits> &) = delete;
|
wire<Bits> &operator=(const wire<Bits> &) = delete;
|
||||||
|
|
||||||
|
wire(wire<Bits> &&) = default;
|
||||||
|
wire<Bits> &operator=(wire<Bits> &&) = default;
|
||||||
|
|
||||||
template<class IntegerT>
|
template<class IntegerT>
|
||||||
CXXRTL_ALWAYS_INLINE
|
CXXRTL_ALWAYS_INLINE
|
||||||
IntegerT get() const {
|
IntegerT get() const {
|
||||||
|
@ -692,6 +700,9 @@ struct memory {
|
||||||
memory(const memory<Width> &) = delete;
|
memory(const memory<Width> &) = delete;
|
||||||
memory<Width> &operator=(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
|
// 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
|
// 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
|
// construct an initializer_list in a constexpr (or something) and so if you try to do that the whole thing is
|
||||||
|
@ -815,7 +826,7 @@ struct metadata {
|
||||||
|
|
||||||
typedef std::map<std::string, metadata> metadata_map;
|
typedef std::map<std::string, metadata> metadata_map;
|
||||||
|
|
||||||
// Helper class to disambiguate values/wires and their aliases.
|
// Tag class to disambiguate values/wires and their aliases.
|
||||||
struct debug_alias {};
|
struct debug_alias {};
|
||||||
|
|
||||||
// This structure is intended for consumption via foreign function interfaces, like Python's ctypes.
|
// This structure is intended for consumption via foreign function interfaces, like Python's ctypes.
|
||||||
|
@ -965,13 +976,25 @@ 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 {};
|
||||||
|
|
||||||
struct module {
|
struct module {
|
||||||
module() {}
|
module() {}
|
||||||
virtual ~module() {}
|
virtual ~module() {}
|
||||||
|
|
||||||
|
// Modules with black boxes cannot be copied. Although not all designs include black boxes,
|
||||||
|
// delete the copy constructor and copy assignment operator to make sure that any downstream
|
||||||
|
// code that manipulates modules doesn't accidentally depend on their availability.
|
||||||
module(const module &) = delete;
|
module(const module &) = delete;
|
||||||
module &operator=(const module &) = delete;
|
module &operator=(const module &) = delete;
|
||||||
|
|
||||||
|
module(module &&) = default;
|
||||||
|
module &operator=(module &&) = default;
|
||||||
|
|
||||||
|
virtual void reset() = 0;
|
||||||
|
|
||||||
virtual bool eval() = 0;
|
virtual bool eval() = 0;
|
||||||
virtual bool commit() = 0;
|
virtual bool commit() = 0;
|
||||||
|
|
||||||
|
|
|
@ -1869,6 +1869,46 @@ struct CxxrtlWorker {
|
||||||
}
|
}
|
||||||
if (has_cells)
|
if (has_cells)
|
||||||
f << "\n";
|
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";
|
||||||
|
inc_indent();
|
||||||
|
f << indent << "*this = " << mangle(module) << "(adopt {}, std::move(*this));\n";
|
||||||
|
dec_indent();
|
||||||
|
f << indent << "}\n";
|
||||||
|
f << "\n";
|
||||||
f << indent << "bool eval() override;\n";
|
f << indent << "bool eval() override;\n";
|
||||||
f << indent << "bool commit() override;\n";
|
f << indent << "bool commit() override;\n";
|
||||||
if (debug_info)
|
if (debug_info)
|
||||||
|
|
|
@ -43,6 +43,10 @@ void cxxrtl_destroy(cxxrtl_handle handle) {
|
||||||
delete handle;
|
delete handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cxxrtl_reset(cxxrtl_handle handle) {
|
||||||
|
handle->module->reset();
|
||||||
|
}
|
||||||
|
|
||||||
int cxxrtl_eval(cxxrtl_handle handle) {
|
int cxxrtl_eval(cxxrtl_handle handle) {
|
||||||
return handle->module->eval();
|
return handle->module->eval();
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,14 @@ cxxrtl_handle cxxrtl_create(cxxrtl_toplevel design);
|
||||||
// Release all resources used by a design and its handle.
|
// Release all resources used by a design and its handle.
|
||||||
void cxxrtl_destroy(cxxrtl_handle handle);
|
void cxxrtl_destroy(cxxrtl_handle handle);
|
||||||
|
|
||||||
|
// Reinitialize the design, replacing the internal state with the reset values while preserving
|
||||||
|
// black boxes.
|
||||||
|
//
|
||||||
|
// This operation is essentially equivalent to a power-on reset. Values, wires, and memories are
|
||||||
|
// returned to their reset state while preserving the state of black boxes and keeping all of
|
||||||
|
// the interior pointers obtained with e.g. `cxxrtl_get` valid.
|
||||||
|
void cxxrtl_reset(cxxrtl_handle handle);
|
||||||
|
|
||||||
// Evaluate the design, propagating changes on inputs to the `next` value of internal state and
|
// Evaluate the design, propagating changes on inputs to the `next` value of internal state and
|
||||||
// output wires.
|
// output wires.
|
||||||
//
|
//
|
||||||
|
|
Loading…
Reference in New Issue