mirror of https://github.com/YosysHQ/yosys.git
cxxrtl: expose driver kind in debug information.
This can be useful to determine whether the wire should be a part of a design checkpoint, whether it can be used to override design state, and whether driving it may cause a conflict.
This commit is contained in:
parent
c7b2f07edf
commit
691418e13a
|
@ -837,6 +837,9 @@ struct debug_item : ::cxxrtl_object {
|
|||
INPUT = CXXRTL_INPUT,
|
||||
OUTPUT = CXXRTL_OUTPUT,
|
||||
INOUT = CXXRTL_INOUT,
|
||||
DRIVEN_SYNC = CXXRTL_DRIVEN_SYNC,
|
||||
DRIVEN_COMB = CXXRTL_DRIVEN_COMB,
|
||||
UNDRIVEN = CXXRTL_UNDRIVEN,
|
||||
};
|
||||
|
||||
debug_item(const ::cxxrtl_object &object) : cxxrtl_object(object) {}
|
||||
|
@ -856,11 +859,11 @@ struct debug_item : ::cxxrtl_object {
|
|||
}
|
||||
|
||||
template<size_t Bits>
|
||||
debug_item(const value<Bits> &item, size_t lsb_offset = 0, uint32_t flags_ = 0) {
|
||||
debug_item(const value<Bits> &item, size_t lsb_offset = 0) {
|
||||
static_assert(sizeof(item) == value<Bits>::chunks * sizeof(chunk_t),
|
||||
"value<Bits> is not compatible with C layout");
|
||||
type = VALUE;
|
||||
flags = flags_;
|
||||
flags = DRIVEN_COMB;
|
||||
width = Bits;
|
||||
lsb_at = lsb_offset;
|
||||
depth = 1;
|
||||
|
@ -903,7 +906,7 @@ struct debug_item : ::cxxrtl_object {
|
|||
static_assert(sizeof(item) == value<Bits>::chunks * sizeof(chunk_t),
|
||||
"value<Bits> is not compatible with C layout");
|
||||
type = ALIAS;
|
||||
flags = 0;
|
||||
flags = DRIVEN_COMB;
|
||||
width = Bits;
|
||||
lsb_at = lsb_offset;
|
||||
depth = 1;
|
||||
|
@ -918,7 +921,7 @@ struct debug_item : ::cxxrtl_object {
|
|||
sizeof(item.next) == value<Bits>::chunks * sizeof(chunk_t),
|
||||
"wire<Bits> is not compatible with C layout");
|
||||
type = ALIAS;
|
||||
flags = 0;
|
||||
flags = DRIVEN_COMB;
|
||||
width = Bits;
|
||||
lsb_at = lsb_offset;
|
||||
depth = 1;
|
||||
|
|
|
@ -273,6 +273,7 @@ struct FlowGraph {
|
|||
std::vector<Node*> nodes;
|
||||
dict<const RTLIL::Wire*, pool<Node*, hash_ptr_ops>> wire_comb_defs, wire_sync_defs, wire_uses;
|
||||
dict<const RTLIL::Wire*, bool> wire_def_elidable, wire_use_elidable;
|
||||
dict<RTLIL::SigBit, bool> bit_has_state;
|
||||
|
||||
~FlowGraph()
|
||||
{
|
||||
|
@ -294,6 +295,8 @@ struct FlowGraph {
|
|||
wire_comb_defs[chunk.wire].insert(node);
|
||||
}
|
||||
}
|
||||
for (auto bit : sig.bits())
|
||||
bit_has_state[bit] |= is_ff;
|
||||
// Only comb defs of an entire wire in the right order can be elided.
|
||||
if (!is_ff && sig.is_wire())
|
||||
wire_def_elidable[sig.as_wire()] = elidable;
|
||||
|
@ -550,6 +553,7 @@ struct CxxrtlWorker {
|
|||
pool<const RTLIL::Wire*> localized_wires;
|
||||
dict<const RTLIL::Wire*, const RTLIL::Wire*> debug_alias_wires;
|
||||
dict<const RTLIL::Wire*, RTLIL::Const> debug_const_wires;
|
||||
dict<RTLIL::SigBit, bool> bit_has_state;
|
||||
dict<const RTLIL::Module*, pool<std::string>> blackbox_specializations;
|
||||
dict<const RTLIL::Module*, bool> eval_converges;
|
||||
|
||||
|
@ -1636,6 +1640,10 @@ struct CxxrtlWorker {
|
|||
size_t count_alias_wires = 0;
|
||||
size_t count_member_wires = 0;
|
||||
size_t count_skipped_wires = 0;
|
||||
size_t count_driven_sync = 0;
|
||||
size_t count_driven_comb = 0;
|
||||
size_t count_undriven = 0;
|
||||
size_t count_mixed_driver = 0;
|
||||
inc_indent();
|
||||
f << indent << "assert(path.empty() || path[path.size() - 1] == ' ');\n";
|
||||
for (auto wire : module->wires()) {
|
||||
|
@ -1661,15 +1669,54 @@ struct CxxrtlWorker {
|
|||
count_alias_wires++;
|
||||
} else if (!localized_wires.count(wire)) {
|
||||
// Member wire
|
||||
std::vector<std::string> flags;
|
||||
|
||||
if (wire->port_input && wire->port_output)
|
||||
flags.push_back("INOUT");
|
||||
else if (wire->port_input)
|
||||
flags.push_back("INPUT");
|
||||
else if (wire->port_output)
|
||||
flags.push_back("OUTPUT");
|
||||
|
||||
bool has_driven_sync = false;
|
||||
bool has_driven_comb = false;
|
||||
bool has_undriven = false;
|
||||
SigSpec sig(wire);
|
||||
for (auto bit : sig.bits())
|
||||
if (!bit_has_state.count(bit))
|
||||
has_undriven = true;
|
||||
else if (bit_has_state[bit])
|
||||
has_driven_sync = true;
|
||||
else
|
||||
has_driven_comb = true;
|
||||
if (has_driven_sync)
|
||||
flags.push_back("DRIVEN_SYNC");
|
||||
if (has_driven_sync && !has_driven_comb && !has_undriven)
|
||||
count_driven_sync++;
|
||||
if (has_driven_comb)
|
||||
flags.push_back("DRIVEN_COMB");
|
||||
if (!has_driven_sync && has_driven_comb && !has_undriven)
|
||||
count_driven_comb++;
|
||||
if (has_undriven)
|
||||
flags.push_back("UNDRIVEN");
|
||||
if (!has_driven_sync && !has_driven_comb && has_undriven)
|
||||
count_undriven++;
|
||||
if (has_driven_sync + has_driven_comb + has_undriven > 1)
|
||||
count_mixed_driver++;
|
||||
|
||||
f << indent << "items.add(path + " << escape_cxx_string(get_hdl_name(wire));
|
||||
f << ", debug_item(" << mangle(wire) << ", ";
|
||||
f << wire->start_offset;
|
||||
if (wire->port_input && wire->port_output)
|
||||
f << ", debug_item::INOUT";
|
||||
else if (wire->port_input)
|
||||
f << ", debug_item::INPUT";
|
||||
else if (wire->port_output)
|
||||
f << ", debug_item::OUTPUT";
|
||||
bool first = true;
|
||||
for (auto flag : flags) {
|
||||
if (first) {
|
||||
first = false;
|
||||
f << ", ";
|
||||
} else {
|
||||
f << "|";
|
||||
}
|
||||
f << "debug_item::" << flag;
|
||||
}
|
||||
f << "));\n";
|
||||
count_member_wires++;
|
||||
} else {
|
||||
|
@ -1698,7 +1745,11 @@ struct CxxrtlWorker {
|
|||
log_debug(" Public wires: %zu, of which:\n", count_public_wires);
|
||||
log_debug(" Const wires: %zu\n", count_const_wires);
|
||||
log_debug(" Alias wires: %zu\n", count_alias_wires);
|
||||
log_debug(" Member wires: %zu\n", count_member_wires);
|
||||
log_debug(" Member wires: %zu, of which:\n", count_member_wires);
|
||||
log_debug(" Driven sync: %zu\n", count_driven_sync);
|
||||
log_debug(" Driven comb: %zu\n", count_driven_comb);
|
||||
log_debug(" Undriven: %zu\n", count_undriven);
|
||||
log_debug(" Mixed driver: %zu\n", count_mixed_driver);
|
||||
log_debug(" Other wires: %zu (no debug information)\n", count_skipped_wires);
|
||||
}
|
||||
|
||||
|
@ -2217,6 +2268,9 @@ struct CxxrtlWorker {
|
|||
|
||||
eval_converges[module] = feedback_wires.empty() && buffered_comb_wires.empty();
|
||||
|
||||
for (auto item : flow.bit_has_state)
|
||||
bit_has_state.insert(item);
|
||||
|
||||
if (debug_info) {
|
||||
// Find wires that alias other wires or are tied to a constant; debug information can be enriched with these
|
||||
// at essentially zero additional cost.
|
||||
|
|
|
@ -73,6 +73,10 @@ int cxxrtl_commit(cxxrtl_handle handle);
|
|||
size_t cxxrtl_step(cxxrtl_handle handle);
|
||||
|
||||
// Type of a simulated object.
|
||||
//
|
||||
// The type of a simulated object indicates the way it is stored and the operations that are legal
|
||||
// to perform on it (i.e. won't crash the simulation). It says very little about object semantics,
|
||||
// which is specified through flags.
|
||||
enum cxxrtl_type {
|
||||
// Values correspond to singly buffered netlist nodes, i.e. nodes driven exclusively by
|
||||
// combinatorial cells, or toplevel input nodes.
|
||||
|
@ -86,7 +90,8 @@ enum cxxrtl_type {
|
|||
CXXRTL_VALUE = 0,
|
||||
|
||||
// Wires correspond to doubly buffered netlist nodes, i.e. nodes driven, at least in part, by
|
||||
// storage cells, or by combinatorial cells that are a part of a feedback path.
|
||||
// storage cells, or by combinatorial cells that are a part of a feedback path. They are also
|
||||
// present in non-optimized builds.
|
||||
//
|
||||
// Wires can be inspected via the `curr` pointer and modified via the `next` pointer (which are
|
||||
// distinct for wires). Note that changes to the bits driven by combinatorial cells will be
|
||||
|
@ -113,6 +118,12 @@ enum cxxrtl_type {
|
|||
};
|
||||
|
||||
// Flags of a simulated object.
|
||||
//
|
||||
// The flags of a simulated object indicate its role in the netlist:
|
||||
// * The flags `CXXRTL_INPUT` and `CXXRTL_OUTPUT` designate module ports.
|
||||
// * The flags `CXXRTL_DRIVEN_SYNC`, `CXXRTL_DRIVEN_COMB`, and `CXXRTL_UNDRIVEN` specify
|
||||
// the semantics of node state. An object with several of these flags set has different bits
|
||||
// follow different semantics.
|
||||
enum cxxrtl_flag {
|
||||
// Node is a module input port.
|
||||
//
|
||||
|
@ -131,6 +142,38 @@ enum cxxrtl_flag {
|
|||
// This flag can be set on objects of type `CXXRTL_WIRE`. It may be combined with other flags.
|
||||
CXXRTL_INOUT = (CXXRTL_INPUT|CXXRTL_OUTPUT),
|
||||
|
||||
// Node has bits that are driven by a storage cell.
|
||||
//
|
||||
// This flag can be set on objects of type `CXXRTL_WIRE`. It may be combined with
|
||||
// `CXXRTL_DRIVEN_COMB` and `CXXRTL_UNDRIVEN`, as well as other flags.
|
||||
//
|
||||
// This flag is set on wires that have bits connected directly to the output of a flip-flop or
|
||||
// a latch, and hold its state. Many `CXXRTL_WIRE` objects may not have the `CXXRTL_DRIVEN_SYNC`
|
||||
// flag set; for example, output ports and feedback wires generally won't. Writing to the `next`
|
||||
// pointer of these wires updates stored state, and for designs without combinatorial loops,
|
||||
// capturing the value from every of these wires through the `curr` pointer creates a complete
|
||||
// snapshot of the design state.
|
||||
CXXRTL_DRIVEN_SYNC = 1 << 2,
|
||||
|
||||
// Node has bits that are driven by a combinatorial cell or another node.
|
||||
//
|
||||
// This flag can be set on objects of type `CXXRTL_VALUE` and `CXXRTL_WIRE`. It may be combined
|
||||
// with `CXXRTL_DRIVEN_SYNC` and `CXXRTL_UNDRIVEN`, as well as other flags.
|
||||
//
|
||||
// This flag is set on objects that have bits connected to the output of a combinatorial cell,
|
||||
// or directly to another node. For designs without combinatorial loops, writing to such bits
|
||||
// through the `next` pointer (if it is not NULL) has no effect.
|
||||
CXXRTL_DRIVEN_COMB = 1 << 3,
|
||||
|
||||
// Node has bits that are not driven.
|
||||
//
|
||||
// This flag can be set on objects of type `CXXRTL_VALUE` and `CXXRTL_WIRE`. It may be combined
|
||||
// with `CXXRTL_DRIVEN_SYNC` and `CXXRTL_DRIVEN_COMB`, as well as other flags.
|
||||
//
|
||||
// This flag is set on objects that have bits not driven by an output of any cell or by another
|
||||
// node, such as inputs and dangling wires.
|
||||
CXXRTL_UNDRIVEN = 1 << 4,
|
||||
|
||||
// More object flags may be added in the future, but the existing ones will never change.
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue