mirror of
https://github.com/YosysHQ/yosys
synced 2025-06-06 14:13:23 +00:00
cxxrtl: generate debug information for non-localized public wires.
Debug information describes values, wires, and memories with a simple C-compatible layout. It can be emitted on demand into a map, which has no runtime cost when it is unused, and allows late bound designs. The `hdlname` attribute is used as the lookup key such that original names, as emitted by the frontend, can be used for debugging and introspection.
This commit is contained in:
parent
784bfec67c
commit
f6e16e7f4c
2 changed files with 131 additions and 2 deletions
|
@ -49,6 +49,8 @@ namespace cxxrtl {
|
|||
// invisible to the compiler, (b) we often operate on non-power-of-2 values and have to clear the high bits anyway.
|
||||
// Therefore, using relatively wide chunks and clearing the high bits explicitly and only when we know they may be
|
||||
// clobbered results in simpler generated code.
|
||||
typedef uint32_t chunk_t;
|
||||
|
||||
template<typename T>
|
||||
struct chunk_traits {
|
||||
static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value,
|
||||
|
@ -65,7 +67,7 @@ template<size_t Bits>
|
|||
struct value : public expr_base<value<Bits>> {
|
||||
static constexpr size_t bits = Bits;
|
||||
|
||||
using chunk = chunk_traits<uint32_t>;
|
||||
using chunk = chunk_traits<chunk_t>;
|
||||
static constexpr chunk::type msb_mask = (Bits % chunk::bits == 0) ? chunk::mask
|
||||
: chunk::mask >> (chunk::bits - (Bits % chunk::bits));
|
||||
|
||||
|
@ -712,6 +714,46 @@ struct metadata {
|
|||
|
||||
typedef std::map<std::string, metadata> metadata_map;
|
||||
|
||||
// This structure is intended for consumption via foreign function interfaces, like Python's ctypes.
|
||||
// Because of this it uses a C-style layout that is easy to parse rather than more idiomatic C++.
|
||||
struct debug_item {
|
||||
enum : uint32_t {
|
||||
VALUE = 0,
|
||||
WIRE = 1,
|
||||
MEMORY = 2,
|
||||
} type;
|
||||
|
||||
size_t width; // in bits
|
||||
size_t depth; // 1 if `type != MEMORY`
|
||||
chunk_t *curr;
|
||||
chunk_t *next; // nullptr if `type == VALUE || type == MEMORY`
|
||||
|
||||
template<size_t Bits>
|
||||
debug_item(value<Bits> &item) : type(VALUE), width(Bits), depth(1),
|
||||
curr(item.data), next(nullptr) {
|
||||
static_assert(sizeof(item) == value<Bits>::chunks * sizeof(chunk_t),
|
||||
"value<Bits> is not compatible with C layout");
|
||||
}
|
||||
|
||||
template<size_t Bits>
|
||||
debug_item(wire<Bits> &item) : type(WIRE), width(Bits), depth(1),
|
||||
curr(item.curr.data), next(item.next.data) {
|
||||
static_assert(sizeof(item.curr) == value<Bits>::chunks * sizeof(chunk_t) &&
|
||||
sizeof(item.next) == value<Bits>::chunks * sizeof(chunk_t),
|
||||
"wire<Bits> is not compatible with C layout");
|
||||
}
|
||||
|
||||
template<size_t Width>
|
||||
debug_item(memory<Width> &item) : type(MEMORY), width(Width), depth(item.data.size()),
|
||||
curr(item.data.empty() ? nullptr : item.data[0].data), next(nullptr) {
|
||||
static_assert(sizeof(item.data[0]) == value<Width>::chunks * sizeof(chunk_t),
|
||||
"memory<Width> is not compatible with C layout");
|
||||
}
|
||||
};
|
||||
static_assert(std::is_standard_layout<debug_item>::value, "debug_item is not compatible with C layout");
|
||||
|
||||
typedef std::map<std::string, debug_item> debug_items;
|
||||
|
||||
struct module {
|
||||
module() {}
|
||||
virtual ~module() {}
|
||||
|
@ -731,6 +773,8 @@ struct module {
|
|||
} while (commit() && !converged);
|
||||
return deltas;
|
||||
}
|
||||
|
||||
virtual void debug_info(debug_items &items, std::string path = "") {}
|
||||
};
|
||||
|
||||
} // namespace cxxrtl
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue