From 75f517426f6255951a23964bc16468b8a4b45920 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Mon, 15 Apr 2024 13:55:54 +0200 Subject: [PATCH 01/51] Add generic topological sort and SCC detection This adds a generic non-recursive implementation of Tarjan's linear time SCC algorithm that produces components in topological order. It can be instantiated to work directly on any graph representation for which the enumerate_nodes and enumerate_successors interface can be implemented. --- kernel/topo_scc.h | 328 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 328 insertions(+) create mode 100644 kernel/topo_scc.h diff --git a/kernel/topo_scc.h b/kernel/topo_scc.h new file mode 100644 index 00000000000..0ae0e696b47 --- /dev/null +++ b/kernel/topo_scc.h @@ -0,0 +1,328 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2024 Jannis Harder + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#ifndef TOPO_SCC_H +#define TOPO_SCC_H + +#include "kernel/yosys.h" + +YOSYS_NAMESPACE_BEGIN + +class SigCellGraph { +public: + typedef int node_type; + + struct successor_enumerator { + std::vector>::const_iterator current, end; + bool finished() const { return current == end; } + node_type next() { + log_assert(!finished()); + node_type result = current->second; + ++current; + return result; + } + }; + + struct node_enumerator { + int current, end; + bool finished() const { return current == end; } + node_type next() { + log_assert(!finished()); + node_type result = current; + ++current; + return result; + } + }; + +private: + idict cell_ids; + idict sig_ids; + std::vector> edges; + std::vector> edge_ranges; + std::vector indices_; + int offset; + bool computed = false; + + void compute() { + offset = GetSize(sig_ids); + edge_ranges.clear(); + indices_.clear(); + indices_.resize(GetSize(sig_ids) + GetSize(cell_ids), -1); + + std::sort(edges.begin(), edges.end()); + auto last = std::unique(edges.begin(), edges.end()); + edges.erase(last, edges.end()); + auto edge = edges.begin(); + auto edge_end = edges.end(); + int range_begin = 0; + for (int node = -offset, node_end = GetSize(cell_ids); node != node_end; ++node) { + while (edge != edge_end && edge->first <= node) + ++edge; + int range_end = edge - edges.begin(); + edge_ranges.emplace_back(std::make_pair(range_begin, range_end)); + range_begin = range_end; + } + } + +public: + node_type node(RTLIL::Cell *cell) { return cell_ids(cell); } + node_type node(SigBit const &bit) { return ~sig_ids(bit); } + + bool is_cell(node_type node) { return node >= 0; } + bool is_sig(node_type node) { return node < 0; } + + Cell *cell(node_type node) { return node >= 0 ? cell_ids[node] : nullptr; } + SigBit sig(node_type node) { return node < 0 ? sig_ids[~node] : SigBit(); } + + template + void add_edge(Src &&src, Dst &&dst) { + computed = false; + node_type src_node = node(std::forward(src)); + node_type dst_node = node(std::forward(dst)); + edges.emplace_back(std::make_pair(src_node, dst_node)); + } + + node_enumerator enumerate_nodes() { + if (!computed) compute(); + return {-GetSize(sig_ids), GetSize(cell_ids)}; + } + + successor_enumerator enumerate_successors(node_type const &node) const { + auto range = edge_ranges[node + offset]; + return {edges.begin() + range.first, edges.begin() + range.second}; + } + + int &dfs_index(node_type const &node) { + return indices_[node + offset]; + } +}; + + +class IntGraph { +public: + typedef int node_type; + + struct successor_enumerator { + std::vector>::const_iterator current, end; + bool finished() const { return current == end; } + node_type next() { + log_assert(!finished()); + node_type result = current->second; + ++current; + return result; + } + }; + + struct node_enumerator { + int current, end; + bool finished() const { return current == end; } + node_type next() { + log_assert(!finished()); + node_type result = current; + ++current; + return result; + } + }; + +private: + std::vector> edges; + std::vector> edge_ranges; + std::vector indices_; + bool computed = false; + + void compute() { + edge_ranges.clear(); + + int node_end = 0; + for (auto const &edge : edges) + node_end = std::max(node_end, std::max(edge.first, edge.second) + 1); + indices_.clear(); + indices_.resize(node_end, -1); + + std::sort(edges.begin(), edges.end()); + auto last = std::unique(edges.begin(), edges.end()); + edges.erase(last, edges.end()); + auto edge = edges.begin(); + auto edge_end = edges.end(); + int range_begin = 0; + for (int node = 0; node != node_end; ++node) { + while (edge != edge_end && edge->first <= node) + ++edge; + int range_end = edge - edges.begin(); + edge_ranges.emplace_back(std::make_pair(range_begin, range_end)); + range_begin = range_end; + } + } + +public: + void add_edge(int src, int dst) { + log_assert(src >= 0); + log_assert(dst >= 0); + computed = false; + edges.emplace_back(std::make_pair(src, dst)); + } + + node_enumerator enumerate_nodes() { + if (!computed) compute(); + return {0, GetSize(indices_)}; + } + + successor_enumerator enumerate_successors(int node) const { + auto range = edge_ranges[node]; + return {edges.begin() + range.first, edges.begin() + range.second}; + } + + int &dfs_index(node_type const &node) { + return indices_[node]; + } +}; + +template +void topo_sorted_sccs(G &graph, ComponentCallback component) +{ + typedef typename G::node_enumerator node_enumerator; + typedef typename G::successor_enumerator successor_enumerator; + typedef typename G::node_type node_type; + + struct dfs_entry { + node_type node; + successor_enumerator successors; + int lowlink; + + dfs_entry(node_type node, successor_enumerator successors, int lowlink) : + node(node), successors(successors), lowlink(lowlink) + {} + }; + + std::vector dfs_stack; + std::vector component_stack; + int next_index = 0; + + + node_enumerator nodes = graph.enumerate_nodes(); + + // iterate over all nodes to ensure we process the whole graph + while (!nodes.finished()) { + node_type node = nodes.next(); + // only start a new search if the node wasn't visited yet + if (graph.dfs_index(node) >= 0) + continue; + + while (true) { + // at this point we're visiting the node for the first time during + // the DFS search + + // we record the timestamp of when we first visited the node as the + // dfs_index + int lowlink = next_index; + next_index++; + graph.dfs_index(node) = lowlink; + + // and we add the node to the component stack where it will remain + // until all nodes of the component containing this node are popped + component_stack.push_back(node); + + // then we start iterating over the successors of this node + successor_enumerator successors = graph.enumerate_successors(node); + while (true) { + if (successors.finished()) { + // when we processed all successors, i.e. when we visited + // the complete DFS subtree rooted at the current node, we + // first check whether the current node is a SCC root + // + // (why this check identifies SCC roots is out of scope for + // this comment, see other material on Tarjan's SCC + // algorithm) + if (lowlink == graph.dfs_index(node)) { + // the SCC containing the current node is at the top of + // the component stack, with the current node at the bottom + int current = GetSize(component_stack); + do { + --current; + } while (component_stack[current] != node); + + // we invoke the callback with a pointer range of the + // nodes in the SCC + + node_type *stack_ptr = component_stack.data(); + node_type *component_begin = stack_ptr + current; + node_type *component_end = stack_ptr + component_stack.size(); + + // note that we allow the callback to permute the nodes + // in this range as well as to modify dfs_index of the + // nodes in the SCC. + component(component_begin, component_end); + + // by setting the dfs_index of all already emitted + // nodes to INT_MAX, we don't need a separate check for + // whether successor nodes are still on the component + // stack before updating the lowlink value + for (; component_begin != component_end; ++component_begin) + graph.dfs_index(*component_begin) = INT_MAX; + component_stack.resize(current); + } + + // after checking for a completed SCC the DFS either + // continues the search at the parent node or returns to + // the outer loop if we already are at the root node. + if (dfs_stack.empty()) + goto next_search; + auto &dfs_top = dfs_stack.back(); + + node = dfs_top.node; + successors = std::move(dfs_top.successors); + + // the parent's lowlink is updated when returning + lowlink = min(lowlink, dfs_top.lowlink); + dfs_stack.pop_back(); + // continue checking the remaining successors of the parent node. + } else { + node_type succ = successors.next(); + if (graph.dfs_index(succ) < 0) { + // if the successor wasn't visted yet, the DFS recurses + // into the successor + + // we save the state for this node and make the + // successor the current node. + dfs_stack.emplace_back(node, std::move(successors), lowlink); + node = succ; + + // this break gets us to the section corresponding to + // the function entry in the recursive version + break; + } else { + // the textbook version guards this update with a check + // whether the successor is still on the component + // stack. If the successor node was already visisted + // but is not on the component stack, it must be part + // of an already emitted SCC. We can avoid this check + // by setting the DFS index of all nodes in a SCC to + // INT_MAX when the SCC is emitted. + lowlink = min(lowlink, graph.dfs_index(succ)); + } + } + } + } + next_search:; + } +} + +YOSYS_NAMESPACE_END + +#endif From 5e874dd95833a1c88fb2cc34300680f745efaf7e Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Mon, 15 Apr 2024 14:01:10 +0200 Subject: [PATCH 02/51] kernel/log: Add log_str helper for custom log_* functions/overloads When implementing custom log_... functions or custom overloads for the core log functions like log_signal it is necessary to return `char *` that are valid long enough. The log_... functions implemented in log.cc use either `log_id_cache` or `string_buf` which both are cleared on log_pop. This commit adds a public `log_str` function which stores its argument in the `log_id_cache` and returns the stored copy, such that custom log functions outside of log.cc can also create strings that remain valid until the next `log_pop`. --- kernel/log.cc | 10 ++++++++++ kernel/log.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/kernel/log.cc b/kernel/log.cc index 9a61e8f08b3..55895da06d7 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -662,6 +662,16 @@ const char *log_id(const RTLIL::IdString &str) return p+1; } +const char *log_str(const char *str) +{ + log_id_cache.push_back(strdup(str)); + return log_id_cache.back(); +} + +const char *log_str(std::string const &str) { + return log_str(str.c_str()); +} + void log_module(RTLIL::Module *module, std::string indent) { std::stringstream buf; diff --git a/kernel/log.h b/kernel/log.h index 53aae58c6bc..4b90cf9dceb 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -206,6 +206,8 @@ void log_check_expected(); const char *log_signal(const RTLIL::SigSpec &sig, bool autoint = true); const char *log_const(const RTLIL::Const &value, bool autoint = true); const char *log_id(const RTLIL::IdString &id); +const char *log_str(const char *str); +const char *log_str(std::string const &str); template static inline const char *log_id(T *obj, const char *nullstr = nullptr) { if (nullstr && obj == nullptr) From 71fbf0b48cc9831ef31bbc35e885f87923c78794 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Mon, 15 Apr 2024 14:08:58 +0200 Subject: [PATCH 03/51] kernel/rtlil: Add `SigBit operator[](int offset)` to `SigChunk` This is already supported by `SigSpec` and since both `SigChunk` and `SigSpec` implement `extract` which is the multi-bit variant of this, there is no good reason for `SigChunk` to not support `SigBit operator[](int offset)`. --- kernel/rtlil.cc | 14 ++++++++++++++ kernel/rtlil.h | 1 + 2 files changed, 15 insertions(+) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index a6aebaa4258..07fb4a1b91c 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -3733,6 +3733,20 @@ RTLIL::SigChunk RTLIL::SigChunk::extract(int offset, int length) const return ret; } +RTLIL::SigBit RTLIL::SigChunk::operator[](int offset) const +{ + log_assert(offset >= 0); + log_assert(offset <= width); + RTLIL::SigBit ret; + if (wire) { + ret.wire = wire; + ret.offset = this->offset + offset; + } else { + ret.data = data[offset]; + } + return ret; +} + bool RTLIL::SigChunk::operator <(const RTLIL::SigChunk &other) const { if (wire && other.wire) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index f9da2949508..685acf90426 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -769,6 +769,7 @@ struct RTLIL::SigChunk SigChunk(const RTLIL::SigBit &bit); RTLIL::SigChunk extract(int offset, int length) const; + RTLIL::SigBit operator[](int offset) const; inline int size() const { return width; } inline bool is_wire() const { return wire != NULL; } From 1f0ddf4d3684bf58f7ed99ab0c56d89b3df8b04c Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Mon, 15 Apr 2024 14:12:16 +0200 Subject: [PATCH 04/51] drivertools: Utility code for indexing and traversing signal drivers It adds `DriveBit`, `DriveChunk` and `DriveSpec` types which are similar to `SigBit`, `SigChunk` and `SigSpec` but can also directly represent cell ports, undriven bits and multiple drivers. For indexing an RTLIL module and for querying signal drivers it comes with a `DriverMap` type which is somewhat similar to a `SigMap` but is guaranteed to produce signal drivers as returned representatives. A `DriverMap` can also optionally preserve connections via intermediate wires (e.g. querying the driver of a cell input port will return a connected intermediate wire, querying the driver of that wire will return the cell output port that's driving the wire). --- Makefile | 2 + kernel/drivertools.cc | 946 +++++++++++++++++++++++++++++ kernel/drivertools.h | 1317 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 2265 insertions(+) create mode 100644 kernel/drivertools.cc create mode 100644 kernel/drivertools.h diff --git a/Makefile b/Makefile index cbf834007fc..a4c8680b8c8 100644 --- a/Makefile +++ b/Makefile @@ -558,6 +558,7 @@ $(eval $(call add_include_file,kernel/celltypes.h)) $(eval $(call add_include_file,kernel/consteval.h)) $(eval $(call add_include_file,kernel/constids.inc)) $(eval $(call add_include_file,kernel/cost.h)) +$(eval $(call add_include_file,kernel/drivertools.h)) $(eval $(call add_include_file,kernel/ff.h)) $(eval $(call add_include_file,kernel/ffinit.h)) $(eval $(call add_include_file,kernel/ffmerge.h)) @@ -598,6 +599,7 @@ $(eval $(call add_include_file,backends/rtlil/rtlil_backend.h)) OBJS += kernel/driver.o kernel/register.o kernel/rtlil.o kernel/log.o kernel/calc.o kernel/yosys.o OBJS += kernel/binding.o OBJS += kernel/cellaigs.o kernel/celledges.o kernel/satgen.o kernel/scopeinfo.o kernel/qcsat.o kernel/mem.o kernel/ffmerge.o kernel/ff.o kernel/yw.o kernel/json.o kernel/fmt.o +OBJS += kernel/drivertools.o ifeq ($(ENABLE_ZLIB),1) OBJS += kernel/fstdata.o endif diff --git a/kernel/drivertools.cc b/kernel/drivertools.cc new file mode 100644 index 00000000000..499a9399c46 --- /dev/null +++ b/kernel/drivertools.cc @@ -0,0 +1,946 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2024 Jannis Harder + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/drivertools.h" + +YOSYS_NAMESPACE_BEGIN + +DriveBit::DriveBit(SigBit const &bit) +{ + if (bit.is_wire()) + *this = DriveBitWire(bit.wire, bit.offset); + else + *this = bit.data; +} + +void DriveBit::merge(DriveBit const &other) +{ + if (other.type_ == DriveType::NONE) + return; + if (type_ == DriveType::NONE) { + *this = other; + return; + } + if (type_ != DriveType::MULTIPLE) { + DriveBitMultiple multi(std::move(*this)); + *this = std::move(multi); + } + multiple().merge(other); +} + + +void DriveBitMultiple::merge(DriveBit const &single) +{ + if (single.type() == DriveType::NONE) + return; + if (single.type() == DriveType::MULTIPLE) { + merge(single.multiple()); + return; + } + multiple_.emplace(single); +} + +void DriveBitMultiple::merge(DriveBit &&single) +{ + if (single.type() == DriveType::NONE) + return; + if (single.type() == DriveType::MULTIPLE) { + merge(std::move(single.multiple())); + return; + } + multiple_.emplace(std::move(single)); +} + +DriveBitMultiple DriveChunkMultiple::operator[](int i) const +{ + DriveBitMultiple result; + for (auto const &single : multiple_) + result.merge(single[i]); + return result; +} + + +bool DriveChunkWire::can_append(DriveBitWire const &bit) const +{ + return bit.wire == wire && bit.offset == offset + width; +} + +bool DriveChunkWire::try_append(DriveBitWire const &bit) +{ + if (!can_append(bit)) + return false; + width += 1; + return true; +} + +bool DriveChunkWire::try_append(DriveChunkWire const &chunk) +{ + if (chunk.wire != wire || chunk.offset != offset + width) + return false; + width += chunk.width; + return true; +} + +bool DriveChunkPort::can_append(DriveBitPort const &bit) const +{ + return bit.cell == cell && bit.port == port && bit.offset == offset + width; +} + +bool DriveChunkPort::try_append(DriveBitPort const &bit) +{ + if (!can_append(bit)) + return false; + width += 1; + return true; +} + +bool DriveChunkPort::try_append(DriveChunkPort const &chunk) +{ + if (chunk.cell != cell || chunk.port != port || chunk.offset != offset + width) + return false; + width += chunk.width; + return true; +} + +bool DriveChunkMarker::can_append(DriveBitMarker const &bit) const +{ + return bit.marker == marker && bit.offset == offset + width; +} + +bool DriveChunkMarker::try_append(DriveBitMarker const &bit) +{ + if (!can_append(bit)) + return false; + width += 1; + return true; +} + +bool DriveChunkMarker::try_append(DriveChunkMarker const &chunk) +{ + if (chunk.marker != marker || chunk.offset != offset + width) + return false; + width += chunk.width; + return true; +} + + +bool DriveChunkMultiple::can_append(DriveBitMultiple const &bit) const +{ + if (bit.multiple().size() != multiple_.size()) + return false; + + int const_drivers = 0; + for (DriveChunk const &single : multiple_) + if (single.is_constant()) + const_drivers += 1; + + if (const_drivers > 1) + return false; + + for (DriveBit const &single : bit.multiple()) + if (single.is_constant()) + const_drivers -= 1; + + if (const_drivers != 0) + return false; + + for (DriveChunk const &single : multiple_) + { + switch (single.type()) + { + case DriveType::CONSTANT: { + } break; + case DriveType::WIRE: { + auto const &wire = single.wire(); + DriveBit next = DriveBitWire(wire.wire, wire.offset + wire.width); + if (!bit.multiple().count(next)) + return false; + } break; + case DriveType::PORT: { + auto const &port = single.port(); + DriveBit next = DriveBitPort(port.cell, port.port, port.offset + port.width); + if (!bit.multiple().count(next)) + return false; + } break; + case DriveType::MARKER: { + auto const &marker = single.marker(); + DriveBit next = DriveBitMarker(marker.marker, marker.offset + marker.width); + if (!bit.multiple().count(next)) + return false; + } break; + default: + return false; + } + } + + return true; +} + +bool DriveChunkMultiple::can_append(DriveChunkMultiple const &chunk) const +{ + if (chunk.multiple().size() != multiple_.size()) + return false; + + int const_drivers = 0; + for (DriveChunk const &single : multiple_) + if (single.is_constant()) + const_drivers += 1; + + if (const_drivers > 1) + return false; + + for (DriveChunk const &single : chunk.multiple()) + if (single.is_constant()) + const_drivers -= 1; + + if (const_drivers != 0) + return false; + + for (DriveChunk const &single : multiple_) + { + switch (single.type()) + { + case DriveType::CONSTANT: { + } break; + case DriveType::WIRE: { + auto const &wire = single.wire(); + DriveChunk next = DriveChunkWire(wire.wire, wire.offset + wire.width, chunk.size()); + if (!chunk.multiple().count(next)) + return false; + } break; + case DriveType::PORT: { + auto const &port = single.port(); + DriveChunk next = DriveChunkPort(port.cell, port.port, port.offset + port.width, chunk.size()); + if (!chunk.multiple().count(next)) + return false; + } break; + case DriveType::MARKER: { + auto const &marker = single.marker(); + DriveChunk next = DriveChunkMarker(marker.marker, marker.offset + marker.width, chunk.size()); + if (!chunk.multiple().count(next)) + return false; + } break; + default: + return false; + } + } + + return true; +} + +bool DriveChunkMultiple::try_append(DriveBitMultiple const &bit) +{ + if (!can_append(bit)) + return false; + width_ += 1; + State constant; + + for (DriveBit const &single : bit.multiple()) + if (single.is_constant()) + constant = single.constant(); + + for (DriveChunk &single : multiple_) + { + switch (single.type()) + { + case DriveType::CONSTANT: { + single.constant().bits.push_back(constant); + } break; + case DriveType::WIRE: { + single.wire().width += 1; + } break; + case DriveType::PORT: { + single.port().width += 1; + } break; + case DriveType::MARKER: { + single.marker().width += 1; + } break; + default: + log_abort(); + } + } + return true; +} + +bool DriveChunkMultiple::try_append(DriveChunkMultiple const &chunk) +{ + if (!can_append(chunk)) + return false; + int width = chunk.size(); + width_ += width; + Const constant; + + for (DriveChunk const &single : chunk.multiple()) + if (single.is_constant()) + constant = single.constant(); + + for (DriveChunk &single : multiple_) + { + switch (single.type()) + { + case DriveType::CONSTANT: { + auto &bits = single.constant().bits; + bits.insert(bits.end(), constant.bits.begin(), constant.bits.end()); + } break; + case DriveType::WIRE: { + single.wire().width += width; + } break; + case DriveType::PORT: { + single.port().width += width; + } break; + case DriveType::MARKER: { + single.marker().width += width; + } break; + default: + log_abort(); + } + } + return true; +} + +bool DriveChunk::can_append(DriveBit const &bit) const +{ + if (size() == 0) + return true; + if (bit.type() != type_) + return false; + switch (type_) + { + case DriveType::NONE: + return true; + case DriveType::CONSTANT: + return true; + case DriveType::WIRE: + return wire_.can_append(bit.wire()); + case DriveType::PORT: + return port_.can_append(bit.port()); + case DriveType::MULTIPLE: + return multiple_.can_append(bit.multiple()); + default: + log_abort(); + } +} + +bool DriveChunk::try_append(DriveBit const &bit) +{ + if (size() == 0) + *this = bit; + if (bit.type() != type_) + return false; + switch (type_) + { + case DriveType::NONE: + none_ += 1; + return true; + case DriveType::CONSTANT: + constant_.bits.push_back(bit.constant()); + return true; + case DriveType::WIRE: + return wire_.try_append(bit.wire()); + case DriveType::PORT: + return port_.try_append(bit.port()); + case DriveType::MULTIPLE: + return multiple_.try_append(bit.multiple()); + default: + log_abort(); + } +} + + +bool DriveChunk::try_append(DriveChunk const &chunk) +{ + if (size() == 0) + *this = chunk; + if (chunk.type_ != type_) + return false; + switch (type_) + { + case DriveType::NONE: + none_ += chunk.none_; + return true; + case DriveType::CONSTANT: + constant_.bits.insert(constant_.bits.end(), chunk.constant_.bits.begin(), chunk.constant_.bits.end()); + return true; + case DriveType::WIRE: + return wire_.try_append(chunk.wire()); + case DriveType::PORT: + return port_.try_append(chunk.port()); + case DriveType::MARKER: + return marker_.try_append(chunk.marker()); + case DriveType::MULTIPLE: + return multiple_.try_append(chunk.multiple()); + } + log_abort(); +} + +void DriveSpec::append(DriveBit const &bit) +{ + hash_ = 0; + if (!packed()) { + bits_.push_back(bit); + width_ += 1; + return; + } + + if (chunks_.empty() || !chunks_.back().try_append(bit)) + chunks_.emplace_back(bit); + width_ += 1; +} + +void DriveSpec::append(DriveChunk const &chunk) +{ + hash_ = 0; + pack(); + if (chunks_.empty() || !chunks_.back().try_append(chunk)) + chunks_.emplace_back(chunk); + width_ += chunk.size(); +} + +void DriveSpec::pack() const { + if (bits_.empty()) + return; + std::vector bits(std::move(bits_)); + for (auto &bit : bits) + if (chunks_.empty() || !chunks_.back().try_append(bit)) + chunks_.emplace_back(std::move(bit)); +} + +void DriveSpec::unpack() const { + if (chunks_.empty()) + return; + for (auto &chunk : chunks_) + { + for (int i = 0, width = chunk.size(); i != width; ++i) + { + bits_.emplace_back(chunk[i]); + } + } + chunks_.clear(); +} + +void DriveSpec::compute_width() +{ + width_ = 0; + for (auto const &chunk : chunks_) + width_ += chunk.size(); +} + +void DriverMap::DriveBitGraph::add_edge(DriveBitId src, DriveBitId dst) +{ + if (first_edges.emplace(src, dst).first->second == dst) + return; + if (second_edges.emplace(src, dst).first->second == dst) + return; + more_edges[src].emplace(dst); +} + +DriverMap::DriveBitId DriverMap::DriveBitGraph::pop_edge(DriveBitId src) +{ + // TODO unused I think? + auto found_more = more_edges.find(src); + if (found_more != more_edges.end()) { + auto result = found_more->second.pop(); + if (found_more->second.empty()) + more_edges.erase(found_more); + return result; + } + + auto found_second = second_edges.find(src); + if (found_second != second_edges.end()) { + auto result = found_second->second; + second_edges.erase(found_second); + return result; + } + + auto found_first = first_edges.find(src); + if (found_first != first_edges.end()) { + auto result = found_first->second; + first_edges.erase(found_first); + return result; + } + + return DriveBitId(); +} + +void DriverMap::DriveBitGraph::clear(DriveBitId src) +{ + first_edges.erase(src); + second_edges.erase(src); + more_edges.erase(src); +} + +bool DriverMap::DriveBitGraph::contains(DriveBitId src) +{ + return first_edges.count(src); +} + +int DriverMap::DriveBitGraph::count(DriveBitId src) +{ + if (!first_edges.count(src)) + return 0; + if (!second_edges.count(src)) + return 1; + auto found = more_edges.find(src); + if (found == more_edges.end()) + return 2; + return GetSize(found->second); +} + +DriverMap::DriveBitId DriverMap::DriveBitGraph::at(DriveBitId src, int index) +{ + if (index == 0) + return first_edges.at(src); + else if (index == 1) + return second_edges.at(src); + else + return *more_edges.at(src).element(index - 2); +} + + +DriverMap::BitMode DriverMap::bit_mode(DriveBit const &bit) +{ + switch (bit.type()) + { + case DriveType::NONE: + return BitMode::NONE; + case DriveType::CONSTANT: + // TODO how to handle Sx here? + return bit.constant() == State::Sz ? BitMode::NONE : BitMode::DRIVER; + case DriveType::WIRE: { + auto const &wire = bit.wire(); + bool driver = wire.wire->port_input; + bool driven = wire.wire->port_output; + + if (driver && !driven) + return BitMode::DRIVER; + else if (driven && !driver) + return BitMode::DRIVEN; + else if (driver && driven) + return BitMode::TRISTATE; + else + return keep_wire(bit.wire().wire) ? BitMode::KEEP : BitMode::NONE; + } + case DriveType::PORT: { + auto const &port = bit.port(); + bool driver = celltypes.cell_output(port.cell->type, port.port); + bool driven = celltypes.cell_input(port.cell->type, port.port); + if (driver && !driven) + return BitMode::DRIVER; + else if (driven && !driver) + return BitMode::DRIVEN_UNIQUE; + else + return BitMode::TRISTATE; + } + case DriveType::MARKER: { + // TODO user supplied classification + log_abort(); + } + default: + log_abort(); + } +} + +DriverMap::DriveBitId DriverMap::id_from_drive_bit(DriveBit const &bit) +{ + switch (bit.type()) + { + case DriveType::NONE: + return -1; + case DriveType::CONSTANT: + return (int)bit.constant(); + case DriveType::WIRE: { + auto const &wire_bit = bit.wire(); + int offset = next_offset; + auto insertion = wire_offsets.emplace(wire_bit.wire, offset); + if (insertion.second) { + if (wire_bit.wire->width == 1) { + log_assert(wire_bit.offset == 0); + isolated_drive_bits.emplace(offset, bit); + } else + drive_bits.emplace(offset, DriveBitWire(wire_bit.wire, 0)); + next_offset += wire_bit.wire->width; + } + return insertion.first->second.id + wire_bit.offset; + } + case DriveType::PORT: { + auto const &port_bit = bit.port(); + auto key = std::make_pair(port_bit.cell, port_bit.port); + int offset = next_offset; + auto insertion = port_offsets.emplace(key, offset); + if (insertion.second) { + int width = port_bit.cell->connections().at(port_bit.port).size(); + if (width == 1 && offset == 0) { + log_assert(port_bit.offset == 0); + isolated_drive_bits.emplace(offset, bit); + } else + drive_bits.emplace(offset, DriveBitPort(port_bit.cell, port_bit.port, 0)); + next_offset += width; + } + return insertion.first->second.id + port_bit.offset; + } + default: + log_assert(false && "unsupported DriveType in DriverMap"); + } + log_abort(); +} + +DriveBit DriverMap::drive_bit_from_id(DriveBitId id) +{ + auto found_isolated = isolated_drive_bits.find(id); + if (found_isolated != isolated_drive_bits.end()) + return found_isolated->second; + + auto found = drive_bits.upper_bound(id); + if (found == drive_bits.begin()) { + return id < 0 ? DriveBit() : DriveBit((State) id.id); + } + --found; + DriveBit result = found->second; + if (result.is_wire()) { + result.wire().offset += id.id - found->first.id; + } else { + log_assert(result.is_port()); + result.port().offset += id.id - found->first.id; + } + return result; +} + +void DriverMap::connect_directed_merge(DriveBitId driven_id, DriveBitId driver_id) +{ + if (driven_id == driver_id) + return; + + same_driver.merge(driven_id, driver_id); + + for (int i = 0, end = connected_drivers.count(driven_id); i != end; ++i) + connected_drivers.add_edge(driver_id, connected_drivers.at(driven_id, i)); + + connected_drivers.clear(driven_id); + + for (int i = 0, end = connected_undirected.count(driven_id); i != end; ++i) + connected_undirected.add_edge(driver_id, connected_undirected.at(driven_id, i)); + + connected_undirected.clear(driven_id); +} + +void DriverMap::connect_directed_buffer(DriveBitId driven_id, DriveBitId driver_id) +{ + connected_drivers.add_edge(driven_id, driver_id); +} + +void DriverMap::connect_undirected(DriveBitId a_id, DriveBitId b_id) +{ + connected_undirected.add_edge(a_id, b_id); + connected_undirected.add_edge(b_id, a_id); +} + +void DriverMap::add(Module *module) +{ + for (auto const &conn : module->connections()) + add(conn.first, conn.second); + + for (auto cell : module->cells()) + for (auto const &conn : cell->connections()) + add_port(cell, conn.first, conn.second); +} + +// Add a single bit connection to the driver map. +void DriverMap::add(DriveBit const &a, DriveBit const &b) +{ + DriveBitId a_id = id_from_drive_bit(a); + DriveBitId b_id = id_from_drive_bit(b); + + DriveBitId orig_a_id = a_id; + DriveBitId orig_b_id = b_id; + + a_id = same_driver.find(a_id); + b_id = same_driver.find(b_id); + + if (a_id == b_id) + return; + + BitMode a_mode = bit_mode(orig_a_id == a_id ? a : drive_bit_from_id(a_id)); + BitMode b_mode = bit_mode(orig_b_id == b_id ? b : drive_bit_from_id(b_id)); + + // If either bit is just a wire that we don't need to keep, merge and + // use the other end as representative bit. + if (a_mode == BitMode::NONE) + connect_directed_merge(a_id, b_id); + else if (b_mode == BitMode::NONE) + connect_directed_merge(b_id, a_id); + // If either bit requires a driven value and has a unique driver, merge + // and use the other end as representative bit. + else if (a_mode == BitMode::DRIVEN_UNIQUE && !(b_mode == BitMode::DRIVEN_UNIQUE || b_mode == BitMode::DRIVEN)) + connect_directed_buffer(a_id, b_id); + else if (b_mode == BitMode::DRIVEN_UNIQUE && !(b_mode == BitMode::DRIVEN_UNIQUE || b_mode == BitMode::DRIVEN)) + connect_directed_buffer(b_id, a_id); + // If either bit only drives a value, store a directed connection from + // it to the other bit. + else if (a_mode == BitMode::DRIVER) + connect_directed_buffer(b_id, a_id); + else if (b_mode == BitMode::DRIVER) + connect_directed_buffer(a_id, b_id); + // Otherwise we store an undirected connection which we will resolve + // during querying. + else + connect_undirected(a_id, b_id); + + return; +} + +// Specialized version that avoids unpacking +void DriverMap::add(SigSpec const &a, SigSpec const &b) +{ + log_assert(a.size() == b.size()); + auto const &a_chunks = a.chunks(); + auto const &b_chunks = b.chunks(); + + auto a_chunk = a_chunks.begin(); + auto a_end = a_chunks.end(); + int a_offset = 0; + + auto b_chunk = b_chunks.begin(); + int b_offset = 0; + + SigChunk tmp_a, tmp_b; + while (a_chunk != a_end) { + int a_width = a_chunk->width - a_offset; + if (a_width == 0) { + a_offset = 0; + ++a_chunk; + continue; + } + int b_width = b_chunk->width - b_offset; + if (b_width == 0) { + b_offset = 0; + ++b_chunk; + continue; + } + int width = std::min(a_width, b_width); + log_assert(width > 0); + + SigChunk const &a_subchunk = + a_offset == 0 && a_width == width ? *a_chunk : a_chunk->extract(a_offset, width); + SigChunk const &b_subchunk = + b_offset == 0 && b_width == width ? *b_chunk : b_chunk->extract(b_offset, width); + + add(a_subchunk, b_subchunk); + + a_offset += width; + b_offset += width; + } +} + +void DriverMap::add_port(Cell *cell, IdString const &port, SigSpec const &b) +{ + int offset = 0; + for (auto const &chunk : b.chunks()) { + add(chunk, DriveChunkPort(cell, port, offset, chunk.width)); + offset += chunk.size(); + } +} + +void DriverMap::orient_undirected(DriveBitId id) +{ + pool &seen = orient_undirected_seen; + pool &drivers = orient_undirected_drivers; + dict &distance = orient_undirected_distance; + seen.clear(); + drivers.clear(); + + seen.emplace(id); + + for (int pos = 0; pos < GetSize(seen); ++pos) { + DriveBitId current = *seen.element(seen.size() - 1 - pos); + DriveBit bit = drive_bit_from_id(current); + + BitMode mode = bit_mode(bit); + + if (mode == BitMode::DRIVER || mode == BitMode::TRISTATE) + drivers.emplace(current); + + if (connected_drivers.contains(current)) + drivers.emplace(current); + + int undirected_driver_count = connected_undirected.count(current); + + for (int i = 0; i != undirected_driver_count; ++i) + seen.emplace(same_driver.find(connected_undirected.at(current, i))); + } + + if (drivers.empty()) + for (auto seen_id : seen) + drivers.emplace(seen_id); + + for (auto driver : drivers) + { + distance.clear(); + distance.emplace(driver, 0); + + for (int pos = 0; pos < GetSize(distance); ++pos) { + auto current_it = distance.element(distance.size() - 1 - pos); + + DriveBitId current = current_it->first; + int undirected_driver_count = connected_undirected.count(current); + + for (int i = 0; i != undirected_driver_count; ++i) + { + DriveBitId next = same_driver.find(connected_undirected.at(current, i)); + auto emplaced = distance.emplace(next, current_it->second + 1); + if (emplaced.first->second == current_it->second + 1) + connected_oriented.add_edge(next, current); + } + } + } + + for (auto seen_id : seen) + oriented_present.emplace(seen_id); +} + +DriveBit DriverMap::operator()(DriveBit const &bit) +{ + if (bit.type() == DriveType::MARKER || bit.type() == DriveType::NONE) + return bit; + if (bit.type() == DriveType::MULTIPLE) + { + DriveBit result; + for (auto const &inner : bit.multiple().multiple()) + result.merge((*this)(inner)); + return result; + } + + DriveBitId bit_id = id_from_drive_bit(bit); + + bit_id = same_driver.find(bit_id); + + DriveBit bit_repr = drive_bit_from_id(bit_id); + + BitMode mode = bit_mode(bit_repr); + + int implicit_driver_count = connected_drivers.count(bit_id); + if (connected_undirected.contains(bit_id) && !oriented_present.count(bit_id)) + orient_undirected(bit_id); + + DriveBit driver; + + if (mode == BitMode::DRIVER || mode == BitMode::TRISTATE) + driver = bit_repr; + + for (int i = 0; i != implicit_driver_count; ++i) + driver.merge(drive_bit_from_id(connected_drivers.at(bit_id, i))); + + int oriented_driver_count = connected_oriented.count(bit_id); + for (int i = 0; i != oriented_driver_count; ++i) + driver.merge(drive_bit_from_id(connected_oriented.at(bit_id, i))); + + return driver; +} + +DriveSpec DriverMap::operator()(DriveSpec spec) +{ + DriveSpec result; + + for (int i = 0, width = spec.size(); i != width; ++i) + result.append((*this)(spec[i])); + + return result; +} + +const char *log_signal(DriveChunkWire const &chunk) +{ + const char *id = log_id(chunk.wire->name); + if (chunk.is_whole()) + return id; + if (chunk.width == 1) + return log_str(stringf("%s [%d]", id, chunk.offset)); + return log_str(stringf("%s [%d:%d]", id, chunk.offset + chunk.width - 1, chunk.offset)); +} + + +const char *log_signal(DriveChunkPort const &chunk) +{ + const char *cell_id = log_id(chunk.cell->name); + const char *port_id = log_id(chunk.port); + if (chunk.is_whole()) + return log_str(stringf("%s <%s>", cell_id, port_id)); + if (chunk.width == 1) + return log_str(stringf("%s <%s> [%d]", cell_id, port_id, chunk.offset)); + return log_str(stringf("%s <%s> [%d:%d]", cell_id, port_id, chunk.offset + chunk.width - 1, chunk.offset)); +} + +const char *log_signal(DriveChunkMarker const &chunk) +{ + if (chunk.width == 1) + return log_str(stringf(" [%d]", chunk.marker, chunk.offset)); + return log_str(stringf(" [%d:%d]", chunk.marker, chunk.offset + chunk.width - 1, chunk.offset)); +} + +const char *log_signal(DriveChunk const &chunk) +{ + switch (chunk.type()) + { + case DriveType::NONE: + return log_str(stringf("", chunk.size())); + case DriveType::CONSTANT: + return log_const(chunk.constant()); + case DriveType::WIRE: + return log_signal(chunk.wire()); + case DriveType::PORT: + return log_signal(chunk.port()); + case DriveType::MARKER: + return log_signal(chunk.marker()); + case DriveType::MULTIPLE: { + std::string str = " + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#ifndef DRIVERTOOLS_H +#define DRIVERTOOLS_H + +#include + +#include "kernel/rtlil.h" +#include "kernel/sigtools.h" +#include "kernel/celltypes.h" + +YOSYS_NAMESPACE_BEGIN + +// TODO move implementation into a .cc file + +struct DriveBit; + +struct DriveChunkWire; +struct DriveChunkPort; +struct DriveChunkMarker; +struct DriveChunk; + +struct DriveSpec; + +const char *log_signal(DriveChunkWire const &chunk); +const char *log_signal(DriveChunkPort const &chunk); +const char *log_signal(DriveChunkMarker const &chunk); +const char *log_signal(DriveChunk const &chunk); +const char *log_signal(DriveSpec const &chunk); + +enum class DriveType : unsigned char +{ + NONE, + CONSTANT, + WIRE, + PORT, + MULTIPLE, + MARKER, +}; + +struct DriveBitWire +{ + Wire *wire; + int offset; + + DriveBitWire(Wire *wire, int offset) : wire(wire), offset(offset) {} + + bool operator==(const DriveBitWire &other) const + { + return wire == other.wire && offset == other.offset; + } + + bool operator<(const DriveBitWire &other) const + { + if (wire != other.wire) + return wire->name < other.wire->name; + return offset < other.offset; + } + + unsigned int hash() const + { + return mkhash_add(wire->name.hash(), offset); + } + + operator SigBit() const + { + return SigBit(wire, offset); + } +}; + +struct DriveBitPort +{ + Cell *cell; + IdString port; + int offset; + + DriveBitPort(Cell *cell, IdString port, int offset) : cell(cell), port(port), offset(offset) {} + + bool operator==(const DriveBitPort &other) const + { + return cell == other.cell && port == other.port && offset == other.offset; + } + + bool operator<(const DriveBitPort &other) const + { + if (cell != other.cell) + return cell->name < other.cell->name; + if (port != other.port) + return port < other.port; + return offset < other.offset; + } + + unsigned int hash() const + { + return mkhash_add(mkhash(cell->name.hash(), port.hash()), offset); + } +}; + + +struct DriveBitMarker +{ + int marker; + int offset; + + DriveBitMarker(int marker, int offset) : marker(marker), offset(offset) {} + + bool operator==(const DriveBitMarker &other) const + { + return marker == other.marker && offset == other.offset; + } + + bool operator<(const DriveBitMarker &other) const + { + if (marker != other.marker) + return marker < other.marker; + return offset < other.offset; + } + + unsigned int hash() const + { + return mkhash_add(marker, offset); + } + +}; + +struct DriveBitMultiple +{ +private: + pool multiple_; + +public: + DriveBitMultiple() {} + DriveBitMultiple(DriveBit const &single) + { + multiple_.emplace(single); + } + + pool const &multiple() const { return multiple_; } + + void merge(DriveBitMultiple const &other) + { + for (DriveBit const &single : other.multiple_) + merge(single); + } + + void merge(DriveBitMultiple &&other) + { + for (DriveBit &single : other.multiple_) + merge(std::move(single)); + } + + void merge(DriveBit const &single); + void merge(DriveBit &&single); + + bool operator==(const DriveBitMultiple &other) const + { + return multiple_ == other.multiple_; + } + + unsigned int hash() const + { + return multiple_.hash(); + } +}; + +struct DriveBit +{ +private: + DriveType type_ = DriveType::NONE; + union + { + State constant_; + DriveBitWire wire_; + DriveBitPort port_; + DriveBitMarker marker_; + DriveBitMultiple multiple_; + }; +public: + DriveBit() {} + + DriveBit(SigBit const &bit); + + DriveBit(DriveBit const &other) { *this = other; } + DriveBit(DriveBit &&other) { *this = other; } + + + DriveBit(State constant) { *this = constant; } + DriveBit(DriveBitWire const &wire) { *this = wire; } + DriveBit(DriveBitWire &&wire) { *this = wire; } + DriveBit(DriveBitPort const &port) { *this = port; } + DriveBit(DriveBitPort &&port) { *this = port; } + DriveBit(DriveBitMarker const &marker) { *this = marker; } + DriveBit(DriveBitMarker &&marker) { *this = marker; } + DriveBit(DriveBitMultiple const &multiple) { *this = multiple; } + DriveBit(DriveBitMultiple &&multiple) { *this = multiple; } + + ~DriveBit() { set_none(); } + + void set_none() + { + switch (type_) + { + case DriveType::NONE: + break; + case DriveType::CONSTANT: + break; + case DriveType::WIRE: + wire_.~DriveBitWire(); + break; + case DriveType::PORT: + port_.~DriveBitPort(); + break; + case DriveType::MARKER: + marker_.~DriveBitMarker(); + break; + case DriveType::MULTIPLE: + multiple_.~DriveBitMultiple(); + break; + } + type_ = DriveType::NONE; + } + + DriveBit &operator=(DriveBit const &other) + { + switch (other.type_) + { + case DriveType::NONE: + set_none(); + break; + case DriveType::CONSTANT: + *this = other.constant_; + break; + case DriveType::WIRE: + *this = other.wire_; + break; + case DriveType::PORT: + *this = other.port_; + break; + case DriveType::MARKER: + *this = other.marker_; + break; + case DriveType::MULTIPLE: + *this = other.multiple_; + break; + } + return *this; + } + + DriveBit &operator=(DriveBit &&other) + { + switch (other.type_) + { + case DriveType::NONE: + set_none(); + break; + case DriveType::CONSTANT: + *this = std::move(other.constant_); + break; + case DriveType::WIRE: + *this = std::move(other.wire_); + break; + case DriveType::PORT: + *this = std::move(other.port_); + break; + case DriveType::MARKER: + *this = std::move(other.marker_); + break; + case DriveType::MULTIPLE: + *this = std::move(other.multiple_); + break; + } + return *this; + } + + DriveBit &operator=(State constant) + { + set_none(); + constant_ = constant; + type_ = DriveType::CONSTANT; + return *this; + } + + DriveBit &operator=(DriveBitWire const &wire) + { + set_none(); + new (&wire_) DriveBitWire(wire); + type_ = DriveType::WIRE; + return *this; + } + + DriveBit &operator=(DriveBitWire &&wire) + { + set_none(); + new (&wire_) DriveBitWire(wire); + type_ = DriveType::WIRE; + return *this; + } + + DriveBit &operator=(DriveBitPort const &port) + { + set_none(); + new (&port_) DriveBitPort(port); + type_ = DriveType::PORT; + return *this; + } + + DriveBit &operator=(DriveBitPort &&port) + { + set_none(); + new (&port_) DriveBitPort(port); + type_ = DriveType::PORT; + return *this; + } + + DriveBit &operator=(DriveBitMarker const &marker) + { + set_none(); + new (&marker_) DriveBitMarker(marker); + type_ = DriveType::MARKER; + return *this; + } + + DriveBit &operator=(DriveBitMarker &&marker) + { + set_none(); + new (&marker_) DriveBitMarker(marker); + type_ = DriveType::MARKER; + return *this; + } + + DriveBit &operator=(DriveBitMultiple const &multiple) + { + set_none(); + if (multiple.multiple().empty()) + return *this; + new (&multiple_) DriveBitMultiple(multiple); + type_ = DriveType::MULTIPLE; + return *this; + } + + DriveBit &operator=(DriveBitMultiple &&multiple) + { + set_none(); + if (multiple.multiple().empty()) + return *this; + new (&multiple_) DriveBitMultiple(multiple); + type_ = DriveType::MULTIPLE; + return *this; + } + + unsigned int hash() const + { + unsigned int inner; + switch (type_) + { + case DriveType::NONE: + inner = 0; + break; + case DriveType::CONSTANT: + inner = constant_; + break; + case DriveType::WIRE: + inner = wire_.hash(); + break; + case DriveType::PORT: + inner = port_.hash(); + break; + case DriveType::MARKER: + inner = marker_.hash(); + break; + case DriveType::MULTIPLE: + inner = multiple_.hash(); + break; + } + return mkhash((unsigned int)type_, inner); + } + + bool operator==(const DriveBit &other) const + { + if (type_ != other.type_) + return false; + + switch (type_) + { + case DriveType::NONE: + return true; + case DriveType::CONSTANT: + return constant_ == other.constant_; + case DriveType::WIRE: + return wire_ == other.wire_; + case DriveType::PORT: + return port_ == other.port_; + case DriveType::MARKER: + return marker_ == other.marker_; + case DriveType::MULTIPLE: + return multiple_ == other.multiple_; + } + log_assert(false); + } + + bool operator!=(const DriveBit &other) const + { + return !(*this == other); + } + + bool operator<(const DriveBit &other) const + { + if (type_ != other.type_) + return type_ < other.type_; + switch (type_) + { + case DriveType::NONE: + return false; + case DriveType::CONSTANT: + return constant_ < other.constant_; + case DriveType::WIRE: + return wire_ < other.wire_; + case DriveType::PORT: + return port_ < other.port_; + case DriveType::MARKER: + return marker_ < other.marker_; + case DriveType::MULTIPLE: + log_assert(!"TODO"); + } + log_abort(); + } + + + DriveType type() const { return type_; } + + bool is_none() const { return type_ == DriveType::NONE; } + bool is_constant() const { return type_ == DriveType::CONSTANT; } + bool is_wire() const { return type_ == DriveType::WIRE; } + bool is_port() const { return type_ == DriveType::PORT; } + bool is_marker() const { return type_ == DriveType::MARKER; } + bool is_multiple() const { return type_ == DriveType::MULTIPLE; } + + State &constant() { log_assert(is_constant()); return constant_; } + State const &constant() const { log_assert(is_constant()); return constant_; } + DriveBitWire &wire() { log_assert(is_wire()); return wire_; } + DriveBitWire const &wire() const { log_assert(is_wire()); return wire_; } + DriveBitPort &port() { log_assert(is_port()); return port_; } + DriveBitPort const &port() const { log_assert(is_port()); return port_; } + DriveBitMarker &marker() { log_assert(is_marker()); return marker_; } + DriveBitMarker const &marker() const { log_assert(is_marker()); return marker_; } + DriveBitMultiple &multiple() { log_assert(is_multiple()); return multiple_; } + DriveBitMultiple const &multiple() const { log_assert(is_multiple()); return multiple_; } + + void merge(DriveBit const &other); + +}; + + +struct DriveChunkWire +{ + Wire *wire; + int offset; + int width; + + DriveChunkWire(Wire *wire, int offset, int width) : wire(wire), offset(offset), width(width) {} + DriveChunkWire(DriveBitWire const &bit) : wire(bit.wire), offset(bit.offset), width(1) {} + + int size() const { return width; } + + DriveBitWire operator[](int i) const + { + log_assert(i >= 0 && i < width); + return DriveBitWire(wire, offset + i); + } + + bool can_append(DriveBitWire const &bit) const; + bool try_append(DriveBitWire const &bit); + bool try_append(DriveChunkWire const &chunk); + + // Whether this chunk is a whole wire + bool is_whole() const { return offset == 0 && width == wire->width; } + + bool operator==(const DriveChunkWire &other) const + { + return wire == other.wire && offset == other.offset && width == other.width; + } + + bool operator<(const DriveChunkWire &other) const + { + if (wire != other.wire) + return wire->name < other.wire->name; + if (width != other.width) + return width < other.width; + return offset < other.offset; + } + + unsigned int hash() const + { + return mkhash_add(mkhash(wire->name.hash(), width), offset); + } + + explicit operator SigChunk() const + { + return SigChunk(wire, offset, width); + } +}; + +struct DriveChunkPort +{ + Cell *cell; + IdString port; + int offset; + int width; + + DriveChunkPort(Cell *cell, IdString port, int offset, int width) : + cell(cell), port(port), offset(offset), width(width) { } + DriveChunkPort(Cell *cell, IdString port) : + cell(cell), port(port), offset(0), width(GetSize(cell->connections().at(port))) { } + DriveChunkPort(Cell *cell, std::pair const &conn) : + cell(cell), port(conn.first), offset(0), width(GetSize(conn.second)) { } + DriveChunkPort(DriveBitPort const &bit) : + cell(bit.cell), port(bit.port), offset(bit.offset), width(1) { } + + int size() const { return width; } + + DriveBitPort operator[](int i) const + { + log_assert(i >= 0 && i < width); + return DriveBitPort(cell, port, offset + i); + } + + bool can_append(DriveBitPort const &bit) const; + bool try_append(DriveBitPort const &bit); + bool try_append(DriveChunkPort const &chunk); + + // Whether this chunk is a whole port + bool is_whole() const + { + return offset == 0 && width == cell->connections().at(port).size(); + } + + bool operator==(const DriveChunkPort &other) const + { + return cell == other.cell && port == other.port && offset == other.offset && width == other.width; + } + + bool operator<(const DriveChunkPort &other) const + { + if (cell != other.cell) + return cell->name < other.cell->name; + if (port != other.port) + return port < other.port; + if (width != other.width) + return width < other.width; + return offset < other.offset; + } + + unsigned int hash() const + { + return mkhash_add(mkhash(mkhash(cell->name.hash(), port.hash()), width), offset); + } +}; + + +struct DriveChunkMarker +{ + int marker; + int offset; + int width; + + DriveChunkMarker(int marker, int offset, int width) : + marker(marker), offset(offset), width(width) {} + DriveChunkMarker(DriveBitMarker const &bit) : + marker(bit.marker), offset(bit.offset), width(1) {} + + int size() const { return width; } + + DriveBitMarker operator[](int i) const + { + log_assert(i >= 0 && i < width); + return DriveBitMarker(marker, offset + i); + } + + bool can_append(DriveBitMarker const &bit) const; + bool try_append(DriveBitMarker const &bit); + bool try_append(DriveChunkMarker const &chunk); + + bool operator==(const DriveChunkMarker &other) const + { + return marker == other.marker && offset == other.offset && width == other.width; + } + + bool operator<(const DriveChunkMarker &other) const + { + if (marker != other.marker) + return marker < other.marker; + if (width != other.width) + return width < other.width; + return offset < other.offset; + } + + unsigned int hash() const + { + return mkhash_add(mkhash(marker, width), offset); + } +}; + +struct DriveChunkMultiple +{ +private: + mutable pool multiple_; + int width_; + +public: + pool const &multiple() const { return multiple_; } + + DriveChunkMultiple(DriveBitMultiple const &bit) : width_(1) { + for (auto const &bit : bit.multiple()) + multiple_.emplace(bit); + } + + int size() const { return width_; } + + DriveBitMultiple operator[](int i) const; + + bool can_append(DriveBitMultiple const &bit) const; + + bool try_append(DriveBitMultiple const &bit); + + + bool can_append(DriveChunkMultiple const &bit) const; + + bool try_append(DriveChunkMultiple const &bit); + + bool operator==(const DriveChunkMultiple &other) const + { + return width_ == other.width_ && multiple_ == other.multiple_; + } + + bool operator<(const DriveChunkMultiple &other) const + { + if (multiple_.size() < other.multiple_.size()) + + multiple_.sort(); + return false; // TODO implement, canonicalize order + } + + unsigned int hash() const + { + return mkhash(width_, multiple_.hash()); + } +}; + +struct DriveChunk +{ +private: + DriveType type_ = DriveType::NONE; + union + { + int none_; + Const constant_; + DriveChunkWire wire_; + DriveChunkPort port_; + DriveChunkMarker marker_; + DriveChunkMultiple multiple_; + }; + +public: + DriveChunk() { set_none(); } + + DriveChunk(DriveChunk const &other) { *this = other; } + DriveChunk(DriveChunk &&other) { *this = other; } + + DriveChunk(DriveBit const &other) { *this = other; } + + DriveChunk(Const const &constant) { *this = constant; } + DriveChunk(Const &&constant) { *this = constant; } + DriveChunk(DriveChunkWire const &wire) { *this = wire; } + DriveChunk(DriveChunkWire &&wire) { *this = wire; } + DriveChunk(DriveChunkPort const &port) { *this = port; } + DriveChunk(DriveChunkPort &&port) { *this = port; } + DriveChunk(DriveChunkMarker const &marker) { *this = marker; } + DriveChunk(DriveChunkMarker &&marker) { *this = marker; } + DriveChunk(DriveChunkMultiple const &multiple) { *this = multiple; } + DriveChunk(DriveChunkMultiple &&multiple) { *this = multiple; } + + ~DriveChunk() { set_none(); } + + DriveBit operator[](int i) const + { + switch (type_) + { + case DriveType::NONE: + return DriveBit(); + case DriveType::CONSTANT: + return constant_[i]; + case DriveType::WIRE: + return wire_[i]; + case DriveType::PORT: + return port_[i]; + case DriveType::MARKER: + return marker_[i]; + case DriveType::MULTIPLE: + return multiple_[i]; + } + log_abort(); + } + + void set_none(int width = 0) + { + switch (type_) + { + case DriveType::NONE: + none_ = width; + break; + case DriveType::CONSTANT: + constant_.~Const(); + break; + case DriveType::WIRE: + wire_.~DriveChunkWire(); + break; + case DriveType::PORT: + port_.~DriveChunkPort(); + break; + case DriveType::MARKER: + marker_.~DriveChunkMarker(); + break; + case DriveType::MULTIPLE: + multiple_.~DriveChunkMultiple(); + break; + } + type_ = DriveType::NONE; + none_ = width; + } + + DriveChunk &operator=(DriveChunk const &other) + { + switch (other.type_) + { + case DriveType::NONE: + set_none(other.none_); + break; + case DriveType::CONSTANT: + *this = other.constant_; + break; + case DriveType::WIRE: + *this = other.wire_; + break; + case DriveType::PORT: + *this = other.port_; + break; + case DriveType::MARKER: + *this = other.marker_; + break; + case DriveType::MULTIPLE: + *this = other.multiple_; + break; + } + return *this; + } + + DriveChunk &operator=(DriveChunk &&other) + { + switch (other.type_) + { + case DriveType::NONE: + set_none(other.none_); + break; + case DriveType::CONSTANT: + *this = std::move(other.constant_); + break; + case DriveType::WIRE: + *this = std::move(other.wire_); + break; + case DriveType::PORT: + *this = std::move(other.port_); + break; + case DriveType::MARKER: + *this = std::move(other.marker_); + break; + case DriveType::MULTIPLE: + *this = std::move(other.multiple_); + break; + } + return *this; + } + + DriveChunk &operator=(Const const &constant) + { + set_none(); + new (&constant_) Const(constant); + type_ = DriveType::CONSTANT; + return *this; + } + + DriveChunk &operator=(Const &&constant) + { + set_none(); + new (&constant_) Const(std::move(constant)); + type_ = DriveType::CONSTANT; + return *this; + } + + DriveChunk &operator=(DriveChunkWire const &wire) + { + set_none(); + new (&wire_) DriveChunkWire(wire); + type_ = DriveType::WIRE; + return *this; + } + + DriveChunk &operator=(DriveChunkWire &&wire) + { + set_none(); + new (&wire_) DriveChunkWire(wire); + type_ = DriveType::WIRE; + return *this; + } + + DriveChunk &operator=(DriveChunkPort const &port) + { + set_none(); + new (&port_) DriveChunkPort(port); + type_ = DriveType::PORT; + return *this; + } + + DriveChunk &operator=(DriveChunkPort &&port) + { + set_none(); + new (&port_) DriveChunkPort(port); + type_ = DriveType::PORT; + return *this; + } + + DriveChunk &operator=(DriveChunkMarker const &marker) + { + set_none(); + new (&marker_) DriveChunkMarker(marker); + type_ = DriveType::MARKER; + return *this; + } + + DriveChunk &operator=(DriveChunkMarker &&marker) + { + set_none(); + new (&marker_) DriveChunkMarker(marker); + type_ = DriveType::MARKER; + return *this; + } + + DriveChunk &operator=(DriveChunkMultiple const &multiple) + { + set_none(multiple.size()); + if (multiple.multiple().empty()) + return *this; + new (&multiple_) DriveChunkMultiple(multiple); + type_ = DriveType::MULTIPLE; + return *this; + } + + DriveChunk &operator=(DriveChunkMultiple &&multiple) + { + set_none(multiple.size()); + if (multiple.multiple().empty()) + return *this; + new (&multiple_) DriveChunkMultiple(multiple); + type_ = DriveType::MULTIPLE; + return *this; + } + + DriveChunk &operator=(DriveBit const &other) + { + switch (other.type()) + { + case DriveType::NONE: + set_none(1); + break; + case DriveType::CONSTANT: + *this = Const(other.constant()); + break; + case DriveType::WIRE: + *this = DriveChunkWire(other.wire()); + break; + case DriveType::PORT: + *this = DriveChunkPort(other.port()); + break; + case DriveType::MARKER: + *this = DriveChunkMarker(other.marker()); + break; + case DriveType::MULTIPLE: + *this = DriveChunkMultiple(other.multiple()); + break; + } + return *this; + } + + bool can_append(DriveBit const &bit) const; + bool try_append(DriveBit const &bit); + bool try_append(DriveChunk const &chunk); + + unsigned int hash() const + { + unsigned int inner; + switch (type_) + { + case DriveType::NONE: + inner = 0; + break; + case DriveType::CONSTANT: + inner = constant_.hash(); + break; + case DriveType::WIRE: + inner = wire_.hash(); + break; + case DriveType::PORT: + inner = port_.hash(); + break; + case DriveType::MARKER: + inner = marker_.hash(); + break; + case DriveType::MULTIPLE: + inner = multiple_.hash(); + break; + } + return mkhash((unsigned int)type_, inner); + } + + bool operator==(const DriveChunk &other) const + { + if (type_ != other.type_) + return false; + + switch (type_) + { + case DriveType::NONE: + return true; + case DriveType::CONSTANT: + return constant_ == other.constant_; + case DriveType::WIRE: + return wire_ == other.wire_; + case DriveType::PORT: + return port_ == other.port_; + case DriveType::MARKER: + return marker_ == other.marker_; + case DriveType::MULTIPLE: + return multiple_ == other.multiple_; + } + log_assert(false); + } + + bool operator!=(const DriveChunk &other) const + { + return !(*this == other); + } + + bool operator<(const DriveChunk &other) const + { + if (type_ != other.type_) + return type_ < other.type_; + switch (type_) + { + case DriveType::NONE: + return false; + case DriveType::CONSTANT: + return constant_ < other.constant_; + case DriveType::WIRE: + return wire_ < other.wire_; + case DriveType::PORT: + return port_ < other.port_; + case DriveType::MARKER: + return marker_ < other.marker_; + case DriveType::MULTIPLE: + return multiple_ < other.multiple_; + } + log_assert(false); + } + + DriveType type() const { return type_; } + + bool is_none() const { return type_ == DriveType::NONE; } + bool is_constant() const { return type_ == DriveType::CONSTANT; } + bool is_wire() const { return type_ == DriveType::WIRE; } + bool is_port() const { return type_ == DriveType::PORT; } + bool is_marker() const { return type_ == DriveType::MARKER; } + bool is_multiple() const { return type_ == DriveType::MULTIPLE; } + + Const &constant() { log_assert(is_constant()); return constant_; } + Const const &constant() const { log_assert(is_constant()); return constant_; } + DriveChunkWire &wire() { log_assert(is_wire()); return wire_; } + DriveChunkWire const &wire() const { log_assert(is_wire()); return wire_; } + DriveChunkPort &port() { log_assert(is_port()); return port_; } + DriveChunkPort const &port() const { log_assert(is_port()); return port_; } + DriveChunkMarker &marker() { log_assert(is_marker()); return marker_; } + DriveChunkMarker const &marker() const { log_assert(is_marker()); return marker_; } + DriveChunkMultiple &multiple() { log_assert(is_multiple()); return multiple_; } + DriveChunkMultiple const &multiple() const { log_assert(is_multiple()); return multiple_; } + + + int size() const + { + switch (type_) + { + case DriveType::NONE: + return none_; + case DriveType::CONSTANT: + return constant_.size(); + case DriveType::WIRE: + return wire_.size(); + case DriveType::PORT: + return port_.size(); + case DriveType::MARKER: + return marker_.size(); + case DriveType::MULTIPLE: + return multiple_.size(); + } + } +}; + +struct DriveSpec +{ +private: + int width_ = 0; + mutable std::vector chunks_; + mutable std::vector bits_; + mutable unsigned int hash_ = 0; +public: + + inline bool packed() const { + return bits_.empty(); + } + + DriveSpec() {} + + DriveSpec(DriveChunk const &chunk) { *this = chunk; } + DriveSpec(DriveChunkWire const &chunk) { *this = chunk; } + DriveSpec(DriveChunkPort const &chunk) { *this = chunk; } + DriveSpec(DriveChunkMarker const &chunk) { *this = chunk; } + DriveSpec(DriveChunkMultiple const &chunk) { *this = chunk; } + + DriveSpec(DriveBit const &bit) { *this = bit; } + DriveSpec(DriveBitWire const &bit) { *this = bit; } + DriveSpec(DriveBitPort const &bit) { *this = bit; } + DriveSpec(DriveBitMarker const &bit) { *this = bit; } + DriveSpec(DriveBitMultiple const &bit) { *this = bit; } + + DriveSpec(std::vector const &chunks) : chunks_(chunks) { compute_width(); } + + DriveSpec(std::vector const &bits) + { + for (auto const &bit : bits) + append(bit); + } + + std::vector const &chunks() const { pack(); return chunks_; } + std::vector const &bits() const { unpack(); return bits_; } + + int size() const { return width_; } + + void append(DriveBit const &bit); + + void append(DriveChunk const &chunk); + + void pack() const; + + void unpack() const; + + DriveBit &operator[](int index) + { + log_assert(index >= 0 && index < size()); + unpack(); + return bits_[index]; + } + + const DriveBit &operator[](int index) const + { + log_assert(index >= 0 && index < size()); + unpack(); + return bits_[index]; + } + + void clear() + { + chunks_.clear(); + bits_.clear(); + width_ = 0; + } + + DriveSpec &operator=(DriveChunk const &chunk) + { + chunks_.clear(); + bits_.clear(); + append(chunk); + return *this; + } + + DriveSpec &operator=(DriveChunkWire const &chunk) { return *this = DriveChunk(chunk); } + DriveSpec &operator=(DriveChunkPort const &chunk) { return *this = DriveChunk(chunk); } + DriveSpec &operator=(DriveChunkMarker const &chunk) { return *this = DriveChunk(chunk); } + DriveSpec &operator=(DriveChunkMultiple const &chunk) { return *this = DriveChunk(chunk); } + + DriveSpec &operator=(DriveBit const &bit) + { + chunks_.clear(); + bits_.clear(); + append(bit); + return *this; + } + + DriveSpec &operator=(DriveBitWire const &bit) { return *this = DriveBit(bit); } + DriveSpec &operator=(DriveBitPort const &bit) { return *this = DriveBit(bit); } + DriveSpec &operator=(DriveBitMarker const &bit) { return *this = DriveBit(bit); } + DriveSpec &operator=(DriveBitMultiple const &bit) { return *this = DriveBit(bit); } + + unsigned int hash() const { + if (hash_ != 0) return hash_; + + pack(); + hash_ = hash_ops>().hash(chunks_); + hash_ |= (hash_ == 0); + return hash_; + } + + bool operator==(DriveSpec const &other) const { + if (size() != other.size() || hash() != other.hash()) + return false; + return chunks() == other.chunks(); + } + +private: + void compute_width(); +}; + + + +struct DriverMap +{ + CellTypes celltypes; + + DriverMap() { celltypes.setup(); } + DriverMap(Design *design) { celltypes.setup(); celltypes.setup_design(design); } + +private: + + // Internally we represent all DriveBits by mapping them to DriveBitIds + // which use less memory and are cheaper to compare. + struct DriveBitId + { + int id = -1; + + DriveBitId() {}; + + DriveBitId(int id) : id(id) { } + + bool operator==(const DriveBitId &other) const { return id == other.id; } + bool operator<(const DriveBitId &other) const { return id < other.id; } + unsigned int hash() const { return id; } + }; + // Essentially a dict> but using less memory + // and fewer allocations + struct DriveBitGraph { + dict first_edges; + dict second_edges; + dict> more_edges; + + void add_edge(DriveBitId src, DriveBitId dst); + DriveBitId pop_edge(DriveBitId src); + void clear(DriveBitId src); + bool contains(DriveBitId src); + int count(DriveBitId src); + + DriveBitId at(DriveBitId src, int index); + }; + + // The following two maps maintain a sparse DriveBit to DriveBitId mapping. + // This saves a lot of memory compared to a `dict` or + // `idict`. + + // Maps wires to the first DriveBitId of the consecutive range used for + // that wire. + dict wire_offsets; + + // Maps cell ports to a the first DriveBitId of the consecutive range used + // for that cell port. + dict, DriveBitId> port_offsets; + + // For the inverse map that maps DriveBitIds back to DriveBits we use a + // sorted map containing only the first DriveBit for each wire and cell + // port. + std::map drive_bits; + + // As a memory optimization for gate level net lists we store single-bit + // wires and cell ports in a `dict` which requires less memory and fewer + // allocations than `std::map` but doesn't support the kind of lookups we + // need for a sparse coarse grained mapping. + dict isolated_drive_bits; + + // Used for allocating DriveBitIds, none and constant states use a fixewd + // mapping to the first few ids, which we need to skip. + int next_offset = 1 + (int)State::Sm; + + // Union-Find over directly connected bits that share the same single + // driver or are undriven. We never merge connections between drivers + // and/or kept wires. + mfp same_driver; + + // For each bit, store a set of connected driver bits for which the + // explicit connection should be preserved and the driving direction is + // locally unambiguous (one side only drives or requires a driven value). + DriveBitGraph connected_drivers; + + // For each bit, store a set of connected driver bits for which the + // explicit connection should be preserved and the driving direction is + // locally ambiguous. Every such ambiguous connection is also present in + // the reverse direction and has to be resolved when querying drivers. + DriveBitGraph connected_undirected; + + // Subset of `connected_undirected` for caching the resolved driving + // direction. In case multiple drivers are present this can still contain + // both orientations of a single connection, but for a single driver only + // one will be present. + DriveBitGraph connected_oriented; + + // Stores for which bits we already resolved the orientation (cached in + // `connected_oriented`). + pool oriented_present; + + + enum class BitMode { + NONE = 0, // Not driven, no need to keep wire + DRIVEN = 1, // Not driven, uses a value driven elsewhere + DRIVEN_UNIQUE = 2, // Uses a value driven elsewhere, has at most one direct connection + KEEP = 3, // Wire that should be kept + TRISTATE = 4, // Can drive a value but can also use a value driven elsewhere + DRIVER = 5, // Drives a value + }; + + BitMode bit_mode(DriveBit const &bit); + DriveBitId id_from_drive_bit(DriveBit const &bit); + DriveBit drive_bit_from_id(DriveBitId id); + + void connect_directed_merge(DriveBitId driven_id, DriveBitId driver_id); + void connect_directed_buffer(DriveBitId driven_id, DriveBitId driver_id); + void connect_undirected(DriveBitId a_id, DriveBitId b_id); + +public: + + void add(Module *module); + + // Add a single bit connection to the driver map. + void add(DriveBit const &a, DriveBit const &b); + + template + static constexpr bool is_sig_type() { + return + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value; + } + + // We use the enable_if to produce better compiler errors when unsupported + // types are used + template + typename std::enable_if() && is_sig_type()>::type + add(T const &a, U const &b) + { + log_assert(a.size() == b.size()); + for (int i = 0; i != GetSize(a); ++i) + add(DriveBit(a[i]), DriveBit(b[i])); + } + + + // Specialized version that avoids unpacking + void add(SigSpec const &a, SigSpec const &b); + +private: + void add_port(Cell *cell, IdString const &port, SigSpec const &b); + + // Only used a local variables in `orient_undirected`, always cleared, only + // stored to reduce allocations. + pool orient_undirected_seen; + pool orient_undirected_drivers; + dict orient_undirected_distance; + + void orient_undirected(DriveBitId id); + +public: + DriveBit operator()(DriveBit const &bit); + + DriveSpec operator()(DriveSpec spec); + +private: + bool keep_wire(Wire *wire) { + // TODO configurable + return wire->has_attribute(ID(keep)); + } +}; + +YOSYS_NAMESPACE_END + +#endif From 0460a1693302ac9f2741c87a047a0acda5d85ebd Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Mon, 15 Apr 2024 14:14:50 +0200 Subject: [PATCH 05/51] WIP temporary drivertools example --- passes/cmds/Makefile.inc | 1 + passes/cmds/example_dt.cc | 140 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 passes/cmds/example_dt.cc diff --git a/passes/cmds/Makefile.inc b/passes/cmds/Makefile.inc index d7e572462b0..caea266c397 100644 --- a/passes/cmds/Makefile.inc +++ b/passes/cmds/Makefile.inc @@ -48,3 +48,4 @@ OBJS += passes/cmds/clean_zerowidth.o OBJS += passes/cmds/xprop.o OBJS += passes/cmds/dft_tag.o OBJS += passes/cmds/future.o +OBJS += passes/cmds/example_dt.o diff --git a/passes/cmds/example_dt.cc b/passes/cmds/example_dt.cc new file mode 100644 index 00000000000..de84fa3cda8 --- /dev/null +++ b/passes/cmds/example_dt.cc @@ -0,0 +1,140 @@ +#include "kernel/yosys.h" +#include "kernel/drivertools.h" +#include "kernel/topo_scc.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + + + + +struct ExampleWorker +{ + DriverMap dm; + Module *module; + + ExampleWorker(Module *module) : module(module) { + dm.celltypes.setup(); + } +}; + +struct ExampleDtPass : public Pass +{ + ExampleDtPass() : Pass("example_dt", "drivertools example") {} + + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + } + + + void execute(std::vector args, RTLIL::Design *design) override + { + size_t argidx = 1; + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) { + ExampleWorker worker(module); + DriverMap dm; + + dm.add(module); + + idict queue; + idict cells; + + IntGraph edges; + + + for (auto cell : module->cells()) { + if (cell->type.in(ID($assert), ID($assume), ID($cover), ID($check))) + queue(DriveBitMarker(cells(cell), 0)); + } + + for (auto wire : module->wires()) { + if (!wire->port_output) + continue; + queue(DriveChunk(DriveChunkWire(wire, 0, wire->width))); + } + +#define emit log +// #define emit(X...) do {} while (false) + + for (int i = 0; i != GetSize(queue); ++i) + { + emit("n%d: ", i); + DriveSpec spec = queue[i]; + if (spec.chunks().size() > 1) { + emit("concat %s <-\n", log_signal(spec)); + for (auto const &chunk : spec.chunks()) { + emit(" * %s\n", log_signal(chunk)); + edges.add_edge(i, queue(chunk)); + } + } else if (spec.chunks().size() == 1) { + DriveChunk chunk = spec.chunks()[0]; + if (chunk.is_wire()) { + DriveChunkWire wire_chunk = chunk.wire(); + if (wire_chunk.is_whole()) { + if (wire_chunk.wire->port_input) { + emit("input %s\n", log_signal(spec)); + } else { + DriveSpec driver = dm(DriveSpec(wire_chunk)); + edges.add_edge(i, queue(driver)); + emit("wire driver %s <- %s\n", log_signal(spec), log_signal(driver)); + } + } else { + DriveChunkWire whole_wire(wire_chunk.wire, 0, wire_chunk.width); + edges.add_edge(i, queue(whole_wire)); + emit("wire slice %s <- %s\n", log_signal(spec), log_signal(DriveSpec(whole_wire))); + } + } else if (chunk.is_port()) { + DriveChunkPort port_chunk = chunk.port(); + if (port_chunk.is_whole()) { + if (dm.celltypes.cell_output(port_chunk.cell->type, port_chunk.port)) { + int cell_marker = queue(DriveBitMarker(cells(port_chunk.cell), 0)); + if (!port_chunk.cell->type.in(ID($dff), ID($ff))) + edges.add_edge(i, cell_marker); + emit("cell output %s %s\n", log_id(port_chunk.cell), log_id(port_chunk.port)); + } else { + DriveSpec driver = dm(DriveSpec(port_chunk)); + edges.add_edge(i, queue(driver)); + emit("cell port driver %s <- %s\n", log_signal(spec), log_signal(driver)); + } + + } else { + DriveChunkPort whole_port(port_chunk.cell, port_chunk.port, 0, GetSize(port_chunk.cell->connections().at(port_chunk.port))); + edges.add_edge(i, queue(whole_port)); + emit("port slice %s <- %s\n", log_signal(spec), log_signal(DriveSpec(whole_port))); + } + } else if (chunk.is_constant()) { + emit("constant %s <- %s\n", log_signal(spec), log_const(chunk.constant())); + } else if (chunk.is_marker()) { + Cell *cell = cells[chunk.marker().marker]; + emit("cell %s %s\n", log_id(cell->type), log_id(cell)); + for (auto const &conn : cell->connections()) { + if (!dm.celltypes.cell_input(cell->type, conn.first)) + continue; + emit(" * %s <- %s\n", log_id(conn.first), log_signal(conn.second)); + edges.add_edge(i, queue(DriveChunkPort(cell, conn))); + } + } else { + log_abort(); + } + } else { + log_abort(); + } + } + + topo_sorted_sccs(edges, [&](int *begin, int *end) { + emit("scc:"); + for (int *i = begin; i != end; ++i) + emit(" n%d", *i); + emit("\n"); + }); + + } + log("Plugin test passed!\n"); + } +} ExampleDtPass; + +PRIVATE_NAMESPACE_END From 2971cf384a9b90ddbf5f3ad38bf2842a45fb7f58 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Thu, 11 Apr 2024 13:47:14 +0200 Subject: [PATCH 06/51] topo_scc: Add sources_first option --- kernel/topo_scc.h | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/kernel/topo_scc.h b/kernel/topo_scc.h index 0ae0e696b47..89df8928aa2 100644 --- a/kernel/topo_scc.h +++ b/kernel/topo_scc.h @@ -194,7 +194,7 @@ class IntGraph { }; template -void topo_sorted_sccs(G &graph, ComponentCallback component) +void topo_sorted_sccs(G &graph, ComponentCallback component, bool sources_first = false) { typedef typename G::node_enumerator node_enumerator; typedef typename G::successor_enumerator successor_enumerator; @@ -217,6 +217,23 @@ void topo_sorted_sccs(G &graph, ComponentCallback component) node_enumerator nodes = graph.enumerate_nodes(); + if (sources_first) { + while (!nodes.finished()) { + node_type node = nodes.next(); + successor_enumerator successors = graph.enumerate_successors(node); + if (successors.finished()) + { + graph.dfs_index(node) = next_index; + next_index++; + component_stack.push_back(node); + component(component_stack.data(), component_stack.data() + 1); + component_stack.clear(); + graph.dfs_index(node) = INT_MAX; + } + } + nodes = graph.enumerate_nodes(); + } + // iterate over all nodes to ensure we process the whole graph while (!nodes.finished()) { node_type node = nodes.next(); From b21d9d296bf10b6c9e2028197231abe00ee316d5 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Thu, 11 Apr 2024 13:48:25 +0200 Subject: [PATCH 07/51] ComputeGraph datatype for the upcoming functional backend --- kernel/functional.h | 369 ++++++++++++++++++++++++++++++++++++++ passes/cmds/example_dt.cc | 178 ++++++++++++++---- 2 files changed, 515 insertions(+), 32 deletions(-) create mode 100644 kernel/functional.h diff --git a/kernel/functional.h b/kernel/functional.h new file mode 100644 index 00000000000..e5ee8824099 --- /dev/null +++ b/kernel/functional.h @@ -0,0 +1,369 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2024 Jannis Harder + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#ifndef FUNCTIONAL_H +#define FUNCTIONAL_H + +#include +#include "kernel/yosys.h" + +YOSYS_NAMESPACE_BEGIN + +template< + typename Fn, // Function type (deduplicated across whole graph) + typename Attr = std::tuple<>, // Call attributes (present in every node) + typename SparseAttr = std::tuple<>, // Sparse call attributes (optional per node) + typename Key = std::tuple<> // Stable keys to refer to nodes +> +struct ComputeGraph +{ + struct Ref; +private: + + // Functions are deduplicated by assigning unique ids + idict functions; + + struct Node { + int fn_index; + int arg_offset; + int arg_count; + Attr attr; + + Node(int fn_index, Attr &&attr, int arg_offset, int arg_count = 0) + : fn_index(fn_index), arg_offset(arg_offset), arg_count(arg_count), attr(std::move(attr)) {} + + Node(int fn_index, Attr const &attr, int arg_offset, int arg_count = 0) + : fn_index(fn_index), arg_offset(arg_offset), arg_count(arg_count), attr(attr) {} + }; + + + std::vector nodes; + std::vector args; + dict keys_; + dict sparse_attrs; + +public: + template + struct BaseRef + { + protected: + friend struct ComputeGraph; + Graph *graph_; + int index_; + BaseRef(Graph *graph, int index) : graph_(graph), index_(index) { + log_assert(index_ >= 0); + check(); + } + + void check() const { log_assert(index_ < graph_->size()); } + + Node const &deref() const { check(); return graph_->nodes[index_]; } + + public: + ComputeGraph const &graph() const { return graph_; } + int index() const { return index_; } + + int size() const { return deref().arg_count; } + + BaseRef arg(int n) const + { + Node const &node = deref(); + log_assert(n >= 0 && n < node.arg_count); + return BaseRef(graph_, graph_->args[node.arg_offset + n]); + } + + std::vector::const_iterator arg_indices_cbegin() const + { + Node const &node = deref(); + return graph_->args.cbegin() + node.arg_offset; + } + + std::vector::const_iterator arg_indices_cend() const + { + Node const &node = deref(); + return graph_->args.cbegin() + node.arg_offset + node.arg_count; + } + + Fn const &function() const { return graph_->functions[deref().fn_index]; } + Attr const &attr() const { return deref().attr; } + + bool has_sparse_attr() const { return graph_->sparse_attrs.count(index_); } + + SparseAttr const &sparse_attr() const + { + auto found = graph_->sparse_attrs.find(index_); + log_assert(found != graph_->sparse_attrs.end()); + return *found; + } + }; + + using ConstRef = BaseRef; + + struct Ref : public BaseRef + { + private: + friend struct ComputeGraph; + Ref(ComputeGraph *graph, int index) : BaseRef(graph, index) {} + Node &deref() const { this->check(); return this->graph_->nodes[this->index_]; } + + public: + void set_function(Fn const &function) const + { + deref().fn_index = this->graph_->functions(function); + } + + Attr &attr() const { return deref().attr; } + + void append_arg(ConstRef arg) const + { + log_assert(arg.graph_ == this->graph_); + append_arg(arg.index()); + } + + void append_arg(int arg) const + { + log_assert(arg >= 0 && arg < this->graph_->size()); + Node &node = deref(); + if (node.arg_offset + node.arg_count != GetSize(this->graph_->args)) + move_args(node); + this->graph_->args.push_back(arg); + node.arg_count++; + } + + operator ConstRef() const + { + return ConstRef(this->graph_, this->index_); + } + + SparseAttr &sparse_attr() const + { + return this->graph_->sparse_attrs[this->index_]; + } + + void clear_sparse_attr() const + { + this->graph_->sparse_attrs.erase(this->index_); + } + + void assign_key(Key const &key) const + { + this->graph_->keys_.emplace(key, this->index_); + } + + private: + void move_args(Node &node) const + { + auto &args = this->graph_->args; + int old_offset = node.arg_offset; + node.arg_offset = GetSize(args); + for (int i = 0; i != node.arg_count; ++i) + args.push_back(args[old_offset + i]); + } + + }; + + bool has_key(Key const &key) const + { + return keys_.count(key); + } + + dict const &keys() const + { + return keys_; + } + + ConstRef operator()(Key const &key) const + { + auto it = keys_.find(key); + log_assert(it != keys_.end()); + return (*this)[it->second]; + } + + Ref operator()(Key const &key) + { + auto it = keys_.find(key); + log_assert(it != keys_.end()); + return (*this)[it->second]; + } + + int size() const { return GetSize(nodes); } + + ConstRef operator[](int index) const { return ConstRef(this, index); } + Ref operator[](int index) { return Ref(this, index); } + + Ref add(Fn const &function, Attr &&attr) + { + int index = GetSize(nodes); + int fn_index = functions(function); + nodes.emplace_back(fn_index, std::move(attr), GetSize(args)); + return Ref(this, index); + } + + Ref add(Fn const &function, Attr const &attr) + { + int index = GetSize(nodes); + int fn_index = functions(function); + nodes.emplace_back(fn_index, attr, GetSize(args)); + return Ref(this, index); + } + + template + Ref add(Fn const &function, Attr const &attr, T const &args) + { + Ref added = add(function, attr); + for (auto arg : args) + added.append_arg(arg); + return added; + } + + template + Ref add(Fn const &function, Attr &&attr, T const &args) + { + Ref added = add(function, std::move(attr)); + for (auto arg : args) + added.append_arg(arg); + return added; + } + + template + Ref add(Fn const &function, Attr const &attr, T begin, T end) + { + Ref added = add(function, attr); + for (; begin != end; ++begin) + added.append_arg(*begin); + return added; + } + + void permute(std::vector const &perm) + { + log_assert(perm.size() <= nodes.size()); + std::vector inv_perm; + inv_perm.resize(nodes.size(), -1); + for (int i = 0; i < GetSize(perm); ++i) + { + int j = perm[i]; + log_assert(j >= 0 && j < GetSize(perm)); + log_assert(inv_perm[j] == -1); + inv_perm[j] = i; + } + permute(perm, inv_perm); + } + + void permute(std::vector const &perm, std::vector const &inv_perm) + { + log_assert(inv_perm.size() == nodes.size()); + std::vector new_nodes; + new_nodes.reserve(perm.size()); + dict new_sparse_attrs; + for (int i : perm) + { + int j = GetSize(new_nodes); + new_nodes.emplace_back(std::move(nodes[i])); + auto found = sparse_attrs.find(i); + if (found != sparse_attrs.end()) + new_sparse_attrs.emplace(j, std::move(found->second)); + } + + std::swap(nodes, new_nodes); + std::swap(sparse_attrs, new_sparse_attrs); + + for (int &arg : args) + { + log_assert(arg < GetSize(inv_perm)); + arg = inv_perm[arg]; + } + + for (auto &key : keys_) + { + log_assert(key.second < GetSize(inv_perm)); + key.second = inv_perm[key.second]; + } + } + + struct SccAdaptor + { + private: + ComputeGraph const &graph_; + std::vector indices_; + public: + SccAdaptor(ComputeGraph const &graph) : graph_(graph) + { + indices_.resize(graph.size(), -1); + } + + + typedef int node_type; + + struct node_enumerator { + private: + friend struct SccAdaptor; + int current, end; + node_enumerator(int current, int end) : current(current), end(end) {} + + public: + + bool finished() const { return current == end; } + node_type next() { + log_assert(!finished()); + node_type result = current; + ++current; + return result; + } + }; + + node_enumerator enumerate_nodes() { + return node_enumerator(0, GetSize(indices_)); + } + + + struct successor_enumerator { + private: + friend struct SccAdaptor; + std::vector::const_iterator current, end; + successor_enumerator(std::vector::const_iterator current, std::vector::const_iterator end) : + current(current), end(end) {} + + public: + bool finished() const { return current == end; } + node_type next() { + log_assert(!finished()); + node_type result = *current; + ++current; + return result; + } + }; + + successor_enumerator enumerate_successors(int index) const { + auto const &ref = graph_[index]; + return successor_enumerator(ref.arg_indices_cbegin(), ref.arg_indices_cend()); + } + + int &dfs_index(node_type const &node) { return indices_[node]; } + + std::vector const &dfs_indices() { return indices_; } + }; + +}; + + + +YOSYS_NAMESPACE_END + + +#endif diff --git a/passes/cmds/example_dt.cc b/passes/cmds/example_dt.cc index de84fa3cda8..dec554d6c71 100644 --- a/passes/cmds/example_dt.cc +++ b/passes/cmds/example_dt.cc @@ -1,6 +1,7 @@ #include "kernel/yosys.h" #include "kernel/drivertools.h" #include "kernel/topo_scc.h" +#include "kernel/functional.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -38,86 +39,137 @@ struct ExampleDtPass : public Pass ExampleWorker worker(module); DriverMap dm; + struct ExampleFn { + IdString name; + dict parameters; + + ExampleFn(IdString name) : name(name) {} + ExampleFn(IdString name, dict parameters) : name(name), parameters(parameters) {} + + bool operator==(ExampleFn const &other) const { + return name == other.name && parameters == other.parameters; + } + + unsigned int hash() const { + return mkhash(name.hash(), parameters.hash()); + } + }; + + typedef ComputeGraph ExampleGraph; + + ExampleGraph compute_graph; + + dm.add(module); idict queue; idict cells; IntGraph edges; + std::vector graph_nodes; + auto enqueue = [&](DriveSpec const &spec) { + int index = queue(spec); + if (index == GetSize(graph_nodes)) + graph_nodes.emplace_back(compute_graph.add(ID($pending), index).index()); + //if (index >= GetSize(graph_nodes)) + return compute_graph[graph_nodes[index]]; + }; for (auto cell : module->cells()) { if (cell->type.in(ID($assert), ID($assume), ID($cover), ID($check))) - queue(DriveBitMarker(cells(cell), 0)); + enqueue(DriveBitMarker(cells(cell), 0)); } for (auto wire : module->wires()) { if (!wire->port_output) continue; - queue(DriveChunk(DriveChunkWire(wire, 0, wire->width))); + enqueue(DriveChunk(DriveChunkWire(wire, 0, wire->width))).assign_key(wire->name); } -#define emit log -// #define emit(X...) do {} while (false) - for (int i = 0; i != GetSize(queue); ++i) { - emit("n%d: ", i); DriveSpec spec = queue[i]; + ExampleGraph::Ref node = compute_graph[i]; + if (spec.chunks().size() > 1) { - emit("concat %s <-\n", log_signal(spec)); + node.set_function(ID($$concat)); + for (auto const &chunk : spec.chunks()) { - emit(" * %s\n", log_signal(chunk)); - edges.add_edge(i, queue(chunk)); + node.append_arg(enqueue(chunk)); } } else if (spec.chunks().size() == 1) { DriveChunk chunk = spec.chunks()[0]; if (chunk.is_wire()) { DriveChunkWire wire_chunk = chunk.wire(); if (wire_chunk.is_whole()) { + node.sparse_attr() = wire_chunk.wire->name; if (wire_chunk.wire->port_input) { - emit("input %s\n", log_signal(spec)); + node.set_function(ExampleFn(ID($$input), {{wire_chunk.wire->name, {}}})); } else { DriveSpec driver = dm(DriveSpec(wire_chunk)); - edges.add_edge(i, queue(driver)); - emit("wire driver %s <- %s\n", log_signal(spec), log_signal(driver)); + node.set_function(ID($$buf)); + + node.append_arg(enqueue(driver)); } } else { DriveChunkWire whole_wire(wire_chunk.wire, 0, wire_chunk.width); - edges.add_edge(i, queue(whole_wire)); - emit("wire slice %s <- %s\n", log_signal(spec), log_signal(DriveSpec(whole_wire))); + node.set_function(ExampleFn(ID($$slice), {{ID(offset), wire_chunk.offset}, {ID(width), wire_chunk.width}})); + node.append_arg(enqueue(whole_wire)); } } else if (chunk.is_port()) { DriveChunkPort port_chunk = chunk.port(); if (port_chunk.is_whole()) { if (dm.celltypes.cell_output(port_chunk.cell->type, port_chunk.port)) { - int cell_marker = queue(DriveBitMarker(cells(port_chunk.cell), 0)); - if (!port_chunk.cell->type.in(ID($dff), ID($ff))) - edges.add_edge(i, cell_marker); - emit("cell output %s %s\n", log_id(port_chunk.cell), log_id(port_chunk.port)); + if (port_chunk.cell->type.in(ID($dff), ID($ff))) + { + Cell *cell = port_chunk.cell; + node.set_function(ExampleFn(ID($$state), {{cell->name, {}}})); + for (auto const &conn : cell->connections()) { + if (!dm.celltypes.cell_input(cell->type, conn.first)) + continue; + enqueue(DriveChunkPort(cell, conn)).assign_key(cell->name); + } + } + else + { + node.set_function(ExampleFn(ID($$cell_output), {{port_chunk.port, {}}})); + node.append_arg(enqueue(DriveBitMarker(cells(port_chunk.cell), 0))); + } } else { + node.set_function(ID($$buf)); + DriveSpec driver = dm(DriveSpec(port_chunk)); - edges.add_edge(i, queue(driver)); - emit("cell port driver %s <- %s\n", log_signal(spec), log_signal(driver)); + node.append_arg(enqueue(driver)); } } else { DriveChunkPort whole_port(port_chunk.cell, port_chunk.port, 0, GetSize(port_chunk.cell->connections().at(port_chunk.port))); - edges.add_edge(i, queue(whole_port)); - emit("port slice %s <- %s\n", log_signal(spec), log_signal(DriveSpec(whole_port))); + node.set_function(ID($$buf)); + node.append_arg(enqueue(whole_port)); } } else if (chunk.is_constant()) { - emit("constant %s <- %s\n", log_signal(spec), log_const(chunk.constant())); + node.set_function(ExampleFn(ID($$const), {{ID(value), chunk.constant()}})); + + } else if (chunk.is_multiple()) { + node.set_function(ID($$multi)); + for (auto const &driver : chunk.multiple().multiple()) + node.append_arg(enqueue(driver)); } else if (chunk.is_marker()) { Cell *cell = cells[chunk.marker().marker]; - emit("cell %s %s\n", log_id(cell->type), log_id(cell)); + + node.set_function(ExampleFn(cell->type, cell->parameters)); for (auto const &conn : cell->connections()) { if (!dm.celltypes.cell_input(cell->type, conn.first)) continue; - emit(" * %s <- %s\n", log_id(conn.first), log_signal(conn.second)); - edges.add_edge(i, queue(DriveChunkPort(cell, conn))); + + node.append_arg(enqueue(DriveChunkPort(cell, conn))); } + } else if (chunk.is_none()) { + node.set_function(ID($$undriven)); + } else { + log_error("unhandled drivespec: %s\n", log_signal(chunk)); log_abort(); } } else { @@ -125,13 +177,75 @@ struct ExampleDtPass : public Pass } } - topo_sorted_sccs(edges, [&](int *begin, int *end) { - emit("scc:"); - for (int *i = begin; i != end; ++i) - emit(" n%d", *i); - emit("\n"); - }); + // Perform topo sort and detect SCCs + ExampleGraph::SccAdaptor compute_graph_scc(compute_graph); + + + std::vector perm; + topo_sorted_sccs(compute_graph_scc, [&](int *begin, int *end) { + perm.insert(perm.end(), begin, end); + if (end > begin + 1) + { + log_warning("SCC:"); + for (int *i = begin; i != end; ++i) + log(" %d", *i); + log("\n"); + } + }, /* sources_first */ true); + compute_graph.permute(perm); + + + // Forward $$buf unless we have a name in the sparse attribute + std::vector alias; + perm.clear(); + + for (int i = 0; i < compute_graph.size(); ++i) + { + if (compute_graph[i].function().name == ID($$buf) && !compute_graph[i].has_sparse_attr() && compute_graph[i].arg(0).index() < i) + { + + alias.push_back(alias[compute_graph[i].arg(0).index()]); + } + else + { + alias.push_back(GetSize(perm)); + perm.push_back(i); + } + } + compute_graph.permute(perm, alias); + + // Dump the compute graph + for (int i = 0; i < compute_graph.size(); ++i) + { + auto ref = compute_graph[i]; + log("n%d ", i); + log("%s", log_id(ref.function().name)); + for (auto const ¶m : ref.function().parameters) + { + if (param.second.empty()) + log("[%s]", log_id(param.first)); + else + log("[%s=%s]", log_id(param.first), log_const(param.second)); + } + log("("); + + for (int i = 0, end = ref.size(); i != end; ++i) + { + if (i > 0) + log(", "); + log("n%d", ref.arg(i).index()); + } + log(")\n"); + if (ref.has_sparse_attr()) + log("// wire %s\n", log_id(ref.sparse_attr())); + log("// was #%d %s\n", ref.attr(), log_signal(queue[ref.attr()])); + } + + for (auto const &key : compute_graph.keys()) + { + log("return %d as %s \n", key.second, log_id(key.first)); + } } log("Plugin test passed!\n"); } From 07907ad5a5e8c97a119dd528d1ffe1d0188d00de Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Wed, 17 Apr 2024 14:52:36 +0200 Subject: [PATCH 08/51] fixup! drivertools: Utility code for indexing and traversing signal drivers --- kernel/drivertools.cc | 23 +++++++++++++---------- kernel/drivertools.h | 1 + 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/kernel/drivertools.cc b/kernel/drivertools.cc index 499a9399c46..286c913a246 100644 --- a/kernel/drivertools.cc +++ b/kernel/drivertools.cc @@ -499,7 +499,7 @@ int DriverMap::DriveBitGraph::count(DriveBitId src) auto found = more_edges.find(src); if (found == more_edges.end()) return 2; - return GetSize(found->second); + return GetSize(found->second) + 2; } DriverMap::DriveBitId DriverMap::DriveBitGraph::at(DriveBitId src, int index) @@ -688,7 +688,7 @@ void DriverMap::add(DriveBit const &a, DriveBit const &b) // and use the other end as representative bit. else if (a_mode == BitMode::DRIVEN_UNIQUE && !(b_mode == BitMode::DRIVEN_UNIQUE || b_mode == BitMode::DRIVEN)) connect_directed_buffer(a_id, b_id); - else if (b_mode == BitMode::DRIVEN_UNIQUE && !(b_mode == BitMode::DRIVEN_UNIQUE || b_mode == BitMode::DRIVEN)) + else if (b_mode == BitMode::DRIVEN_UNIQUE && !(a_mode == BitMode::DRIVEN_UNIQUE || a_mode == BitMode::DRIVEN)) connect_directed_buffer(b_id, a_id); // If either bit only drives a value, store a directed connection from // it to the other bit. @@ -827,15 +827,18 @@ DriveBit DriverMap::operator()(DriveBit const &bit) DriveBitId bit_id = id_from_drive_bit(bit); - bit_id = same_driver.find(bit_id); + DriveBitId bit_repr_id = same_driver.find(bit_id); - DriveBit bit_repr = drive_bit_from_id(bit_id); + DriveBit bit_repr = drive_bit_from_id(bit_repr_id); BitMode mode = bit_mode(bit_repr); - int implicit_driver_count = connected_drivers.count(bit_id); - if (connected_undirected.contains(bit_id) && !oriented_present.count(bit_id)) - orient_undirected(bit_id); + if (mode == BitMode::KEEP && bit_repr_id != bit_id) + return bit_repr; + + int implicit_driver_count = connected_drivers.count(bit_repr_id); + if (connected_undirected.contains(bit_repr_id) && !oriented_present.count(bit_repr_id)) + orient_undirected(bit_repr_id); DriveBit driver; @@ -843,11 +846,11 @@ DriveBit DriverMap::operator()(DriveBit const &bit) driver = bit_repr; for (int i = 0; i != implicit_driver_count; ++i) - driver.merge(drive_bit_from_id(connected_drivers.at(bit_id, i))); + driver.merge(drive_bit_from_id(connected_drivers.at(bit_repr_id, i))); - int oriented_driver_count = connected_oriented.count(bit_id); + int oriented_driver_count = connected_oriented.count(bit_repr_id); for (int i = 0; i != oriented_driver_count; ++i) - driver.merge(drive_bit_from_id(connected_oriented.at(bit_id, i))); + driver.merge(drive_bit_from_id(connected_oriented.at(bit_repr_id, i))); return driver; } diff --git a/kernel/drivertools.h b/kernel/drivertools.h index b440afddaa2..1cb835df2cc 100644 --- a/kernel/drivertools.h +++ b/kernel/drivertools.h @@ -1165,6 +1165,7 @@ struct DriverMap DriveBitId(int id) : id(id) { } bool operator==(const DriveBitId &other) const { return id == other.id; } + bool operator!=(const DriveBitId &other) const { return id != other.id; } bool operator<(const DriveBitId &other) const { return id < other.id; } unsigned int hash() const { return id; } }; From 8a30f0351deb28fdb4ab77bee6ba7fa561b33f2d Mon Sep 17 00:00:00 2001 From: Emily Schmidt Date: Wed, 1 May 2024 11:47:16 +0100 Subject: [PATCH 09/51] fix bugs in drivertools --- kernel/drivertools.cc | 4 ++-- passes/cmds/example_dt.cc | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/kernel/drivertools.cc b/kernel/drivertools.cc index 286c913a246..9627a467015 100644 --- a/kernel/drivertools.cc +++ b/kernel/drivertools.cc @@ -680,9 +680,9 @@ void DriverMap::add(DriveBit const &a, DriveBit const &b) // If either bit is just a wire that we don't need to keep, merge and // use the other end as representative bit. - if (a_mode == BitMode::NONE) + if (a_mode == BitMode::NONE && !(b_mode == BitMode::DRIVEN_UNIQUE || b_mode == BitMode::DRIVEN)) connect_directed_merge(a_id, b_id); - else if (b_mode == BitMode::NONE) + else if (b_mode == BitMode::NONE && !(a_mode == BitMode::DRIVEN_UNIQUE || a_mode == BitMode::DRIVEN)) connect_directed_merge(b_id, a_id); // If either bit requires a driven value and has a unique driver, merge // and use the other end as representative bit. diff --git a/passes/cmds/example_dt.cc b/passes/cmds/example_dt.cc index dec554d6c71..859b0b7ba4b 100644 --- a/passes/cmds/example_dt.cc +++ b/passes/cmds/example_dt.cc @@ -113,7 +113,7 @@ struct ExampleDtPass : public Pass node.append_arg(enqueue(driver)); } } else { - DriveChunkWire whole_wire(wire_chunk.wire, 0, wire_chunk.width); + DriveChunkWire whole_wire(wire_chunk.wire, 0, wire_chunk.wire->width); node.set_function(ExampleFn(ID($$slice), {{ID(offset), wire_chunk.offset}, {ID(width), wire_chunk.width}})); node.append_arg(enqueue(whole_wire)); } @@ -145,7 +145,7 @@ struct ExampleDtPass : public Pass } else { DriveChunkPort whole_port(port_chunk.cell, port_chunk.port, 0, GetSize(port_chunk.cell->connections().at(port_chunk.port))); - node.set_function(ID($$buf)); + node.set_function(ExampleFn(ID($$slice), {{ID(offset), port_chunk.offset}})); node.append_arg(enqueue(whole_port)); } } else if (chunk.is_constant()) { From d4e3430d224989022f3e1f76bbc234c4d217c324 Mon Sep 17 00:00:00 2001 From: Emily Schmidt Date: Wed, 1 May 2024 11:48:04 +0100 Subject: [PATCH 10/51] add initial version of functional C++ backend --- backends/functional/Makefile.inc | 1 + backends/functional/cxx.cc | 417 ++++++++++++++++++++++++++ backends/functional/cxx_runtime/sim.h | 366 ++++++++++++++++++++++ kernel/graphtools.h | 332 ++++++++++++++++++++ 4 files changed, 1116 insertions(+) create mode 100644 backends/functional/Makefile.inc create mode 100644 backends/functional/cxx.cc create mode 100644 backends/functional/cxx_runtime/sim.h create mode 100644 kernel/graphtools.h diff --git a/backends/functional/Makefile.inc b/backends/functional/Makefile.inc new file mode 100644 index 00000000000..011e662646c --- /dev/null +++ b/backends/functional/Makefile.inc @@ -0,0 +1 @@ +OBJS += backends/functional/cxx.o diff --git a/backends/functional/cxx.cc b/backends/functional/cxx.cc new file mode 100644 index 00000000000..46ce88bd62c --- /dev/null +++ b/backends/functional/cxx.cc @@ -0,0 +1,417 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2024 Emily Schmidt + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" +#include "kernel/drivertools.h" +#include "kernel/topo_scc.h" +#include "kernel/functional.h" +#include "kernel/graphtools.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +const char *reserved_keywords[] = { + "alignas","alignof","and","and_eq","asm","atomic_cancel","atomic_commit", + "atomic_noexcept","auto","bitand","bitor","bool","break","case", + "catch","char","char16_t","char32_t","char8_t","class","co_await", + "co_return","co_yield","compl","concept","const","const_cast","consteval", + "constexpr","constinit","continue","decltype","default","delete", + "do","double","dynamic_cast","else","enum","explicit","export", + "extern","false","float","for","friend","goto","if","inline", + "int","long","mutable","namespace","new","noexcept","not","not_eq", + "nullptr","operator","or","or_eq","private","protected","public", + "reflexpr","register","reinterpret_cast","requires","return","short", + "signed","sizeof","static","static_assert","static_cast","struct", + "switch","synchronized","template","this","thread_local","throw", + "true","try","typedef","typeid","typename","union","unsigned", + "using","virtual","void","volatile","wchar_t","while","xor","xor_eq", + nullptr +}; + +struct CxxScope { + pool used_names; + dict name_map; + + CxxScope() { + for(const char **p = reserved_keywords; *p != nullptr; p++) + reserve(*p); + } + void reserve(std::string name) { + used_names.insert(name); + } + std::string insert(IdString id) { + std::string str = RTLIL::unescape_id(id); + for(size_t i = 0; i < str.size(); i++) + if(strchr("!\"#%&'()*+,-./:;<=>?@[]\\^`{|}~ ", str[i])) + str[i] = '_'; + if(used_names.count(str) == 0){ + used_names.insert(str); + name_map.insert({id, str}); + return str; + } + for (int idx = 0 ; ; idx++){ + std::string suffixed = str + "_" + std::to_string(idx); + if (used_names.count(suffixed) == 0) { + used_names.insert(suffixed); + if(name_map.count(id) == 0) + name_map.insert({id, suffixed}); + return suffixed; + } + } + } + std::string operator[](IdString id) { + if(name_map.count(id) > 0) + return name_map[id]; + else + return insert(id); + } +}; + +struct CxxWriter { + std::ostream &f; + CxxWriter(std::ostream &out) : f(out) {} + void printf(const char *fmt, ...) + { + va_list va; + va_start(va, fmt); + f << vstringf(fmt, va); + va_end(va); + } +}; + +struct CxxStruct { + std::string name; + dict types; + CxxScope scope; + CxxStruct(std::string name) : name(name) { + scope.reserve("out"); + scope.reserve("dump"); + } + void insert(IdString name, std::string type) { + scope.insert(name); + types.insert({name, type}); + } + void print(CxxWriter &f) { + f.printf("struct %s {\n", name.c_str()); + for (auto p : types) { + f.printf("\t%s %s;\n", p.second.c_str(), scope[p.first].c_str()); + } + f.printf("\n\ttemplate void dump(T &out) {\n"); + for (auto p : types) { + f.printf("\t\tout(\"%s\", %s);\n", RTLIL::unescape_id(p.first).c_str(), scope[p.first].c_str()); + } + f.printf("\t}\n};\n\n"); + } + std::string operator[](IdString field) { + return scope[field]; + } +}; + +struct CxxFunction { + IdString name; + int width; + dict parameters; + + CxxFunction(IdString name, int width) : name(name), width(width) {} + CxxFunction(IdString name, int width, dict parameters) : name(name), width(width), parameters(parameters) {} + + bool operator==(CxxFunction const &other) const { + return name == other.name && parameters == other.parameters && width == other.width; + } + + unsigned int hash() const { + return mkhash(name.hash(), parameters.hash()); + } +}; + +typedef ComputeGraph CxxComputeGraph; + +class CxxComputeGraphFactory { + CxxComputeGraph &graph; + using T = CxxComputeGraph::Ref; + static bool is_single_output(IdString type) + { + auto it = yosys_celltypes.cell_types.find(type); + return it != yosys_celltypes.cell_types.end() && it->second.outputs.size() <= 1; + } +public: + CxxComputeGraphFactory(CxxComputeGraph &g) : graph(g) {} + T slice(T a, int in_width, int offset, int out_width) { + assert(offset + out_width <= in_width); + return graph.add(CxxFunction(ID($$slice), out_width, {{ID(offset), offset}}), 0, std::array{a}); + } + T extend(T a, int in_width, int out_width, bool is_signed) { + assert(in_width < out_width); + if(is_signed) + return graph.add(CxxFunction(ID($sign_extend), out_width, {{ID(WIDTH), out_width}}), 0, std::array{a}); + else + return graph.add(CxxFunction(ID($zero_extend), out_width, {{ID(WIDTH), out_width}}), 0, std::array{a}); + } + T concat(T a, int a_width, T b, int b_width) { + return graph.add(CxxFunction(ID($$concat), a_width + b_width), 0, std::array{a, b}); + } + T add(T a, T b, int width) { return graph.add(CxxFunction(ID($add), width), 0, std::array{a, b}); } + T sub(T a, T b, int width) { return graph.add(CxxFunction(ID($sub), width), 0, std::array{a, b}); } + T bitwise_and(T a, T b, int width) { return graph.add(CxxFunction(ID($and), width), 0, std::array{a, b}); } + T bitwise_or(T a, T b, int width) { return graph.add(CxxFunction(ID($or), width), 0, std::array{a, b}); } + T bitwise_xor(T a, T b, int width) { return graph.add(CxxFunction(ID($xor), width), 0, std::array{a, b}); } + T bitwise_not(T a, int width) { return graph.add(CxxFunction(ID($not), width), 0, std::array{a}); } + T neg(T a, int width) { return graph.add(CxxFunction(ID($neg), width), 0, std::array{a}); } + T mux(T a, T b, T s, int width) { return graph.add(CxxFunction(ID($mux), width), 0, std::array{a, b, s}); } + T pmux(T a, T b, T s, int width, int) { return graph.add(CxxFunction(ID($pmux), width), 0, std::array{a, b, s}); } + T reduce_and(T a, int) { return graph.add(CxxFunction(ID($reduce_and), 1), 0, std::array{a}); } + T reduce_or(T a, int) { return graph.add(CxxFunction(ID($reduce_or), 1), 0, std::array{a}); } + T reduce_xor(T a, int) { return graph.add(CxxFunction(ID($reduce_xor), 1), 0, std::array{a}); } + T eq(T a, T b, int) { return graph.add(CxxFunction(ID($eq), 1), 0, std::array{a, b}); } + T ne(T a, T b, int) { return graph.add(CxxFunction(ID($ne), 1), 0, std::array{a, b}); } + T gt(T a, T b, int) { return graph.add(CxxFunction(ID($gt), 1), 0, std::array{a, b}); } + T ge(T a, T b, int) { return graph.add(CxxFunction(ID($ge), 1), 0, std::array{a, b}); } + T ugt(T a, T b, int) { return graph.add(CxxFunction(ID($ugt), 1), 0, std::array{a, b}); } + T uge(T a, T b, int) { return graph.add(CxxFunction(ID($uge), 1), 0, std::array{a, b}); } + T logical_shift_left(T a, T b, int y_width, int) { return graph.add(CxxFunction(ID($shl), y_width, {{ID(WIDTH), y_width}}), 0, std::array{a, b}); } + T logical_shift_right(T a, T b, int y_width, int) { return graph.add(CxxFunction(ID($shr), y_width, {{ID(WIDTH), y_width}}), 0, std::array{a, b}); } + T arithmetic_shift_right(T a, T b, int y_width, int) { return graph.add(CxxFunction(ID($asr), y_width, {{ID(WIDTH), y_width}}), 0, std::array{a, b}); } + + T constant(RTLIL::Const value) { + return graph.add(CxxFunction(ID($$const), value.size(), {{ID(value), value}}), 0); + } + T input(IdString name, int width) { return graph.add(CxxFunction(ID($$input), width, {{name, {}}}), 0); } + T state(IdString name, int width) { return graph.add(CxxFunction(ID($$state), width, {{name, {}}}), 0); } + T cell_output(T cell, IdString type, IdString name, int width) { + if (is_single_output(type)) + return cell; + else + return graph.add(CxxFunction(ID($$cell_output), width, {{name, {}}}), 0, std::array{cell}); + } + T multiple(vector args, int width) { + return graph.add(CxxFunction(ID($$multiple), width), 0, args); + } + T undriven(int width) { + return graph.add(CxxFunction(ID($$undriven), width), 0); + } + + T create_pending(int width) { + return graph.add(CxxFunction(ID($$pending), width), 0); + } + void update_pending(T pending, T node) { + assert(pending.function().name == ID($$pending)); + pending.set_function(CxxFunction(ID($$buf), pending.function().width)); + pending.append_arg(node); + } + void declare_output(T node, IdString name) { + node.assign_key(name); + } + void declare_state(T node, IdString name) { + node.assign_key(name); + } + void suggest_name(T node, IdString name) { + node.sparse_attr() = name; + } +}; + +struct FunctionalCxxBackend : public Backend +{ + FunctionalCxxBackend() : Backend("functional_cxx", "convert design to C++ using the functional backend") {} + + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + } + + CxxComputeGraph calculate_compute_graph(RTLIL::Module *module) + { + CxxComputeGraph compute_graph; + CxxComputeGraphFactory factory(compute_graph); + ComputeGraphConstruction construction(factory); + construction.add_module(module); + construction.process_queue(); + + // Perform topo sort and detect SCCs + CxxComputeGraph::SccAdaptor compute_graph_scc(compute_graph); + + bool scc = false; + std::vector perm; + topo_sorted_sccs(compute_graph_scc, [&](int *begin, int *end) { + perm.insert(perm.end(), begin, end); + if (end > begin + 1) + { + log_warning("SCC:"); + for (int *i = begin; i != end; ++i) + log(" %d(%s)(%s)", *i, compute_graph[*i].function().name.c_str(), compute_graph[*i].has_sparse_attr() ? compute_graph[*i].sparse_attr().c_str() : ""); + log("\n"); + scc = true; + } + }, /* sources_first */ true); + compute_graph.permute(perm); + if(scc) log_error("combinational loops, aborting\n"); + + // Forward $$buf + std::vector alias; + perm.clear(); + + for (int i = 0; i < compute_graph.size(); ++i) + { + auto node = compute_graph[i]; + if (node.function().name == ID($$buf) && node.arg(0).index() < i) + { + int target_index = alias[node.arg(0).index()]; + auto target_node = compute_graph[perm[target_index]]; + if(!target_node.has_sparse_attr() && node.has_sparse_attr()) + target_node.sparse_attr() = node.sparse_attr(); + alias.push_back(target_index); + } + else + { + alias.push_back(GetSize(perm)); + perm.push_back(i); + } + } + compute_graph.permute(perm, alias); + return compute_graph; + } + + void printCxx(std::ostream &stream, std::string, std::string const & name, CxxComputeGraph &compute_graph) + { + dict inputs, state; + CxxWriter f(stream); + + // Dump the compute graph + for (int i = 0; i < compute_graph.size(); ++i) + { + auto ref = compute_graph[i]; + if(ref.function().name == ID($$input)) + inputs[ref.function().parameters.begin()->first] = ref.function().width; + if(ref.function().name == ID($$state)) + state[ref.function().parameters.begin()->first] = ref.function().width; + } + f.printf("#include \"sim.h\"\n"); + CxxStruct input_struct(name + "_Inputs"); + for (auto const &input : inputs) + input_struct.insert(input.first, "Signal<" + std::to_string(input.second) + ">"); + CxxStruct output_struct(name + "_Outputs"); + for (auto const &key : compute_graph.keys()) + if(state.count(key.first) == 0) + output_struct.insert(key.first, "Signal<" + std::to_string(compute_graph[key.second].function().width) + ">"); + CxxStruct state_struct(name + "_State"); + for (auto const &state_var : state) + state_struct.insert(state_var.first, "Signal<" + std::to_string(state_var.second) + ">"); + + idict node_names; + CxxScope locals; + + input_struct.print(f); + output_struct.print(f); + state_struct.print(f); + + f.printf("void %s(%s_Inputs const &input, %s_Outputs &output, %s_State const ¤t_state, %s_State &next_state)\n{\n", name.c_str(), name.c_str(), name.c_str(), name.c_str(), name.c_str()); + locals.reserve("input"); + locals.reserve("output"); + locals.reserve("current_state"); + locals.reserve("next_state"); + for (int i = 0; i < compute_graph.size(); ++i) + { + auto ref = compute_graph[i]; + int width = ref.function().width; + std::string name; + if(ref.has_sparse_attr()) + name = locals.insert(ref.sparse_attr()); + else + name = locals.insert("\\n" + std::to_string(i)); + node_names(name); + if(ref.function().name == ID($$input)) + f.printf("\tSignal<%d> %s = input.%s;\n", width, name.c_str(), input_struct[ref.function().parameters.begin()->first].c_str()); + else if(ref.function().name == ID($$state)) + f.printf("\tSignal<%d> %s = current_state.%s;\n", width, name.c_str(), state_struct[ref.function().parameters.begin()->first].c_str()); + else if(ref.function().name == ID($$buf)) + f.printf("\tSignal<%d> %s = %s;\n", width, name.c_str(), node_names[ref.arg(0).index()].c_str()); + else if(ref.function().name == ID($$cell_output)) + f.printf("\tSignal<%d> %s = %s.%s;\n", width, name.c_str(), node_names[ref.arg(0).index()].c_str(), RTLIL::unescape_id(ref.function().parameters.begin()->first).c_str()); + else if(ref.function().name == ID($$const)){ + auto c = ref.function().parameters.begin()->second; + if(c.size() <= 32){ + f.printf("\tSignal<%d> %s = $const<%d>(%#x);\n", width, name.c_str(), width, (uint32_t) c.as_int()); + }else{ + f.printf("\tSignal<%d> %s = $const<%d>({%#x", width, name.c_str(), width, (uint32_t) c.as_int()); + while(c.size() > 32){ + c = c.extract(32, c.size() - 32); + f.printf(", %#x", c.as_int()); + } + f.printf("});\n"); + } + }else if(ref.function().name == ID($$undriven)) + f.printf("\tSignal<%d> %s; //undriven\n", width, name.c_str()); + else if(ref.function().name == ID($$slice)) + f.printf("\tSignal<%d> %s = slice<%d>(%s, %d);\n", width, name.c_str(), width, node_names[ref.arg(0).index()].c_str(), ref.function().parameters.at(ID(offset)).as_int()); + else if(ref.function().name == ID($$concat)){ + f.printf("\tauto %s = concat(", name.c_str()); + for (int i = 0, end = ref.size(); i != end; ++i){ + if(i > 0) + f.printf(", "); + f.printf("%s", node_names[ref.arg(i).index()].c_str()); + } + f.printf(");\n"); + }else{ + f.printf("\t"); + if(ref.function().width > 0) + f.printf("Signal<%d>", ref.function().width); + else + f.printf("%s_Outputs", log_id(ref.function().name)); + f.printf(" %s = %s", name.c_str(), log_id(ref.function().name)); + if(ref.function().parameters.count(ID(WIDTH))){ + f.printf("<%d>", ref.function().parameters.at(ID(WIDTH)).as_int()); + } + f.printf("("); + for (int i = 0, end = ref.size(); i != end; ++i) + f.printf("%s%s", i>0?", ":"", node_names[ref.arg(i).index()].c_str()); + f.printf("); //"); + for (auto const ¶m : ref.function().parameters) + { + if (param.second.empty()) + f.printf("[%s]", log_id(param.first)); + else + f.printf("[%s=%s]", log_id(param.first), log_const(param.second)); + } + f.printf("\n"); + } + } + + for (auto const &key : compute_graph.keys()) + { + f.printf("\t%s.%s = %s;\n", state.count(key.first) > 0 ? "next_state" : "output", state_struct[key.first].c_str(), node_names[key.second].c_str()); + } + f.printf("}\n"); + } + + void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) override + { + log_header(design, "Executing Functional C++ backend.\n"); + + size_t argidx = 1; + extra_args(f, filename, args, argidx, design); + + for (auto module : design->selected_modules()) { + log("Dumping module `%s'.\n", module->name.c_str()); + auto compute_graph = calculate_compute_graph(module); + printCxx(*f, filename, RTLIL::unescape_id(module->name), compute_graph); + } + } +} FunctionalCxxBackend; + +PRIVATE_NAMESPACE_END diff --git a/backends/functional/cxx_runtime/sim.h b/backends/functional/cxx_runtime/sim.h new file mode 100644 index 00000000000..4e7d9b60142 --- /dev/null +++ b/backends/functional/cxx_runtime/sim.h @@ -0,0 +1,366 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2024 Emily Schmidt + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#ifndef SIM_H +#define SIM_H + +#include + +template +using Signal = std::array; + +template +Signal slice(Signal const& a, size_t offset) +{ + Signal ret; + + std::copy(a.begin() + offset, a.begin() + offset + n, ret.begin()); + return ret; +} + +template +Signal $const(uint32_t val) +{ + size_t i; + Signal ret; + + for(i = 0; i < n; i++) + if(i < 32) + ret[i] = val & (1< +Signal $const(std::initializer_list vals) +{ + size_t k, i; + Signal ret; + + k = 0; + for (auto val : vals) { + for(i = 0; i < 32; i++) + if(i + k < n) + ret[i + k] = val & (1< +bool as_bool(Signal sig) +{ + for(int i = 0; i < n; i++) + if(sig[i]) + return true; + return false; +} + +template +uint32_t as_int(Signal sig) +{ + uint32_t ret = 0; + for(int i = 0; i < n; i++) + if(sig[i] && i < 32) + ret |= 1< +Signal $mux(Signal const& a, Signal const &b, Signal<1> const &s) +{ + return s[0] ? b : a; +} + +template +Signal $not(Signal const& a) +{ + Signal ret; + for(size_t i = 0; i < n; i++) + ret[i] = !a[i]; + return ret; +} + +template +Signal $neg(Signal const& a) +{ + Signal ret; + bool carry = true; + for(size_t i = 0; i < n; i++) { + int r = !a[i] + carry; + ret[i] = (r & 1) != 0; + carry = (r >> 1) != 0; + } + return ret; +} + +template +Signal<1> $reduce_or(Signal const& a) +{ + return { as_bool(a) }; +} + +template +Signal<1> $reduce_and(Signal const& a) +{ + for(size_t i = 0; i < n; i++) + if(!a[i]) + return { false }; + return { true }; +} + +template +Signal<1> $reduce_bool(Signal const& a) +{ + return { as_bool(a) }; +} + +template +Signal<1> $logic_and(Signal const& a, Signal const& b) +{ + return { as_bool(a) && as_bool(b) }; +} + +template +Signal<1> $logic_or(Signal const& a, Signal const& b) +{ + return { as_bool(a) || as_bool(b) }; +} + +template +Signal<1> $logic_not(Signal const& a) +{ + return { !as_bool(a) }; +} + +template +Signal $add(Signal const& a, Signal const &b) +{ + Signal ret; + size_t i; + int x = 0; + for(i = 0; i < n; i++){ + x += (int)a[i] + (int)b[i]; + ret[i] = x & 1; + x >>= 1; + } + return ret; +} +template +Signal $sub(Signal const& a, Signal const &b) +{ + Signal ret; + int x = 1; + for(size_t i = 0; i < n; i++){ + x += (int)a[i] + (int)!b[i]; + ret[i] = x & 1; + x >>= 1; + } + return ret; +} + +template +Signal<1> $uge(Signal const& a, Signal const &b) +{ + for(size_t i = n; i-- != 0; ) + if(a[i] != b[i]) + return { a[i] }; + return { true }; +} + +template +Signal<1> $ugt(Signal const& a, Signal const &b) +{ + for(size_t i = n; i-- != 0; ) + if(a[i] != b[i]) + return { a[i] }; + return { false }; +} + +template +Signal<1> $ge(Signal const& a, Signal const &b) +{ + if(a[n-1] != b[n-1]) + return { b[n-1] }; + return $uge(a, b); +} + +template +Signal<1> $gt(Signal const& a, Signal const &b) +{ + if(a[n-1] != b[n-1]) + return { b[n-1] }; + return $ugt(a, b); +} + +template Signal<1> $ule(Signal const& a, Signal const &b) { return $uge(b, a); } +template Signal<1> $ult(Signal const& a, Signal const &b) { return $ugt(b, a); } +template Signal<1> $le(Signal const& a, Signal const &b) { return $ge(b, a); } +template Signal<1> $lt(Signal const& a, Signal const &b) { return $gt(b, a); } + +template +Signal $and(Signal const& a, Signal const &b) +{ + Signal ret; + for(size_t i = 0; i < n; i++) + ret[i] = a[i] && b[i]; + return ret; +} + +template +Signal $or(Signal const& a, Signal const &b) +{ + Signal ret; + for(size_t i = 0; i < n; i++) + ret[i] = a[i] || b[i]; + return ret; +} + +template +Signal $xor(Signal const& a, Signal const &b) +{ + Signal ret; + for(size_t i = 0; i < n; i++) + ret[i] = a[i] != b[i]; + return ret; +} + +template +Signal $shl(Signal const& a, Signal const &b) +{ + if(nb >= sizeof(int) * 8 - 1) + for(size_t i = sizeof(int) * 8 - 1; i < nb; i++) + assert(!b[i]); + size_t amount = as_int(b); + Signal ret = $const(0); + if(amount < n){ + if(amount + na > n) + std::copy(a.begin(), a.begin() + (n - amount), ret.begin() + amount); + else + std::copy(a.begin(), a.end(), ret.begin() + amount); + } + return ret; +} + +template +Signal $shr(Signal const& a, Signal const &b) +{ + if(nb >= sizeof(int) * 8 - 1) + for(size_t i = sizeof(int) * 8 - 1; i < nb; i++) + assert(!b[i]); + size_t amount = as_int(b); + Signal ret; + for (size_t i = 0; i < n; i++) { + if(i + amount < n) + ret[i] = a[i + amount]; + else + ret[i] = false; + } + return ret; +} + +template +Signal $asr(Signal const& a, Signal const &b) +{ + if(nb >= sizeof(int) * 8 - 1) + for(size_t i = sizeof(int) * 8 - 1; i < nb; i++) + assert(!b[i]); + size_t amount = as_int(b); + Signal ret; + for (size_t i = 0; i < n; i++) { + if(i + amount < n) + ret[i] = a[i + amount]; + else + ret[i] = a[n - 1]; + } + return ret; +} + +template +Signal<1> $eq(Signal const& a, Signal const &b) +{ + for(size_t i = 0; i < n; i++) + if(a[i] != b[i]) + return { false }; + return { true }; +} + +template +Signal<1> $ne(Signal const& a, Signal const &b) +{ + for(size_t i = 0; i < n; i++) + if(a[i] != b[i]) + return { true }; + return { false }; +} + +template +Signal $pmux(Signal const& a, Signal const &b, Signal const &s) +{ + bool found; + Signal ret; + + found = false; + ret = a; + for(size_t i = 0; i < ns; i++){ + if(s[i]){ + if(found) + return $const(0); + found = true; + ret = slice(b, n * i); + } + } + return ret; +} + +template +Signal concat(Signal const& a, Signal const& b) +{ + Signal ret; + std::copy(a.begin(), a.end(), ret.begin()); + std::copy(b.begin(), b.end(), ret.begin() + n); + return ret; +} + +template +Signal $zero_extend(Signal const& a) +{ + assert(n >= m); + Signal ret; + std::copy(a.begin(), a.end(), ret.begin()); + for(size_t i = m; i < n; i++) + ret[i] = false; + return ret; +} + +template +Signal $sign_extend(Signal const& a) +{ + assert(n >= m); + Signal ret; + std::copy(a.begin(), a.end(), ret.begin()); + for(size_t i = m; i < n; i++) + ret[i] = a[m-1]; + return ret; +} + +#endif diff --git a/kernel/graphtools.h b/kernel/graphtools.h new file mode 100644 index 00000000000..1a59ef1b537 --- /dev/null +++ b/kernel/graphtools.h @@ -0,0 +1,332 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2024 Emily Schmidt + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#ifndef GRAPHTOOLS_H +#define GRAPHTOOLS_H + +#include "kernel/yosys.h" +#include "kernel/drivertools.h" +#include "kernel/functional.h" + +USING_YOSYS_NAMESPACE +YOSYS_NAMESPACE_BEGIN + +template +class CellSimplifier { + Factory &factory; + T reduce_shift_width(T b, int b_width, int y_width, int &reduced_b_width) { + log_assert(y_width > 0); + int new_width = sizeof(int) * 8 - __builtin_clz(y_width); + if (b_width <= new_width) { + reduced_b_width = b_width; + return b; + } else { + reduced_b_width = new_width; + T lower_b = factory.slice(b, b_width, 0, new_width); + T overflow = factory.gt(b, factory.constant(RTLIL::Const(y_width, b_width)), b_width); + return factory.mux(lower_b, factory.constant(RTLIL::Const(y_width, new_width)), overflow, new_width); + } + } +public: + T reduce_or(T a, int width) { + if (width == 1) + return a; + return factory.reduce_or(a, width); + } + T extend(T a, int in_width, int out_width, bool is_signed) { + if(in_width == out_width) + return a; + if(in_width > out_width) + return factory.slice(a, in_width, 0, out_width); + return factory.extend(a, in_width, out_width, is_signed); + } + T logical_shift_left(T a, T b, int y_width, int b_width) { + int reduced_b_width; + T reduced_b = reduce_shift_width(b, b_width, y_width, reduced_b_width); + return factory.logical_shift_left(a, reduced_b, y_width, reduced_b_width); + } + T logical_shift_right(T a, T b, int y_width, int b_width) { + int reduced_b_width; + T reduced_b = reduce_shift_width(b, b_width, y_width, reduced_b_width); + return factory.logical_shift_right(a, reduced_b, y_width, reduced_b_width); + } + T arithmetic_shift_right(T a, T b, int y_width, int b_width) { + int reduced_b_width; + T reduced_b = reduce_shift_width(b, b_width, y_width, reduced_b_width); + return factory.arithmetic_shift_right(a, reduced_b, y_width, reduced_b_width); + } + CellSimplifier(Factory &f) : factory(f) {} + T handle(IdString cellType, dict parameters, dict inputs) + { + int a_width = parameters.at(ID(A_WIDTH), Const(-1)).as_int(); + int b_width = parameters.at(ID(B_WIDTH), Const(-1)).as_int(); + int y_width = parameters.at(ID(Y_WIDTH), Const(-1)).as_int(); + bool a_signed = parameters.at(ID(A_SIGNED), Const(0)).as_bool(); + bool b_signed = parameters.at(ID(B_SIGNED), Const(0)).as_bool(); + if(cellType.in({ID($add), ID($sub), ID($and), ID($or), ID($xor), ID($xnor)})){ + bool is_signed = a_signed && b_signed; + T a = extend(inputs.at(ID(A)), a_width, y_width, is_signed); + T b = extend(inputs.at(ID(B)), b_width, y_width, is_signed); + if(cellType == ID($add)) + return factory.add(a, b, y_width); + else if(cellType == ID($sub)) + return factory.sub(a, b, y_width); + else if(cellType == ID($and)) + return factory.bitwise_and(a, b, y_width); + else if(cellType == ID($or)) + return factory.bitwise_or(a, b, y_width); + else if(cellType == ID($xor)) + return factory.bitwise_xor(a, b, y_width); + else if(cellType == ID($xnor)) + return factory.bitwise_not(factory.bitwise_xor(a, b, y_width), y_width); + else + log_abort(); + }else if(cellType.in({ID($eq), ID($ne), ID($eqx), ID($nex), ID($le), ID($lt), ID($ge), ID($gt)})){ + bool is_signed = a_signed && b_signed; + int width = max(a_width, b_width); + T a = extend(inputs.at(ID(A)), a_width, width, is_signed); + T b = extend(inputs.at(ID(B)), b_width, width, is_signed); + if(cellType.in({ID($eq), ID($eqx)})) + return extend(factory.eq(a, b, width), 1, y_width, false); + if(cellType.in({ID($ne), ID($nex)})) + return extend(factory.ne(a, b, width), 1, y_width, false); + else if(cellType == ID($lt)) + return extend(is_signed ? factory.gt(b, a, width) : factory.ugt(b, a, width), 1, y_width, false); + else if(cellType == ID($le)) + return extend(is_signed ? factory.ge(b, a, width) : factory.uge(b, a, width), 1, y_width, false); + else if(cellType == ID($gt)) + return extend(is_signed ? factory.gt(a, b, width) : factory.ugt(a, b, width), 1, y_width, false); + else if(cellType == ID($ge)) + return extend(is_signed ? factory.ge(a, b, width) : factory.uge(a, b, width), 1, y_width, false); + else + log_abort(); + }else if(cellType.in({ID($logic_or), ID($logic_and)})){ + T a = reduce_or(inputs.at(ID(A)), a_width); + T b = reduce_or(inputs.at(ID(B)), b_width); + T y = cellType == ID($logic_and) ? factory.bitwise_and(a, b, 1) : factory.bitwise_or(a, b, 1); + return extend(y, 1, y_width, false); + }else if(cellType == ID($not)){ + T a = extend(inputs.at(ID(A)), a_width, y_width, a_signed); + return factory.bitwise_not(a, y_width); + }else if(cellType == ID($pos)){ + return extend(inputs.at(ID(A)), a_width, y_width, a_signed); + }else if(cellType == ID($neg)){ + T a = extend(inputs.at(ID(A)), a_width, y_width, a_signed); + return factory.neg(a, y_width); + }else if(cellType == ID($logic_not)){ + T a = reduce_or(inputs.at(ID(A)), a_width); + T y = factory.bitwise_not(a, 1); + return extend(y, 1, y_width, false); + }else if(cellType.in({ID($reduce_or), ID($reduce_bool)})){ + T a = reduce_or(inputs.at(ID(A)), a_width); + return extend(a, 1, y_width, false); + }else if(cellType == ID($reduce_and)){ + T a = factory.reduce_and(inputs.at(ID(A)), a_width); + return extend(a, 1, y_width, false); + }else if(cellType.in({ID($reduce_xor), ID($reduce_xnor)})){ + T a = factory.reduce_xor(inputs.at(ID(A)), a_width); + T y = cellType == ID($reduce_xnor) ? factory.bitwise_not(a, 1) : a; + return extend(y, 1, y_width, false); + }else if(cellType == ID($shl) || cellType == ID($sshl)){ + T a = extend(inputs.at(ID(A)), a_width, y_width, a_signed); + T b = inputs.at(ID(B)); + return logical_shift_left(a, b, y_width, b_width); + }else if(cellType == ID($shr) || cellType == ID($sshr)){ + int width = max(a_width, y_width); + T a = extend(inputs.at(ID(A)), a_width, width, a_signed); + T b = inputs.at(ID(B)); + T y = a_signed && cellType == ID($sshr) ? + arithmetic_shift_right(a, b, width, b_width) : + logical_shift_right(a, b, width, b_width); + return extend(y, width, y_width, a_signed); + }else if(cellType == ID($shiftx) || cellType == ID($shift)){ + int width = max(a_width, y_width); + T a = extend(inputs.at(ID(A)), a_width, width, cellType == ID($shift) && a_signed); + T b = inputs.at(ID(B)); + T shr = logical_shift_right(a, b, width, b_width); + if(b_signed) { + T sign_b = factory.slice(b, b_width, b_width - 1, 1); + T shl = logical_shift_left(a, factory.neg(b, b_width), width, b_width); + T y = factory.mux(shr, shl, sign_b, width); + return extend(y, width, y_width, false); + } else { + return extend(shr, width, y_width, false); + } + }else if(cellType == ID($mux)){ + int width = parameters.at(ID(WIDTH)).as_int(); + return factory.mux(inputs.at(ID(A)), inputs.at(ID(B)), inputs.at(ID(S)), width); + }else if(cellType == ID($pmux)){ + int width = parameters.at(ID(WIDTH)).as_int(); + int s_width = parameters.at(ID(S_WIDTH)).as_int(); + return factory.pmux(inputs.at(ID(A)), inputs.at(ID(B)), inputs.at(ID(S)), width, s_width); + }else if(cellType == ID($concat)){ + T a = inputs.at(ID(A)); + T b = inputs.at(ID(B)); + return factory.concat(a, a_width, b, b_width); + }else if(cellType == ID($slice)){ + int offset = parameters.at(ID(OFFSET)).as_int(); + T a = inputs.at(ID(A)); + return factory.slice(a, a_width, offset, y_width); + }else{ + log_error("unhandled cell in CellSimplifier %s\n", cellType.c_str()); + } + } +}; + +template +class ComputeGraphConstruction { + std::deque queue; + dict graph_nodes; + idict cells; + DriverMap driver_map; + Factory& factory; + CellSimplifier simplifier; + + T enqueue(DriveSpec const &spec) + { + auto it = graph_nodes.find(spec); + if(it == graph_nodes.end()){ + auto node = factory.create_pending(spec.size()); + graph_nodes.insert({spec, node}); + queue.emplace_back(spec); + return node; + }else + return it->second; + } +public: + ComputeGraphConstruction(Factory &f) : factory(f), simplifier(f) {} + void add_module(Module *module) + { + driver_map.add(module); + for (auto cell : module->cells()) { + if (cell->type.in(ID($assert), ID($assume), ID($cover), ID($check))) + enqueue(DriveBitMarker(cells(cell), 0)); + } + for (auto wire : module->wires()) { + if (wire->port_output) { + T node = enqueue(DriveChunk(DriveChunkWire(wire, 0, wire->width))); + factory.declare_output(node, wire->name); + } + } + } + void process_queue() + { + for (; !queue.empty(); queue.pop_front()) { + DriveSpec spec = queue.front(); + T pending = graph_nodes.at(spec); + + if (spec.chunks().size() > 1) { + auto chunks = spec.chunks(); + T node = enqueue(chunks[0]); + int width = chunks[0].size(); + for(size_t i = 1; i < chunks.size(); i++) { + node = factory.concat(node, width, enqueue(chunks[i]), chunks[i].size()); + width += chunks[i].size(); + } + factory.update_pending(pending, node); + } else if (spec.chunks().size() == 1) { + DriveChunk chunk = spec.chunks()[0]; + if (chunk.is_wire()) { + DriveChunkWire wire_chunk = chunk.wire(); + if (wire_chunk.is_whole()) { + if (wire_chunk.wire->port_input) { + T node = factory.input(wire_chunk.wire->name, wire_chunk.width); + factory.suggest_name(node, wire_chunk.wire->name); + factory.update_pending(pending, node); + } else { + DriveSpec driver = driver_map(DriveSpec(wire_chunk)); + T node = enqueue(driver); + factory.suggest_name(node, wire_chunk.wire->name); + factory.update_pending(pending, node); + } + } else { + DriveChunkWire whole_wire(wire_chunk.wire, 0, wire_chunk.wire->width); + T node = factory.slice(enqueue(whole_wire), wire_chunk.wire->width, wire_chunk.offset, wire_chunk.width); + factory.update_pending(pending, node); + } + } else if (chunk.is_port()) { + DriveChunkPort port_chunk = chunk.port(); + if (port_chunk.is_whole()) { + if (driver_map.celltypes.cell_output(port_chunk.cell->type, port_chunk.port)) { + if (port_chunk.cell->type.in(ID($dff), ID($ff))) + { + Cell *cell = port_chunk.cell; + T node = factory.state(cell->name, port_chunk.width); + factory.suggest_name(node, port_chunk.cell->name); + factory.update_pending(pending, node); + for (auto const &conn : cell->connections()) { + if (driver_map.celltypes.cell_input(cell->type, conn.first)) { + T node = enqueue(DriveChunkPort(cell, conn)); + factory.declare_state(node, cell->name); + } + } + } + else + { + T cell = enqueue(DriveChunkMarker(cells(port_chunk.cell), 0, port_chunk.width)); + factory.suggest_name(cell, port_chunk.cell->name); + T node = factory.cell_output(cell, port_chunk.cell->type, port_chunk.port, port_chunk.width); + factory.suggest_name(node, port_chunk.cell->name.str() + "$" + port_chunk.port.str()); + factory.update_pending(pending, node); + } + } else { + DriveSpec driver = driver_map(DriveSpec(port_chunk)); + factory.update_pending(pending, enqueue(driver)); + } + } else { + DriveChunkPort whole_port(port_chunk.cell, port_chunk.port, 0, GetSize(port_chunk.cell->connections().at(port_chunk.port))); + T node = factory.slice(enqueue(whole_port), whole_port.width, port_chunk.offset, port_chunk.width); + factory.update_pending(pending, node); + } + } else if (chunk.is_constant()) { + T node = factory.constant(chunk.constant()); + factory.suggest_name(node, "$const" + std::to_string(chunk.size()) + "b" + chunk.constant().as_string()); + factory.update_pending(pending, node); + } else if (chunk.is_multiple()) { + vector args; + for (auto const &driver : chunk.multiple().multiple()) + args.push_back(enqueue(driver)); + T node = factory.multiple(args, chunk.size()); + factory.update_pending(pending, node); + } else if (chunk.is_marker()) { + Cell *cell = cells[chunk.marker().marker]; + dict connections; + for(auto const &conn : cell->connections()) { + if(driver_map.celltypes.cell_input(cell->type, conn.first)) + connections.insert({ conn.first, enqueue(DriveChunkPort(cell, conn)) }); + } + T node = simplifier.handle(cell->type, cell->parameters, connections); + factory.update_pending(pending, node); + } else if (chunk.is_none()) { + T node = factory.undriven(chunk.size()); + factory.update_pending(pending, node); + } else { + log_error("unhandled drivespec: %s\n", log_signal(chunk)); + log_abort(); + } + } else { + log_abort(); + } + } + } +}; + +YOSYS_NAMESPACE_END + +#endif From e8f510113e6217a148d84b406fcf7fb84b8786a3 Mon Sep 17 00:00:00 2001 From: Emily Schmidt Date: Thu, 23 May 2024 11:40:41 +0100 Subject: [PATCH 11/51] add initial version of functional smtlib backend --- backends/functional/Makefile.inc | 1 + backends/functional/cxx.cc | 4 +- backends/functional/smtlib.cc | 541 +++++++++++++++++++++++++++++++ kernel/graphtools.h | 6 +- 4 files changed, 547 insertions(+), 5 deletions(-) create mode 100644 backends/functional/smtlib.cc diff --git a/backends/functional/Makefile.inc b/backends/functional/Makefile.inc index 011e662646c..c712d2aefe5 100644 --- a/backends/functional/Makefile.inc +++ b/backends/functional/Makefile.inc @@ -1 +1,2 @@ OBJS += backends/functional/cxx.o +OBJS += backends/functional/smtlib.o diff --git a/backends/functional/cxx.cc b/backends/functional/cxx.cc index 46ce88bd62c..c0444e7fe5a 100644 --- a/backends/functional/cxx.cc +++ b/backends/functional/cxx.cc @@ -214,10 +214,10 @@ class CxxComputeGraphFactory { pending.set_function(CxxFunction(ID($$buf), pending.function().width)); pending.append_arg(node); } - void declare_output(T node, IdString name) { + void declare_output(T node, IdString name, int) { node.assign_key(name); } - void declare_state(T node, IdString name) { + void declare_state(T node, IdString name, int) { node.assign_key(name); } void suggest_name(T node, IdString name) { diff --git a/backends/functional/smtlib.cc b/backends/functional/smtlib.cc new file mode 100644 index 00000000000..f6af797919b --- /dev/null +++ b/backends/functional/smtlib.cc @@ -0,0 +1,541 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2024 Emily Schmidt + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" +#include "kernel/drivertools.h" +#include "kernel/topo_scc.h" +#include "kernel/functional.h" +#include "kernel/graphtools.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct SmtlibScope { + pool used_names; + dict name_map; + + SmtlibScope() { + /*for(const char **p = reserved_keywords; *p != nullptr; p++) + reserve(*p);*/ + } + void reserve(std::string name) { + used_names.insert(name); + } + std::string insert(IdString id) { + std::string str = RTLIL::unescape_id(id); + for(size_t i = 0; i < str.size(); i++) + if(!((unsigned char)str[i] < 0x80 && (isalnum(str[i]) || strchr("~!@$%^&*_-+=<>.?/", str[i])))) + str[i] = '_'; + if(used_names.count(str) == 0){ + used_names.insert(str); + name_map.insert({id, str}); + return str; + } + for (int idx = 0 ; ; idx++){ + std::string suffixed = str + "_" + std::to_string(idx); + if (used_names.count(suffixed) == 0) { + used_names.insert(suffixed); + if(name_map.count(id) == 0) + name_map.insert({id, suffixed}); + return suffixed; + } + } + } + std::string operator[](IdString id) { + if(name_map.count(id) > 0) + return name_map[id]; + else + return insert(id); + } +}; + +struct SmtlibWriter { + std::ostream &f; + SmtlibWriter(std::ostream &out) : f(out) {} + void printf(const char *fmt, ...) + { + va_list va; + va_start(va, fmt); + f << vstringf(fmt, va); + va_end(va); + } + template + SmtlibWriter & operator <<(T &&arg) { + f << std::forward(arg); + return *this; + } +}; + +struct Arg { + int n; + explicit Arg(int n_) : n(n_) {} + bool operator ==(Arg const &other) const { return n == other.n; } +}; + +class SExpr { + enum class Type { + None, + List, + Atom, + Arg, + }; + Type type = Type::None; + union { + std::string atom_; + vector list_; + Arg arg_; + }; + void set_none() { + switch(type) { + case Type::None: break; + case Type::Atom: atom_.~basic_string(); break; + case Type::List: list_.~vector(); break; + case Type::Arg: arg_.~Arg(); break; + } + type = Type::None; + } +public: + SExpr() {} + SExpr(const char *atom) : type(Type::Atom), atom_(atom) {} + SExpr(std::string atom) : type(Type::Atom), atom_(atom) {} + SExpr(int n) : type(Type::Atom), atom_(std::to_string(n)) {} + SExpr(RTLIL::Const const & n) : type(Type::Atom) { + new(&atom_) std::string("#b"); + atom_.reserve(n.size() + 2); + for (size_t i = n.size(); i > 0; i--) + if(n[i-1] == State::S1) + atom_ += "1"; + else + atom_ += "0"; + } + SExpr(vector &&list) : type(Type::List), list_(list) {} + SExpr(std::initializer_list list) : type(Type::List), list_(list) {} + SExpr(Arg arg) : type(Type::Arg), arg_(arg) {} + SExpr(SExpr const &other) { *this = other; } + SExpr(SExpr &&other) { *this = std::move(other); } + SExpr &operator =(SExpr const &other) { + set_none(); + switch(other.type) { + case Type::None: break; + case Type::Atom: new(&atom_) std::string(other.atom_); break; + case Type::List: new(&list_) vector(other.list_); break; + case Type::Arg: new(&arg_) Arg(other.arg_); break; + } + type = other.type; + return *this; + } + SExpr &operator =(SExpr &&other) { + set_none(); + switch(other.type) { + case Type::None: break; + case Type::Atom: new(&atom_) std::string(std::move(other.atom_)); break; + case Type::List: new(&list_) vector(std::move(other.list_)); break; + case Type::Arg: new(&arg_) Arg(std::move(other.arg_)); break; + } + type = other.type; + return *this; + } + ~SExpr() { set_none(); } + bool operator==(SExpr const &other) const { + if(type != other.type) return false; + switch(type) { + case Type::None: return true; + case Type::Atom: return atom_ == other.atom_; + case Type::List: return list_ == other.list_; + case Type::Arg: return arg_ == other.arg_; + } + } + bool is_none() const { return type == Type::None; } + bool is_atom() const { return type == Type::Atom; } + bool is_list() const { return type == Type::List; } + bool is_arg() const { return type == Type::Arg; } + std::string const &atom() const { log_assert(is_atom()); return atom_; } + std::vector const &list() const { log_assert(is_list()); return list_; } + Arg const &arg() const { log_assert(is_arg()); return arg_; } + unsigned int hash() const { + unsigned int inner; + switch(type) { + case Type::None: inner = 0; break; + case Type::Atom: inner = mkhash(atom_); break; + case Type::List: inner = mkhash(list_); break; + case Type::Arg: inner = arg_.n; break; + } + return mkhash((unsigned int) type, inner); + } + SExpr subst_args(std::vector const & args) const { + switch(type) { + case Type::None: + case Type::Atom: + return *this; + case Type::List: { + vector ret; + for(auto & a : list_) + ret.emplace_back(a.subst_args(args)); + return SExpr(std::move(ret)); + } + case Type::Arg: + if(arg_.n >= 1 && (size_t)arg_.n <= args.size()) + return args[arg_.n - 1]; + else + return *this; + } + } +}; + +std::ostream& operator << (std::ostream &os, SExpr const &s) { + if(s.is_atom()) + os << s.atom(); + else if(s.is_list()){ + os << "("; + bool first = true; + for(auto &el: s.list()) { + if(!first) os << " "; + else first = false; + os << el; + } + os << ")"; + }else if(s.is_arg()) + os << "#" << s.arg().n; + else if(s.is_none()) + os << ""; + else + os << "???"; + return os; +} + +struct SmtlibStruct { + SmtlibScope &scope; + std::string name; + idict members; + vector widths; + vector accessors; + SmtlibStruct(std::string name, SmtlibScope &scope) : scope(scope), name(name) { + } + std::string insert(IdString field, int width) { + if(members.at(field, -1) == -1){ + members(field); + scope.insert(field); + widths.push_back(width); + accessors.push_back(scope.insert(std::string("\\") + name + "_" + RTLIL::unescape_id(field))); + } + return scope[field]; + } + void print(SmtlibWriter &f) { + f.printf("(declare-datatype %s ((%s\n", name.c_str(), name.c_str()); + for (size_t i = 0; i < members.size(); i++) + f.printf(" (%s (_ BitVec %d))\n", accessors[i].c_str(), widths[i]); + f.printf(")))\n"); + } + void print_value(SmtlibWriter &f, dict values, int indentation) { + std::string spaces(indentation, ' '); + f << spaces << "(" << name << "\n"; + for (size_t i = 0; i < members.size(); i++) + f << spaces << " " << values[members[i]] << " ; " << RTLIL::unescape_id(members[i]) << "\n"; + f << spaces << ")\n"; + } + SExpr access(SExpr record, IdString member) { + int i = members.at(member); + return SExpr{accessors[i], record}; + } + std::string operator[](IdString field) { + return scope[field]; + } +}; + +struct Node { + SExpr expr; + int width; + + Node(SExpr &&expr, int width) : expr(std::move(expr)), width(width) {} + + bool operator==(Node const &other) const { + return expr == other.expr && width == other.width; + } + + unsigned int hash() const { + return mkhash(expr.hash(), width); + } +}; + +typedef ComputeGraph SmtlibComputeGraph; + +struct SmtlibModule { + std::string name; + SmtlibScope global_scope; + SmtlibStruct input_struct; + SmtlibStruct output_struct; + SmtlibStruct state_struct; + SmtlibComputeGraph compute_graph; + + SmtlibModule(std::string const &name) : + name(name), + input_struct(name + "_inputs", global_scope), + output_struct(name + "_outputs", global_scope), + state_struct(name + "_state", global_scope) + { } + void calculate_compute_graph(RTLIL::Module *module); + void write(std::ostream &stream); +}; + +class SmtlibComputeGraphFactory { + SmtlibModule &module; + SmtlibComputeGraph &graph; + using T = SmtlibComputeGraph::Ref; + static bool is_single_output(IdString type) + { + auto it = yosys_celltypes.cell_types.find(type); + return it != yosys_celltypes.cell_types.end() && it->second.outputs.size() <= 1; + } + T node(SExpr &&expr, int width, std::initializer_list args) { + return graph.add(Node(std::move(expr), width), 0, args); + } + T shift(const char *name, T a, T b, int y_width, int b_width, bool a_signed = false) { + int width = max(y_width, b_width); + T a_ = y_width < width ? extend(a, y_width, width, a_signed) : a; + T b_ = b_width < width ? extend(b, b_width, width, false) : b; + T y_ = node(SExpr {name, Arg(1), Arg(2)}, width, {a_, b_}); + if(y_width < width) + return slice(y_, width, 0, y_width); + else + return y_; + } + SExpr from_bool(SExpr &&arg) { + return SExpr{"ite", std::move(arg), RTLIL::Const(State::S1), RTLIL::Const(State::S0)}; + } + SExpr to_bool(SExpr &&arg) { + return SExpr{"=", std::move(arg), RTLIL::Const(State::S1)}; + } + SExpr extract(SExpr &&arg, int offset, int out_width) { + return SExpr {SExpr {"_", "extract", offset + out_width - 1, offset}, std::move(arg)}; + } +public: + SmtlibComputeGraphFactory(SmtlibModule &mod) : module(mod), graph(mod.compute_graph) {} + T slice(T a, int in_width, int offset, int out_width) { + assert(offset + out_width <= in_width); + return node(extract(Arg(1), offset, out_width), out_width, {a}); + } + T extend(T a, int in_width, int out_width, bool is_signed) { + assert(in_width < out_width); + if(is_signed) + return node(SExpr {SExpr {"_", "sign_extend", out_width - in_width}, Arg(1)}, out_width, {a}); + else + return node(SExpr {SExpr {"_", "zero_extend", out_width - in_width}, Arg(1)}, out_width, {a}); + } + T concat(T a, int a_width, T b, int b_width) { + return node(SExpr {"concat", Arg(1), Arg(2)}, a_width + b_width, {a, b}); + } + T add(T a, T b, int width) { return node(SExpr {"bvadd", Arg(1), Arg(2)}, width, {a, b}); } + T sub(T a, T b, int width) { return node(SExpr {"bvsub", Arg(1), Arg(2)}, width, {a, b}); } + T bitwise_and(T a, T b, int width) { return node(SExpr {"bvand", Arg(1), Arg(2)}, width, {a, b}); } + T bitwise_or(T a, T b, int width) { return node(SExpr {"bvor", Arg(1), Arg(2)}, width, {a, b}); } + T bitwise_xor(T a, T b, int width) { return node(SExpr {"bvxor", Arg(1), Arg(2)}, width, {a, b}); } + T bitwise_not(T a, int width) { return node(SExpr {"bvnot", Arg(1)}, width, {a}); } + T neg(T a, int width) { return node(SExpr {"bvneg", Arg(1)}, width, {a}); } + T mux(T a, T b, T s, int width) { return node(SExpr {"ite", to_bool(Arg(1)), Arg(2), Arg(3)}, width, {s, a, b}); } + T pmux(T a, T b, T s, int width, int s_width) { + T rv = a; + for(int i = 0; i < s_width; i++) + rv = node(SExpr {"ite", to_bool(extract(Arg(1), i, 1)), extract(Arg(2), width * i, width), Arg(3)}, width, {s, b, rv}); + return rv; + } + T reduce_and(T a, int width) { return node(from_bool(SExpr {"=", Arg(1), RTLIL::Const(State::S1, width)}), 1, {a}); } + T reduce_or(T a, int width) { return node(from_bool(SExpr {"distinct", Arg(1), RTLIL::Const(State::S0, width)}), 1, {a}); } + T reduce_xor(T a, int) { return node(SExpr {"reduce_xor", Arg(1)}, 1, {a}); } + T eq(T a, T b, int) { return node(from_bool(SExpr {"=", Arg(1), Arg(2)}), 1, {a, b}); } + T ne(T a, T b, int) { return node(from_bool(SExpr {"distinct", Arg(1), Arg(2)}), 1, {a, b}); } + T gt(T a, T b, int) { return node(from_bool(SExpr {"bvsgt", Arg(1), Arg(2)}), 1, {a, b}); } + T ge(T a, T b, int) { return node(from_bool(SExpr {"bvsge", Arg(1), Arg(2)}), 1, {a, b}); } + T ugt(T a, T b, int) { return node(from_bool(SExpr {"bvugt", Arg(1), Arg(2)}), 1, {a, b}); } + T uge(T a, T b, int) { return node(from_bool(SExpr {"bvuge", Arg(1), Arg(2)}), 1, {a, b}); } + T logical_shift_left(T a, T b, int y_width, int b_width) { return shift("bvshl", a, b, y_width, b_width); } + T logical_shift_right(T a, T b, int y_width, int b_width) { return shift("bvlshl", a, b, y_width, b_width); } + T arithmetic_shift_right(T a, T b, int y_width, int b_width) { return shift("bvashr", a, b, y_width, b_width, true); } + + T constant(RTLIL::Const value) { return node(SExpr(value), value.size(), {}); } + T input(IdString name, int width) { + module.input_struct.insert(name, width); + return node(module.input_struct.access("inputs", name), width, {}); + } + T state(IdString name, int width) { + module.state_struct.insert(name, width); + return node(module.state_struct.access("current_state", name), width, {}); + } + T cell_output(T cell, IdString type, IdString name, int width) { + if (is_single_output(type)) + return cell; + else + return node(SExpr {"cell_output", Arg(1), RTLIL::unescape_id(name)}, width, {cell}); + } + T multiple(vector args, int width) { + vector expr; + expr.reserve(args.size() + 1); + expr.push_back("multiple"); + for(size_t i = 1; i <= args.size(); i++) + expr.push_back(Arg(i)); + return graph.add(Node(SExpr(std::move(expr)), width), 0, args); + } + T undriven(int width) { + return constant(RTLIL::Const(State::S0, width)); + //return node(SExpr {"undriven"}, width, {}); + } + T create_pending(int width) { + return node(SExpr(), width, {}); + } + void update_pending(T pending, T node) { + assert(pending.function().expr.is_none()); + pending.set_function(Node(Arg(1), pending.function().width)); + pending.append_arg(node); + } + void declare_output(T node, IdString name, int width) { + module.output_struct.insert(name, width); + node.assign_key(name); + } + void declare_state(T node, IdString name, int width) { + module.state_struct.insert(name, width); + node.assign_key(name); + } + void suggest_name(T node, IdString name) { + node.sparse_attr() = name; + } +}; + +void SmtlibModule::calculate_compute_graph(RTLIL::Module *module) +{ + SmtlibComputeGraphFactory factory(*this); + ComputeGraphConstruction construction(factory); + construction.add_module(module); + construction.process_queue(); + + // Perform topo sort and detect SCCs + SmtlibComputeGraph::SccAdaptor compute_graph_scc(compute_graph); + + bool scc = false; + std::vector perm; + topo_sorted_sccs(compute_graph_scc, [&](int *begin, int *end) { + perm.insert(perm.end(), begin, end); + if (end > begin + 1) + { + log_warning("SCC:"); + for (int *i = begin; i != end; ++i) + log(" %d", *i); + log("\n"); + scc = true; + } + }, /* sources_first */ true); + compute_graph.permute(perm); + if(scc) log_error("combinational loops, aborting\n"); + + // Forward $$buf + std::vector alias; + perm.clear(); + + for (int i = 0; i < compute_graph.size(); ++i) + { + auto node = compute_graph[i]; + if (node.function().expr == Arg(1) && node.arg(0).index() < i) + { + int target_index = alias[node.arg(0).index()]; + auto target_node = compute_graph[perm[target_index]]; + if(!target_node.has_sparse_attr() && node.has_sparse_attr()) + target_node.sparse_attr() = node.sparse_attr(); + alias.push_back(target_index); + } + else + { + alias.push_back(GetSize(perm)); + perm.push_back(i); + } + } + compute_graph.permute(perm, alias); +} + +void SmtlibModule::write(std::ostream &stream) +{ + SmtlibWriter f(stream); + + idict node_names; + SmtlibScope locals; + int paren_count = 0; + + input_struct.print(f); + output_struct.print(f); + state_struct.print(f); + + f << "(declare-datatypes ((Pair 2)) ((par (X Y) ((pair (first X) (second Y))))))\n"; + f.printf("(define-fun %s_step ((inputs %s_inputs) (current_state %s_state)) (Pair %s_outputs %s_state)\n", + name.c_str(), name.c_str(), name.c_str(), name.c_str(), name.c_str()); + + for (int i = 0; i < compute_graph.size(); ++i) + { + auto ref = compute_graph[i]; + std::string name; + if(ref.has_sparse_attr()) + name = locals.insert(ref.sparse_attr()); + else + name = locals.insert("\\n" + std::to_string(i)); + node_names(name); + vector args; + args.reserve(ref.size()); + for (int i = 0, end = ref.size(); i != end; ++i) + args.push_back(node_names[ref.arg(i).index()]); + f << " (let " << SExpr{{SExpr{name, ref.function().expr.subst_args(args)}}} << "\n"; + paren_count++; + } + dict outputs; + for(auto &a: compute_graph.keys()) + outputs.insert({a.first, node_names[a.second]}); + f.printf(" (pair \n"); + output_struct.print_value(f, outputs, 6); + state_struct.print_value(f, outputs, 6); + f.printf(" )\n"); + while(paren_count > 0){ + int n = min(paren_count, 80); + f << " " << std::string(n, ')') << "\n"; + paren_count -= n; + } + f.printf(")\n"); +} + +struct FunctionalSmtlibBackend : public Backend +{ + FunctionalSmtlibBackend() : Backend("functional_smtlib", "convert design to SMTLIB using the functional backend") {} + + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + } + + void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) override + { + log_header(design, "Executing Functional SMTLIB backend.\n"); + + size_t argidx = 1; + extra_args(f, filename, args, argidx, design); + + for (auto module : design->selected_modules()) { + log("Dumping module `%s'.\n", module->name.c_str()); + SmtlibModule smt(RTLIL::unescape_id(module->name)); + smt.calculate_compute_graph(module); + smt.write(*f); + } + } +} FunctionalSmtlibBackend; + +PRIVATE_NAMESPACE_END diff --git a/kernel/graphtools.h b/kernel/graphtools.h index 1a59ef1b537..adf4764c201 100644 --- a/kernel/graphtools.h +++ b/kernel/graphtools.h @@ -32,7 +32,7 @@ class CellSimplifier { Factory &factory; T reduce_shift_width(T b, int b_width, int y_width, int &reduced_b_width) { log_assert(y_width > 0); - int new_width = sizeof(int) * 8 - __builtin_clz(y_width); + int new_width = ceil_log2(y_width + 1); if (b_width <= new_width) { reduced_b_width = b_width; return b; @@ -221,7 +221,7 @@ class ComputeGraphConstruction { for (auto wire : module->wires()) { if (wire->port_output) { T node = enqueue(DriveChunk(DriveChunkWire(wire, 0, wire->width))); - factory.declare_output(node, wire->name); + factory.declare_output(node, wire->name, wire->width); } } } @@ -273,7 +273,7 @@ class ComputeGraphConstruction { for (auto const &conn : cell->connections()) { if (driver_map.celltypes.cell_input(cell->type, conn.first)) { T node = enqueue(DriveChunkPort(cell, conn)); - factory.declare_state(node, cell->name); + factory.declare_state(node, cell->name, port_chunk.width); } } } From a852d0c4cad8506101a18760ae2cdcfe93364880 Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Fri, 24 May 2024 12:17:10 +0200 Subject: [PATCH 12/51] Some missing includes --- backends/functional/cxx.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backends/functional/cxx.cc b/backends/functional/cxx.cc index c0444e7fe5a..5038a9af252 100644 --- a/backends/functional/cxx.cc +++ b/backends/functional/cxx.cc @@ -17,6 +17,8 @@ * */ +#include +#include #include "kernel/yosys.h" #include "kernel/drivertools.h" #include "kernel/topo_scc.h" From 596f6dee7b8f13ce20aa6cdf33c375c305277dc8 Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Fri, 24 May 2024 12:21:26 +0200 Subject: [PATCH 13/51] Move Driver* implementation to drivertools.cc --- kernel/drivertools.cc | 2633 ++++++++++++++++++++++++++++++----------- kernel/drivertools.h | 1639 +++++++------------------ 2 files changed, 2396 insertions(+), 1876 deletions(-) diff --git a/kernel/drivertools.cc b/kernel/drivertools.cc index 9627a467015..c3936277978 100644 --- a/kernel/drivertools.cc +++ b/kernel/drivertools.cc @@ -21,929 +21,2190 @@ YOSYS_NAMESPACE_BEGIN +DriveBitWire::DriveBitWire(Wire *wire, int offset) : wire(wire), offset(offset) {} + +bool DriveBitWire::operator==(const DriveBitWire &other) const +{ + return wire == other.wire && offset == other.offset; +} + +bool DriveBitWire::operator<(const DriveBitWire &other) const +{ + if (wire != other.wire) + return wire->name < other.wire->name; + return offset < other.offset; +} + +unsigned int DriveBitWire::hash() const +{ + return mkhash_add(wire->name.hash(), offset); +} + +DriveBitWire::operator SigBit() const +{ + return SigBit(wire, offset); +} + +DriveBitPort::DriveBitPort(Cell *cell, IdString port, int offset) + : cell(cell), port(port), offset(offset) {} + +bool DriveBitPort::operator==(const DriveBitPort &other) const +{ + return cell == other.cell && port == other.port && offset == other.offset; +} + +bool DriveBitPort::operator<(const DriveBitPort &other) const +{ + if (cell != other.cell) + return cell->name < other.cell->name; + if (port != other.port) + return port < other.port; + return offset < other.offset; +} + +unsigned int DriveBitPort::hash() const +{ + return mkhash_add(mkhash(cell->name.hash(), port.hash()), offset); +} + +DriveBitMarker::DriveBitMarker(int marker, int offset) : marker(marker), offset(offset) {} + +bool DriveBitMarker::operator==(const DriveBitMarker &other) const +{ + return marker == other.marker && offset == other.offset; +} + +bool DriveBitMarker::operator<(const DriveBitMarker &other) const +{ + if (marker != other.marker) + return marker < other.marker; + return offset < other.offset; +} + +unsigned int DriveBitMarker::hash() const +{ + return mkhash_add(marker, offset); +} + DriveBit::DriveBit(SigBit const &bit) { - if (bit.is_wire()) - *this = DriveBitWire(bit.wire, bit.offset); - else - *this = bit.data; + if (bit.is_wire()) + *this = DriveBitWire(bit.wire, bit.offset); + else + *this = bit.data; +} + +void DriveBit::merge(DriveBit const &other) +{ + if (other.type_ == DriveType::NONE) + return; + if (type_ == DriveType::NONE) { + *this = other; + return; + } + if (type_ != DriveType::MULTIPLE) { + DriveBitMultiple multi(std::move(*this)); + *this = std::move(multi); + } + multiple().merge(other); +} + +DriveBitMultiple::DriveBitMultiple() {} + +DriveBitMultiple::DriveBitMultiple(DriveBit const &single) +{ + multiple_.emplace(single); +} + +pool const &DriveBitMultiple::multiple() const +{ + return multiple_; +} + +void DriveBitMultiple::merge(DriveBitMultiple const &other) +{ + for (DriveBit const &single : other.multiple_) + merge(single); +} + +void DriveBitMultiple::merge(DriveBitMultiple &&other) +{ + for (DriveBit &single : other.multiple_) + merge(std::move(single)); +} + +void DriveBitMultiple::merge(DriveBit const &single) +{ + multiple_.emplace(single); +} + +void DriveBitMultiple::merge(DriveBit &&single) +{ + multiple_.emplace(std::move(single)); +} + +bool DriveBitMultiple::operator==(const DriveBitMultiple &other) const +{ + return multiple_ == other.multiple_; +} + +unsigned int DriveBitMultiple::hash() const +{ + return multiple_.hash(); +} + +DriveBit::DriveBit() {} + +DriveBit::DriveBit(DriveBit const &other) +{ + *this = other; +} + +DriveBit::DriveBit(DriveBit &&other) +{ + *this = std::move(other); +} + +DriveBit::DriveBit(State constant) +{ + *this = constant; +} + +DriveBit::DriveBit(DriveBitWire const &wire) +{ + *this = wire; +} + +DriveBit::DriveBit(DriveBitWire &&wire) +{ + *this = std::move(wire); +} + +DriveBit::DriveBit(DriveBitPort const &port) +{ + *this = port; +} + +DriveBit::DriveBit(DriveBitPort &&port) +{ + *this = std::move(port); +} + +DriveBit::DriveBit(DriveBitMarker const &marker) +{ + *this = marker; +} + +DriveBit::DriveBit(DriveBitMarker &&marker) +{ + *this = std::move(marker); +} + +DriveBit::DriveBit(DriveBitMultiple const &multiple) +{ + *this = multiple; +} + +DriveBit::DriveBit(DriveBitMultiple &&multiple) +{ + *this = std::move(multiple); +} + +DriveBit::~DriveBit() +{ + set_none(); +} + +void DriveBit::set_none() +{ + switch (type_) + { + case DriveType::NONE: + break; + case DriveType::CONSTANT: + break; + case DriveType::WIRE: + wire_.~DriveBitWire(); + break; + case DriveType::PORT: + port_.~DriveBitPort(); + break; + case DriveType::MARKER: + marker_.~DriveBitMarker(); + break; + case DriveType::MULTIPLE: + multiple_.~DriveBitMultiple(); + break; + } + type_ = DriveType::NONE; +} + +DriveBit &DriveBit::operator=(DriveBit const &other) +{ + switch (other.type_) + { + case DriveType::NONE: + set_none(); + break; + case DriveType::CONSTANT: + *this = other.constant_; + break; + case DriveType::WIRE: + *this = other.wire_; + break; + case DriveType::PORT: + *this = other.port_; + break; + case DriveType::MARKER: + *this = other.marker_; + break; + case DriveType::MULTIPLE: + *this = other.multiple_; + break; + } + return *this; +} + +DriveBit &DriveBit::operator=(DriveBit &&other) +{ + switch (other.type_) + { + case DriveType::NONE: + set_none(); + break; + case DriveType::CONSTANT: + *this = std::move(other.constant_); + break; + case DriveType::WIRE: + *this = std::move(other.wire_); + break; + case DriveType::PORT: + *this = std::move(other.port_); + break; + case DriveType::MARKER: + *this = std::move(other.marker_); + break; + case DriveType::MULTIPLE: + *this = std::move(other.multiple_); + break; + } + return *this; +} + +DriveBit &DriveBit::operator=(State constant) +{ + set_none(); + constant_ = constant; + type_ = DriveType::CONSTANT; + return *this; +} + +DriveBit &DriveBit::operator=(DriveBitWire const &wire) +{ + set_none(); + new (&wire_) DriveBitWire(wire); + type_ = DriveType::WIRE; + return *this; +} + +DriveBit &DriveBit::operator=(DriveBitWire &&wire) +{ + set_none(); + new (&wire_) DriveBitWire(std::move(wire)); + type_ = DriveType::WIRE; + return *this; +} + +DriveBit &DriveBit::operator=(DriveBitPort const &port) +{ + set_none(); + new (&port_) DriveBitPort(port); + type_ = DriveType::PORT; + return *this; +} + +DriveBit &DriveBit::operator=(DriveBitPort &&port) +{ + set_none(); + new (&port_) DriveBitPort(std::move(port)); + type_ = DriveType::PORT; + return *this; +} + +DriveBit &DriveBit::operator=(DriveBitMarker const &marker) +{ + set_none(); + new (&marker_) DriveBitMarker(marker); + type_ = DriveType::MARKER; + return *this; +} + +DriveBit &DriveBit::operator=(DriveBitMarker &&marker) +{ + set_none(); + new (&marker_) DriveBitMarker(std::move(marker)); + type_ = DriveType::MARKER; + return *this; +} + +DriveBit &DriveBit::operator=(DriveBitMultiple const &multiple) +{ + set_none(); + if (multiple.multiple().empty()) + return *this; + new (&multiple_) DriveBitMultiple(multiple); + type_ = DriveType::MULTIPLE; + return *this; +} + +DriveBit &DriveBit::operator=(DriveBitMultiple &&multiple) +{ + set_none(); + if (multiple.multiple().empty()) + return *this; + new (&multiple_) DriveBitMultiple(std::move(multiple)); + type_ = DriveType::MULTIPLE; + return *this; +} + +unsigned int DriveBit::hash() const +{ + unsigned int inner; + switch (type_) + { + case DriveType::NONE: + inner = 0; + break; + case DriveType::CONSTANT: + inner = constant_; + break; + case DriveType::WIRE: + inner = wire_.hash(); + break; + case DriveType::PORT: + inner = port_.hash(); + break; + case DriveType::MARKER: + inner = marker_.hash(); + break; + case DriveType::MULTIPLE: + inner = multiple_.hash(); + break; + } + return mkhash((unsigned int)type_, inner); +} + +bool DriveBit::operator==(const DriveBit &other) const +{ + if (type_ != other.type_) + return false; + + switch (type_) + { + case DriveType::NONE: + return true; + case DriveType::CONSTANT: + return constant_ == other.constant_; + case DriveType::WIRE: + return wire_ == other.wire_; + case DriveType::PORT: + return port_ == other.port_; + case DriveType::MARKER: + return marker_ == other.marker_; + case DriveType::MULTIPLE: + return multiple_ == other.multiple_; + } + log_assert(false); +} + +bool DriveBit::operator!=(const DriveBit &other) const +{ + return !(*this == other); +} + +bool DriveBit::operator<(const DriveBit &other) const +{ + if (type_ != other.type_) + return type_ < other.type_; + switch (type_) + { + case DriveType::NONE: + return false; + case DriveType::CONSTANT: + return constant_ < other.constant_; + case DriveType::WIRE: + return wire_ < other.wire_; + case DriveType::PORT: + return port_ < other.port_; + case DriveType::MARKER: + return marker_ < other.marker_; + case DriveType::MULTIPLE: + log_assert(!"TODO"); + } + log_abort(); +} + +DriveType DriveBit::type() const +{ + return type_; +} + +bool DriveBit::is_none() const +{ + return type_ == DriveType::NONE; +} + +bool DriveBit::is_constant() const +{ + return type_ == DriveType::CONSTANT; +} + +bool DriveBit::is_wire() const +{ + return type_ == DriveType::WIRE; +} + +bool DriveBit::is_port() const +{ + return type_ == DriveType::PORT; +} + +bool DriveBit::is_marker() const +{ + return type_ == DriveType::MARKER; +} + +bool DriveBit::is_multiple() const +{ + return type_ == DriveType::MULTIPLE; +} + +State &DriveBit::constant() +{ + log_assert(is_constant()); + return constant_; +} + +State const &DriveBit::constant() const +{ + log_assert(is_constant()); + return constant_; +} + +DriveBitWire &DriveBit::wire() +{ + log_assert(is_wire()); + return wire_; +} + +DriveBitWire const &DriveBit::wire() const +{ + log_assert(is_wire()); + return wire_; +} + +DriveBitPort &DriveBit::port() +{ + log_assert(is_port()); + return port_; +} + +DriveBitPort const &DriveBit::port() const +{ + log_assert(is_port()); + return port_; +} + +DriveBitMarker &DriveBit::marker() +{ + log_assert(is_marker()); + return marker_; +} + +DriveBitMarker const &DriveBit::marker() const +{ + log_assert(is_marker()); + return marker_; +} + +DriveBitMultiple &DriveBit::multiple() +{ + log_assert(is_multiple()); + return multiple_; +} + +DriveBitMultiple const &DriveBit::multiple() const +{ + log_assert(is_multiple()); + return multiple_; +} + +DriveBitMultiple DriveChunkMultiple::operator[](int i) const +{ + DriveBitMultiple result; + for (auto const &single : multiple_) + result.merge(single[i]); + return result; +} + +DriveChunkWire::DriveChunkWire(Wire *wire, int offset, int width) + : wire(wire), offset(offset), width(width) {} + +DriveChunkWire::DriveChunkWire(DriveBitWire const &bit) + : wire(bit.wire), offset(bit.offset), width(1) {} + +int DriveChunkWire::size() const { return width; } + +DriveBitWire DriveChunkWire::operator[](int i) const +{ + log_assert(i >= 0 && i < width); + return DriveBitWire(wire, offset + i); +} + +bool DriveChunkWire::is_whole() const +{ + return offset == 0 && width == wire->width; +} + +bool DriveChunkWire::operator==(const DriveChunkWire &other) const +{ + return wire == other.wire && offset == other.offset && width == other.width; +} + +bool DriveChunkWire::operator<(const DriveChunkWire &other) const +{ + if (wire != other.wire) + return wire->name < other.wire->name; + if (width != other.width) + return width < other.width; + return offset < other.offset; +} + +unsigned int DriveChunkWire::hash() const +{ + return mkhash_add(mkhash(wire->name.hash(), width), offset); +} + +DriveChunkWire::operator SigChunk() const +{ + return SigChunk(wire, offset, width); +} + +bool DriveChunkWire::can_append(DriveBitWire const &bit) const +{ + return bit.wire == wire && bit.offset == offset + width; +} + + + +bool DriveChunkWire::try_append(DriveBitWire const &bit) +{ + if (!can_append(bit)) + return false; + width += 1; + return true; +} + +bool DriveChunkWire::try_append(DriveChunkWire const &chunk) +{ + if (chunk.wire != wire || chunk.offset != offset + width) + return false; + width += chunk.width; + return true; +} + + + +bool DriveChunkPort::can_append(DriveBitPort const &bit) const +{ + return bit.cell == cell && bit.port == port && bit.offset == offset + width; +} + +bool DriveChunkPort::try_append(DriveBitPort const &bit) +{ + if (!can_append(bit)) + return false; + width += 1; + return true; +} + +bool DriveChunkPort::try_append(DriveChunkPort const &chunk) +{ + if (chunk.cell != cell || chunk.port != port || chunk.offset != offset + width) + return false; + width += chunk.width; + return true; +} + +DriveChunkPort::DriveChunkPort(Cell *cell, IdString port, int offset, int width) + : cell(cell), port(port), offset(offset), width(width) {} + +DriveChunkPort::DriveChunkPort(Cell *cell, IdString port) + : cell(cell), port(port), offset(0), width(GetSize(cell->connections().at(port))) {} + +DriveChunkPort::DriveChunkPort(Cell *cell, std::pair const &conn) + : cell(cell), port(conn.first), offset(0), width(GetSize(conn.second)) {} + +DriveChunkPort::DriveChunkPort(DriveBitPort const &bit) + : cell(bit.cell), port(bit.port), offset(bit.offset), width(1) {} + +int DriveChunkPort::size() const { return width; } + +DriveBitPort DriveChunkPort::operator[](int i) const +{ + log_assert(i >= 0 && i < width); + return DriveBitPort(cell, port, offset + i); +} + +bool DriveChunkPort::is_whole() const +{ + return offset == 0 && width == cell->connections().at(port).size(); +} + +bool DriveChunkPort::operator==(const DriveChunkPort &other) const +{ + return cell == other.cell && port == other.port && offset == other.offset && width == other.width; +} + +bool DriveChunkPort::operator<(const DriveChunkPort &other) const +{ + if (cell != other.cell) + return cell->name < other.cell->name; + if (port != other.port) + return port < other.port; + if (width != other.width) + return width < other.width; + return offset < other.offset; +} + +unsigned int DriveChunkPort::hash() const +{ + return mkhash_add(mkhash(mkhash(cell->name.hash(), port.hash()), width), offset); +} + +bool DriveChunkMarker::can_append(DriveBitMarker const &bit) const +{ + return bit.marker == marker && bit.offset == offset + width; +} + +bool DriveChunkMarker::try_append(DriveBitMarker const &bit) +{ + if (!can_append(bit)) + return false; + width += 1; + return true; +} + +bool DriveChunkMarker::try_append(DriveChunkMarker const &chunk) +{ + if (chunk.marker != marker || chunk.offset != offset + width) + return false; + width += chunk.width; + return true; +} + +DriveChunkMarker::DriveChunkMarker(int marker, int offset, int width) + : marker(marker), offset(offset), width(width) {} + +DriveChunkMarker::DriveChunkMarker(DriveBitMarker const &bit) + : marker(bit.marker), offset(bit.offset), width(1) {} + +int DriveChunkMarker::size() const { return width; } + +DriveBitMarker DriveChunkMarker::operator[](int i) const +{ + log_assert(i >= 0 && i < width); + return DriveBitMarker(marker, offset + i); +} + +bool DriveChunkMarker::operator==(const DriveChunkMarker &other) const +{ + return marker == other.marker && offset == other.offset && width == other.width; +} + +bool DriveChunkMarker::operator<(const DriveChunkMarker &other) const +{ + if (marker != other.marker) + return marker < other.marker; + if (width != other.width) + return width < other.width; + return offset < other.offset; +} + +unsigned int DriveChunkMarker::hash() const +{ + return mkhash_add(mkhash(marker, width), offset); +} + +bool DriveChunkMultiple::can_append(DriveBitMultiple const &bit) const +{ + if (bit.multiple().size() != multiple_.size()) + return false; + + int const_drivers = 0; + for (DriveChunk const &single : multiple_) + if (single.is_constant()) + const_drivers += 1; + + if (const_drivers > 1) + return false; + + for (DriveBit const &single : bit.multiple()) + if (single.is_constant()) + const_drivers -= 1; + + if (const_drivers != 0) + return false; + + for (DriveChunk const &single : multiple_) + { + switch (single.type()) + { + case DriveType::CONSTANT: { + } break; + case DriveType::WIRE: { + auto const &wire = single.wire(); + DriveBit next = DriveBitWire(wire.wire, wire.offset + wire.width); + if (!bit.multiple().count(next)) + return false; + } break; + case DriveType::PORT: { + auto const &port = single.port(); + DriveBit next = DriveBitPort(port.cell, port.port, port.offset + port.width); + if (!bit.multiple().count(next)) + return false; + } break; + case DriveType::MARKER: { + auto const &marker = single.marker(); + DriveBit next = DriveBitMarker(marker.marker, marker.offset + marker.width); + if (!bit.multiple().count(next)) + return false; + } break; + default: + return false; + } + } + + return true; +} + +bool DriveChunkMultiple::can_append(DriveChunkMultiple const &chunk) const +{ + if (chunk.multiple().size() != multiple_.size()) + return false; + + int const_drivers = 0; + for (DriveChunk const &single : multiple_) + if (single.is_constant()) + const_drivers += 1; + + if (const_drivers > 1) + return false; + + for (DriveChunk const &single : chunk.multiple()) + if (single.is_constant()) + const_drivers -= 1; + + if (const_drivers != 0) + return false; + + for (DriveChunk const &single : multiple_) + { + switch (single.type()) + { + case DriveType::CONSTANT: { + } break; + case DriveType::WIRE: { + auto const &wire = single.wire(); + DriveChunk next = DriveChunkWire(wire.wire, wire.offset + wire.width, chunk.size()); + if (!chunk.multiple().count(next)) + return false; + } break; + case DriveType::PORT: { + auto const &port = single.port(); + DriveChunk next = DriveChunkPort(port.cell, port.port, port.offset + port.width, chunk.size()); + if (!chunk.multiple().count(next)) + return false; + } break; + case DriveType::MARKER: { + auto const &marker = single.marker(); + DriveChunk next = DriveChunkMarker(marker.marker, marker.offset + marker.width, chunk.size()); + if (!chunk.multiple().count(next)) + return false; + } break; + default: + return false; + } + } + + return true; } -void DriveBit::merge(DriveBit const &other) +bool DriveChunkMultiple::try_append(DriveBitMultiple const &bit) { - if (other.type_ == DriveType::NONE) - return; - if (type_ == DriveType::NONE) { - *this = other; - return; + if (!can_append(bit)) + return false; + width_ += 1; + State constant; + + for (DriveBit const &single : bit.multiple()) + if (single.is_constant()) + constant = single.constant(); + + for (DriveChunk &single : multiple_) + { + switch (single.type()) + { + case DriveType::CONSTANT: { + single.constant().bits.push_back(constant); + } break; + case DriveType::WIRE: { + single.wire().width += 1; + } break; + case DriveType::PORT: { + single.port().width += 1; + } break; + case DriveType::MARKER: { + single.marker().width += 1; + } break; + default: + log_abort(); } - if (type_ != DriveType::MULTIPLE) { - DriveBitMultiple multi(std::move(*this)); - *this = std::move(multi); + } + return true; +} + +bool DriveChunkMultiple::try_append(DriveChunkMultiple const &chunk) +{ + if (!can_append(chunk)) + return false; + int width = chunk.size(); + width_ += width; + Const constant; + + for (DriveChunk const &single : chunk.multiple()) + if (single.is_constant()) + constant = single.constant(); + + for (DriveChunk &single : multiple_) + { + switch (single.type()) + { + case DriveType::CONSTANT: { + auto &bits = single.constant().bits; + bits.insert(bits.end(), constant.bits.begin(), constant.bits.end()); + } break; + case DriveType::WIRE: { + single.wire().width += width; + } break; + case DriveType::PORT: { + single.port().width += width; + } break; + case DriveType::MARKER: { + single.marker().width += width; + } break; + default: + log_abort(); } - multiple().merge(other); + } + return true; } +DriveChunkMultiple::DriveChunkMultiple(DriveBitMultiple const &bit) + : width_(1) +{ + for (auto const &bit : bit.multiple()) + multiple_.emplace(bit); +} -void DriveBitMultiple::merge(DriveBit const &single) +pool const &DriveChunkMultiple::multiple() const { - if (single.type() == DriveType::NONE) - return; - if (single.type() == DriveType::MULTIPLE) { - merge(single.multiple()); - return; - } - multiple_.emplace(single); + return multiple_; } -void DriveBitMultiple::merge(DriveBit &&single) +int DriveChunkMultiple::size() const { return width_; } + + +bool DriveChunkMultiple::operator==(const DriveChunkMultiple &other) const { - if (single.type() == DriveType::NONE) - return; - if (single.type() == DriveType::MULTIPLE) { - merge(std::move(single.multiple())); - return; - } - multiple_.emplace(std::move(single)); + return width_ == other.width_ && multiple_ == other.multiple_; } -DriveBitMultiple DriveChunkMultiple::operator[](int i) const +bool DriveChunkMultiple::operator<(const DriveChunkMultiple &other) const { - DriveBitMultiple result; - for (auto const &single : multiple_) - result.merge(single[i]); - return result; + if (multiple_.size() < other.multiple_.size()) + multiple_.sort(); + return false; // TODO: implement, canonicalize order } +unsigned int DriveChunkMultiple::hash() const +{ + return mkhash(width_, multiple_.hash()); +} -bool DriveChunkWire::can_append(DriveBitWire const &bit) const +bool DriveChunk::can_append(DriveBit const &bit) const { - return bit.wire == wire && bit.offset == offset + width; + if (size() == 0) + return true; + if (bit.type() != type_) + return false; + switch (type_) + { + case DriveType::NONE: + return true; + case DriveType::CONSTANT: + return true; + case DriveType::WIRE: + return wire_.can_append(bit.wire()); + case DriveType::PORT: + return port_.can_append(bit.port()); + case DriveType::MULTIPLE: + return multiple_.can_append(bit.multiple()); + default: + log_abort(); + } } -bool DriveChunkWire::try_append(DriveBitWire const &bit) +bool DriveChunk::try_append(DriveBit const &bit) { - if (!can_append(bit)) - return false; - width += 1; - return true; + if (size() == 0) + *this = bit; + if (bit.type() != type_) + return false; + switch (type_) + { + case DriveType::NONE: + none_ += 1; + return true; + case DriveType::CONSTANT: + constant_.bits.push_back(bit.constant()); + return true; + case DriveType::WIRE: + return wire_.try_append(bit.wire()); + case DriveType::PORT: + return port_.try_append(bit.port()); + case DriveType::MULTIPLE: + return multiple_.try_append(bit.multiple()); + default: + log_abort(); + } } -bool DriveChunkWire::try_append(DriveChunkWire const &chunk) + +bool DriveChunk::try_append(DriveChunk const &chunk) { - if (chunk.wire != wire || chunk.offset != offset + width) - return false; - width += chunk.width; - return true; + if (size() == 0) + *this = chunk; + if (chunk.type_ != type_) + return false; + switch (type_) + { + case DriveType::NONE: + none_ += chunk.none_; + return true; + case DriveType::CONSTANT: + constant_.bits.insert(constant_.bits.end(), chunk.constant_.bits.begin(), chunk.constant_.bits.end()); + return true; + case DriveType::WIRE: + return wire_.try_append(chunk.wire()); + case DriveType::PORT: + return port_.try_append(chunk.port()); + case DriveType::MARKER: + return marker_.try_append(chunk.marker()); + case DriveType::MULTIPLE: + return multiple_.try_append(chunk.multiple()); + } + log_abort(); } -bool DriveChunkPort::can_append(DriveBitPort const &bit) const +DriveChunk::DriveChunk() { set_none(); } + +DriveChunk::DriveChunk(DriveChunk const &other) { *this = other; } + +DriveChunk::DriveChunk(DriveChunk &&other) { *this = std::move(other); } + +DriveChunk::DriveChunk(DriveBit const &other) { *this = other; } + +DriveChunk::DriveChunk(Const const &constant) { *this = constant; } + +DriveChunk::DriveChunk(Const &&constant) { *this = std::move(constant); } + +DriveChunk::DriveChunk(DriveChunkWire const &wire) { *this = wire; } + +DriveChunk::DriveChunk(DriveChunkWire &&wire) { *this = std::move(wire); } + +DriveChunk::DriveChunk(DriveChunkPort const &port) { *this = port; } + +DriveChunk::DriveChunk(DriveChunkPort &&port) { *this = std::move(port); } + +DriveChunk::DriveChunk(DriveChunkMarker const &marker) { *this = marker; } + +DriveChunk::DriveChunk(DriveChunkMarker &&marker) { *this = std::move(marker); } + +DriveChunk::DriveChunk(DriveChunkMultiple const &multiple) { *this = multiple; } + +DriveChunk::DriveChunk(DriveChunkMultiple &&multiple) { *this = std::move(multiple); } + +DriveChunk::~DriveChunk() { set_none(); } + +DriveBit DriveChunk::operator[](int i) const { - return bit.cell == cell && bit.port == port && bit.offset == offset + width; + switch (type_) + { + case DriveType::NONE: + return DriveBit(); + case DriveType::CONSTANT: + return constant_[i]; + case DriveType::WIRE: + return wire_[i]; + case DriveType::PORT: + return port_[i]; + case DriveType::MARKER: + return marker_[i]; + case DriveType::MULTIPLE: + return multiple_[i]; + } + log_abort(); } -bool DriveChunkPort::try_append(DriveBitPort const &bit) +void DriveChunk::set_none(int width) { - if (!can_append(bit)) - return false; - width += 1; - return true; + switch (type_) + { + case DriveType::NONE: + none_ = width; + break; + case DriveType::CONSTANT: + constant_.~Const(); + break; + case DriveType::WIRE: + wire_.~DriveChunkWire(); + break; + case DriveType::PORT: + port_.~DriveChunkPort(); + break; + case DriveType::MARKER: + marker_.~DriveChunkMarker(); + break; + case DriveType::MULTIPLE: + multiple_.~DriveChunkMultiple(); + break; + } + type_ = DriveType::NONE; + none_ = width; } -bool DriveChunkPort::try_append(DriveChunkPort const &chunk) +DriveChunk &DriveChunk::operator=(DriveChunk const &other) { - if (chunk.cell != cell || chunk.port != port || chunk.offset != offset + width) - return false; - width += chunk.width; - return true; + switch (other.type_) + { + case DriveType::NONE: + set_none(other.none_); + break; + case DriveType::CONSTANT: + *this = other.constant_; + break; + case DriveType::WIRE: + *this = other.wire_; + break; + case DriveType::PORT: + *this = other.port_; + break; + case DriveType::MARKER: + *this = other.marker_; + break; + case DriveType::MULTIPLE: + *this = other.multiple_; + break; + } + return *this; } -bool DriveChunkMarker::can_append(DriveBitMarker const &bit) const +DriveChunk &DriveChunk::operator=(DriveChunk &&other) { - return bit.marker == marker && bit.offset == offset + width; + switch (other.type_) + { + case DriveType::NONE: + set_none(other.none_); + break; + case DriveType::CONSTANT: + *this = std::move(other.constant_); + break; + case DriveType::WIRE: + *this = std::move(other.wire_); + break; + case DriveType::PORT: + *this = std::move(other.port_); + break; + case DriveType::MARKER: + *this = std::move(other.marker_); + break; + case DriveType::MULTIPLE: + *this = std::move(other.multiple_); + break; + } + return *this; } -bool DriveChunkMarker::try_append(DriveBitMarker const &bit) +DriveChunk &DriveChunk::operator=(Const const &constant) { - if (!can_append(bit)) - return false; - width += 1; - return true; + set_none(); + new (&constant_) Const(constant); + type_ = DriveType::CONSTANT; + return *this; } -bool DriveChunkMarker::try_append(DriveChunkMarker const &chunk) +DriveChunk &DriveChunk::operator=(Const &&constant) { - if (chunk.marker != marker || chunk.offset != offset + width) - return false; - width += chunk.width; - return true; + set_none(); + new (&constant_) Const(std::move(constant)); + type_ = DriveType::CONSTANT; + return *this; } +DriveChunk &DriveChunk::operator=(DriveChunkWire const &wire) +{ + set_none(); + new (&wire_) DriveChunkWire(wire); + type_ = DriveType::WIRE; + return *this; +} -bool DriveChunkMultiple::can_append(DriveBitMultiple const &bit) const +DriveChunk &DriveChunk::operator=(DriveChunkWire &&wire) +{ + set_none(); + new (&wire_) DriveChunkWire(std::move(wire)); + type_ = DriveType::WIRE; + return *this; +} + +DriveChunk &DriveChunk::operator=(DriveChunkPort const &port) +{ + set_none(); + new (&port_) DriveChunkPort(port); + type_ = DriveType::PORT; + return *this; +} + +DriveChunk &DriveChunk::operator=(DriveChunkPort &&port) +{ + set_none(); + new (&port_) DriveChunkPort(std::move(port)); + type_ = DriveType::PORT; + return *this; +} + +DriveChunk &DriveChunk::operator=(DriveChunkMarker const &marker) { - if (bit.multiple().size() != multiple_.size()) - return false; + set_none(); + new (&marker_) DriveChunkMarker(marker); + type_ = DriveType::MARKER; + return *this; +} - int const_drivers = 0; - for (DriveChunk const &single : multiple_) - if (single.is_constant()) - const_drivers += 1; +DriveChunk &DriveChunk::operator=(DriveChunkMarker &&marker) +{ + set_none(); + new (&marker_) DriveChunkMarker(std::move(marker)); + type_ = DriveType::MARKER; + return *this; +} - if (const_drivers > 1) - return false; +DriveChunk &DriveChunk::operator=(DriveChunkMultiple const &multiple) +{ + set_none(multiple.size()); + if (multiple.multiple().empty()) + return *this; + new (&multiple_) DriveChunkMultiple(multiple); + type_ = DriveType::MULTIPLE; + return *this; +} - for (DriveBit const &single : bit.multiple()) - if (single.is_constant()) - const_drivers -= 1; +DriveChunk &DriveChunk::operator=(DriveChunkMultiple &&multiple) +{ + set_none(multiple.size()); + if (multiple.multiple().empty()) + return *this; + new (&multiple_) DriveChunkMultiple(std::move(multiple)); + type_ = DriveType::MULTIPLE; + return *this; +} - if (const_drivers != 0) - return false; +DriveChunk &DriveChunk::operator=(DriveBit const &other) +{ + switch (other.type()) + { + case DriveType::NONE: + set_none(1); + break; + case DriveType::CONSTANT: + *this = Const(other.constant()); + break; + case DriveType::WIRE: + *this = DriveChunkWire(other.wire()); + break; + case DriveType::PORT: + *this = DriveChunkPort(other.port()); + break; + case DriveType::MARKER: + *this = DriveChunkMarker(other.marker()); + break; + case DriveType::MULTIPLE: + *this = DriveChunkMultiple(other.multiple()); + break; + } + return *this; +} - for (DriveChunk const &single : multiple_) - { - switch (single.type()) - { - case DriveType::CONSTANT: { - } break; - case DriveType::WIRE: { - auto const &wire = single.wire(); - DriveBit next = DriveBitWire(wire.wire, wire.offset + wire.width); - if (!bit.multiple().count(next)) - return false; - } break; - case DriveType::PORT: { - auto const &port = single.port(); - DriveBit next = DriveBitPort(port.cell, port.port, port.offset + port.width); - if (!bit.multiple().count(next)) - return false; - } break; - case DriveType::MARKER: { - auto const &marker = single.marker(); - DriveBit next = DriveBitMarker(marker.marker, marker.offset + marker.width); - if (!bit.multiple().count(next)) - return false; - } break; - default: - return false; - } - } +unsigned int DriveChunk::hash() const +{ + unsigned int inner; + switch (type_) + { + case DriveType::NONE: + inner = 0; + break; + case DriveType::CONSTANT: + inner = constant_.hash(); + break; + case DriveType::WIRE: + inner = wire_.hash(); + break; + case DriveType::PORT: + inner = port_.hash(); + break; + case DriveType::MARKER: + inner = marker_.hash(); + break; + case DriveType::MULTIPLE: + inner = multiple_.hash(); + break; + } + return mkhash((unsigned int)type_, inner); +} - return true; +bool DriveChunk::operator==(const DriveChunk &other) const +{ + if (type_ != other.type_) + return false; + + switch (type_) + { + case DriveType::NONE: + return true; + case DriveType::CONSTANT: + return constant_ == other.constant_; + case DriveType::WIRE: + return wire_ == other.wire_; + case DriveType::PORT: + return port_ == other.port_; + case DriveType::MARKER: + return marker_ == other.marker_; + case DriveType::MULTIPLE: + return multiple_ == other.multiple_; + } + log_assert(false); } -bool DriveChunkMultiple::can_append(DriveChunkMultiple const &chunk) const +bool DriveChunk::operator!=(const DriveChunk &other) const +{ + return !(*this == other); +} + +bool DriveChunk::operator<(const DriveChunk &other) const { - if (chunk.multiple().size() != multiple_.size()) - return false; + if (type_ != other.type_) + return type_ < other.type_; + switch (type_) + { + case DriveType::NONE: + return false; + case DriveType::CONSTANT: + return constant_ < other.constant_; + case DriveType::WIRE: + return wire_ < other.wire_; + case DriveType::PORT: + return port_ < other.port_; + case DriveType::MARKER: + return marker_ < other.marker_; + case DriveType::MULTIPLE: + return multiple_ < other.multiple_; + } + log_assert(false); +} - int const_drivers = 0; - for (DriveChunk const &single : multiple_) - if (single.is_constant()) - const_drivers += 1; +DriveType DriveChunk::type() const { return type_; } - if (const_drivers > 1) - return false; +bool DriveChunk::is_none() const { return type_ == DriveType::NONE; } - for (DriveChunk const &single : chunk.multiple()) - if (single.is_constant()) - const_drivers -= 1; +bool DriveChunk::is_constant() const { return type_ == DriveType::CONSTANT; } - if (const_drivers != 0) - return false; +bool DriveChunk::is_wire() const { return type_ == DriveType::WIRE; } - for (DriveChunk const &single : multiple_) - { - switch (single.type()) - { - case DriveType::CONSTANT: { - } break; - case DriveType::WIRE: { - auto const &wire = single.wire(); - DriveChunk next = DriveChunkWire(wire.wire, wire.offset + wire.width, chunk.size()); - if (!chunk.multiple().count(next)) - return false; - } break; - case DriveType::PORT: { - auto const &port = single.port(); - DriveChunk next = DriveChunkPort(port.cell, port.port, port.offset + port.width, chunk.size()); - if (!chunk.multiple().count(next)) - return false; - } break; - case DriveType::MARKER: { - auto const &marker = single.marker(); - DriveChunk next = DriveChunkMarker(marker.marker, marker.offset + marker.width, chunk.size()); - if (!chunk.multiple().count(next)) - return false; - } break; - default: - return false; - } - } +bool DriveChunk::is_port() const { return type_ == DriveType::PORT; } + +bool DriveChunk::is_marker() const { return type_ == DriveType::MARKER; } - return true; +bool DriveChunk::is_multiple() const { return type_ == DriveType::MULTIPLE; } + +Const &DriveChunk::constant() +{ + log_assert(is_constant()); + return constant_; } -bool DriveChunkMultiple::try_append(DriveBitMultiple const &bit) +Const const &DriveChunk::constant() const { - if (!can_append(bit)) - return false; - width_ += 1; - State constant; + log_assert(is_constant()); + return constant_; +} - for (DriveBit const &single : bit.multiple()) - if (single.is_constant()) - constant = single.constant(); +DriveChunkWire &DriveChunk::wire() +{ + log_assert(is_wire()); + return wire_; +} - for (DriveChunk &single : multiple_) - { - switch (single.type()) - { - case DriveType::CONSTANT: { - single.constant().bits.push_back(constant); - } break; - case DriveType::WIRE: { - single.wire().width += 1; - } break; - case DriveType::PORT: { - single.port().width += 1; - } break; - case DriveType::MARKER: { - single.marker().width += 1; - } break; - default: - log_abort(); - } - } - return true; +DriveChunkWire const &DriveChunk::wire() const +{ + log_assert(is_wire()); + return wire_; } -bool DriveChunkMultiple::try_append(DriveChunkMultiple const &chunk) +DriveChunkPort &DriveChunk::port() { - if (!can_append(chunk)) - return false; - int width = chunk.size(); - width_ += width; - Const constant; + log_assert(is_port()); + return port_; +} - for (DriveChunk const &single : chunk.multiple()) - if (single.is_constant()) - constant = single.constant(); +DriveChunkPort const &DriveChunk::port() const +{ + log_assert(is_port()); + return port_; +} - for (DriveChunk &single : multiple_) - { - switch (single.type()) - { - case DriveType::CONSTANT: { - auto &bits = single.constant().bits; - bits.insert(bits.end(), constant.bits.begin(), constant.bits.end()); - } break; - case DriveType::WIRE: { - single.wire().width += width; - } break; - case DriveType::PORT: { - single.port().width += width; - } break; - case DriveType::MARKER: { - single.marker().width += width; - } break; - default: - log_abort(); - } - } - return true; +DriveChunkMarker &DriveChunk::marker() +{ + log_assert(is_marker()); + return marker_; } -bool DriveChunk::can_append(DriveBit const &bit) const +DriveChunkMarker const &DriveChunk::marker() const { - if (size() == 0) - return true; - if (bit.type() != type_) - return false; - switch (type_) - { - case DriveType::NONE: - return true; - case DriveType::CONSTANT: - return true; - case DriveType::WIRE: - return wire_.can_append(bit.wire()); - case DriveType::PORT: - return port_.can_append(bit.port()); - case DriveType::MULTIPLE: - return multiple_.can_append(bit.multiple()); - default: - log_abort(); - } + log_assert(is_marker()); + return marker_; } -bool DriveChunk::try_append(DriveBit const &bit) +DriveChunkMultiple &DriveChunk::multiple() { - if (size() == 0) - *this = bit; - if (bit.type() != type_) - return false; - switch (type_) - { - case DriveType::NONE: - none_ += 1; - return true; - case DriveType::CONSTANT: - constant_.bits.push_back(bit.constant()); - return true; - case DriveType::WIRE: - return wire_.try_append(bit.wire()); - case DriveType::PORT: - return port_.try_append(bit.port()); - case DriveType::MULTIPLE: - return multiple_.try_append(bit.multiple()); - default: - log_abort(); - } + log_assert(is_multiple()); + return multiple_; } +DriveChunkMultiple const &DriveChunk::multiple() const +{ + log_assert(is_multiple()); + return multiple_; +} -bool DriveChunk::try_append(DriveChunk const &chunk) +int DriveChunk::size() const { - if (size() == 0) - *this = chunk; - if (chunk.type_ != type_) - return false; - switch (type_) - { - case DriveType::NONE: - none_ += chunk.none_; - return true; - case DriveType::CONSTANT: - constant_.bits.insert(constant_.bits.end(), chunk.constant_.bits.begin(), chunk.constant_.bits.end()); - return true; - case DriveType::WIRE: - return wire_.try_append(chunk.wire()); - case DriveType::PORT: - return port_.try_append(chunk.port()); - case DriveType::MARKER: - return marker_.try_append(chunk.marker()); - case DriveType::MULTIPLE: - return multiple_.try_append(chunk.multiple()); - } - log_abort(); + switch (type_) + { + case DriveType::NONE: + return none_; + case DriveType::CONSTANT: + return constant_.size(); + case DriveType::WIRE: + return wire_.size(); + case DriveType::PORT: + return port_.size(); + case DriveType::MARKER: + return marker_.size(); + case DriveType::MULTIPLE: + return multiple_.size(); + default: + log_assert(false && "unsupported type"); + } } void DriveSpec::append(DriveBit const &bit) { - hash_ = 0; - if (!packed()) { - bits_.push_back(bit); - width_ += 1; - return; - } - - if (chunks_.empty() || !chunks_.back().try_append(bit)) - chunks_.emplace_back(bit); - width_ += 1; + hash_ = 0; + if (!packed()) { + bits_.push_back(bit); + width_ += 1; + return; + } + + if (chunks_.empty() || !chunks_.back().try_append(bit)) + chunks_.emplace_back(bit); + width_ += 1; } void DriveSpec::append(DriveChunk const &chunk) { - hash_ = 0; - pack(); - if (chunks_.empty() || !chunks_.back().try_append(chunk)) - chunks_.emplace_back(chunk); - width_ += chunk.size(); + hash_ = 0; + pack(); + if (chunks_.empty() || !chunks_.back().try_append(chunk)) + chunks_.emplace_back(chunk); + width_ += chunk.size(); } void DriveSpec::pack() const { - if (bits_.empty()) - return; - std::vector bits(std::move(bits_)); - for (auto &bit : bits) - if (chunks_.empty() || !chunks_.back().try_append(bit)) - chunks_.emplace_back(std::move(bit)); + if (bits_.empty()) + return; + std::vector bits(std::move(bits_)); + for (auto &bit : bits) + if (chunks_.empty() || !chunks_.back().try_append(bit)) + chunks_.emplace_back(std::move(bit)); } void DriveSpec::unpack() const { - if (chunks_.empty()) - return; - for (auto &chunk : chunks_) + if (chunks_.empty()) + return; + for (auto &chunk : chunks_) + { + for (int i = 0, width = chunk.size(); i != width; ++i) { - for (int i = 0, width = chunk.size(); i != width; ++i) - { - bits_.emplace_back(chunk[i]); - } + bits_.emplace_back(chunk[i]); } - chunks_.clear(); + } + chunks_.clear(); } void DriveSpec::compute_width() { - width_ = 0; - for (auto const &chunk : chunks_) - width_ += chunk.size(); + width_ = 0; + for (auto const &chunk : chunks_) + width_ += chunk.size(); } -void DriverMap::DriveBitGraph::add_edge(DriveBitId src, DriveBitId dst) + +inline bool DriveSpec::packed() const { - if (first_edges.emplace(src, dst).first->second == dst) - return; - if (second_edges.emplace(src, dst).first->second == dst) - return; - more_edges[src].emplace(dst); + return bits_.empty(); } -DriverMap::DriveBitId DriverMap::DriveBitGraph::pop_edge(DriveBitId src) +DriveSpec::DriveSpec() {} + +DriveSpec::DriveSpec(DriveChunk const &chunk) { - // TODO unused I think? - auto found_more = more_edges.find(src); - if (found_more != more_edges.end()) { - auto result = found_more->second.pop(); - if (found_more->second.empty()) - more_edges.erase(found_more); - return result; - } + *this = chunk; +} - auto found_second = second_edges.find(src); - if (found_second != second_edges.end()) { - auto result = found_second->second; - second_edges.erase(found_second); - return result; - } +DriveSpec::DriveSpec(DriveChunkWire const &chunk) +{ + *this = chunk; +} - auto found_first = first_edges.find(src); - if (found_first != first_edges.end()) { - auto result = found_first->second; - first_edges.erase(found_first); - return result; - } +DriveSpec::DriveSpec(DriveChunkPort const &chunk) +{ + *this = chunk; +} + +DriveSpec::DriveSpec(DriveChunkMarker const &chunk) +{ + *this = chunk; +} + +DriveSpec::DriveSpec(DriveChunkMultiple const &chunk) +{ + *this = chunk; +} + +DriveSpec::DriveSpec(DriveBit const &bit) +{ + *this = bit; +} + +DriveSpec::DriveSpec(DriveBitWire const &bit) +{ + *this = bit; +} + +DriveSpec::DriveSpec(DriveBitPort const &bit) +{ + *this = bit; +} + +DriveSpec::DriveSpec(DriveBitMarker const &bit) +{ + *this = bit; +} + +DriveSpec::DriveSpec(DriveBitMultiple const &bit) +{ + *this = bit; +} + +DriveSpec::DriveSpec(std::vector const &chunks) : chunks_(chunks) +{ + compute_width(); +} + +DriveSpec::DriveSpec(std::vector const &bits) +{ + for (auto const &bit : bits) + append(bit); +} + +std::vector const &DriveSpec::chunks() const +{ + pack(); + return chunks_; +} + +std::vector const &DriveSpec::bits() const +{ + unpack(); + return bits_; +} + +int DriveSpec::size() const +{ + return width_; +} + +DriveBit &DriveSpec::operator[](int index) +{ + log_assert(index >= 0 && index < size()); + unpack(); + return bits_[index]; +} + +const DriveBit &DriveSpec::operator[](int index) const +{ + log_assert(index >= 0 && index < size()); + unpack(); + return bits_[index]; +} + +void DriveSpec::clear() +{ + chunks_.clear(); + bits_.clear(); + width_ = 0; +} + +DriveSpec &DriveSpec::operator=(DriveChunk const &chunk) +{ + chunks_.clear(); + bits_.clear(); + append(chunk); + return *this; +} + +DriveSpec &DriveSpec::operator=(DriveChunkWire const &chunk) +{ + return *this = DriveChunk(chunk); +} + +DriveSpec &DriveSpec::operator=(DriveChunkPort const &chunk) +{ + return *this = DriveChunk(chunk); +} + +DriveSpec &DriveSpec::operator=(DriveChunkMarker const &chunk) +{ + return *this = DriveChunk(chunk); +} + +DriveSpec &DriveSpec::operator=(DriveChunkMultiple const &chunk) +{ + return *this = DriveChunk(chunk); +} + +DriveSpec &DriveSpec::operator=(DriveBit const &bit) +{ + chunks_.clear(); + bits_.clear(); + append(bit); + return *this; +} + +DriveSpec &DriveSpec::operator=(DriveBitWire const &bit) +{ + return *this = DriveBit(bit); +} + +DriveSpec &DriveSpec::operator=(DriveBitPort const &bit) +{ + return *this = DriveBit(bit); +} + +DriveSpec &DriveSpec::operator=(DriveBitMarker const &bit) +{ + return *this = DriveBit(bit); +} + +DriveSpec &DriveSpec::operator=(DriveBitMultiple const &bit) +{ + return *this = DriveBit(bit); +} + +unsigned int DriveSpec::hash() const +{ + if (hash_ != 0) + return hash_; + + pack(); + hash_ = hash_ops>().hash(chunks_); + hash_ |= (hash_ == 0); + return hash_; +} + +bool DriveSpec::operator==(DriveSpec const &other) const +{ + if (size() != other.size() || hash() != other.hash()) + return false; + return chunks() == other.chunks(); +} + +void DriverMap::DriveBitGraph::add_edge(DriveBitId src, DriveBitId dst) +{ + if (first_edges.emplace(src, dst).first->second == dst) + return; + if (second_edges.emplace(src, dst).first->second == dst) + return; + more_edges[src].emplace(dst); +} - return DriveBitId(); +DriverMap::DriveBitId DriverMap::DriveBitGraph::pop_edge(DriveBitId src) +{ + // TODO unused I think? + auto found_more = more_edges.find(src); + if (found_more != more_edges.end()) { + auto result = found_more->second.pop(); + if (found_more->second.empty()) + more_edges.erase(found_more); + return result; + } + + auto found_second = second_edges.find(src); + if (found_second != second_edges.end()) { + auto result = found_second->second; + second_edges.erase(found_second); + return result; + } + + auto found_first = first_edges.find(src); + if (found_first != first_edges.end()) { + auto result = found_first->second; + first_edges.erase(found_first); + return result; + } + + return DriveBitId(); } void DriverMap::DriveBitGraph::clear(DriveBitId src) { - first_edges.erase(src); - second_edges.erase(src); - more_edges.erase(src); + first_edges.erase(src); + second_edges.erase(src); + more_edges.erase(src); } bool DriverMap::DriveBitGraph::contains(DriveBitId src) { - return first_edges.count(src); + return first_edges.count(src); } int DriverMap::DriveBitGraph::count(DriveBitId src) { - if (!first_edges.count(src)) - return 0; - if (!second_edges.count(src)) - return 1; - auto found = more_edges.find(src); - if (found == more_edges.end()) - return 2; - return GetSize(found->second) + 2; + if (!first_edges.count(src)) + return 0; + if (!second_edges.count(src)) + return 1; + auto found = more_edges.find(src); + if (found == more_edges.end()) + return 2; + return GetSize(found->second) + 2; } DriverMap::DriveBitId DriverMap::DriveBitGraph::at(DriveBitId src, int index) { - if (index == 0) - return first_edges.at(src); - else if (index == 1) - return second_edges.at(src); - else - return *more_edges.at(src).element(index - 2); + if (index == 0) + return first_edges.at(src); + else if (index == 1) + return second_edges.at(src); + else + return *more_edges.at(src).element(index - 2); } DriverMap::BitMode DriverMap::bit_mode(DriveBit const &bit) { - switch (bit.type()) - { - case DriveType::NONE: - return BitMode::NONE; - case DriveType::CONSTANT: - // TODO how to handle Sx here? - return bit.constant() == State::Sz ? BitMode::NONE : BitMode::DRIVER; - case DriveType::WIRE: { - auto const &wire = bit.wire(); - bool driver = wire.wire->port_input; - bool driven = wire.wire->port_output; - - if (driver && !driven) - return BitMode::DRIVER; - else if (driven && !driver) - return BitMode::DRIVEN; - else if (driver && driven) - return BitMode::TRISTATE; - else - return keep_wire(bit.wire().wire) ? BitMode::KEEP : BitMode::NONE; - } - case DriveType::PORT: { - auto const &port = bit.port(); - bool driver = celltypes.cell_output(port.cell->type, port.port); - bool driven = celltypes.cell_input(port.cell->type, port.port); - if (driver && !driven) - return BitMode::DRIVER; - else if (driven && !driver) - return BitMode::DRIVEN_UNIQUE; - else - return BitMode::TRISTATE; - } - case DriveType::MARKER: { - // TODO user supplied classification - log_abort(); - } - default: - log_abort(); - } + switch (bit.type()) + { + case DriveType::NONE: + return BitMode::NONE; + case DriveType::CONSTANT: + // TODO how to handle Sx here? + return bit.constant() == State::Sz ? BitMode::NONE : BitMode::DRIVER; + case DriveType::WIRE: { + auto const &wire = bit.wire(); + bool driver = wire.wire->port_input; + bool driven = wire.wire->port_output; + + if (driver && !driven) + return BitMode::DRIVER; + else if (driven && !driver) + return BitMode::DRIVEN; + else if (driver && driven) + return BitMode::TRISTATE; + else + return keep_wire(bit.wire().wire) ? BitMode::KEEP : BitMode::NONE; + } + case DriveType::PORT: { + auto const &port = bit.port(); + bool driver = celltypes.cell_output(port.cell->type, port.port); + bool driven = celltypes.cell_input(port.cell->type, port.port); + if (driver && !driven) + return BitMode::DRIVER; + else if (driven && !driver) + return BitMode::DRIVEN_UNIQUE; + else + return BitMode::TRISTATE; + } + case DriveType::MARKER: { + // TODO user supplied classification + log_abort(); + } + default: + log_abort(); + } } DriverMap::DriveBitId DriverMap::id_from_drive_bit(DriveBit const &bit) { - switch (bit.type()) - { - case DriveType::NONE: - return -1; - case DriveType::CONSTANT: - return (int)bit.constant(); - case DriveType::WIRE: { - auto const &wire_bit = bit.wire(); - int offset = next_offset; - auto insertion = wire_offsets.emplace(wire_bit.wire, offset); - if (insertion.second) { - if (wire_bit.wire->width == 1) { - log_assert(wire_bit.offset == 0); - isolated_drive_bits.emplace(offset, bit); - } else - drive_bits.emplace(offset, DriveBitWire(wire_bit.wire, 0)); - next_offset += wire_bit.wire->width; - } - return insertion.first->second.id + wire_bit.offset; - } - case DriveType::PORT: { - auto const &port_bit = bit.port(); - auto key = std::make_pair(port_bit.cell, port_bit.port); - int offset = next_offset; - auto insertion = port_offsets.emplace(key, offset); - if (insertion.second) { - int width = port_bit.cell->connections().at(port_bit.port).size(); - if (width == 1 && offset == 0) { - log_assert(port_bit.offset == 0); - isolated_drive_bits.emplace(offset, bit); - } else - drive_bits.emplace(offset, DriveBitPort(port_bit.cell, port_bit.port, 0)); - next_offset += width; - } - return insertion.first->second.id + port_bit.offset; - } - default: - log_assert(false && "unsupported DriveType in DriverMap"); - } - log_abort(); + switch (bit.type()) + { + case DriveType::NONE: + return -1; + case DriveType::CONSTANT: + return (int)bit.constant(); + case DriveType::WIRE: { + auto const &wire_bit = bit.wire(); + int offset = next_offset; + auto insertion = wire_offsets.emplace(wire_bit.wire, offset); + if (insertion.second) { + if (wire_bit.wire->width == 1) { + log_assert(wire_bit.offset == 0); + isolated_drive_bits.emplace(offset, bit); + } else + drive_bits.emplace(offset, DriveBitWire(wire_bit.wire, 0)); + next_offset += wire_bit.wire->width; + } + return insertion.first->second.id + wire_bit.offset; + } + case DriveType::PORT: { + auto const &port_bit = bit.port(); + auto key = std::make_pair(port_bit.cell, port_bit.port); + int offset = next_offset; + auto insertion = port_offsets.emplace(key, offset); + if (insertion.second) { + int width = port_bit.cell->connections().at(port_bit.port).size(); + if (width == 1 && offset == 0) { + log_assert(port_bit.offset == 0); + isolated_drive_bits.emplace(offset, bit); + } else + drive_bits.emplace(offset, DriveBitPort(port_bit.cell, port_bit.port, 0)); + next_offset += width; + } + return insertion.first->second.id + port_bit.offset; + } + default: + log_assert(false && "unsupported DriveType in DriverMap"); + } + log_abort(); } DriveBit DriverMap::drive_bit_from_id(DriveBitId id) { - auto found_isolated = isolated_drive_bits.find(id); - if (found_isolated != isolated_drive_bits.end()) - return found_isolated->second; - - auto found = drive_bits.upper_bound(id); - if (found == drive_bits.begin()) { - return id < 0 ? DriveBit() : DriveBit((State) id.id); - } - --found; - DriveBit result = found->second; - if (result.is_wire()) { - result.wire().offset += id.id - found->first.id; - } else { - log_assert(result.is_port()); - result.port().offset += id.id - found->first.id; - } - return result; + auto found_isolated = isolated_drive_bits.find(id); + if (found_isolated != isolated_drive_bits.end()) + return found_isolated->second; + + auto found = drive_bits.upper_bound(id); + if (found == drive_bits.begin()) { + return id < 0 ? DriveBit() : DriveBit((State) id.id); + } + --found; + DriveBit result = found->second; + if (result.is_wire()) { + result.wire().offset += id.id - found->first.id; + } else { + log_assert(result.is_port()); + result.port().offset += id.id - found->first.id; + } + return result; } void DriverMap::connect_directed_merge(DriveBitId driven_id, DriveBitId driver_id) { - if (driven_id == driver_id) - return; + if (driven_id == driver_id) + return; - same_driver.merge(driven_id, driver_id); + same_driver.merge(driven_id, driver_id); - for (int i = 0, end = connected_drivers.count(driven_id); i != end; ++i) - connected_drivers.add_edge(driver_id, connected_drivers.at(driven_id, i)); + for (int i = 0, end = connected_drivers.count(driven_id); i != end; ++i) + connected_drivers.add_edge(driver_id, connected_drivers.at(driven_id, i)); - connected_drivers.clear(driven_id); + connected_drivers.clear(driven_id); - for (int i = 0, end = connected_undirected.count(driven_id); i != end; ++i) - connected_undirected.add_edge(driver_id, connected_undirected.at(driven_id, i)); + for (int i = 0, end = connected_undirected.count(driven_id); i != end; ++i) + connected_undirected.add_edge(driver_id, connected_undirected.at(driven_id, i)); - connected_undirected.clear(driven_id); + connected_undirected.clear(driven_id); } void DriverMap::connect_directed_buffer(DriveBitId driven_id, DriveBitId driver_id) { - connected_drivers.add_edge(driven_id, driver_id); + connected_drivers.add_edge(driven_id, driver_id); } void DriverMap::connect_undirected(DriveBitId a_id, DriveBitId b_id) { - connected_undirected.add_edge(a_id, b_id); - connected_undirected.add_edge(b_id, a_id); + connected_undirected.add_edge(a_id, b_id); + connected_undirected.add_edge(b_id, a_id); } void DriverMap::add(Module *module) { - for (auto const &conn : module->connections()) - add(conn.first, conn.second); + for (auto const &conn : module->connections()) + add(conn.first, conn.second); - for (auto cell : module->cells()) - for (auto const &conn : cell->connections()) - add_port(cell, conn.first, conn.second); + for (auto cell : module->cells()) + for (auto const &conn : cell->connections()) + add_port(cell, conn.first, conn.second); } // Add a single bit connection to the driver map. void DriverMap::add(DriveBit const &a, DriveBit const &b) { - DriveBitId a_id = id_from_drive_bit(a); - DriveBitId b_id = id_from_drive_bit(b); - - DriveBitId orig_a_id = a_id; - DriveBitId orig_b_id = b_id; - - a_id = same_driver.find(a_id); - b_id = same_driver.find(b_id); - - if (a_id == b_id) - return; - - BitMode a_mode = bit_mode(orig_a_id == a_id ? a : drive_bit_from_id(a_id)); - BitMode b_mode = bit_mode(orig_b_id == b_id ? b : drive_bit_from_id(b_id)); - - // If either bit is just a wire that we don't need to keep, merge and - // use the other end as representative bit. - if (a_mode == BitMode::NONE && !(b_mode == BitMode::DRIVEN_UNIQUE || b_mode == BitMode::DRIVEN)) - connect_directed_merge(a_id, b_id); - else if (b_mode == BitMode::NONE && !(a_mode == BitMode::DRIVEN_UNIQUE || a_mode == BitMode::DRIVEN)) - connect_directed_merge(b_id, a_id); - // If either bit requires a driven value and has a unique driver, merge - // and use the other end as representative bit. - else if (a_mode == BitMode::DRIVEN_UNIQUE && !(b_mode == BitMode::DRIVEN_UNIQUE || b_mode == BitMode::DRIVEN)) - connect_directed_buffer(a_id, b_id); - else if (b_mode == BitMode::DRIVEN_UNIQUE && !(a_mode == BitMode::DRIVEN_UNIQUE || a_mode == BitMode::DRIVEN)) - connect_directed_buffer(b_id, a_id); - // If either bit only drives a value, store a directed connection from - // it to the other bit. - else if (a_mode == BitMode::DRIVER) - connect_directed_buffer(b_id, a_id); - else if (b_mode == BitMode::DRIVER) - connect_directed_buffer(a_id, b_id); - // Otherwise we store an undirected connection which we will resolve - // during querying. - else - connect_undirected(a_id, b_id); - - return; + DriveBitId a_id = id_from_drive_bit(a); + DriveBitId b_id = id_from_drive_bit(b); + + DriveBitId orig_a_id = a_id; + DriveBitId orig_b_id = b_id; + + a_id = same_driver.find(a_id); + b_id = same_driver.find(b_id); + + if (a_id == b_id) + return; + + BitMode a_mode = bit_mode(orig_a_id == a_id ? a : drive_bit_from_id(a_id)); + BitMode b_mode = bit_mode(orig_b_id == b_id ? b : drive_bit_from_id(b_id)); + + // If either bit is just a wire that we don't need to keep, merge and + // use the other end as representative bit. + if (a_mode == BitMode::NONE && !(b_mode == BitMode::DRIVEN_UNIQUE || b_mode == BitMode::DRIVEN)) + connect_directed_merge(a_id, b_id); + else if (b_mode == BitMode::NONE && !(a_mode == BitMode::DRIVEN_UNIQUE || a_mode == BitMode::DRIVEN)) + connect_directed_merge(b_id, a_id); + // If either bit requires a driven value and has a unique driver, merge + // and use the other end as representative bit. + else if (a_mode == BitMode::DRIVEN_UNIQUE && !(b_mode == BitMode::DRIVEN_UNIQUE || b_mode == BitMode::DRIVEN)) + connect_directed_buffer(a_id, b_id); + else if (b_mode == BitMode::DRIVEN_UNIQUE && !(a_mode == BitMode::DRIVEN_UNIQUE || a_mode == BitMode::DRIVEN)) + connect_directed_buffer(b_id, a_id); + // If either bit only drives a value, store a directed connection from + // it to the other bit. + else if (a_mode == BitMode::DRIVER) + connect_directed_buffer(b_id, a_id); + else if (b_mode == BitMode::DRIVER) + connect_directed_buffer(a_id, b_id); + // Otherwise we store an undirected connection which we will resolve + // during querying. + else + connect_undirected(a_id, b_id); + + return; } // Specialized version that avoids unpacking void DriverMap::add(SigSpec const &a, SigSpec const &b) { - log_assert(a.size() == b.size()); - auto const &a_chunks = a.chunks(); - auto const &b_chunks = b.chunks(); - - auto a_chunk = a_chunks.begin(); - auto a_end = a_chunks.end(); - int a_offset = 0; - - auto b_chunk = b_chunks.begin(); - int b_offset = 0; - - SigChunk tmp_a, tmp_b; - while (a_chunk != a_end) { - int a_width = a_chunk->width - a_offset; - if (a_width == 0) { - a_offset = 0; - ++a_chunk; - continue; - } - int b_width = b_chunk->width - b_offset; - if (b_width == 0) { - b_offset = 0; - ++b_chunk; - continue; - } - int width = std::min(a_width, b_width); - log_assert(width > 0); - - SigChunk const &a_subchunk = - a_offset == 0 && a_width == width ? *a_chunk : a_chunk->extract(a_offset, width); - SigChunk const &b_subchunk = - b_offset == 0 && b_width == width ? *b_chunk : b_chunk->extract(b_offset, width); - - add(a_subchunk, b_subchunk); - - a_offset += width; - b_offset += width; - } + log_assert(a.size() == b.size()); + auto const &a_chunks = a.chunks(); + auto const &b_chunks = b.chunks(); + + auto a_chunk = a_chunks.begin(); + auto a_end = a_chunks.end(); + int a_offset = 0; + + auto b_chunk = b_chunks.begin(); + int b_offset = 0; + + SigChunk tmp_a, tmp_b; + while (a_chunk != a_end) { + int a_width = a_chunk->width - a_offset; + if (a_width == 0) { + a_offset = 0; + ++a_chunk; + continue; + } + int b_width = b_chunk->width - b_offset; + if (b_width == 0) { + b_offset = 0; + ++b_chunk; + continue; + } + int width = std::min(a_width, b_width); + log_assert(width > 0); + + SigChunk const &a_subchunk = + a_offset == 0 && a_width == width ? *a_chunk : a_chunk->extract(a_offset, width); + SigChunk const &b_subchunk = + b_offset == 0 && b_width == width ? *b_chunk : b_chunk->extract(b_offset, width); + + add(a_subchunk, b_subchunk); + + a_offset += width; + b_offset += width; + } } void DriverMap::add_port(Cell *cell, IdString const &port, SigSpec const &b) { - int offset = 0; - for (auto const &chunk : b.chunks()) { - add(chunk, DriveChunkPort(cell, port, offset, chunk.width)); - offset += chunk.size(); - } + int offset = 0; + for (auto const &chunk : b.chunks()) { + add(chunk, DriveChunkPort(cell, port, offset, chunk.width)); + offset += chunk.size(); + } } void DriverMap::orient_undirected(DriveBitId id) { - pool &seen = orient_undirected_seen; - pool &drivers = orient_undirected_drivers; - dict &distance = orient_undirected_distance; - seen.clear(); - drivers.clear(); + pool &seen = orient_undirected_seen; + pool &drivers = orient_undirected_drivers; + dict &distance = orient_undirected_distance; + seen.clear(); + drivers.clear(); - seen.emplace(id); + seen.emplace(id); - for (int pos = 0; pos < GetSize(seen); ++pos) { - DriveBitId current = *seen.element(seen.size() - 1 - pos); - DriveBit bit = drive_bit_from_id(current); + for (int pos = 0; pos < GetSize(seen); ++pos) { + DriveBitId current = *seen.element(seen.size() - 1 - pos); + DriveBit bit = drive_bit_from_id(current); - BitMode mode = bit_mode(bit); + BitMode mode = bit_mode(bit); - if (mode == BitMode::DRIVER || mode == BitMode::TRISTATE) - drivers.emplace(current); + if (mode == BitMode::DRIVER || mode == BitMode::TRISTATE) + drivers.emplace(current); - if (connected_drivers.contains(current)) - drivers.emplace(current); + if (connected_drivers.contains(current)) + drivers.emplace(current); - int undirected_driver_count = connected_undirected.count(current); + int undirected_driver_count = connected_undirected.count(current); - for (int i = 0; i != undirected_driver_count; ++i) - seen.emplace(same_driver.find(connected_undirected.at(current, i))); - } + for (int i = 0; i != undirected_driver_count; ++i) + seen.emplace(same_driver.find(connected_undirected.at(current, i))); + } - if (drivers.empty()) - for (auto seen_id : seen) - drivers.emplace(seen_id); + if (drivers.empty()) + for (auto seen_id : seen) + drivers.emplace(seen_id); - for (auto driver : drivers) - { - distance.clear(); - distance.emplace(driver, 0); - - for (int pos = 0; pos < GetSize(distance); ++pos) { - auto current_it = distance.element(distance.size() - 1 - pos); - - DriveBitId current = current_it->first; - int undirected_driver_count = connected_undirected.count(current); - - for (int i = 0; i != undirected_driver_count; ++i) - { - DriveBitId next = same_driver.find(connected_undirected.at(current, i)); - auto emplaced = distance.emplace(next, current_it->second + 1); - if (emplaced.first->second == current_it->second + 1) - connected_oriented.add_edge(next, current); - } - } - } + for (auto driver : drivers) + { + distance.clear(); + distance.emplace(driver, 0); + + for (int pos = 0; pos < GetSize(distance); ++pos) { + auto current_it = distance.element(distance.size() - 1 - pos); - for (auto seen_id : seen) - oriented_present.emplace(seen_id); + DriveBitId current = current_it->first; + int undirected_driver_count = connected_undirected.count(current); + + for (int i = 0; i != undirected_driver_count; ++i) + { + DriveBitId next = same_driver.find(connected_undirected.at(current, i)); + auto emplaced = distance.emplace(next, current_it->second + 1); + if (emplaced.first->second == current_it->second + 1) + connected_oriented.add_edge(next, current); + } + } + } + + for (auto seen_id : seen) + oriented_present.emplace(seen_id); } DriveBit DriverMap::operator()(DriveBit const &bit) { - if (bit.type() == DriveType::MARKER || bit.type() == DriveType::NONE) - return bit; - if (bit.type() == DriveType::MULTIPLE) - { - DriveBit result; - for (auto const &inner : bit.multiple().multiple()) - result.merge((*this)(inner)); - return result; - } + if (bit.type() == DriveType::MARKER || bit.type() == DriveType::NONE) + return bit; + if (bit.type() == DriveType::MULTIPLE) + { + DriveBit result; + for (auto const &inner : bit.multiple().multiple()) + result.merge((*this)(inner)); + return result; + } - DriveBitId bit_id = id_from_drive_bit(bit); + DriveBitId bit_id = id_from_drive_bit(bit); - DriveBitId bit_repr_id = same_driver.find(bit_id); + DriveBitId bit_repr_id = same_driver.find(bit_id); - DriveBit bit_repr = drive_bit_from_id(bit_repr_id); + DriveBit bit_repr = drive_bit_from_id(bit_repr_id); - BitMode mode = bit_mode(bit_repr); + BitMode mode = bit_mode(bit_repr); - if (mode == BitMode::KEEP && bit_repr_id != bit_id) - return bit_repr; + if (mode == BitMode::KEEP && bit_repr_id != bit_id) + return bit_repr; - int implicit_driver_count = connected_drivers.count(bit_repr_id); - if (connected_undirected.contains(bit_repr_id) && !oriented_present.count(bit_repr_id)) - orient_undirected(bit_repr_id); + int implicit_driver_count = connected_drivers.count(bit_repr_id); + if (connected_undirected.contains(bit_repr_id) && !oriented_present.count(bit_repr_id)) + orient_undirected(bit_repr_id); - DriveBit driver; + DriveBit driver; - if (mode == BitMode::DRIVER || mode == BitMode::TRISTATE) - driver = bit_repr; + if (mode == BitMode::DRIVER || mode == BitMode::TRISTATE) + driver = bit_repr; - for (int i = 0; i != implicit_driver_count; ++i) - driver.merge(drive_bit_from_id(connected_drivers.at(bit_repr_id, i))); + for (int i = 0; i != implicit_driver_count; ++i) + driver.merge(drive_bit_from_id(connected_drivers.at(bit_repr_id, i))); - int oriented_driver_count = connected_oriented.count(bit_repr_id); - for (int i = 0; i != oriented_driver_count; ++i) - driver.merge(drive_bit_from_id(connected_oriented.at(bit_repr_id, i))); + int oriented_driver_count = connected_oriented.count(bit_repr_id); + for (int i = 0; i != oriented_driver_count; ++i) + driver.merge(drive_bit_from_id(connected_oriented.at(bit_repr_id, i))); - return driver; + return driver; } DriveSpec DriverMap::operator()(DriveSpec spec) { - DriveSpec result; + DriveSpec result; - for (int i = 0, width = spec.size(); i != width; ++i) - result.append((*this)(spec[i])); + for (int i = 0, width = spec.size(); i != width; ++i) + result.append((*this)(spec[i])); - return result; + return result; } const char *log_signal(DriveChunkWire const &chunk) { - const char *id = log_id(chunk.wire->name); - if (chunk.is_whole()) - return id; - if (chunk.width == 1) - return log_str(stringf("%s [%d]", id, chunk.offset)); - return log_str(stringf("%s [%d:%d]", id, chunk.offset + chunk.width - 1, chunk.offset)); + const char *id = log_id(chunk.wire->name); + if (chunk.is_whole()) + return id; + if (chunk.width == 1) + return log_str(stringf("%s [%d]", id, chunk.offset)); + return log_str(stringf("%s [%d:%d]", id, chunk.offset + chunk.width - 1, chunk.offset)); } const char *log_signal(DriveChunkPort const &chunk) { - const char *cell_id = log_id(chunk.cell->name); - const char *port_id = log_id(chunk.port); - if (chunk.is_whole()) - return log_str(stringf("%s <%s>", cell_id, port_id)); - if (chunk.width == 1) - return log_str(stringf("%s <%s> [%d]", cell_id, port_id, chunk.offset)); - return log_str(stringf("%s <%s> [%d:%d]", cell_id, port_id, chunk.offset + chunk.width - 1, chunk.offset)); + const char *cell_id = log_id(chunk.cell->name); + const char *port_id = log_id(chunk.port); + if (chunk.is_whole()) + return log_str(stringf("%s <%s>", cell_id, port_id)); + if (chunk.width == 1) + return log_str(stringf("%s <%s> [%d]", cell_id, port_id, chunk.offset)); + return log_str(stringf("%s <%s> [%d:%d]", cell_id, port_id, chunk.offset + chunk.width - 1, chunk.offset)); } const char *log_signal(DriveChunkMarker const &chunk) { - if (chunk.width == 1) - return log_str(stringf(" [%d]", chunk.marker, chunk.offset)); - return log_str(stringf(" [%d:%d]", chunk.marker, chunk.offset + chunk.width - 1, chunk.offset)); + if (chunk.width == 1) + return log_str(stringf(" [%d]", chunk.marker, chunk.offset)); + return log_str(stringf(" [%d:%d]", chunk.marker, chunk.offset + chunk.width - 1, chunk.offset)); } const char *log_signal(DriveChunk const &chunk) { - switch (chunk.type()) - { - case DriveType::NONE: - return log_str(stringf("", chunk.size())); - case DriveType::CONSTANT: - return log_const(chunk.constant()); - case DriveType::WIRE: - return log_signal(chunk.wire()); - case DriveType::PORT: - return log_signal(chunk.port()); - case DriveType::MARKER: - return log_signal(chunk.marker()); - case DriveType::MULTIPLE: { - std::string str = "", chunk.size())); + case DriveType::CONSTANT: + return log_const(chunk.constant()); + case DriveType::WIRE: + return log_signal(chunk.wire()); + case DriveType::PORT: + return log_signal(chunk.port()); + case DriveType::MARKER: + return log_signal(chunk.marker()); + case DriveType::MULTIPLE: { + std::string str = "(State::Sm)) +{ + celltypes.setup(); +} - for (auto i = chunks.rbegin(), end = chunks.rend(); i != end; ++i) - { - str += sep; - sep = " "; - str += log_signal(*i); - } - str += " }"; +DriverMap::DriverMap(Design *design) : next_offset(1 + static_cast(State::Sm)) +{ + celltypes.setup(); + celltypes.setup_design(design); +} + +DriverMap::DriveBitId::DriveBitId() : id(-1) {} + +DriverMap::DriveBitId::DriveBitId(int id) : id(id) {} + +bool DriverMap::DriveBitId::operator==(const DriveBitId &other) const +{ + return id == other.id; +} + +bool DriverMap::DriveBitId::operator!=(const DriveBitId &other) const +{ + return id != other.id; +} + +bool DriverMap::DriveBitId::operator<(const DriveBitId &other) const +{ + return id < other.id; +} - return log_str(str); +unsigned int DriverMap::DriveBitId::hash() const +{ + return id; +} + +bool DriverMap::keep_wire(Wire *wire) { + // TODO configurable + return wire->has_attribute(ID(keep)); } + YOSYS_NAMESPACE_END diff --git a/kernel/drivertools.h b/kernel/drivertools.h index 1cb835df2cc..cd0ac5399bd 100644 --- a/kernel/drivertools.h +++ b/kernel/drivertools.h @@ -28,8 +28,6 @@ YOSYS_NAMESPACE_BEGIN -// TODO move implementation into a .cc file - struct DriveBit; struct DriveChunkWire; @@ -46,1271 +44,532 @@ const char *log_signal(DriveChunk const &chunk); const char *log_signal(DriveSpec const &chunk); enum class DriveType : unsigned char -{ - NONE, - CONSTANT, - WIRE, - PORT, - MULTIPLE, - MARKER, -}; + { + NONE, + CONSTANT, + WIRE, + PORT, + MULTIPLE, + MARKER, + }; struct DriveBitWire { - Wire *wire; - int offset; - - DriveBitWire(Wire *wire, int offset) : wire(wire), offset(offset) {} - - bool operator==(const DriveBitWire &other) const - { - return wire == other.wire && offset == other.offset; - } - - bool operator<(const DriveBitWire &other) const - { - if (wire != other.wire) - return wire->name < other.wire->name; - return offset < other.offset; - } - - unsigned int hash() const - { - return mkhash_add(wire->name.hash(), offset); - } - - operator SigBit() const - { - return SigBit(wire, offset); - } + Wire *wire; + int offset; + + DriveBitWire(Wire *wire, int offset); + + bool operator==(const DriveBitWire &other) const; + + bool operator<(const DriveBitWire &other) const; + + unsigned int hash() const; + + operator SigBit() const; }; struct DriveBitPort { - Cell *cell; - IdString port; - int offset; - - DriveBitPort(Cell *cell, IdString port, int offset) : cell(cell), port(port), offset(offset) {} - - bool operator==(const DriveBitPort &other) const - { - return cell == other.cell && port == other.port && offset == other.offset; - } - - bool operator<(const DriveBitPort &other) const - { - if (cell != other.cell) - return cell->name < other.cell->name; - if (port != other.port) - return port < other.port; - return offset < other.offset; - } - - unsigned int hash() const - { - return mkhash_add(mkhash(cell->name.hash(), port.hash()), offset); - } -}; + Cell *cell; + IdString port; + int offset; + + DriveBitPort(Cell *cell, IdString port, int offset); + + bool operator==(const DriveBitPort &other) const; + + bool operator<(const DriveBitPort &other) const; + unsigned int hash() const; +}; struct DriveBitMarker { - int marker; - int offset; - - DriveBitMarker(int marker, int offset) : marker(marker), offset(offset) {} + int marker; + int offset; - bool operator==(const DriveBitMarker &other) const - { - return marker == other.marker && offset == other.offset; - } + DriveBitMarker(int marker, int offset); - bool operator<(const DriveBitMarker &other) const - { - if (marker != other.marker) - return marker < other.marker; - return offset < other.offset; - } + bool operator==(const DriveBitMarker &other) const; - unsigned int hash() const - { - return mkhash_add(marker, offset); - } + bool operator<(const DriveBitMarker &other) const; + unsigned int hash() const; }; struct DriveBitMultiple { private: - pool multiple_; + pool multiple_; public: - DriveBitMultiple() {} - DriveBitMultiple(DriveBit const &single) - { - multiple_.emplace(single); - } - - pool const &multiple() const { return multiple_; } - - void merge(DriveBitMultiple const &other) - { - for (DriveBit const &single : other.multiple_) - merge(single); - } - - void merge(DriveBitMultiple &&other) - { - for (DriveBit &single : other.multiple_) - merge(std::move(single)); - } - - void merge(DriveBit const &single); - void merge(DriveBit &&single); - - bool operator==(const DriveBitMultiple &other) const - { - return multiple_ == other.multiple_; - } - - unsigned int hash() const - { - return multiple_.hash(); - } + DriveBitMultiple(); + DriveBitMultiple(DriveBit const &single); + + pool const &multiple() const; + + void merge(DriveBitMultiple const &other); + void merge(DriveBitMultiple &&other); + void merge(DriveBit const &single); + void merge(DriveBit &&single); + + bool operator==(const DriveBitMultiple &other) const; + + unsigned int hash() const; }; struct DriveBit { private: - DriveType type_ = DriveType::NONE; - union - { - State constant_; - DriveBitWire wire_; - DriveBitPort port_; - DriveBitMarker marker_; - DriveBitMultiple multiple_; - }; -public: - DriveBit() {} - - DriveBit(SigBit const &bit); - - DriveBit(DriveBit const &other) { *this = other; } - DriveBit(DriveBit &&other) { *this = other; } - - - DriveBit(State constant) { *this = constant; } - DriveBit(DriveBitWire const &wire) { *this = wire; } - DriveBit(DriveBitWire &&wire) { *this = wire; } - DriveBit(DriveBitPort const &port) { *this = port; } - DriveBit(DriveBitPort &&port) { *this = port; } - DriveBit(DriveBitMarker const &marker) { *this = marker; } - DriveBit(DriveBitMarker &&marker) { *this = marker; } - DriveBit(DriveBitMultiple const &multiple) { *this = multiple; } - DriveBit(DriveBitMultiple &&multiple) { *this = multiple; } - - ~DriveBit() { set_none(); } - - void set_none() - { - switch (type_) - { - case DriveType::NONE: - break; - case DriveType::CONSTANT: - break; - case DriveType::WIRE: - wire_.~DriveBitWire(); - break; - case DriveType::PORT: - port_.~DriveBitPort(); - break; - case DriveType::MARKER: - marker_.~DriveBitMarker(); - break; - case DriveType::MULTIPLE: - multiple_.~DriveBitMultiple(); - break; - } - type_ = DriveType::NONE; - } - - DriveBit &operator=(DriveBit const &other) - { - switch (other.type_) - { - case DriveType::NONE: - set_none(); - break; - case DriveType::CONSTANT: - *this = other.constant_; - break; - case DriveType::WIRE: - *this = other.wire_; - break; - case DriveType::PORT: - *this = other.port_; - break; - case DriveType::MARKER: - *this = other.marker_; - break; - case DriveType::MULTIPLE: - *this = other.multiple_; - break; - } - return *this; - } - - DriveBit &operator=(DriveBit &&other) - { - switch (other.type_) - { - case DriveType::NONE: - set_none(); - break; - case DriveType::CONSTANT: - *this = std::move(other.constant_); - break; - case DriveType::WIRE: - *this = std::move(other.wire_); - break; - case DriveType::PORT: - *this = std::move(other.port_); - break; - case DriveType::MARKER: - *this = std::move(other.marker_); - break; - case DriveType::MULTIPLE: - *this = std::move(other.multiple_); - break; - } - return *this; - } - - DriveBit &operator=(State constant) - { - set_none(); - constant_ = constant; - type_ = DriveType::CONSTANT; - return *this; - } - - DriveBit &operator=(DriveBitWire const &wire) - { - set_none(); - new (&wire_) DriveBitWire(wire); - type_ = DriveType::WIRE; - return *this; - } - - DriveBit &operator=(DriveBitWire &&wire) - { - set_none(); - new (&wire_) DriveBitWire(wire); - type_ = DriveType::WIRE; - return *this; - } - - DriveBit &operator=(DriveBitPort const &port) - { - set_none(); - new (&port_) DriveBitPort(port); - type_ = DriveType::PORT; - return *this; - } - - DriveBit &operator=(DriveBitPort &&port) - { - set_none(); - new (&port_) DriveBitPort(port); - type_ = DriveType::PORT; - return *this; - } - - DriveBit &operator=(DriveBitMarker const &marker) - { - set_none(); - new (&marker_) DriveBitMarker(marker); - type_ = DriveType::MARKER; - return *this; - } - - DriveBit &operator=(DriveBitMarker &&marker) - { - set_none(); - new (&marker_) DriveBitMarker(marker); - type_ = DriveType::MARKER; - return *this; - } - - DriveBit &operator=(DriveBitMultiple const &multiple) - { - set_none(); - if (multiple.multiple().empty()) - return *this; - new (&multiple_) DriveBitMultiple(multiple); - type_ = DriveType::MULTIPLE; - return *this; - } - - DriveBit &operator=(DriveBitMultiple &&multiple) - { - set_none(); - if (multiple.multiple().empty()) - return *this; - new (&multiple_) DriveBitMultiple(multiple); - type_ = DriveType::MULTIPLE; - return *this; - } - - unsigned int hash() const - { - unsigned int inner; - switch (type_) - { - case DriveType::NONE: - inner = 0; - break; - case DriveType::CONSTANT: - inner = constant_; - break; - case DriveType::WIRE: - inner = wire_.hash(); - break; - case DriveType::PORT: - inner = port_.hash(); - break; - case DriveType::MARKER: - inner = marker_.hash(); - break; - case DriveType::MULTIPLE: - inner = multiple_.hash(); - break; - } - return mkhash((unsigned int)type_, inner); - } - - bool operator==(const DriveBit &other) const - { - if (type_ != other.type_) - return false; - - switch (type_) - { - case DriveType::NONE: - return true; - case DriveType::CONSTANT: - return constant_ == other.constant_; - case DriveType::WIRE: - return wire_ == other.wire_; - case DriveType::PORT: - return port_ == other.port_; - case DriveType::MARKER: - return marker_ == other.marker_; - case DriveType::MULTIPLE: - return multiple_ == other.multiple_; - } - log_assert(false); - } - - bool operator!=(const DriveBit &other) const - { - return !(*this == other); - } - - bool operator<(const DriveBit &other) const - { - if (type_ != other.type_) - return type_ < other.type_; - switch (type_) - { - case DriveType::NONE: - return false; - case DriveType::CONSTANT: - return constant_ < other.constant_; - case DriveType::WIRE: - return wire_ < other.wire_; - case DriveType::PORT: - return port_ < other.port_; - case DriveType::MARKER: - return marker_ < other.marker_; - case DriveType::MULTIPLE: - log_assert(!"TODO"); - } - log_abort(); - } - - - DriveType type() const { return type_; } - - bool is_none() const { return type_ == DriveType::NONE; } - bool is_constant() const { return type_ == DriveType::CONSTANT; } - bool is_wire() const { return type_ == DriveType::WIRE; } - bool is_port() const { return type_ == DriveType::PORT; } - bool is_marker() const { return type_ == DriveType::MARKER; } - bool is_multiple() const { return type_ == DriveType::MULTIPLE; } - - State &constant() { log_assert(is_constant()); return constant_; } - State const &constant() const { log_assert(is_constant()); return constant_; } - DriveBitWire &wire() { log_assert(is_wire()); return wire_; } - DriveBitWire const &wire() const { log_assert(is_wire()); return wire_; } - DriveBitPort &port() { log_assert(is_port()); return port_; } - DriveBitPort const &port() const { log_assert(is_port()); return port_; } - DriveBitMarker &marker() { log_assert(is_marker()); return marker_; } - DriveBitMarker const &marker() const { log_assert(is_marker()); return marker_; } - DriveBitMultiple &multiple() { log_assert(is_multiple()); return multiple_; } - DriveBitMultiple const &multiple() const { log_assert(is_multiple()); return multiple_; } - - void merge(DriveBit const &other); + DriveType type_ = DriveType::NONE; + union + { + State constant_; + DriveBitWire wire_; + DriveBitPort port_; + DriveBitMarker marker_; + DriveBitMultiple multiple_; + }; +public: + DriveBit(); + + DriveBit(SigBit const &bit); + + DriveBit(DriveBit const &other); + DriveBit(DriveBit &&other); + + DriveBit(State constant); + DriveBit(DriveBitWire const &wire); + DriveBit(DriveBitWire &&wire); + DriveBit(DriveBitPort const &port); + DriveBit(DriveBitPort &&port); + DriveBit(DriveBitMarker const &marker); + DriveBit(DriveBitMarker &&marker); + DriveBit(DriveBitMultiple const &multiple); + DriveBit(DriveBitMultiple &&multiple); + + ~DriveBit(); + + void set_none(); + + DriveBit &operator=(DriveBit const &other); + DriveBit &operator=(DriveBit &&other); + + DriveBit &operator=(State constant); + DriveBit &operator=(DriveBitWire const &wire); + DriveBit &operator=(DriveBitWire &&wire); + DriveBit &operator=(DriveBitPort const &port); + DriveBit &operator=(DriveBitPort &&port); + DriveBit &operator=(DriveBitMarker const &marker); + DriveBit &operator=(DriveBitMarker &&marker); + DriveBit &operator=(DriveBitMultiple const &multiple); + DriveBit &operator=(DriveBitMultiple &&multiple); + + unsigned int hash() const; + + bool operator==(const DriveBit &other) const; + bool operator!=(const DriveBit &other) const; + + bool operator<(const DriveBit &other) const; + + DriveType type() const; + + bool is_none() const; + bool is_constant() const; + bool is_wire() const; + bool is_port() const; + bool is_marker() const; + bool is_multiple() const; + + State &constant(); + State const &constant() const; + DriveBitWire &wire(); + DriveBitWire const &wire() const; + DriveBitPort &port(); + DriveBitPort const &port() const; + DriveBitMarker &marker(); + DriveBitMarker const &marker() const; + DriveBitMultiple &multiple(); + DriveBitMultiple const &multiple() const; + + void merge(DriveBit const &other); }; - struct DriveChunkWire { - Wire *wire; - int offset; - int width; - - DriveChunkWire(Wire *wire, int offset, int width) : wire(wire), offset(offset), width(width) {} - DriveChunkWire(DriveBitWire const &bit) : wire(bit.wire), offset(bit.offset), width(1) {} - - int size() const { return width; } - - DriveBitWire operator[](int i) const - { - log_assert(i >= 0 && i < width); - return DriveBitWire(wire, offset + i); - } - - bool can_append(DriveBitWire const &bit) const; - bool try_append(DriveBitWire const &bit); - bool try_append(DriveChunkWire const &chunk); - - // Whether this chunk is a whole wire - bool is_whole() const { return offset == 0 && width == wire->width; } - - bool operator==(const DriveChunkWire &other) const - { - return wire == other.wire && offset == other.offset && width == other.width; - } - - bool operator<(const DriveChunkWire &other) const - { - if (wire != other.wire) - return wire->name < other.wire->name; - if (width != other.width) - return width < other.width; - return offset < other.offset; - } - - unsigned int hash() const - { - return mkhash_add(mkhash(wire->name.hash(), width), offset); - } - - explicit operator SigChunk() const - { - return SigChunk(wire, offset, width); - } + Wire *wire; + int offset; + int width; + + DriveChunkWire(Wire *wire, int offset, int width); + DriveChunkWire(DriveBitWire const &bit); + + int size() const; + DriveBitWire operator[](int i) const; + bool can_append(DriveBitWire const &bit) const; + bool try_append(DriveBitWire const &bit); + bool try_append(DriveChunkWire const &chunk); + bool is_whole() const; + bool operator==(const DriveChunkWire &other) const; + bool operator<(const DriveChunkWire &other) const; + unsigned int hash() const; + explicit operator SigChunk() const; }; struct DriveChunkPort { - Cell *cell; - IdString port; - int offset; - int width; - - DriveChunkPort(Cell *cell, IdString port, int offset, int width) : - cell(cell), port(port), offset(offset), width(width) { } - DriveChunkPort(Cell *cell, IdString port) : - cell(cell), port(port), offset(0), width(GetSize(cell->connections().at(port))) { } - DriveChunkPort(Cell *cell, std::pair const &conn) : - cell(cell), port(conn.first), offset(0), width(GetSize(conn.second)) { } - DriveChunkPort(DriveBitPort const &bit) : - cell(bit.cell), port(bit.port), offset(bit.offset), width(1) { } - - int size() const { return width; } - - DriveBitPort operator[](int i) const - { - log_assert(i >= 0 && i < width); - return DriveBitPort(cell, port, offset + i); - } - - bool can_append(DriveBitPort const &bit) const; - bool try_append(DriveBitPort const &bit); - bool try_append(DriveChunkPort const &chunk); - - // Whether this chunk is a whole port - bool is_whole() const - { - return offset == 0 && width == cell->connections().at(port).size(); - } - - bool operator==(const DriveChunkPort &other) const - { - return cell == other.cell && port == other.port && offset == other.offset && width == other.width; - } - - bool operator<(const DriveChunkPort &other) const - { - if (cell != other.cell) - return cell->name < other.cell->name; - if (port != other.port) - return port < other.port; - if (width != other.width) - return width < other.width; - return offset < other.offset; - } - - unsigned int hash() const - { - return mkhash_add(mkhash(mkhash(cell->name.hash(), port.hash()), width), offset); - } + Cell *cell; + IdString port; + int offset; + int width; + + DriveChunkPort(Cell *cell, IdString port, int offset, int width); + DriveChunkPort(Cell *cell, IdString port); + DriveChunkPort(Cell *cell, std::pair const &conn); + DriveChunkPort(DriveBitPort const &bit); + + int size() const; + DriveBitPort operator[](int i) const; + bool can_append(DriveBitPort const &bit) const; + bool try_append(DriveBitPort const &bit); + bool try_append(DriveChunkPort const &chunk); + bool is_whole() const; + bool operator==(const DriveChunkPort &other) const; + bool operator<(const DriveChunkPort &other) const; + unsigned int hash() const; }; - struct DriveChunkMarker { - int marker; - int offset; - int width; - - DriveChunkMarker(int marker, int offset, int width) : - marker(marker), offset(offset), width(width) {} - DriveChunkMarker(DriveBitMarker const &bit) : - marker(bit.marker), offset(bit.offset), width(1) {} - - int size() const { return width; } - - DriveBitMarker operator[](int i) const - { - log_assert(i >= 0 && i < width); - return DriveBitMarker(marker, offset + i); - } - - bool can_append(DriveBitMarker const &bit) const; - bool try_append(DriveBitMarker const &bit); - bool try_append(DriveChunkMarker const &chunk); - - bool operator==(const DriveChunkMarker &other) const - { - return marker == other.marker && offset == other.offset && width == other.width; - } - - bool operator<(const DriveChunkMarker &other) const - { - if (marker != other.marker) - return marker < other.marker; - if (width != other.width) - return width < other.width; - return offset < other.offset; - } - - unsigned int hash() const - { - return mkhash_add(mkhash(marker, width), offset); - } + int marker; + int offset; + int width; + + DriveChunkMarker(int marker, int offset, int width); + DriveChunkMarker(DriveBitMarker const &bit); + + int size() const; + DriveBitMarker operator[](int i) const; + bool can_append(DriveBitMarker const &bit) const; + bool try_append(DriveBitMarker const &bit); + bool try_append(DriveChunkMarker const &chunk); + bool operator==(const DriveChunkMarker &other) const; + bool operator<(const DriveChunkMarker &other) const; + unsigned int hash() const; }; struct DriveChunkMultiple { private: - mutable pool multiple_; - int width_; + mutable pool multiple_; + int width_; public: - pool const &multiple() const { return multiple_; } - - DriveChunkMultiple(DriveBitMultiple const &bit) : width_(1) { - for (auto const &bit : bit.multiple()) - multiple_.emplace(bit); - } - - int size() const { return width_; } - - DriveBitMultiple operator[](int i) const; - - bool can_append(DriveBitMultiple const &bit) const; - - bool try_append(DriveBitMultiple const &bit); - - - bool can_append(DriveChunkMultiple const &bit) const; - - bool try_append(DriveChunkMultiple const &bit); - - bool operator==(const DriveChunkMultiple &other) const - { - return width_ == other.width_ && multiple_ == other.multiple_; - } - - bool operator<(const DriveChunkMultiple &other) const - { - if (multiple_.size() < other.multiple_.size()) - - multiple_.sort(); - return false; // TODO implement, canonicalize order - } - - unsigned int hash() const - { - return mkhash(width_, multiple_.hash()); - } + pool const &multiple() const; + + DriveChunkMultiple(DriveBitMultiple const &bit); + + int size() const; + DriveBitMultiple operator[](int i) const; + bool can_append(DriveBitMultiple const &bit) const; + bool try_append(DriveBitMultiple const &bit); + bool can_append(DriveChunkMultiple const &bit) const; + bool try_append(DriveChunkMultiple const &bit); + bool operator==(const DriveChunkMultiple &other) const; + bool operator<(const DriveChunkMultiple &other) const; + unsigned int hash() const; }; struct DriveChunk { private: - DriveType type_ = DriveType::NONE; - union - { - int none_; - Const constant_; - DriveChunkWire wire_; - DriveChunkPort port_; - DriveChunkMarker marker_; - DriveChunkMultiple multiple_; - }; + DriveType type_ = DriveType::NONE; + union + { + int none_; + Const constant_; + DriveChunkWire wire_; + DriveChunkPort port_; + DriveChunkMarker marker_; + DriveChunkMultiple multiple_; + }; public: - DriveChunk() { set_none(); } - - DriveChunk(DriveChunk const &other) { *this = other; } - DriveChunk(DriveChunk &&other) { *this = other; } - - DriveChunk(DriveBit const &other) { *this = other; } - - DriveChunk(Const const &constant) { *this = constant; } - DriveChunk(Const &&constant) { *this = constant; } - DriveChunk(DriveChunkWire const &wire) { *this = wire; } - DriveChunk(DriveChunkWire &&wire) { *this = wire; } - DriveChunk(DriveChunkPort const &port) { *this = port; } - DriveChunk(DriveChunkPort &&port) { *this = port; } - DriveChunk(DriveChunkMarker const &marker) { *this = marker; } - DriveChunk(DriveChunkMarker &&marker) { *this = marker; } - DriveChunk(DriveChunkMultiple const &multiple) { *this = multiple; } - DriveChunk(DriveChunkMultiple &&multiple) { *this = multiple; } - - ~DriveChunk() { set_none(); } - - DriveBit operator[](int i) const - { - switch (type_) - { - case DriveType::NONE: - return DriveBit(); - case DriveType::CONSTANT: - return constant_[i]; - case DriveType::WIRE: - return wire_[i]; - case DriveType::PORT: - return port_[i]; - case DriveType::MARKER: - return marker_[i]; - case DriveType::MULTIPLE: - return multiple_[i]; - } - log_abort(); - } - - void set_none(int width = 0) - { - switch (type_) - { - case DriveType::NONE: - none_ = width; - break; - case DriveType::CONSTANT: - constant_.~Const(); - break; - case DriveType::WIRE: - wire_.~DriveChunkWire(); - break; - case DriveType::PORT: - port_.~DriveChunkPort(); - break; - case DriveType::MARKER: - marker_.~DriveChunkMarker(); - break; - case DriveType::MULTIPLE: - multiple_.~DriveChunkMultiple(); - break; - } - type_ = DriveType::NONE; - none_ = width; - } - - DriveChunk &operator=(DriveChunk const &other) - { - switch (other.type_) - { - case DriveType::NONE: - set_none(other.none_); - break; - case DriveType::CONSTANT: - *this = other.constant_; - break; - case DriveType::WIRE: - *this = other.wire_; - break; - case DriveType::PORT: - *this = other.port_; - break; - case DriveType::MARKER: - *this = other.marker_; - break; - case DriveType::MULTIPLE: - *this = other.multiple_; - break; - } - return *this; - } - - DriveChunk &operator=(DriveChunk &&other) - { - switch (other.type_) - { - case DriveType::NONE: - set_none(other.none_); - break; - case DriveType::CONSTANT: - *this = std::move(other.constant_); - break; - case DriveType::WIRE: - *this = std::move(other.wire_); - break; - case DriveType::PORT: - *this = std::move(other.port_); - break; - case DriveType::MARKER: - *this = std::move(other.marker_); - break; - case DriveType::MULTIPLE: - *this = std::move(other.multiple_); - break; - } - return *this; - } - - DriveChunk &operator=(Const const &constant) - { - set_none(); - new (&constant_) Const(constant); - type_ = DriveType::CONSTANT; - return *this; - } - - DriveChunk &operator=(Const &&constant) - { - set_none(); - new (&constant_) Const(std::move(constant)); - type_ = DriveType::CONSTANT; - return *this; - } - - DriveChunk &operator=(DriveChunkWire const &wire) - { - set_none(); - new (&wire_) DriveChunkWire(wire); - type_ = DriveType::WIRE; - return *this; - } - - DriveChunk &operator=(DriveChunkWire &&wire) - { - set_none(); - new (&wire_) DriveChunkWire(wire); - type_ = DriveType::WIRE; - return *this; - } - - DriveChunk &operator=(DriveChunkPort const &port) - { - set_none(); - new (&port_) DriveChunkPort(port); - type_ = DriveType::PORT; - return *this; - } - - DriveChunk &operator=(DriveChunkPort &&port) - { - set_none(); - new (&port_) DriveChunkPort(port); - type_ = DriveType::PORT; - return *this; - } - - DriveChunk &operator=(DriveChunkMarker const &marker) - { - set_none(); - new (&marker_) DriveChunkMarker(marker); - type_ = DriveType::MARKER; - return *this; - } - - DriveChunk &operator=(DriveChunkMarker &&marker) - { - set_none(); - new (&marker_) DriveChunkMarker(marker); - type_ = DriveType::MARKER; - return *this; - } - - DriveChunk &operator=(DriveChunkMultiple const &multiple) - { - set_none(multiple.size()); - if (multiple.multiple().empty()) - return *this; - new (&multiple_) DriveChunkMultiple(multiple); - type_ = DriveType::MULTIPLE; - return *this; - } - - DriveChunk &operator=(DriveChunkMultiple &&multiple) - { - set_none(multiple.size()); - if (multiple.multiple().empty()) - return *this; - new (&multiple_) DriveChunkMultiple(multiple); - type_ = DriveType::MULTIPLE; - return *this; - } - - DriveChunk &operator=(DriveBit const &other) - { - switch (other.type()) - { - case DriveType::NONE: - set_none(1); - break; - case DriveType::CONSTANT: - *this = Const(other.constant()); - break; - case DriveType::WIRE: - *this = DriveChunkWire(other.wire()); - break; - case DriveType::PORT: - *this = DriveChunkPort(other.port()); - break; - case DriveType::MARKER: - *this = DriveChunkMarker(other.marker()); - break; - case DriveType::MULTIPLE: - *this = DriveChunkMultiple(other.multiple()); - break; - } - return *this; - } - - bool can_append(DriveBit const &bit) const; - bool try_append(DriveBit const &bit); - bool try_append(DriveChunk const &chunk); - - unsigned int hash() const - { - unsigned int inner; - switch (type_) - { - case DriveType::NONE: - inner = 0; - break; - case DriveType::CONSTANT: - inner = constant_.hash(); - break; - case DriveType::WIRE: - inner = wire_.hash(); - break; - case DriveType::PORT: - inner = port_.hash(); - break; - case DriveType::MARKER: - inner = marker_.hash(); - break; - case DriveType::MULTIPLE: - inner = multiple_.hash(); - break; - } - return mkhash((unsigned int)type_, inner); - } - - bool operator==(const DriveChunk &other) const - { - if (type_ != other.type_) - return false; - - switch (type_) - { - case DriveType::NONE: - return true; - case DriveType::CONSTANT: - return constant_ == other.constant_; - case DriveType::WIRE: - return wire_ == other.wire_; - case DriveType::PORT: - return port_ == other.port_; - case DriveType::MARKER: - return marker_ == other.marker_; - case DriveType::MULTIPLE: - return multiple_ == other.multiple_; - } - log_assert(false); - } - - bool operator!=(const DriveChunk &other) const - { - return !(*this == other); - } - - bool operator<(const DriveChunk &other) const - { - if (type_ != other.type_) - return type_ < other.type_; - switch (type_) - { - case DriveType::NONE: - return false; - case DriveType::CONSTANT: - return constant_ < other.constant_; - case DriveType::WIRE: - return wire_ < other.wire_; - case DriveType::PORT: - return port_ < other.port_; - case DriveType::MARKER: - return marker_ < other.marker_; - case DriveType::MULTIPLE: - return multiple_ < other.multiple_; - } - log_assert(false); - } - - DriveType type() const { return type_; } - - bool is_none() const { return type_ == DriveType::NONE; } - bool is_constant() const { return type_ == DriveType::CONSTANT; } - bool is_wire() const { return type_ == DriveType::WIRE; } - bool is_port() const { return type_ == DriveType::PORT; } - bool is_marker() const { return type_ == DriveType::MARKER; } - bool is_multiple() const { return type_ == DriveType::MULTIPLE; } - - Const &constant() { log_assert(is_constant()); return constant_; } - Const const &constant() const { log_assert(is_constant()); return constant_; } - DriveChunkWire &wire() { log_assert(is_wire()); return wire_; } - DriveChunkWire const &wire() const { log_assert(is_wire()); return wire_; } - DriveChunkPort &port() { log_assert(is_port()); return port_; } - DriveChunkPort const &port() const { log_assert(is_port()); return port_; } - DriveChunkMarker &marker() { log_assert(is_marker()); return marker_; } - DriveChunkMarker const &marker() const { log_assert(is_marker()); return marker_; } - DriveChunkMultiple &multiple() { log_assert(is_multiple()); return multiple_; } - DriveChunkMultiple const &multiple() const { log_assert(is_multiple()); return multiple_; } - - - int size() const - { - switch (type_) - { - case DriveType::NONE: - return none_; - case DriveType::CONSTANT: - return constant_.size(); - case DriveType::WIRE: - return wire_.size(); - case DriveType::PORT: - return port_.size(); - case DriveType::MARKER: - return marker_.size(); - case DriveType::MULTIPLE: - return multiple_.size(); - } - } + DriveChunk(); + DriveChunk(DriveChunk const &other); + DriveChunk(DriveChunk &&other); + DriveChunk(DriveBit const &other); + DriveChunk(Const const &constant); + DriveChunk(Const &&constant); + DriveChunk(DriveChunkWire const &wire); + DriveChunk(DriveChunkWire &&wire); + DriveChunk(DriveChunkPort const &port); + DriveChunk(DriveChunkPort &&port); + DriveChunk(DriveChunkMarker const &marker); + DriveChunk(DriveChunkMarker &&marker); + DriveChunk(DriveChunkMultiple const &multiple); + DriveChunk(DriveChunkMultiple &&multiple); + ~DriveChunk(); + + DriveBit operator[](int i) const; + void set_none(int width = 0); + DriveChunk &operator=(DriveChunk const &other); + DriveChunk &operator=(DriveChunk &&other); + DriveChunk &operator=(Const const &constant); + DriveChunk &operator=(Const &&constant); + DriveChunk &operator=(DriveChunkWire const &wire); + DriveChunk &operator=(DriveChunkWire &&wire); + DriveChunk &operator=(DriveChunkPort const &port); + DriveChunk &operator=(DriveChunkPort &&port); + DriveChunk &operator=(DriveChunkMarker const &marker); + DriveChunk &operator=(DriveChunkMarker &&marker); + DriveChunk &operator=(DriveChunkMultiple const &multiple); + DriveChunk &operator=(DriveChunkMultiple &&multiple); + DriveChunk &operator=(DriveBit const &other); + bool can_append(DriveBit const &bit) const; + bool try_append(DriveBit const &bit); + bool try_append(DriveChunk const &chunk); + unsigned int hash() const; + bool operator==(const DriveChunk &other) const; + bool operator!=(const DriveChunk &other) const; + bool operator<(const DriveChunk &other) const; + DriveType type() const; + bool is_none() const; + bool is_constant() const; + bool is_wire() const; + bool is_port() const; + bool is_marker() const; + bool is_multiple() const; + Const &constant(); + Const const &constant() const; + DriveChunkWire &wire(); + DriveChunkWire const &wire() const; + DriveChunkPort &port(); + DriveChunkPort const &port() const; + DriveChunkMarker &marker(); + DriveChunkMarker const &marker() const; + DriveChunkMultiple &multiple(); + DriveChunkMultiple const &multiple() const; + int size() const; }; struct DriveSpec { private: - int width_ = 0; - mutable std::vector chunks_; - mutable std::vector bits_; - mutable unsigned int hash_ = 0; + int width_ = 0; + mutable std::vector chunks_; + mutable std::vector bits_; + mutable unsigned int hash_ = 0; + public: + inline bool packed() const; + + DriveSpec(); + DriveSpec(DriveChunk const &chunk); + DriveSpec(DriveChunkWire const &chunk); + DriveSpec(DriveChunkPort const &chunk); + DriveSpec(DriveChunkMarker const &chunk); + DriveSpec(DriveChunkMultiple const &chunk); - inline bool packed() const { - return bits_.empty(); - } - - DriveSpec() {} - - DriveSpec(DriveChunk const &chunk) { *this = chunk; } - DriveSpec(DriveChunkWire const &chunk) { *this = chunk; } - DriveSpec(DriveChunkPort const &chunk) { *this = chunk; } - DriveSpec(DriveChunkMarker const &chunk) { *this = chunk; } - DriveSpec(DriveChunkMultiple const &chunk) { *this = chunk; } - - DriveSpec(DriveBit const &bit) { *this = bit; } - DriveSpec(DriveBitWire const &bit) { *this = bit; } - DriveSpec(DriveBitPort const &bit) { *this = bit; } - DriveSpec(DriveBitMarker const &bit) { *this = bit; } - DriveSpec(DriveBitMultiple const &bit) { *this = bit; } - - DriveSpec(std::vector const &chunks) : chunks_(chunks) { compute_width(); } - - DriveSpec(std::vector const &bits) - { - for (auto const &bit : bits) - append(bit); - } - - std::vector const &chunks() const { pack(); return chunks_; } - std::vector const &bits() const { unpack(); return bits_; } - - int size() const { return width_; } - - void append(DriveBit const &bit); - - void append(DriveChunk const &chunk); - - void pack() const; - - void unpack() const; - - DriveBit &operator[](int index) - { - log_assert(index >= 0 && index < size()); - unpack(); - return bits_[index]; - } - - const DriveBit &operator[](int index) const - { - log_assert(index >= 0 && index < size()); - unpack(); - return bits_[index]; - } - - void clear() - { - chunks_.clear(); - bits_.clear(); - width_ = 0; - } - - DriveSpec &operator=(DriveChunk const &chunk) - { - chunks_.clear(); - bits_.clear(); - append(chunk); - return *this; - } - - DriveSpec &operator=(DriveChunkWire const &chunk) { return *this = DriveChunk(chunk); } - DriveSpec &operator=(DriveChunkPort const &chunk) { return *this = DriveChunk(chunk); } - DriveSpec &operator=(DriveChunkMarker const &chunk) { return *this = DriveChunk(chunk); } - DriveSpec &operator=(DriveChunkMultiple const &chunk) { return *this = DriveChunk(chunk); } - - DriveSpec &operator=(DriveBit const &bit) - { - chunks_.clear(); - bits_.clear(); - append(bit); - return *this; - } - - DriveSpec &operator=(DriveBitWire const &bit) { return *this = DriveBit(bit); } - DriveSpec &operator=(DriveBitPort const &bit) { return *this = DriveBit(bit); } - DriveSpec &operator=(DriveBitMarker const &bit) { return *this = DriveBit(bit); } - DriveSpec &operator=(DriveBitMultiple const &bit) { return *this = DriveBit(bit); } - - unsigned int hash() const { - if (hash_ != 0) return hash_; - - pack(); - hash_ = hash_ops>().hash(chunks_); - hash_ |= (hash_ == 0); - return hash_; - } - - bool operator==(DriveSpec const &other) const { - if (size() != other.size() || hash() != other.hash()) - return false; - return chunks() == other.chunks(); - } + DriveSpec(DriveBit const &bit); + DriveSpec(DriveBitWire const &bit); + DriveSpec(DriveBitPort const &bit); + DriveSpec(DriveBitMarker const &bit); + DriveSpec(DriveBitMultiple const &bit); -private: - void compute_width(); -}; + DriveSpec(std::vector const &chunks); + DriveSpec(std::vector const &bits); + std::vector const &chunks() const; + std::vector const &bits() const; + int size() const; -struct DriverMap -{ - CellTypes celltypes; + void append(DriveBit const &bit); + void append(DriveChunk const &chunk); - DriverMap() { celltypes.setup(); } - DriverMap(Design *design) { celltypes.setup(); celltypes.setup_design(design); } + void pack() const; + void unpack() const; -private: + DriveBit &operator[](int index); + const DriveBit &operator[](int index) const; - // Internally we represent all DriveBits by mapping them to DriveBitIds - // which use less memory and are cheaper to compare. - struct DriveBitId - { - int id = -1; - - DriveBitId() {}; - - DriveBitId(int id) : id(id) { } - - bool operator==(const DriveBitId &other) const { return id == other.id; } - bool operator!=(const DriveBitId &other) const { return id != other.id; } - bool operator<(const DriveBitId &other) const { return id < other.id; } - unsigned int hash() const { return id; } - }; - // Essentially a dict> but using less memory - // and fewer allocations - struct DriveBitGraph { - dict first_edges; - dict second_edges; - dict> more_edges; - - void add_edge(DriveBitId src, DriveBitId dst); - DriveBitId pop_edge(DriveBitId src); - void clear(DriveBitId src); - bool contains(DriveBitId src); - int count(DriveBitId src); - - DriveBitId at(DriveBitId src, int index); - }; - - // The following two maps maintain a sparse DriveBit to DriveBitId mapping. - // This saves a lot of memory compared to a `dict` or - // `idict`. - - // Maps wires to the first DriveBitId of the consecutive range used for - // that wire. - dict wire_offsets; - - // Maps cell ports to a the first DriveBitId of the consecutive range used - // for that cell port. - dict, DriveBitId> port_offsets; - - // For the inverse map that maps DriveBitIds back to DriveBits we use a - // sorted map containing only the first DriveBit for each wire and cell - // port. - std::map drive_bits; - - // As a memory optimization for gate level net lists we store single-bit - // wires and cell ports in a `dict` which requires less memory and fewer - // allocations than `std::map` but doesn't support the kind of lookups we - // need for a sparse coarse grained mapping. - dict isolated_drive_bits; - - // Used for allocating DriveBitIds, none and constant states use a fixewd - // mapping to the first few ids, which we need to skip. - int next_offset = 1 + (int)State::Sm; - - // Union-Find over directly connected bits that share the same single - // driver or are undriven. We never merge connections between drivers - // and/or kept wires. - mfp same_driver; - - // For each bit, store a set of connected driver bits for which the - // explicit connection should be preserved and the driving direction is - // locally unambiguous (one side only drives or requires a driven value). - DriveBitGraph connected_drivers; - - // For each bit, store a set of connected driver bits for which the - // explicit connection should be preserved and the driving direction is - // locally ambiguous. Every such ambiguous connection is also present in - // the reverse direction and has to be resolved when querying drivers. - DriveBitGraph connected_undirected; - - // Subset of `connected_undirected` for caching the resolved driving - // direction. In case multiple drivers are present this can still contain - // both orientations of a single connection, but for a single driver only - // one will be present. - DriveBitGraph connected_oriented; - - // Stores for which bits we already resolved the orientation (cached in - // `connected_oriented`). - pool oriented_present; - - - enum class BitMode { - NONE = 0, // Not driven, no need to keep wire - DRIVEN = 1, // Not driven, uses a value driven elsewhere - DRIVEN_UNIQUE = 2, // Uses a value driven elsewhere, has at most one direct connection - KEEP = 3, // Wire that should be kept - TRISTATE = 4, // Can drive a value but can also use a value driven elsewhere - DRIVER = 5, // Drives a value - }; - - BitMode bit_mode(DriveBit const &bit); - DriveBitId id_from_drive_bit(DriveBit const &bit); - DriveBit drive_bit_from_id(DriveBitId id); - - void connect_directed_merge(DriveBitId driven_id, DriveBitId driver_id); - void connect_directed_buffer(DriveBitId driven_id, DriveBitId driver_id); - void connect_undirected(DriveBitId a_id, DriveBitId b_id); + void clear(); -public: + DriveSpec &operator=(DriveChunk const &chunk); + DriveSpec &operator=(DriveChunkWire const &chunk); + DriveSpec &operator=(DriveChunkPort const &chunk); + DriveSpec &operator=(DriveChunkMarker const &chunk); + DriveSpec &operator=(DriveChunkMultiple const &chunk); - void add(Module *module); - - // Add a single bit connection to the driver map. - void add(DriveBit const &a, DriveBit const &b); - - template - static constexpr bool is_sig_type() { - return - std::is_same::value || - std::is_same::value || - std::is_same::value || - std::is_same::value || - std::is_same::value || - std::is_same::value || - std::is_same::value; - } - - // We use the enable_if to produce better compiler errors when unsupported - // types are used - template - typename std::enable_if() && is_sig_type()>::type - add(T const &a, U const &b) - { - log_assert(a.size() == b.size()); - for (int i = 0; i != GetSize(a); ++i) - add(DriveBit(a[i]), DriveBit(b[i])); - } - - - // Specialized version that avoids unpacking - void add(SigSpec const &a, SigSpec const &b); + DriveSpec &operator=(DriveBit const &bit); + DriveSpec &operator=(DriveBitWire const &bit); + DriveSpec &operator=(DriveBitPort const &bit); + DriveSpec &operator=(DriveBitMarker const &bit); + DriveSpec &operator=(DriveBitMultiple const &bit); -private: - void add_port(Cell *cell, IdString const &port, SigSpec const &b); + unsigned int hash() const; - // Only used a local variables in `orient_undirected`, always cleared, only - // stored to reduce allocations. - pool orient_undirected_seen; - pool orient_undirected_drivers; - dict orient_undirected_distance; + bool operator==(DriveSpec const &other) const; - void orient_undirected(DriveBitId id); +private: + void compute_width(); +}; -public: - DriveBit operator()(DriveBit const &bit); +struct DriverMap +{ + CellTypes celltypes; - DriveSpec operator()(DriveSpec spec); + DriverMap(); + DriverMap(Design *design); private: - bool keep_wire(Wire *wire) { - // TODO configurable - return wire->has_attribute(ID(keep)); - } + + // Internally we represent all DriveBits by mapping them to DriveBitIds + // which use less memory and are cheaper to compare. + struct DriveBitId + { + int id; + + DriveBitId(); + DriveBitId(int id); + + bool operator==(const DriveBitId &other) const; + bool operator!=(const DriveBitId &other) const; + bool operator<(const DriveBitId &other) const; + unsigned int hash() const; + }; + + // Essentially a dict> but using less memory + // and fewer allocations + struct DriveBitGraph + { + dict first_edges; + dict second_edges; + dict> more_edges; + + void add_edge(DriveBitId src, DriveBitId dst); + DriveBitId pop_edge(DriveBitId src); + void clear(DriveBitId src); + bool contains(DriveBitId src); + int count(DriveBitId src); + DriveBitId at(DriveBitId src, int index); + }; + + + // The following two maps maintain a sparse DriveBit to DriveBitId mapping. + // This saves a lot of memory compared to a `dict` or + // `idict`. + + // Maps wires to the first DriveBitId of the consecutive range used for + // that wire. + dict wire_offsets; + + // Maps cell ports to a the first DriveBitId of the consecutive range used + // for that cell port. + dict, DriveBitId> port_offsets; + + // For the inverse map that maps DriveBitIds back to DriveBits we use a + // sorted map containing only the first DriveBit for each wire and cell + // port. + std::map drive_bits; + + // As a memory optimization for gate level net lists we store single-bit + // wires and cell ports in a `dict` which requires less memory and fewer + // allocations than `std::map` but doesn't support the kind of lookups we + // need for a sparse coarse grained mapping. + dict isolated_drive_bits; + + // Used for allocating DriveBitIds, none and constant states use a fixewd + // mapping to the first few ids, which we need to skip. + int next_offset = 1 + (int)State::Sm; + + // Union-Find over directly connected bits that share the same single + // driver or are undriven. We never merge connections between drivers + // and/or kept wires. + mfp same_driver; + + // For each bit, store a set of connected driver bits for which the + // explicit connection should be preserved and the driving direction is + // locally unambiguous (one side only drives or requires a driven value). + DriveBitGraph connected_drivers; + + // For each bit, store a set of connected driver bits for which the + // explicit connection should be preserved and the driving direction is + // locally ambiguous. Every such ambiguous connection is also present in + // the reverse direction and has to be resolved when querying drivers. + DriveBitGraph connected_undirected; + + // Subset of `connected_undirected` for caching the resolved driving + // direction. In case multiple drivers are present this can still contain + // both orientations of a single connection, but for a single driver only + // one will be present. + DriveBitGraph connected_oriented; + + // Stores for which bits we already resolved the orientation (cached in + // `connected_oriented`). + pool oriented_present; + + enum class BitMode { + NONE = 0, // Not driven, no need to keep wire + DRIVEN = 1, // Not driven, uses a value driven elsewhere + DRIVEN_UNIQUE = 2, // Uses a value driven elsewhere, has at most one direct connection + KEEP = 3, // Wire that should be kept + TRISTATE = 4, // Can drive a value but can also use a value driven elsewhere + DRIVER = 5, // Drives a value + }; + + BitMode bit_mode(DriveBit const &bit); + DriveBitId id_from_drive_bit(DriveBit const &bit); + DriveBit drive_bit_from_id(DriveBitId id); + void connect_directed_merge(DriveBitId driven_id, DriveBitId driver_id); + void connect_directed_buffer(DriveBitId driven_id, DriveBitId driver_id); + void connect_undirected(DriveBitId a_id, DriveBitId b_id); + void add_port(Cell *cell, IdString const &port, SigSpec const &b); + void orient_undirected(DriveBitId id); + bool keep_wire(Wire *wire); + + // Only used a local variables in `orient_undirected`, always cleared, only + // stored to reduce allocations. + pool orient_undirected_seen; + pool orient_undirected_drivers; + dict orient_undirected_distance; + + +public: + void add(Module *module); + void add(DriveBit const &a, DriveBit const &b); + + + template + static constexpr bool is_sig_type() { + return + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value; + } + + // We use the enable_if to produce better compiler errors when unsupported + // types are used + template + typename std::enable_if() && is_sig_type()>::type + add(T const &a, U const &b) + { + log_assert(a.size() == b.size()); + for (int i = 0; i != GetSize(a); ++i) + add(DriveBit(a[i]), DriveBit(b[i])); + } + + // Specialized version that avoids unpacking + void add(SigSpec const &a, SigSpec const &b); + DriveBit operator()(DriveBit const &bit); + DriveSpec operator()(DriveSpec spec); }; YOSYS_NAMESPACE_END From 4828e8d860840c48c5db7c73a6861abcc477c4bd Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Fri, 24 May 2024 13:49:39 +0200 Subject: [PATCH 14/51] Include cassert --- backends/functional/smtlib.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/backends/functional/smtlib.cc b/backends/functional/smtlib.cc index f6af797919b..cd11111b9d8 100644 --- a/backends/functional/smtlib.cc +++ b/backends/functional/smtlib.cc @@ -17,6 +17,7 @@ * */ +#include #include "kernel/yosys.h" #include "kernel/drivertools.h" #include "kernel/topo_scc.h" From 2eb24db8c3c5d79cbcbbe474c0c908710b9b4353 Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Sat, 25 May 2024 10:39:18 +0200 Subject: [PATCH 15/51] Created tests for functional C++ backend, comparing its VCD output to CXXRTL VCD output, using vcdiff from CERN --- backends/functional/cxx.cc | 714 +++++++++++++------------- backends/functional/cxx_runtime/sim.h | 2 + flake.nix | 27 +- tests/functional/.gitignore | 5 + tests/functional/run-test.sh | 7 + tests/functional/vcd_harness.cpp | 140 +++++ tests/functional/verilog/and.v | 9 + 7 files changed, 546 insertions(+), 358 deletions(-) create mode 100644 tests/functional/.gitignore create mode 100755 tests/functional/run-test.sh create mode 100644 tests/functional/vcd_harness.cpp create mode 100644 tests/functional/verilog/and.v diff --git a/backends/functional/cxx.cc b/backends/functional/cxx.cc index 5038a9af252..a1060c58d79 100644 --- a/backends/functional/cxx.cc +++ b/backends/functional/cxx.cc @@ -29,391 +29,391 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN const char *reserved_keywords[] = { - "alignas","alignof","and","and_eq","asm","atomic_cancel","atomic_commit", - "atomic_noexcept","auto","bitand","bitor","bool","break","case", - "catch","char","char16_t","char32_t","char8_t","class","co_await", - "co_return","co_yield","compl","concept","const","const_cast","consteval", - "constexpr","constinit","continue","decltype","default","delete", - "do","double","dynamic_cast","else","enum","explicit","export", - "extern","false","float","for","friend","goto","if","inline", - "int","long","mutable","namespace","new","noexcept","not","not_eq", - "nullptr","operator","or","or_eq","private","protected","public", - "reflexpr","register","reinterpret_cast","requires","return","short", - "signed","sizeof","static","static_assert","static_cast","struct", - "switch","synchronized","template","this","thread_local","throw", - "true","try","typedef","typeid","typename","union","unsigned", - "using","virtual","void","volatile","wchar_t","while","xor","xor_eq", - nullptr + "alignas","alignof","and","and_eq","asm","atomic_cancel","atomic_commit", + "atomic_noexcept","auto","bitand","bitor","bool","break","case", + "catch","char","char16_t","char32_t","char8_t","class","co_await", + "co_return","co_yield","compl","concept","const","const_cast","consteval", + "constexpr","constinit","continue","decltype","default","delete", + "do","double","dynamic_cast","else","enum","explicit","export", + "extern","false","float","for","friend","goto","if","inline", + "int","long","mutable","namespace","new","noexcept","not","not_eq", + "nullptr","operator","or","or_eq","private","protected","public", + "reflexpr","register","reinterpret_cast","requires","return","short", + "signed","sizeof","static","static_assert","static_cast","struct", + "switch","synchronized","template","this","thread_local","throw", + "true","try","typedef","typeid","typename","union","unsigned", + "using","virtual","void","volatile","wchar_t","while","xor","xor_eq", + nullptr }; struct CxxScope { - pool used_names; - dict name_map; - - CxxScope() { - for(const char **p = reserved_keywords; *p != nullptr; p++) - reserve(*p); - } - void reserve(std::string name) { - used_names.insert(name); - } - std::string insert(IdString id) { - std::string str = RTLIL::unescape_id(id); - for(size_t i = 0; i < str.size(); i++) - if(strchr("!\"#%&'()*+,-./:;<=>?@[]\\^`{|}~ ", str[i])) - str[i] = '_'; - if(used_names.count(str) == 0){ - used_names.insert(str); - name_map.insert({id, str}); - return str; - } - for (int idx = 0 ; ; idx++){ - std::string suffixed = str + "_" + std::to_string(idx); - if (used_names.count(suffixed) == 0) { - used_names.insert(suffixed); - if(name_map.count(id) == 0) - name_map.insert({id, suffixed}); - return suffixed; - } - } - } - std::string operator[](IdString id) { - if(name_map.count(id) > 0) - return name_map[id]; - else - return insert(id); - } + pool used_names; + dict name_map; + + CxxScope() { + for(const char **p = reserved_keywords; *p != nullptr; p++) + reserve(*p); + } + void reserve(std::string name) { + used_names.insert(name); + } + std::string insert(IdString id) { + std::string str = RTLIL::unescape_id(id); + for(size_t i = 0; i < str.size(); i++) + if(strchr("!\"#%&'()*+,-./:;<=>?@[]\\^`{|}~ ", str[i])) + str[i] = '_'; + if(used_names.count(str) == 0){ + used_names.insert(str); + name_map.insert({id, str}); + return str; + } + for (int idx = 0 ; ; idx++){ + std::string suffixed = str + "_" + std::to_string(idx); + if (used_names.count(suffixed) == 0) { + used_names.insert(suffixed); + if(name_map.count(id) == 0) + name_map.insert({id, suffixed}); + return suffixed; + } + } + } + std::string operator[](IdString id) { + if(name_map.count(id) > 0) + return name_map[id]; + else + return insert(id); + } }; struct CxxWriter { - std::ostream &f; - CxxWriter(std::ostream &out) : f(out) {} - void printf(const char *fmt, ...) - { - va_list va; - va_start(va, fmt); - f << vstringf(fmt, va); - va_end(va); - } + std::ostream &f; + CxxWriter(std::ostream &out) : f(out) {} + void printf(const char *fmt, ...) + { + va_list va; + va_start(va, fmt); + f << vstringf(fmt, va); + va_end(va); + } }; struct CxxStruct { - std::string name; - dict types; - CxxScope scope; - CxxStruct(std::string name) : name(name) { - scope.reserve("out"); - scope.reserve("dump"); - } - void insert(IdString name, std::string type) { - scope.insert(name); - types.insert({name, type}); - } - void print(CxxWriter &f) { - f.printf("struct %s {\n", name.c_str()); - for (auto p : types) { - f.printf("\t%s %s;\n", p.second.c_str(), scope[p.first].c_str()); - } - f.printf("\n\ttemplate void dump(T &out) {\n"); - for (auto p : types) { - f.printf("\t\tout(\"%s\", %s);\n", RTLIL::unescape_id(p.first).c_str(), scope[p.first].c_str()); - } - f.printf("\t}\n};\n\n"); - } - std::string operator[](IdString field) { - return scope[field]; - } + std::string name; + dict types; + CxxScope scope; + CxxStruct(std::string name) : name(name) { + scope.reserve("out"); + scope.reserve("dump"); + } + void insert(IdString name, std::string type) { + scope.insert(name); + types.insert({name, type}); + } + void print(CxxWriter &f) { + f.printf("struct %s {\n", name.c_str()); + for (auto p : types) { + f.printf("\t%s %s;\n", p.second.c_str(), scope[p.first].c_str()); + } + f.printf("\n\ttemplate void dump(T &out) {\n"); + for (auto p : types) { + f.printf("\t\tout(\"%s\", %s);\n", RTLIL::unescape_id(p.first).c_str(), scope[p.first].c_str()); + } + f.printf("\t}\n};\n\n"); + } + std::string operator[](IdString field) { + return scope[field]; + } }; struct CxxFunction { - IdString name; - int width; - dict parameters; + IdString name; + int width; + dict parameters; - CxxFunction(IdString name, int width) : name(name), width(width) {} - CxxFunction(IdString name, int width, dict parameters) : name(name), width(width), parameters(parameters) {} + CxxFunction(IdString name, int width) : name(name), width(width) {} + CxxFunction(IdString name, int width, dict parameters) : name(name), width(width), parameters(parameters) {} - bool operator==(CxxFunction const &other) const { - return name == other.name && parameters == other.parameters && width == other.width; - } + bool operator==(CxxFunction const &other) const { + return name == other.name && parameters == other.parameters && width == other.width; + } - unsigned int hash() const { - return mkhash(name.hash(), parameters.hash()); - } + unsigned int hash() const { + return mkhash(name.hash(), parameters.hash()); + } }; typedef ComputeGraph CxxComputeGraph; class CxxComputeGraphFactory { - CxxComputeGraph &graph; - using T = CxxComputeGraph::Ref; - static bool is_single_output(IdString type) - { - auto it = yosys_celltypes.cell_types.find(type); - return it != yosys_celltypes.cell_types.end() && it->second.outputs.size() <= 1; - } + CxxComputeGraph &graph; + using T = CxxComputeGraph::Ref; + static bool is_single_output(IdString type) + { + auto it = yosys_celltypes.cell_types.find(type); + return it != yosys_celltypes.cell_types.end() && it->second.outputs.size() <= 1; + } public: - CxxComputeGraphFactory(CxxComputeGraph &g) : graph(g) {} - T slice(T a, int in_width, int offset, int out_width) { - assert(offset + out_width <= in_width); - return graph.add(CxxFunction(ID($$slice), out_width, {{ID(offset), offset}}), 0, std::array{a}); - } - T extend(T a, int in_width, int out_width, bool is_signed) { - assert(in_width < out_width); - if(is_signed) - return graph.add(CxxFunction(ID($sign_extend), out_width, {{ID(WIDTH), out_width}}), 0, std::array{a}); - else - return graph.add(CxxFunction(ID($zero_extend), out_width, {{ID(WIDTH), out_width}}), 0, std::array{a}); - } - T concat(T a, int a_width, T b, int b_width) { - return graph.add(CxxFunction(ID($$concat), a_width + b_width), 0, std::array{a, b}); - } - T add(T a, T b, int width) { return graph.add(CxxFunction(ID($add), width), 0, std::array{a, b}); } - T sub(T a, T b, int width) { return graph.add(CxxFunction(ID($sub), width), 0, std::array{a, b}); } - T bitwise_and(T a, T b, int width) { return graph.add(CxxFunction(ID($and), width), 0, std::array{a, b}); } - T bitwise_or(T a, T b, int width) { return graph.add(CxxFunction(ID($or), width), 0, std::array{a, b}); } - T bitwise_xor(T a, T b, int width) { return graph.add(CxxFunction(ID($xor), width), 0, std::array{a, b}); } - T bitwise_not(T a, int width) { return graph.add(CxxFunction(ID($not), width), 0, std::array{a}); } - T neg(T a, int width) { return graph.add(CxxFunction(ID($neg), width), 0, std::array{a}); } - T mux(T a, T b, T s, int width) { return graph.add(CxxFunction(ID($mux), width), 0, std::array{a, b, s}); } - T pmux(T a, T b, T s, int width, int) { return graph.add(CxxFunction(ID($pmux), width), 0, std::array{a, b, s}); } - T reduce_and(T a, int) { return graph.add(CxxFunction(ID($reduce_and), 1), 0, std::array{a}); } - T reduce_or(T a, int) { return graph.add(CxxFunction(ID($reduce_or), 1), 0, std::array{a}); } - T reduce_xor(T a, int) { return graph.add(CxxFunction(ID($reduce_xor), 1), 0, std::array{a}); } - T eq(T a, T b, int) { return graph.add(CxxFunction(ID($eq), 1), 0, std::array{a, b}); } - T ne(T a, T b, int) { return graph.add(CxxFunction(ID($ne), 1), 0, std::array{a, b}); } - T gt(T a, T b, int) { return graph.add(CxxFunction(ID($gt), 1), 0, std::array{a, b}); } - T ge(T a, T b, int) { return graph.add(CxxFunction(ID($ge), 1), 0, std::array{a, b}); } - T ugt(T a, T b, int) { return graph.add(CxxFunction(ID($ugt), 1), 0, std::array{a, b}); } - T uge(T a, T b, int) { return graph.add(CxxFunction(ID($uge), 1), 0, std::array{a, b}); } - T logical_shift_left(T a, T b, int y_width, int) { return graph.add(CxxFunction(ID($shl), y_width, {{ID(WIDTH), y_width}}), 0, std::array{a, b}); } - T logical_shift_right(T a, T b, int y_width, int) { return graph.add(CxxFunction(ID($shr), y_width, {{ID(WIDTH), y_width}}), 0, std::array{a, b}); } - T arithmetic_shift_right(T a, T b, int y_width, int) { return graph.add(CxxFunction(ID($asr), y_width, {{ID(WIDTH), y_width}}), 0, std::array{a, b}); } - - T constant(RTLIL::Const value) { - return graph.add(CxxFunction(ID($$const), value.size(), {{ID(value), value}}), 0); - } - T input(IdString name, int width) { return graph.add(CxxFunction(ID($$input), width, {{name, {}}}), 0); } - T state(IdString name, int width) { return graph.add(CxxFunction(ID($$state), width, {{name, {}}}), 0); } - T cell_output(T cell, IdString type, IdString name, int width) { - if (is_single_output(type)) - return cell; - else - return graph.add(CxxFunction(ID($$cell_output), width, {{name, {}}}), 0, std::array{cell}); - } - T multiple(vector args, int width) { - return graph.add(CxxFunction(ID($$multiple), width), 0, args); - } - T undriven(int width) { - return graph.add(CxxFunction(ID($$undriven), width), 0); - } - - T create_pending(int width) { - return graph.add(CxxFunction(ID($$pending), width), 0); - } - void update_pending(T pending, T node) { - assert(pending.function().name == ID($$pending)); - pending.set_function(CxxFunction(ID($$buf), pending.function().width)); - pending.append_arg(node); - } - void declare_output(T node, IdString name, int) { - node.assign_key(name); - } - void declare_state(T node, IdString name, int) { - node.assign_key(name); - } - void suggest_name(T node, IdString name) { - node.sparse_attr() = name; - } + CxxComputeGraphFactory(CxxComputeGraph &g) : graph(g) {} + T slice(T a, int in_width, int offset, int out_width) { + assert(offset + out_width <= in_width); + return graph.add(CxxFunction(ID($$slice), out_width, {{ID(offset), offset}}), 0, std::array{a}); + } + T extend(T a, int in_width, int out_width, bool is_signed) { + assert(in_width < out_width); + if(is_signed) + return graph.add(CxxFunction(ID($sign_extend), out_width, {{ID(WIDTH), out_width}}), 0, std::array{a}); + else + return graph.add(CxxFunction(ID($zero_extend), out_width, {{ID(WIDTH), out_width}}), 0, std::array{a}); + } + T concat(T a, int a_width, T b, int b_width) { + return graph.add(CxxFunction(ID($$concat), a_width + b_width), 0, std::array{a, b}); + } + T add(T a, T b, int width) { return graph.add(CxxFunction(ID($add), width), 0, std::array{a, b}); } + T sub(T a, T b, int width) { return graph.add(CxxFunction(ID($sub), width), 0, std::array{a, b}); } + T bitwise_and(T a, T b, int width) { return graph.add(CxxFunction(ID($and), width), 0, std::array{a, b}); } + T bitwise_or(T a, T b, int width) { return graph.add(CxxFunction(ID($or), width), 0, std::array{a, b}); } + T bitwise_xor(T a, T b, int width) { return graph.add(CxxFunction(ID($xor), width), 0, std::array{a, b}); } + T bitwise_not(T a, int width) { return graph.add(CxxFunction(ID($not), width), 0, std::array{a}); } + T neg(T a, int width) { return graph.add(CxxFunction(ID($neg), width), 0, std::array{a}); } + T mux(T a, T b, T s, int width) { return graph.add(CxxFunction(ID($mux), width), 0, std::array{a, b, s}); } + T pmux(T a, T b, T s, int width, int) { return graph.add(CxxFunction(ID($pmux), width), 0, std::array{a, b, s}); } + T reduce_and(T a, int) { return graph.add(CxxFunction(ID($reduce_and), 1), 0, std::array{a}); } + T reduce_or(T a, int) { return graph.add(CxxFunction(ID($reduce_or), 1), 0, std::array{a}); } + T reduce_xor(T a, int) { return graph.add(CxxFunction(ID($reduce_xor), 1), 0, std::array{a}); } + T eq(T a, T b, int) { return graph.add(CxxFunction(ID($eq), 1), 0, std::array{a, b}); } + T ne(T a, T b, int) { return graph.add(CxxFunction(ID($ne), 1), 0, std::array{a, b}); } + T gt(T a, T b, int) { return graph.add(CxxFunction(ID($gt), 1), 0, std::array{a, b}); } + T ge(T a, T b, int) { return graph.add(CxxFunction(ID($ge), 1), 0, std::array{a, b}); } + T ugt(T a, T b, int) { return graph.add(CxxFunction(ID($ugt), 1), 0, std::array{a, b}); } + T uge(T a, T b, int) { return graph.add(CxxFunction(ID($uge), 1), 0, std::array{a, b}); } + T logical_shift_left(T a, T b, int y_width, int) { return graph.add(CxxFunction(ID($shl), y_width, {{ID(WIDTH), y_width}}), 0, std::array{a, b}); } + T logical_shift_right(T a, T b, int y_width, int) { return graph.add(CxxFunction(ID($shr), y_width, {{ID(WIDTH), y_width}}), 0, std::array{a, b}); } + T arithmetic_shift_right(T a, T b, int y_width, int) { return graph.add(CxxFunction(ID($asr), y_width, {{ID(WIDTH), y_width}}), 0, std::array{a, b}); } + + T constant(RTLIL::Const value) { + return graph.add(CxxFunction(ID($$const), value.size(), {{ID(value), value}}), 0); + } + T input(IdString name, int width) { return graph.add(CxxFunction(ID($$input), width, {{name, {}}}), 0); } + T state(IdString name, int width) { return graph.add(CxxFunction(ID($$state), width, {{name, {}}}), 0); } + T cell_output(T cell, IdString type, IdString name, int width) { + if (is_single_output(type)) + return cell; + else + return graph.add(CxxFunction(ID($$cell_output), width, {{name, {}}}), 0, std::array{cell}); + } + T multiple(vector args, int width) { + return graph.add(CxxFunction(ID($$multiple), width), 0, args); + } + T undriven(int width) { + return graph.add(CxxFunction(ID($$undriven), width), 0); + } + + T create_pending(int width) { + return graph.add(CxxFunction(ID($$pending), width), 0); + } + void update_pending(T pending, T node) { + assert(pending.function().name == ID($$pending)); + pending.set_function(CxxFunction(ID($$buf), pending.function().width)); + pending.append_arg(node); + } + void declare_output(T node, IdString name, int) { + node.assign_key(name); + } + void declare_state(T node, IdString name, int) { + node.assign_key(name); + } + void suggest_name(T node, IdString name) { + node.sparse_attr() = name; + } }; struct FunctionalCxxBackend : public Backend { - FunctionalCxxBackend() : Backend("functional_cxx", "convert design to C++ using the functional backend") {} - - void help() override + FunctionalCxxBackend() : Backend("functional_cxx", "convert design to C++ using the functional backend") {} + + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + } + + CxxComputeGraph calculate_compute_graph(RTLIL::Module *module) + { + CxxComputeGraph compute_graph; + CxxComputeGraphFactory factory(compute_graph); + ComputeGraphConstruction construction(factory); + construction.add_module(module); + construction.process_queue(); + + // Perform topo sort and detect SCCs + CxxComputeGraph::SccAdaptor compute_graph_scc(compute_graph); + + bool scc = false; + std::vector perm; + topo_sorted_sccs(compute_graph_scc, [&](int *begin, int *end) { + perm.insert(perm.end(), begin, end); + if (end > begin + 1) { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - } - - CxxComputeGraph calculate_compute_graph(RTLIL::Module *module) - { - CxxComputeGraph compute_graph; - CxxComputeGraphFactory factory(compute_graph); - ComputeGraphConstruction construction(factory); - construction.add_module(module); - construction.process_queue(); - - // Perform topo sort and detect SCCs - CxxComputeGraph::SccAdaptor compute_graph_scc(compute_graph); - - bool scc = false; - std::vector perm; - topo_sorted_sccs(compute_graph_scc, [&](int *begin, int *end) { - perm.insert(perm.end(), begin, end); - if (end > begin + 1) - { - log_warning("SCC:"); - for (int *i = begin; i != end; ++i) - log(" %d(%s)(%s)", *i, compute_graph[*i].function().name.c_str(), compute_graph[*i].has_sparse_attr() ? compute_graph[*i].sparse_attr().c_str() : ""); - log("\n"); - scc = true; - } - }, /* sources_first */ true); - compute_graph.permute(perm); - if(scc) log_error("combinational loops, aborting\n"); - - // Forward $$buf - std::vector alias; - perm.clear(); - - for (int i = 0; i < compute_graph.size(); ++i) - { - auto node = compute_graph[i]; - if (node.function().name == ID($$buf) && node.arg(0).index() < i) - { - int target_index = alias[node.arg(0).index()]; - auto target_node = compute_graph[perm[target_index]]; - if(!target_node.has_sparse_attr() && node.has_sparse_attr()) - target_node.sparse_attr() = node.sparse_attr(); - alias.push_back(target_index); - } - else - { - alias.push_back(GetSize(perm)); - perm.push_back(i); - } - } - compute_graph.permute(perm, alias); - return compute_graph; - } - - void printCxx(std::ostream &stream, std::string, std::string const & name, CxxComputeGraph &compute_graph) - { - dict inputs, state; - CxxWriter f(stream); - - // Dump the compute graph - for (int i = 0; i < compute_graph.size(); ++i) - { - auto ref = compute_graph[i]; - if(ref.function().name == ID($$input)) - inputs[ref.function().parameters.begin()->first] = ref.function().width; - if(ref.function().name == ID($$state)) - state[ref.function().parameters.begin()->first] = ref.function().width; - } - f.printf("#include \"sim.h\"\n"); - CxxStruct input_struct(name + "_Inputs"); - for (auto const &input : inputs) - input_struct.insert(input.first, "Signal<" + std::to_string(input.second) + ">"); - CxxStruct output_struct(name + "_Outputs"); - for (auto const &key : compute_graph.keys()) - if(state.count(key.first) == 0) - output_struct.insert(key.first, "Signal<" + std::to_string(compute_graph[key.second].function().width) + ">"); - CxxStruct state_struct(name + "_State"); - for (auto const &state_var : state) - state_struct.insert(state_var.first, "Signal<" + std::to_string(state_var.second) + ">"); - - idict node_names; - CxxScope locals; - - input_struct.print(f); - output_struct.print(f); - state_struct.print(f); - - f.printf("void %s(%s_Inputs const &input, %s_Outputs &output, %s_State const ¤t_state, %s_State &next_state)\n{\n", name.c_str(), name.c_str(), name.c_str(), name.c_str(), name.c_str()); - locals.reserve("input"); - locals.reserve("output"); - locals.reserve("current_state"); - locals.reserve("next_state"); - for (int i = 0; i < compute_graph.size(); ++i) - { - auto ref = compute_graph[i]; - int width = ref.function().width; - std::string name; - if(ref.has_sparse_attr()) - name = locals.insert(ref.sparse_attr()); - else - name = locals.insert("\\n" + std::to_string(i)); - node_names(name); - if(ref.function().name == ID($$input)) - f.printf("\tSignal<%d> %s = input.%s;\n", width, name.c_str(), input_struct[ref.function().parameters.begin()->first].c_str()); - else if(ref.function().name == ID($$state)) - f.printf("\tSignal<%d> %s = current_state.%s;\n", width, name.c_str(), state_struct[ref.function().parameters.begin()->first].c_str()); - else if(ref.function().name == ID($$buf)) - f.printf("\tSignal<%d> %s = %s;\n", width, name.c_str(), node_names[ref.arg(0).index()].c_str()); - else if(ref.function().name == ID($$cell_output)) - f.printf("\tSignal<%d> %s = %s.%s;\n", width, name.c_str(), node_names[ref.arg(0).index()].c_str(), RTLIL::unescape_id(ref.function().parameters.begin()->first).c_str()); - else if(ref.function().name == ID($$const)){ - auto c = ref.function().parameters.begin()->second; - if(c.size() <= 32){ - f.printf("\tSignal<%d> %s = $const<%d>(%#x);\n", width, name.c_str(), width, (uint32_t) c.as_int()); - }else{ - f.printf("\tSignal<%d> %s = $const<%d>({%#x", width, name.c_str(), width, (uint32_t) c.as_int()); - while(c.size() > 32){ - c = c.extract(32, c.size() - 32); - f.printf(", %#x", c.as_int()); - } - f.printf("});\n"); - } - }else if(ref.function().name == ID($$undriven)) - f.printf("\tSignal<%d> %s; //undriven\n", width, name.c_str()); - else if(ref.function().name == ID($$slice)) - f.printf("\tSignal<%d> %s = slice<%d>(%s, %d);\n", width, name.c_str(), width, node_names[ref.arg(0).index()].c_str(), ref.function().parameters.at(ID(offset)).as_int()); - else if(ref.function().name == ID($$concat)){ - f.printf("\tauto %s = concat(", name.c_str()); - for (int i = 0, end = ref.size(); i != end; ++i){ - if(i > 0) - f.printf(", "); - f.printf("%s", node_names[ref.arg(i).index()].c_str()); - } - f.printf(");\n"); - }else{ - f.printf("\t"); - if(ref.function().width > 0) - f.printf("Signal<%d>", ref.function().width); - else - f.printf("%s_Outputs", log_id(ref.function().name)); - f.printf(" %s = %s", name.c_str(), log_id(ref.function().name)); - if(ref.function().parameters.count(ID(WIDTH))){ - f.printf("<%d>", ref.function().parameters.at(ID(WIDTH)).as_int()); - } - f.printf("("); - for (int i = 0, end = ref.size(); i != end; ++i) - f.printf("%s%s", i>0?", ":"", node_names[ref.arg(i).index()].c_str()); - f.printf("); //"); - for (auto const ¶m : ref.function().parameters) - { - if (param.second.empty()) - f.printf("[%s]", log_id(param.first)); - else - f.printf("[%s=%s]", log_id(param.first), log_const(param.second)); - } - f.printf("\n"); - } - } - - for (auto const &key : compute_graph.keys()) - { - f.printf("\t%s.%s = %s;\n", state.count(key.first) > 0 ? "next_state" : "output", state_struct[key.first].c_str(), node_names[key.second].c_str()); - } - f.printf("}\n"); + log_warning("SCC:"); + for (int *i = begin; i != end; ++i) + log(" %d(%s)(%s)", *i, compute_graph[*i].function().name.c_str(), compute_graph[*i].has_sparse_attr() ? compute_graph[*i].sparse_attr().c_str() : ""); + log("\n"); + scc = true; } - - void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) override - { - log_header(design, "Executing Functional C++ backend.\n"); - - size_t argidx = 1; - extra_args(f, filename, args, argidx, design); - - for (auto module : design->selected_modules()) { - log("Dumping module `%s'.\n", module->name.c_str()); - auto compute_graph = calculate_compute_graph(module); - printCxx(*f, filename, RTLIL::unescape_id(module->name), compute_graph); - } + }, /* sources_first */ true); + compute_graph.permute(perm); + if(scc) log_error("combinational loops, aborting\n"); + + // Forward $$buf + std::vector alias; + perm.clear(); + + for (int i = 0; i < compute_graph.size(); ++i) + { + auto node = compute_graph[i]; + if (node.function().name == ID($$buf) && node.arg(0).index() < i) + { + int target_index = alias[node.arg(0).index()]; + auto target_node = compute_graph[perm[target_index]]; + if(!target_node.has_sparse_attr() && node.has_sparse_attr()) + target_node.sparse_attr() = node.sparse_attr(); + alias.push_back(target_index); + } + else + { + alias.push_back(GetSize(perm)); + perm.push_back(i); + } + } + compute_graph.permute(perm, alias); + return compute_graph; + } + + void printCxx(std::ostream &stream, std::string, std::string const & name, CxxComputeGraph &compute_graph) + { + dict inputs, state; + CxxWriter f(stream); + + // Dump the compute graph + for (int i = 0; i < compute_graph.size(); ++i) + { + auto ref = compute_graph[i]; + if(ref.function().name == ID($$input)) + inputs[ref.function().parameters.begin()->first] = ref.function().width; + if(ref.function().name == ID($$state)) + state[ref.function().parameters.begin()->first] = ref.function().width; + } + f.printf("#include \"sim.h\"\n"); + CxxStruct input_struct(name + "_Inputs"); + for (auto const &input : inputs) + input_struct.insert(input.first, "Signal<" + std::to_string(input.second) + ">"); + CxxStruct output_struct(name + "_Outputs"); + for (auto const &key : compute_graph.keys()) + if(state.count(key.first) == 0) + output_struct.insert(key.first, "Signal<" + std::to_string(compute_graph[key.second].function().width) + ">"); + CxxStruct state_struct(name + "_State"); + for (auto const &state_var : state) + state_struct.insert(state_var.first, "Signal<" + std::to_string(state_var.second) + ">"); + + idict node_names; + CxxScope locals; + + input_struct.print(f); + output_struct.print(f); + state_struct.print(f); + + f.printf("void %s(%s_Inputs const &input, %s_Outputs &output, %s_State const ¤t_state, %s_State &next_state)\n{\n", name.c_str(), name.c_str(), name.c_str(), name.c_str(), name.c_str()); + locals.reserve("input"); + locals.reserve("output"); + locals.reserve("current_state"); + locals.reserve("next_state"); + for (int i = 0; i < compute_graph.size(); ++i) + { + auto ref = compute_graph[i]; + int width = ref.function().width; + std::string name; + if(ref.has_sparse_attr()) + name = locals.insert(ref.sparse_attr()); + else + name = locals.insert("\\n" + std::to_string(i)); + node_names(name); + if(ref.function().name == ID($$input)) + f.printf("\tSignal<%d> %s = input.%s;\n", width, name.c_str(), input_struct[ref.function().parameters.begin()->first].c_str()); + else if(ref.function().name == ID($$state)) + f.printf("\tSignal<%d> %s = current_state.%s;\n", width, name.c_str(), state_struct[ref.function().parameters.begin()->first].c_str()); + else if(ref.function().name == ID($$buf)) + f.printf("\tSignal<%d> %s = %s;\n", width, name.c_str(), node_names[ref.arg(0).index()].c_str()); + else if(ref.function().name == ID($$cell_output)) + f.printf("\tSignal<%d> %s = %s.%s;\n", width, name.c_str(), node_names[ref.arg(0).index()].c_str(), RTLIL::unescape_id(ref.function().parameters.begin()->first).c_str()); + else if(ref.function().name == ID($$const)){ + auto c = ref.function().parameters.begin()->second; + if(c.size() <= 32){ + f.printf("\tSignal<%d> %s = $const<%d>(%#x);\n", width, name.c_str(), width, (uint32_t) c.as_int()); + }else{ + f.printf("\tSignal<%d> %s = $const<%d>({%#x", width, name.c_str(), width, (uint32_t) c.as_int()); + while(c.size() > 32){ + c = c.extract(32, c.size() - 32); + f.printf(", %#x", c.as_int()); + } + f.printf("});\n"); + } + }else if(ref.function().name == ID($$undriven)) + f.printf("\tSignal<%d> %s; //undriven\n", width, name.c_str()); + else if(ref.function().name == ID($$slice)) + f.printf("\tSignal<%d> %s = slice<%d>(%s, %d);\n", width, name.c_str(), width, node_names[ref.arg(0).index()].c_str(), ref.function().parameters.at(ID(offset)).as_int()); + else if(ref.function().name == ID($$concat)){ + f.printf("\tauto %s = concat(", name.c_str()); + for (int i = 0, end = ref.size(); i != end; ++i){ + if(i > 0) + f.printf(", "); + f.printf("%s", node_names[ref.arg(i).index()].c_str()); + } + f.printf(");\n"); + }else{ + f.printf("\t"); + if(ref.function().width > 0) + f.printf("Signal<%d>", ref.function().width); + else + f.printf("%s_Outputs", log_id(ref.function().name)); + f.printf(" %s = %s", name.c_str(), log_id(ref.function().name)); + if(ref.function().parameters.count(ID(WIDTH))){ + f.printf("<%d>", ref.function().parameters.at(ID(WIDTH)).as_int()); + } + f.printf("("); + for (int i = 0, end = ref.size(); i != end; ++i) + f.printf("%s%s", i>0?", ":"", node_names[ref.arg(i).index()].c_str()); + f.printf("); //"); + for (auto const ¶m : ref.function().parameters) + { + if (param.second.empty()) + f.printf("[%s]", log_id(param.first)); + else + f.printf("[%s=%s]", log_id(param.first), log_const(param.second)); + } + f.printf("\n"); } + } + + for (auto const &key : compute_graph.keys()) + { + f.printf("\t%s.%s = %s;\n", state.count(key.first) > 0 ? "next_state" : "output", state_struct[key.first].c_str(), node_names[key.second].c_str()); + } + f.printf("}\n"); + } + + void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) override + { + log_header(design, "Executing Functional C++ backend.\n"); + + size_t argidx = 1; + extra_args(f, filename, args, argidx, design); + + for (auto module : design->selected_modules()) { + log("Dumping module `%s'.\n", module->name.c_str()); + auto compute_graph = calculate_compute_graph(module); + printCxx(*f, filename, RTLIL::unescape_id(module->name), compute_graph); + } + } } FunctionalCxxBackend; PRIVATE_NAMESPACE_END diff --git a/backends/functional/cxx_runtime/sim.h b/backends/functional/cxx_runtime/sim.h index 4e7d9b60142..829266da0e6 100644 --- a/backends/functional/cxx_runtime/sim.h +++ b/backends/functional/cxx_runtime/sim.h @@ -21,6 +21,8 @@ #define SIM_H #include +#include +#include template using Signal = std::array; diff --git a/flake.nix b/flake.nix index 1e202324647..63c1e13720d 100644 --- a/flake.nix +++ b/flake.nix @@ -37,11 +37,36 @@ maintainers = with maintainers; [ ]; }; }; + vcdiff = pkgs.stdenv.mkDerivation { + pname = "vcdiff"; + version = "1.1"; + + src = pkgs.fetchFromGitHub { + owner = "orsonmmz"; + repo = "vcdiff"; + rev = "master"; + hash = "sha256-jTuok3TjuGW7+ATc11R9osKDPxbhRtuEbM8tRE4+AAI="; + }; + + buildInputs = [ pkgs.gcc ]; + + installPhase = '' + mkdir -p $out/bin + cp vcdiff $out/bin/ + ''; + + meta = with pkgs.lib; { + description = "The ultimate VCD files comparator"; + license = licenses.gpl3; + maintainers = with maintainers; [ orsonmmz ]; + }; + }; in { packages.default = yosys; defaultPackage = yosys; + packages.vcdiff = vcdiff; devShell = pkgs.mkShell { - buildInputs = with pkgs; [ clang bison flex libffi tcl readline python3 llvmPackages.libcxxClang zlib git gtest abc-verifier ]; + buildInputs = with pkgs; [ clang bison flex libffi tcl readline python3 llvmPackages.libcxxClang zlib git gtest abc-verifier gtkwave vcdiff ]; }; } ); diff --git a/tests/functional/.gitignore b/tests/functional/.gitignore new file mode 100644 index 00000000000..06af41869c9 --- /dev/null +++ b/tests/functional/.gitignore @@ -0,0 +1,5 @@ +and_cxxrtl.cc +and_functional_cxx.cc +vcd_harness +cxxrtl.vcd +functional_cxx.vcd \ No newline at end of file diff --git a/tests/functional/run-test.sh b/tests/functional/run-test.sh new file mode 100755 index 00000000000..be4bef9c32b --- /dev/null +++ b/tests/functional/run-test.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +set -ex + +../../yosys -p "read_verilog verilog/and.v; write_cxxrtl and_cxxrtl.cc; write_functional_cxx and_functional_cxx.cc" +${CXX:-g++} -g -fprofile-arcs -ftest-coverage vcd_harness.cpp -I ../../backends/functional/cxx_runtime/ -I ../../backends/cxxrtl/runtime/ -o vcd_harness +./vcd_harness diff --git a/tests/functional/vcd_harness.cpp b/tests/functional/vcd_harness.cpp new file mode 100644 index 00000000000..dc3ad3b9c2b --- /dev/null +++ b/tests/functional/vcd_harness.cpp @@ -0,0 +1,140 @@ +#include +#include +#include +#include + +#include + +#include "and_cxxrtl.cc" +#include "and_functional_cxx.cc" + +struct DumpHeader { + std::ofstream &ofs; + DumpHeader(std::ofstream &ofs) : ofs(ofs) {} + template + void operator()(const char *name, Signal value) { + ofs << "$var wire " << n << " " << name[0] << " " << name << " $end\n"; + } +}; + +struct Dump { + std::ofstream &ofs; + Dump(std::ofstream &ofs) : ofs(ofs) {} + template + void operator()(const char *name, Signal value) { + // Bit + if (n == 1) { + ofs << (value[0] ? '1' : '0'); + ofs << name[0] << "\n"; + return; + } + // vector (multi-bit) signals + ofs << "b"; + for (size_t i = n; i-- > 0;) + ofs << (value[i] ? '1' : '0'); + ofs << " " << name[0] << "\n"; + } +}; + +int main(int argc, char **argv) +{ + constexpr int steps = 10; + constexpr int number_timescale = 1; + const std::string units_timescale = "us"; + Adder_Inputs inputs; + Adder_Outputs outputs; + Adder_State state; + Adder_State next_state; + + std::ofstream vcd_file("functional_cxx.vcd"); + + vcd_file << "$timescale " << number_timescale << " " << units_timescale << " $end\n"; //$scope module logic $end\n"; + { + DumpHeader d(vcd_file); + inputs.dump(d); + outputs.dump(d); + // vcd_file << "$scope module state $end\n"; + state.dump(d); + } + vcd_file << "$enddefinitions $end\n$dumpvars\n"; + + cxxrtl_design::p_Adder top; + + // debug_items maps the hierarchical names of signals and memories in the design + // to a cxxrtl_object (a value, a wire, or a memory) + cxxrtl::debug_items all_debug_items; + cxxrtl::debug_scope debug_scope; + // Load the debug items of the top down the whole design hierarchy + top.debug_info(&all_debug_items, nullptr, ""); + + // vcd_writer is the CXXRTL object that's responsible for creating a string with + // the VCD file contents. + cxxrtl::vcd_writer vcd; + vcd.timescale(number_timescale, units_timescale); + + // Here we tell the vcd writer to dump all the signals of the design, except for the + // memories, to the VCD file. + // + // It's not necessary to load all debug objects to the VCD. There is, for example, + // a vcd.add(, )) method which allows creating your custom filter to decide + // what to add and what not. + vcd.add_without_memories(all_debug_items); + + std::ofstream waves("cxxrtl.vcd"); + + top.p_a.set(false); + top.p_b.set(false); + top.step(); + + // We need to manually tell the VCD writer when to sample and write out the traced items. + // This is only a slight inconvenience and allows for complete flexibility. + // E.g. you could only start waveform tracing when an internal signal has reached some specific + // value etc. + vcd.sample(0); + vcd_file << "#0\n"; + inputs.a = $const<1>(false); + inputs.b = $const<1>(false); + { + Dump d(vcd_file); + inputs.dump(d); + outputs.dump(d); + state.dump(d); + } + + // Initialize random number generator + std::random_device rd; + std::mt19937 gen(rd()); + std::bernoulli_distribution dist(0.5); // 50% chance for true or false + + for (int step = 0; step < steps; ++step) { + const bool a_value = dist(gen); + const bool b_value = dist(gen); + + // cxxrtl + top.p_a.set(a_value); + top.p_b.set(b_value); + top.step(); + vcd.sample(step + 1); + + waves << vcd.buffer; + vcd.buffer.clear(); + + // Functional backend cxx + vcd_file << "#" << (step + 1) << "\n"; + inputs.a = $const<1>(a_value); + inputs.b = $const<1>(b_value); + Adder(inputs, outputs, state, next_state); + { + Dump d(vcd_file); + inputs.dump(d); + outputs.dump(d); + state.dump(d); + } + state = next_state; + } + + vcd_file.close(); + waves.close(); + + return 0; +} diff --git a/tests/functional/verilog/and.v b/tests/functional/verilog/and.v new file mode 100644 index 00000000000..11cf481e96b --- /dev/null +++ b/tests/functional/verilog/and.v @@ -0,0 +1,9 @@ +module Adder( + input a, + input b, + output sum + ); + // Perform addition + assign sum = a + b; + +endmodule From ad63997829ed5875ab222081e4c7f4c7b84010e3 Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Sat, 25 May 2024 10:47:56 +0200 Subject: [PATCH 16/51] Check vcdiff output --- tests/functional/run-test.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/functional/run-test.sh b/tests/functional/run-test.sh index be4bef9c32b..3e9de003fc2 100755 --- a/tests/functional/run-test.sh +++ b/tests/functional/run-test.sh @@ -4,4 +4,17 @@ set -ex ../../yosys -p "read_verilog verilog/and.v; write_cxxrtl and_cxxrtl.cc; write_functional_cxx and_functional_cxx.cc" ${CXX:-g++} -g -fprofile-arcs -ftest-coverage vcd_harness.cpp -I ../../backends/functional/cxx_runtime/ -I ../../backends/cxxrtl/runtime/ -o vcd_harness +# Generate VCD files cxxrtl.vcd and functional_cxx.vcd ./vcd_harness +# Run vcdiff and capture the output +output=$(vcdiff cxxrtl.vcd functional_cxx.vcd) + +# Check if there is any output +if [ -n "$output" ]; then + echo "Differences detected:" + echo "$output" + exit 1 +else + echo "No differences detected." + exit 0 +fi From 6644127c6d301571c05961f882efa959e5dc5e0c Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Sat, 25 May 2024 11:35:31 +0200 Subject: [PATCH 17/51] Test all files in verilog dir --- flake.nix | 2 +- tests/functional/.gitignore | 4 +- tests/functional/coverage_report/amber.png | Bin 0 -> 141 bytes tests/functional/coverage_report/emerald.png | Bin 0 -> 141 bytes .../functional/and_cxxrtl.cc.func-sort-c.html | 100 + .../functional/and_cxxrtl.cc.func.html | 100 + .../functional/and_cxxrtl.cc.gcov.html | 161 ++ .../and_functional_cxx.cc.func-sort-c.html | 84 + .../and_functional_cxx.cc.func.html | 84 + .../and_functional_cxx.cc.gcov.html | 108 + .../functional/index-sort-f.html | 113 + .../functional/index-sort-l.html | 113 + .../coverage_report/functional/index.html | 113 + .../vcd_harness.cpp.func-sort-c.html | 84 + .../functional/vcd_harness.cpp.func.html | 84 + .../functional/vcd_harness.cpp.gcov.html | 216 ++ tests/functional/coverage_report/gcov.css | 519 ++++ tests/functional/coverage_report/glass.png | Bin 0 -> 167 bytes .../runtime/cxxrtl/cxxrtl.h.func-sort-c.html | 108 + .../cxxrtl/runtime/cxxrtl/cxxrtl.h.func.html | 108 + .../cxxrtl/runtime/cxxrtl/cxxrtl.h.gcov.html | 2182 +++++++++++++++++ .../cxxrtl/cxxrtl_vcd.h.func-sort-c.html | 136 + .../runtime/cxxrtl/cxxrtl_vcd.h.func.html | 136 + .../runtime/cxxrtl/cxxrtl_vcd.h.gcov.html | 351 +++ .../cxxrtl/runtime/cxxrtl/index-sort-f.html | 103 + .../cxxrtl/runtime/cxxrtl/index-sort-l.html | 103 + .../backends/cxxrtl/runtime/cxxrtl/index.html | 103 + .../functional/cxx_runtime/index-sort-f.html | 93 + .../functional/cxx_runtime/index-sort-l.html | 93 + .../functional/cxx_runtime/index.html | 93 + .../cxx_runtime/sim.h.func-sort-c.html | 72 + .../functional/cxx_runtime/sim.h.func.html | 72 + .../functional/cxx_runtime/sim.h.gcov.html | 444 ++++ .../functional/and_cxxrtl.cc.func-sort-c.html | 100 + .../tests/functional/and_cxxrtl.cc.func.html | 100 + .../tests/functional/and_cxxrtl.cc.gcov.html | 161 ++ .../and_functional_cxx.cc.func-sort-c.html | 84 + .../and_functional_cxx.cc.func.html | 84 + .../and_functional_cxx.cc.gcov.html | 108 + .../tests/functional/index-sort-f.html | 113 + .../tests/functional/index-sort-l.html | 113 + .../my_yosys/tests/functional/index.html | 113 + .../vcd_harness.cpp.func-sort-c.html | 84 + .../functional/vcd_harness.cpp.func.html | 84 + .../functional/vcd_harness.cpp.gcov.html | 216 ++ .../coverage_report/index-sort-f.html | 93 + .../coverage_report/index-sort-l.html | 93 + tests/functional/coverage_report/index.html | 93 + .../include/bits/string_fortified.h.gcov.html | 54 + tests/functional/coverage_report/ruby.png | Bin 0 -> 141 bytes tests/functional/coverage_report/snow.png | Bin 0 -> 141 bytes tests/functional/coverage_report/updown.png | Bin 0 -> 117 bytes .../coverage_report/vcd_harness.info | 0 tests/functional/generate_coverage.sh | 19 + tests/functional/run-test.sh | 40 +- tests/functional/vcd_harness.cpp | 16 +- tests/functional/verilog/add.v | 9 + tests/functional/verilog/and.v | 14 +- tests/functional/verilog/my_module_div.v | 9 + tests/functional/verilog/my_module_eqx.v | 9 + tests/functional/verilog/my_module_ge.v | 9 + tests/functional/verilog/my_module_gt.v | 9 + tests/functional/verilog/my_module_le.v | 9 + .../functional/verilog/my_module_logic_and.v | 9 + tests/functional/verilog/my_module_logic_or.v | 9 + tests/functional/verilog/my_module_lt.v | 9 + tests/functional/verilog/my_module_mod.v | 9 + tests/functional/verilog/my_module_mul.v | 9 + tests/functional/verilog/my_module_ne.v | 9 + tests/functional/verilog/my_module_nex.v | 9 + tests/functional/verilog/my_module_or.v | 9 + tests/functional/verilog/my_module_pow.v | 9 + tests/functional/verilog/my_module_shl.v | 9 + tests/functional/verilog/my_module_shr.v | 9 + tests/functional/verilog/my_module_sshl.v | 9 + tests/functional/verilog/my_module_sshr.v | 9 + tests/functional/verilog/my_module_sub.v | 9 + tests/functional/verilog/my_module_xnor.v | 9 + tests/functional/verilog/my_module_xor.v | 9 + 79 files changed, 8029 insertions(+), 33 deletions(-) create mode 100644 tests/functional/coverage_report/amber.png create mode 100644 tests/functional/coverage_report/emerald.png create mode 100644 tests/functional/coverage_report/functional/and_cxxrtl.cc.func-sort-c.html create mode 100644 tests/functional/coverage_report/functional/and_cxxrtl.cc.func.html create mode 100644 tests/functional/coverage_report/functional/and_cxxrtl.cc.gcov.html create mode 100644 tests/functional/coverage_report/functional/and_functional_cxx.cc.func-sort-c.html create mode 100644 tests/functional/coverage_report/functional/and_functional_cxx.cc.func.html create mode 100644 tests/functional/coverage_report/functional/and_functional_cxx.cc.gcov.html create mode 100644 tests/functional/coverage_report/functional/index-sort-f.html create mode 100644 tests/functional/coverage_report/functional/index-sort-l.html create mode 100644 tests/functional/coverage_report/functional/index.html create mode 100644 tests/functional/coverage_report/functional/vcd_harness.cpp.func-sort-c.html create mode 100644 tests/functional/coverage_report/functional/vcd_harness.cpp.func.html create mode 100644 tests/functional/coverage_report/functional/vcd_harness.cpp.gcov.html create mode 100644 tests/functional/coverage_report/gcov.css create mode 100644 tests/functional/coverage_report/glass.png create mode 100644 tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h.func-sort-c.html create mode 100644 tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h.func.html create mode 100644 tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h.gcov.html create mode 100644 tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl_vcd.h.func-sort-c.html create mode 100644 tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl_vcd.h.func.html create mode 100644 tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl_vcd.h.gcov.html create mode 100644 tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/index-sort-f.html create mode 100644 tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/index-sort-l.html create mode 100644 tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/index.html create mode 100644 tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/index-sort-f.html create mode 100644 tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/index-sort-l.html create mode 100644 tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/index.html create mode 100644 tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/sim.h.func-sort-c.html create mode 100644 tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/sim.h.func.html create mode 100644 tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/sim.h.gcov.html create mode 100644 tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_cxxrtl.cc.func-sort-c.html create mode 100644 tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_cxxrtl.cc.func.html create mode 100644 tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_cxxrtl.cc.gcov.html create mode 100644 tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_functional_cxx.cc.func-sort-c.html create mode 100644 tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_functional_cxx.cc.func.html create mode 100644 tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_functional_cxx.cc.gcov.html create mode 100644 tests/functional/coverage_report/home/roland/my_yosys/tests/functional/index-sort-f.html create mode 100644 tests/functional/coverage_report/home/roland/my_yosys/tests/functional/index-sort-l.html create mode 100644 tests/functional/coverage_report/home/roland/my_yosys/tests/functional/index.html create mode 100644 tests/functional/coverage_report/home/roland/my_yosys/tests/functional/vcd_harness.cpp.func-sort-c.html create mode 100644 tests/functional/coverage_report/home/roland/my_yosys/tests/functional/vcd_harness.cpp.func.html create mode 100644 tests/functional/coverage_report/home/roland/my_yosys/tests/functional/vcd_harness.cpp.gcov.html create mode 100644 tests/functional/coverage_report/index-sort-f.html create mode 100644 tests/functional/coverage_report/index-sort-l.html create mode 100644 tests/functional/coverage_report/index.html create mode 100644 tests/functional/coverage_report/nix/store/B0S2LKF593R3585038WS4JD3LYLF2WDX-glibc-2.38-44-dev/include/bits/string_fortified.h.gcov.html create mode 100644 tests/functional/coverage_report/ruby.png create mode 100644 tests/functional/coverage_report/snow.png create mode 100644 tests/functional/coverage_report/updown.png create mode 100644 tests/functional/coverage_report/vcd_harness.info create mode 100755 tests/functional/generate_coverage.sh create mode 100644 tests/functional/verilog/add.v create mode 100755 tests/functional/verilog/my_module_div.v create mode 100755 tests/functional/verilog/my_module_eqx.v create mode 100755 tests/functional/verilog/my_module_ge.v create mode 100755 tests/functional/verilog/my_module_gt.v create mode 100755 tests/functional/verilog/my_module_le.v create mode 100755 tests/functional/verilog/my_module_logic_and.v create mode 100755 tests/functional/verilog/my_module_logic_or.v create mode 100755 tests/functional/verilog/my_module_lt.v create mode 100755 tests/functional/verilog/my_module_mod.v create mode 100755 tests/functional/verilog/my_module_mul.v create mode 100755 tests/functional/verilog/my_module_ne.v create mode 100755 tests/functional/verilog/my_module_nex.v create mode 100755 tests/functional/verilog/my_module_or.v create mode 100755 tests/functional/verilog/my_module_pow.v create mode 100755 tests/functional/verilog/my_module_shl.v create mode 100755 tests/functional/verilog/my_module_shr.v create mode 100755 tests/functional/verilog/my_module_sshl.v create mode 100755 tests/functional/verilog/my_module_sshr.v create mode 100755 tests/functional/verilog/my_module_sub.v create mode 100755 tests/functional/verilog/my_module_xnor.v create mode 100755 tests/functional/verilog/my_module_xor.v diff --git a/flake.nix b/flake.nix index 63c1e13720d..6ed167dab80 100644 --- a/flake.nix +++ b/flake.nix @@ -66,7 +66,7 @@ defaultPackage = yosys; packages.vcdiff = vcdiff; devShell = pkgs.mkShell { - buildInputs = with pkgs; [ clang bison flex libffi tcl readline python3 llvmPackages.libcxxClang zlib git gtest abc-verifier gtkwave vcdiff ]; + buildInputs = with pkgs; [ clang bison flex libffi tcl readline python3 llvmPackages.libcxxClang zlib git gtest abc-verifier gtkwave vcdiff lcov ]; }; } ); diff --git a/tests/functional/.gitignore b/tests/functional/.gitignore index 06af41869c9..6ee14e70604 100644 --- a/tests/functional/.gitignore +++ b/tests/functional/.gitignore @@ -1,5 +1,5 @@ -and_cxxrtl.cc -and_functional_cxx.cc +my_module_cxxrtl.cc +my_module_functional_cxx.cc vcd_harness cxxrtl.vcd functional_cxx.vcd \ No newline at end of file diff --git a/tests/functional/coverage_report/amber.png b/tests/functional/coverage_report/amber.png new file mode 100644 index 0000000000000000000000000000000000000000..2cab170d8359081983a4e343848dfe06bc490f12 GIT binary patch literal 141 zcmeAS@N?(olHy`uVBq!ia0vp^j3CU&3?x-=hn)ga>?NMQuI!iC1^G2tW}LqE04T&+ z;1OBOz`!j8!i<;h*8KqrvZOouIx;Y9?C1WI$O`1M1^9%x{(levWG?NMQuI!iC1^Jb!lvI6;R0X`wF(yt=9xVZRt1vCRixIA4P dLn>}1Cji+@42)0J?}79&c)I$ztaD0e0sy@GAL0N2 literal 0 HcmV?d00001 diff --git a/tests/functional/coverage_report/functional/and_cxxrtl.cc.func-sort-c.html b/tests/functional/coverage_report/functional/and_cxxrtl.cc.func-sort-c.html new file mode 100644 index 00000000000..e8c04ffebc6 --- /dev/null +++ b/tests/functional/coverage_report/functional/and_cxxrtl.cc.func-sort-c.html @@ -0,0 +1,100 @@ + + + + + + + LCOV - vcd_harness.info - functional/and_cxxrtl.cc - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - functional - and_cxxrtl.cc (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:222975.9 %
Date:1980-01-01 00:00:00Functions:5771.4 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN13cxxrtl_design7p_Adder10debug_evalEv0
cxxrtl_design_create0
_ZN13cxxrtl_design7p_Adder10debug_infoEPN6cxxrtl11debug_itemsEPNS1_12debug_scopesENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEOSt3mapISB_NS1_8metadataESt4lessISB_ESaISt4pairIKSB_SD_EEE3
_ZN13cxxrtl_design7p_Adder5resetEv3
_ZN13cxxrtl_design7p_AdderC2Ev3
_ZN13cxxrtl_design7p_Adder4evalEPN6cxxrtl9performerE33
_ZN13cxxrtl_design7p_Adder6commitEv33
+
+
+ + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/functional/and_cxxrtl.cc.func.html b/tests/functional/coverage_report/functional/and_cxxrtl.cc.func.html new file mode 100644 index 00000000000..c7717a2dc84 --- /dev/null +++ b/tests/functional/coverage_report/functional/and_cxxrtl.cc.func.html @@ -0,0 +1,100 @@ + + + + + + + LCOV - vcd_harness.info - functional/and_cxxrtl.cc - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - functional - and_cxxrtl.cc (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:222975.9 %
Date:1980-01-01 00:00:00Functions:5771.4 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN13cxxrtl_design7p_Adder10debug_evalEv0
_ZN13cxxrtl_design7p_Adder10debug_infoEPN6cxxrtl11debug_itemsEPNS1_12debug_scopesENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEOSt3mapISB_NS1_8metadataESt4lessISB_ESaISt4pairIKSB_SD_EEE3
_ZN13cxxrtl_design7p_Adder4evalEPN6cxxrtl9performerE33
_ZN13cxxrtl_design7p_Adder5resetEv3
_ZN13cxxrtl_design7p_Adder6commitEv33
_ZN13cxxrtl_design7p_AdderC2Ev3
cxxrtl_design_create0
+
+
+ + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/functional/and_cxxrtl.cc.gcov.html b/tests/functional/coverage_report/functional/and_cxxrtl.cc.gcov.html new file mode 100644 index 00000000000..796a2e71920 --- /dev/null +++ b/tests/functional/coverage_report/functional/and_cxxrtl.cc.gcov.html @@ -0,0 +1,161 @@ + + + + + + + LCOV - vcd_harness.info - functional/and_cxxrtl.cc + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - functional - and_cxxrtl.cc (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:222975.9 %
Date:1980-01-01 00:00:00Functions:5771.4 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : #include <cxxrtl/cxxrtl.h>
+       2             : 
+       3             : #if defined(CXXRTL_INCLUDE_CAPI_IMPL) || \
+       4             :     defined(CXXRTL_INCLUDE_VCD_CAPI_IMPL)
+       5             : #include <cxxrtl/capi/cxxrtl_capi.cc>
+       6             : #endif
+       7             : 
+       8             : #if defined(CXXRTL_INCLUDE_VCD_CAPI_IMPL)
+       9             : #include <cxxrtl/capi/cxxrtl_capi_vcd.cc>
+      10             : #endif
+      11             : 
+      12             : using namespace cxxrtl_yosys;
+      13             : 
+      14             : namespace cxxrtl_design {
+      15             : 
+      16             : // \top: 1
+      17             : // \src: verilog/and.v:1.1-9.10
+      18           3 : struct p_Adder : public module {
+      19             :         // \src: verilog/and.v:4.14-4.17
+      20             :         /*output*/ value<1> p_sum;
+      21             :         // \src: verilog/and.v:3.14-3.15
+      22             :         /*input*/ value<1> p_b;
+      23             :         // \src: verilog/and.v:2.14-2.15
+      24             :         /*input*/ value<1> p_a;
+      25             :         p_Adder(interior) {}
+      26           3 :         p_Adder() {
+      27           3 :                 reset();
+      28           3 :         };
+      29             : 
+      30             :         void reset() override;
+      31             : 
+      32             :         bool eval(performer *performer = nullptr) override;
+      33             : 
+      34             :         template<class ObserverT>
+      35             :         bool commit(ObserverT &observer) {
+      36          33 :                 bool changed = false;
+      37             :                 return changed;
+      38             :         }
+      39             : 
+      40          33 :         bool commit() override {
+      41          33 :                 observer observer;
+      42          33 :                 return commit<>(observer);
+      43             :         }
+      44             : 
+      45             :         void debug_eval();
+      46             : 
+      47             :         void debug_info(debug_items *items, debug_scopes *scopes, std::string path, metadata_map &&cell_attrs = {}) override;
+      48             : }; // struct p_Adder
+      49             : 
+      50           3 : void p_Adder::reset() {
+      51           3 : }
+      52             : 
+      53          33 : bool p_Adder::eval(performer *performer) {
+      54          33 :         bool converged = true;
+      55             :         // \src: verilog/and.v:7.17-7.22
+      56             :         // cell $add$verilog/and.v:7$1
+      57          33 :         p_sum = add_uu<1>(p_a, p_b);
+      58          33 :         return converged;
+      59             : }
+      60             : 
+      61           0 : void p_Adder::debug_eval() {
+      62           0 : }
+      63             : 
+      64             : CXXRTL_EXTREMELY_COLD
+      65           3 : void p_Adder::debug_info(debug_items *items, debug_scopes *scopes, std::string path, metadata_map &&cell_attrs) {
+      66           3 :         assert(path.empty() || path[path.size() - 1] == ' ');
+      67           3 :         if (scopes) {
+      68           0 :                 scopes->add(path.empty() ? path : path.substr(0, path.size() - 1), "Adder", metadata_map({
+      69           0 :                         { "top", UINT64_C(1) },
+      70             :                         { "src", "verilog/and.v:1.1-9.10" },
+      71           0 :                 }), std::move(cell_attrs));
+      72             :         }
+      73           3 :         if (items) {
+      74           3 :                 items->add(path, "sum", "src\000sverilog/and.v:4.14-4.17\000", p_sum, 0, debug_item::OUTPUT|debug_item::DRIVEN_COMB);
+      75           3 :                 items->add(path, "b", "src\000sverilog/and.v:3.14-3.15\000", p_b, 0, debug_item::INPUT|debug_item::UNDRIVEN);
+      76           3 :                 items->add(path, "a", "src\000sverilog/and.v:2.14-2.15\000", p_a, 0, debug_item::INPUT|debug_item::UNDRIVEN);
+      77             :         }
+      78           3 : }
+      79             : 
+      80             : } // namespace cxxrtl_design
+      81             : 
+      82             : extern "C"
+      83           0 : cxxrtl_toplevel cxxrtl_design_create() {
+      84           0 :         return new _cxxrtl_toplevel { std::unique_ptr<cxxrtl_design::p_Adder>(new cxxrtl_design::p_Adder) };
+      85             : }
+
+
+
+ + + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/functional/and_functional_cxx.cc.func-sort-c.html b/tests/functional/coverage_report/functional/and_functional_cxx.cc.func-sort-c.html new file mode 100644 index 00000000000..5c1ad8cc617 --- /dev/null +++ b/tests/functional/coverage_report/functional/and_functional_cxx.cc.func-sort-c.html @@ -0,0 +1,84 @@ + + + + + + + LCOV - vcd_harness.info - functional/and_functional_cxx.cc - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - functional - and_functional_cxx.cc (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:1313100.0 %
Date:1980-01-01 00:00:00Functions:33100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN12Adder_Inputs4dumpI10DumpHeaderEEvRT_3
_Z5AdderRK12Adder_InputsR13Adder_OutputsRK11Adder_StateRS4_30
_ZN12Adder_Inputs4dumpI4DumpEEvRT_33
+
+
+ + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/functional/and_functional_cxx.cc.func.html b/tests/functional/coverage_report/functional/and_functional_cxx.cc.func.html new file mode 100644 index 00000000000..bd54f13143e --- /dev/null +++ b/tests/functional/coverage_report/functional/and_functional_cxx.cc.func.html @@ -0,0 +1,84 @@ + + + + + + + LCOV - vcd_harness.info - functional/and_functional_cxx.cc - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - functional - and_functional_cxx.cc (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:1313100.0 %
Date:1980-01-01 00:00:00Functions:33100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_Z5AdderRK12Adder_InputsR13Adder_OutputsRK11Adder_StateRS4_30
_ZN12Adder_Inputs4dumpI10DumpHeaderEEvRT_3
_ZN12Adder_Inputs4dumpI4DumpEEvRT_33
+
+
+ + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/functional/and_functional_cxx.cc.gcov.html b/tests/functional/coverage_report/functional/and_functional_cxx.cc.gcov.html new file mode 100644 index 00000000000..46ae8931131 --- /dev/null +++ b/tests/functional/coverage_report/functional/and_functional_cxx.cc.gcov.html @@ -0,0 +1,108 @@ + + + + + + + LCOV - vcd_harness.info - functional/and_functional_cxx.cc + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - functional - and_functional_cxx.cc (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:1313100.0 %
Date:1980-01-01 00:00:00Functions:33100.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : #include "sim.h"
+       2             : struct Adder_Inputs {
+       3             :         Signal<1> b;
+       4             :         Signal<1> a;
+       5             : 
+       6          36 :         template <typename T> void dump(T &out) {
+       7          36 :                 out("b", b);
+       8          36 :                 out("a", a);
+       9          36 :         }
+      10             : };
+      11             : 
+      12             : struct Adder_Outputs {
+      13             :         Signal<1> sum;
+      14             : 
+      15          36 :         template <typename T> void dump(T &out) {
+      16          36 :                 out("sum", sum);
+      17          36 :         }
+      18             : };
+      19             : 
+      20             : struct Adder_State {
+      21             : 
+      22             :         template <typename T> void dump(T &out) {
+      23             :         }
+      24             : };
+      25             : 
+      26          30 : void Adder(Adder_Inputs const &input, Adder_Outputs &output, Adder_State const &current_state, Adder_State &next_state)
+      27             : {
+      28          30 :         Signal<1> b = input.b;
+      29          30 :         Signal<1> a = input.a;
+      30          30 :         Signal<1> $add$verilog_and_v_7$1$_Y = $add(a, b); //
+      31          30 :         output.sum = $add$verilog_and_v_7$1$_Y;
+      32          30 : }
+
+
+
+ + + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/functional/index-sort-f.html b/tests/functional/coverage_report/functional/index-sort-f.html new file mode 100644 index 00000000000..c6f3150f801 --- /dev/null +++ b/tests/functional/coverage_report/functional/index-sort-f.html @@ -0,0 +1,113 @@ + + + + + + + LCOV - vcd_harness.info - functional + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - functionalHitTotalCoverage
Test:vcd_harness.infoLines:10511293.8 %
Date:1980-01-01 00:00:00Functions:111384.6 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
and_cxxrtl.cc +
75.9%75.9%
+
75.9 %22 / 2971.4 %5 / 7
and_functional_cxx.cc +
100.0%
+
100.0 %13 / 13100.0 %3 / 3
vcd_harness.cpp +
100.0%
+
100.0 %70 / 70100.0 %3 / 3
+
+
+ + + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/functional/index-sort-l.html b/tests/functional/coverage_report/functional/index-sort-l.html new file mode 100644 index 00000000000..85e33c02ae9 --- /dev/null +++ b/tests/functional/coverage_report/functional/index-sort-l.html @@ -0,0 +1,113 @@ + + + + + + + LCOV - vcd_harness.info - functional + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - functionalHitTotalCoverage
Test:vcd_harness.infoLines:10511293.8 %
Date:1980-01-01 00:00:00Functions:111384.6 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
and_cxxrtl.cc +
75.9%75.9%
+
75.9 %22 / 2971.4 %5 / 7
and_functional_cxx.cc +
100.0%
+
100.0 %13 / 13100.0 %3 / 3
vcd_harness.cpp +
100.0%
+
100.0 %70 / 70100.0 %3 / 3
+
+
+ + + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/functional/index.html b/tests/functional/coverage_report/functional/index.html new file mode 100644 index 00000000000..3b31f9d7e6e --- /dev/null +++ b/tests/functional/coverage_report/functional/index.html @@ -0,0 +1,113 @@ + + + + + + + LCOV - vcd_harness.info - functional + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - functionalHitTotalCoverage
Test:vcd_harness.infoLines:10511293.8 %
Date:1980-01-01 00:00:00Functions:111384.6 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
and_cxxrtl.cc +
75.9%75.9%
+
75.9 %22 / 2971.4 %5 / 7
and_functional_cxx.cc +
100.0%
+
100.0 %13 / 13100.0 %3 / 3
vcd_harness.cpp +
100.0%
+
100.0 %70 / 70100.0 %3 / 3
+
+
+ + + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/functional/vcd_harness.cpp.func-sort-c.html b/tests/functional/coverage_report/functional/vcd_harness.cpp.func-sort-c.html new file mode 100644 index 00000000000..36a518367b0 --- /dev/null +++ b/tests/functional/coverage_report/functional/vcd_harness.cpp.func-sort-c.html @@ -0,0 +1,84 @@ + + + + + + + LCOV - vcd_harness.info - functional/vcd_harness.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - functional - vcd_harness.cpp (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:7070100.0 %
Date:1980-01-01 00:00:00Functions:33100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
main3
_ZN10DumpHeaderclILm1EEEvPKcSt5arrayIbXT_EE9
_ZN4DumpclILm1EEEvPKcSt5arrayIbXT_EE99
+
+
+ + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/functional/vcd_harness.cpp.func.html b/tests/functional/coverage_report/functional/vcd_harness.cpp.func.html new file mode 100644 index 00000000000..351dd96a848 --- /dev/null +++ b/tests/functional/coverage_report/functional/vcd_harness.cpp.func.html @@ -0,0 +1,84 @@ + + + + + + + LCOV - vcd_harness.info - functional/vcd_harness.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - functional - vcd_harness.cpp (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:7070100.0 %
Date:1980-01-01 00:00:00Functions:33100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN10DumpHeaderclILm1EEEvPKcSt5arrayIbXT_EE9
_ZN4DumpclILm1EEEvPKcSt5arrayIbXT_EE99
main3
+
+
+ + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/functional/vcd_harness.cpp.gcov.html b/tests/functional/coverage_report/functional/vcd_harness.cpp.gcov.html new file mode 100644 index 00000000000..d5c0afbc10c --- /dev/null +++ b/tests/functional/coverage_report/functional/vcd_harness.cpp.gcov.html @@ -0,0 +1,216 @@ + + + + + + + LCOV - vcd_harness.info - functional/vcd_harness.cpp + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - functional - vcd_harness.cpp (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:7070100.0 %
Date:1980-01-01 00:00:00Functions:33100.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : #include <cstdio>
+       2             : #include <iostream>
+       3             : #include <fstream>
+       4             : #include <random>
+       5             : 
+       6             : #include <cxxrtl/cxxrtl_vcd.h>
+       7             : 
+       8             : #include "and_cxxrtl.cc"
+       9             : #include "and_functional_cxx.cc"
+      10             : 
+      11             : struct DumpHeader {
+      12             :     std::ofstream &ofs;
+      13           3 :     DumpHeader(std::ofstream &ofs) : ofs(ofs) {}
+      14             :     template <size_t n>
+      15           9 :     void operator()(const char *name, Signal<n> value) {
+      16           9 :         ofs << "$var wire " << n << " " << name[0] << " " << name << " $end\n";
+      17           9 :     }
+      18             : };
+      19             : 
+      20             : struct Dump {
+      21             :     std::ofstream &ofs;
+      22          33 :     Dump(std::ofstream &ofs) : ofs(ofs) {}
+      23             :     template <size_t n>
+      24          99 :     void operator()(const char *name, Signal<n> value) {
+      25             :         // Bit
+      26             :         if (n == 1) {
+      27         156 :             ofs << (value[0] ? '1' : '0');
+      28          99 :             ofs << name[0] << "\n";
+      29             :             return;
+      30             :         }
+      31             :         // vector (multi-bit) signals
+      32             :         ofs << "b";
+      33             :         for (size_t i = n; i-- > 0;)
+      34             :             ofs << (value[i] ? '1' : '0');
+      35             :         ofs << " " << name[0] << "\n";
+      36             :     }
+      37             : };
+      38             : 
+      39           3 : int main(int argc, char **argv)
+      40             : {
+      41           3 :     constexpr int steps = 10;
+      42           3 :     constexpr int number_timescale = 1;
+      43           3 :     const std::string units_timescale = "us";
+      44           3 :     Adder_Inputs inputs;
+      45           3 :     Adder_Outputs outputs;
+      46           3 :     Adder_State state;
+      47           3 :     Adder_State next_state;
+      48             : 
+      49           3 :     std::ofstream vcd_file("functional_cxx.vcd");
+      50             : 
+      51           3 :     vcd_file << "$timescale " << number_timescale << " " << units_timescale << " $end\n"; //$scope module logic $end\n";
+      52           3 :     {
+      53           3 :         DumpHeader d(vcd_file);
+      54           3 :         inputs.dump(d);
+      55           3 :         outputs.dump(d);
+      56             :         // vcd_file << "$scope module state $end\n";
+      57           3 :         state.dump(d);
+      58             :     }
+      59           3 :     vcd_file << "$enddefinitions $end\n$dumpvars\n";
+      60             : 
+      61           3 :     cxxrtl_design::p_Adder top;
+      62             : 
+      63             :     // debug_items maps the hierarchical names of signals and memories in the design
+      64             :     // to a cxxrtl_object (a value, a wire, or a memory)
+      65           3 :     cxxrtl::debug_items all_debug_items;
+      66           3 :     cxxrtl::debug_scope debug_scope;
+      67             :     // Load the debug items of the top down the whole design hierarchy
+      68           6 :     top.debug_info(&all_debug_items, nullptr, "");
+      69             : 
+      70             :     // vcd_writer is the CXXRTL object that's responsible for creating a string with
+      71             :     // the VCD file contents.
+      72           3 :     cxxrtl::vcd_writer vcd;
+      73           3 :     vcd.timescale(number_timescale, units_timescale);
+      74             : 
+      75             :     // Here we tell the vcd writer to dump all the signals of the design, except for the
+      76             :     // memories, to the VCD file.
+      77             :     //
+      78             :     // It's not necessary to load all debug objects to the VCD. There is, for example,
+      79             :     // a  vcd.add(<debug items>, <filter>)) method which allows creating your custom filter to decide
+      80             :     // what to add and what not.
+      81           3 :     vcd.add_without_memories(all_debug_items);
+      82             : 
+      83           3 :     std::ofstream waves("cxxrtl.vcd");
+      84             : 
+      85           3 :     top.p_a.set<bool>(false);
+      86           3 :     top.p_b.set<bool>(false);
+      87           3 :     top.step();
+      88             : 
+      89             :     // We need to manually tell the VCD writer when to sample and write out the traced items.
+      90             :     // This is only a slight inconvenience and allows for complete flexibility.
+      91             :     // E.g. you could only start waveform tracing when an internal signal has reached some specific
+      92             :     // value etc.
+      93           3 :     vcd.sample(0);
+      94           3 :     vcd_file << "#0\n";
+      95           3 :     inputs.a = $const<1>(false);
+      96           3 :     inputs.b = $const<1>(false);
+      97           3 :     {
+      98           3 :         Dump d(vcd_file);
+      99           3 :         inputs.dump(d);
+     100           3 :         outputs.dump(d);
+     101           3 :         state.dump(d);
+     102             :     }
+     103             : 
+     104             :     // Initialize random number generator
+     105           3 :     std::random_device rd;
+     106           3 :     std::mt19937 gen(rd());
+     107           3 :     std::bernoulli_distribution dist(0.5); // 50% chance for true or false
+     108             :     
+     109          33 :     for (int step = 0; step < steps; ++step) {
+     110          30 :       const bool a_value = dist(gen);
+     111          30 :       const bool b_value = dist(gen);
+     112             : 
+     113             :         // cxxrtl
+     114          30 :         top.p_a.set<bool>(a_value);
+     115          30 :         top.p_b.set<bool>(b_value);
+     116          30 :         top.step();
+     117          30 :         vcd.sample(step + 1);
+     118             : 
+     119          30 :         waves << vcd.buffer;
+     120          30 :         vcd.buffer.clear();
+     121             : 
+     122             :         // Functional backend cxx
+     123          30 :         vcd_file << "#" << (step + 1) << "\n";
+     124          30 :         inputs.a = $const<1>(a_value);
+     125          30 :         inputs.b = $const<1>(b_value);
+     126          30 :         Adder(inputs, outputs, state, next_state);
+     127          30 :         {
+     128          30 :             Dump d(vcd_file);
+     129          30 :             inputs.dump(d);
+     130          30 :             outputs.dump(d);
+     131          30 :             state.dump(d);
+     132             :         }
+     133          30 :         state = next_state;
+     134             :     }
+     135             : 
+     136           3 :     vcd_file.close();
+     137           3 :     waves.close();
+     138             : 
+     139           3 :     return 0;
+     140           3 : }
+
+
+
+ + + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/gcov.css b/tests/functional/coverage_report/gcov.css new file mode 100644 index 00000000000..0fcdff13cea --- /dev/null +++ b/tests/functional/coverage_report/gcov.css @@ -0,0 +1,519 @@ +/* All views: initial background and text color */ +body +{ + color: #000000; + background-color: #ffffff; +} + +/* All views: standard link format*/ +a:link +{ + color: #284fa8; + text-decoration: underline; +} + +/* All views: standard link - visited format */ +a:visited +{ + color: #00cb40; + text-decoration: underline; +} + +/* All views: standard link - activated format */ +a:active +{ + color: #ff0040; + text-decoration: underline; +} + +/* All views: main title format */ +td.title +{ + text-align: center; + padding-bottom: 10px; + font-family: sans-serif; + font-size: 20pt; + font-style: italic; + font-weight: bold; +} + +/* All views: header item format */ +td.headerItem +{ + text-align: right; + padding-right: 6px; + font-family: sans-serif; + font-weight: bold; + vertical-align: top; + white-space: nowrap; +} + +/* All views: header item value format */ +td.headerValue +{ + text-align: left; + color: #284fa8; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; +} + +/* All views: header item coverage table heading */ +td.headerCovTableHead +{ + text-align: center; + padding-right: 6px; + padding-left: 6px; + padding-bottom: 0px; + font-family: sans-serif; + font-size: 80%; + white-space: nowrap; +} + +/* All views: header item coverage table entry */ +td.headerCovTableEntry +{ + text-align: right; + color: #284fa8; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; + padding-left: 12px; + padding-right: 4px; + background-color: #dae7fe; +} + +/* All views: header item coverage table entry for high coverage rate */ +td.headerCovTableEntryHi +{ + text-align: right; + color: #000000; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; + padding-left: 12px; + padding-right: 4px; + background-color: #a7fc9d; +} + +/* All views: header item coverage table entry for medium coverage rate */ +td.headerCovTableEntryMed +{ + text-align: right; + color: #000000; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; + padding-left: 12px; + padding-right: 4px; + background-color: #ffea20; +} + +/* All views: header item coverage table entry for ow coverage rate */ +td.headerCovTableEntryLo +{ + text-align: right; + color: #000000; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; + padding-left: 12px; + padding-right: 4px; + background-color: #ff0000; +} + +/* All views: header legend value for legend entry */ +td.headerValueLeg +{ + text-align: left; + color: #000000; + font-family: sans-serif; + font-size: 80%; + white-space: nowrap; + padding-top: 4px; +} + +/* All views: color of horizontal ruler */ +td.ruler +{ + background-color: #6688d4; +} + +/* All views: version string format */ +td.versionInfo +{ + text-align: center; + padding-top: 2px; + font-family: sans-serif; + font-style: italic; +} + +/* Directory view/File view (all)/Test case descriptions: + table headline format */ +td.tableHead +{ + text-align: center; + color: #ffffff; + background-color: #6688d4; + font-family: sans-serif; + font-size: 120%; + font-weight: bold; + white-space: nowrap; + padding-left: 4px; + padding-right: 4px; +} + +span.tableHeadSort +{ + padding-right: 4px; +} + +/* Directory view/File view (all): filename entry format */ +td.coverFile +{ + text-align: left; + padding-left: 10px; + padding-right: 20px; + color: #284fa8; + background-color: #dae7fe; + font-family: monospace; +} + +/* Directory view/File view (all): bar-graph entry format*/ +td.coverBar +{ + padding-left: 10px; + padding-right: 10px; + background-color: #dae7fe; +} + +/* Directory view/File view (all): bar-graph outline color */ +td.coverBarOutline +{ + background-color: #000000; +} + +/* Directory view/File view (all): percentage entry for files with + high coverage rate */ +td.coverPerHi +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #a7fc9d; + font-weight: bold; + font-family: sans-serif; +} + +/* Directory view/File view (all): line count entry for files with + high coverage rate */ +td.coverNumHi +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #a7fc9d; + white-space: nowrap; + font-family: sans-serif; +} + +/* Directory view/File view (all): percentage entry for files with + medium coverage rate */ +td.coverPerMed +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #ffea20; + font-weight: bold; + font-family: sans-serif; +} + +/* Directory view/File view (all): line count entry for files with + medium coverage rate */ +td.coverNumMed +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #ffea20; + white-space: nowrap; + font-family: sans-serif; +} + +/* Directory view/File view (all): percentage entry for files with + low coverage rate */ +td.coverPerLo +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #ff0000; + font-weight: bold; + font-family: sans-serif; +} + +/* Directory view/File view (all): line count entry for files with + low coverage rate */ +td.coverNumLo +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #ff0000; + white-space: nowrap; + font-family: sans-serif; +} + +/* File view (all): "show/hide details" link format */ +a.detail:link +{ + color: #B8D0FF; + font-size:80%; +} + +/* File view (all): "show/hide details" link - visited format */ +a.detail:visited +{ + color: #B8D0FF; + font-size:80%; +} + +/* File view (all): "show/hide details" link - activated format */ +a.detail:active +{ + color: #ffffff; + font-size:80%; +} + +/* File view (detail): test name entry */ +td.testName +{ + text-align: right; + padding-right: 10px; + background-color: #dae7fe; + font-family: sans-serif; +} + +/* File view (detail): test percentage entry */ +td.testPer +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #dae7fe; + font-family: sans-serif; +} + +/* File view (detail): test lines count entry */ +td.testNum +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #dae7fe; + font-family: sans-serif; +} + +/* Test case descriptions: test name format*/ +dt +{ + font-family: sans-serif; + font-weight: bold; +} + +/* Test case descriptions: description table body */ +td.testDescription +{ + padding-top: 10px; + padding-left: 30px; + padding-bottom: 10px; + padding-right: 30px; + background-color: #dae7fe; +} + +/* Source code view: function entry */ +td.coverFn +{ + text-align: left; + padding-left: 10px; + padding-right: 20px; + color: #284fa8; + background-color: #dae7fe; + font-family: monospace; +} + +/* Source code view: function entry zero count*/ +td.coverFnLo +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #ff0000; + font-weight: bold; + font-family: sans-serif; +} + +/* Source code view: function entry nonzero count*/ +td.coverFnHi +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #dae7fe; + font-weight: bold; + font-family: sans-serif; +} + +/* Source code view: source code format */ +pre.source +{ + font-family: monospace; + white-space: pre; + margin-top: 2px; +} + +/* Source code view: line number format */ +span.lineNum +{ + background-color: #efe383; +} + +/* Source code view: format for lines which were executed */ +td.lineCov, +span.lineCov +{ + background-color: #cad7fe; +} + +/* Source code view: format for Cov legend */ +span.coverLegendCov +{ + padding-left: 10px; + padding-right: 10px; + padding-bottom: 2px; + background-color: #cad7fe; +} + +/* Source code view: format for lines which were not executed */ +td.lineNoCov, +span.lineNoCov +{ + background-color: #ff6230; +} + +/* Source code view: format for NoCov legend */ +span.coverLegendNoCov +{ + padding-left: 10px; + padding-right: 10px; + padding-bottom: 2px; + background-color: #ff6230; +} + +/* Source code view (function table): standard link - visited format */ +td.lineNoCov > a:visited, +td.lineCov > a:visited +{ + color: #000000; + text-decoration: underline; +} + +/* Source code view: format for lines which were executed only in a + previous version */ +span.lineDiffCov +{ + background-color: #b5f7af; +} + +/* Source code view: format for branches which were executed + * and taken */ +span.branchCov +{ + background-color: #cad7fe; +} + +/* Source code view: format for branches which were executed + * but not taken */ +span.branchNoCov +{ + background-color: #ff6230; +} + +/* Source code view: format for branches which were not executed */ +span.branchNoExec +{ + background-color: #ff6230; +} + +/* Source code view: format for the source code heading line */ +pre.sourceHeading +{ + white-space: pre; + font-family: monospace; + font-weight: bold; + margin: 0px; +} + +/* All views: header legend value for low rate */ +td.headerValueLegL +{ + font-family: sans-serif; + text-align: center; + white-space: nowrap; + padding-left: 4px; + padding-right: 2px; + background-color: #ff0000; + font-size: 80%; +} + +/* All views: header legend value for med rate */ +td.headerValueLegM +{ + font-family: sans-serif; + text-align: center; + white-space: nowrap; + padding-left: 2px; + padding-right: 2px; + background-color: #ffea20; + font-size: 80%; +} + +/* All views: header legend value for hi rate */ +td.headerValueLegH +{ + font-family: sans-serif; + text-align: center; + white-space: nowrap; + padding-left: 2px; + padding-right: 4px; + background-color: #a7fc9d; + font-size: 80%; +} + +/* All views except source code view: legend format for low coverage */ +span.coverLegendCovLo +{ + padding-left: 10px; + padding-right: 10px; + padding-top: 2px; + background-color: #ff0000; +} + +/* All views except source code view: legend format for med coverage */ +span.coverLegendCovMed +{ + padding-left: 10px; + padding-right: 10px; + padding-top: 2px; + background-color: #ffea20; +} + +/* All views except source code view: legend format for hi coverage */ +span.coverLegendCovHi +{ + padding-left: 10px; + padding-right: 10px; + padding-top: 2px; + background-color: #a7fc9d; +} diff --git a/tests/functional/coverage_report/glass.png b/tests/functional/coverage_report/glass.png new file mode 100644 index 0000000000000000000000000000000000000000..e1abc00680a3093c49fdb775ae6bdb6764c95af2 GIT binary patch literal 167 zcmeAS@N?(olHy`uVBq!ia0vp^j3CU&3?x-=hn)gaEa{HEjtmSN`?>!lvI6;R0X`wF z|Ns97GD8ntt^-nxB|(0{3=Yq3q=7g|-tI089jvk*Kn`btM`SSr1Gf+eGhVt|_XjA* zUgGKN%6^Gmn4d%Ph(nkFP>9RZ#WAE}PI3Z}&BVayv3^M*kj3EX>gTe~DWM4f=_Dpv literal 0 HcmV?d00001 diff --git a/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h.func-sort-c.html b/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h.func-sort-c.html new file mode 100644 index 00000000000..b16f35764ec --- /dev/null +++ b/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h.func-sort-c.html @@ -0,0 +1,108 @@ + + + + + + + LCOV - vcd_harness.info - /home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl - cxxrtl.h (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:9011876.3 %
Date:1980-01-01 00:00:00Functions:7977.8 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN6cxxrtl12debug_scopes3addERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES8_OSt3mapIS6_NS_8metadataESt4lessIS6_ESaISt4pairIS7_SA_EEESH_0
_ZZN6cxxrtl8metadata11deserializeB5cxx11EPKcENKUlvE_clEv0
_ZN6cxxrtl11debug_items3addERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEONS_10debug_itemEOSt3mapIS6_NS_8metadataESt4lessIS6_ESaISt4pairIS7_SC_EEE9
_ZN6cxxrtl11debug_items3addIJRNS_5valueILm1EEEijEEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEPKcSE_DpOT_9
_ZN6cxxrtl8metadata11deserializeB5cxx11EPKc9
_ZN6cxxrtl8metadataC2ERKS0_18
_ZN6cxxrtl6module4stepEPNS_9performerE33
_ZNK6cxxrtl5valueILm1EE3addERKS1_33
_ZNK6cxxrtl5valueILm1EE3aluILb0ELb0EEESt4pairIS1_bERKS1_33
+
+
+ + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h.func.html b/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h.func.html new file mode 100644 index 00000000000..c7d08356953 --- /dev/null +++ b/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h.func.html @@ -0,0 +1,108 @@ + + + + + + + LCOV - vcd_harness.info - /home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl - cxxrtl.h (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:9011876.3 %
Date:1980-01-01 00:00:00Functions:7977.8 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN6cxxrtl11debug_items3addERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEONS_10debug_itemEOSt3mapIS6_NS_8metadataESt4lessIS6_ESaISt4pairIS7_SC_EEE9
_ZN6cxxrtl11debug_items3addIJRNS_5valueILm1EEEijEEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEPKcSE_DpOT_9
_ZN6cxxrtl12debug_scopes3addERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES8_OSt3mapIS6_NS_8metadataESt4lessIS6_ESaISt4pairIS7_SA_EEESH_0
_ZN6cxxrtl6module4stepEPNS_9performerE33
_ZN6cxxrtl8metadata11deserializeB5cxx11EPKc9
_ZN6cxxrtl8metadataC2ERKS0_18
_ZNK6cxxrtl5valueILm1EE3addERKS1_33
_ZNK6cxxrtl5valueILm1EE3aluILb0ELb0EEESt4pairIS1_bERKS1_33
_ZZN6cxxrtl8metadata11deserializeB5cxx11EPKcENKUlvE_clEv0
+
+
+ + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h.gcov.html b/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h.gcov.html new file mode 100644 index 00000000000..699d0521133 --- /dev/null +++ b/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h.gcov.html @@ -0,0 +1,2182 @@ + + + + + + + LCOV - vcd_harness.info - /home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl - cxxrtl.h (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:9011876.3 %
Date:1980-01-01 00:00:00Functions:7977.8 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : /*
+       2             :  *  yosys -- Yosys Open SYnthesis Suite
+       3             :  *
+       4             :  *  Copyright (C) 2019-2020  whitequark <whitequark@whitequark.org>
+       5             :  *
+       6             :  *  Permission to use, copy, modify, and/or distribute this software for any
+       7             :  *  purpose with or without fee is hereby granted.
+       8             :  *
+       9             :  *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+      10             :  *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+      11             :  *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+      12             :  *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+      13             :  *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+      14             :  *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+      15             :  *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+      16             :  *
+      17             :  */
+      18             : 
+      19             : // This file is included by the designs generated with `write_cxxrtl`. It is not used in Yosys itself.
+      20             : //
+      21             : // The CXXRTL support library implements compile time specialized arbitrary width arithmetics, as well as provides
+      22             : // composite lvalues made out of bit slices and concatenations of lvalues. This allows the `write_cxxrtl` pass
+      23             : // to perform a straightforward translation of RTLIL structures to readable C++, relying on the C++ compiler
+      24             : // to unwrap the abstraction and generate efficient code.
+      25             : 
+      26             : #ifndef CXXRTL_H
+      27             : #define CXXRTL_H
+      28             : 
+      29             : #include <cstddef>
+      30             : #include <cstdint>
+      31             : #include <cstring>
+      32             : #include <cassert>
+      33             : #include <limits>
+      34             : #include <type_traits>
+      35             : #include <tuple>
+      36             : #include <vector>
+      37             : #include <map>
+      38             : #include <algorithm>
+      39             : #include <memory>
+      40             : #include <functional>
+      41             : #include <sstream>
+      42             : #include <iostream>
+      43             : 
+      44             : // `cxxrtl::debug_item` has to inherit from `cxxrtl_object` to satisfy strict aliasing requirements.
+      45             : #include <cxxrtl/capi/cxxrtl_capi.h>
+      46             : 
+      47             : #ifndef __has_attribute
+      48             : #       define __has_attribute(x) 0
+      49             : #endif
+      50             : 
+      51             : // CXXRTL essentially uses the C++ compiler as a hygienic macro engine that feeds an instruction selector.
+      52             : // It generates a lot of specialized template functions with relatively large bodies that, when inlined
+      53             : // into the caller and (for those with loops) unrolled, often expose many new optimization opportunities.
+      54             : // Because of this, most of the CXXRTL runtime must be always inlined for best performance.
+      55             : #if __has_attribute(always_inline)
+      56             : #define CXXRTL_ALWAYS_INLINE inline __attribute__((__always_inline__))
+      57             : #else
+      58             : #define CXXRTL_ALWAYS_INLINE inline
+      59             : #endif
+      60             : // Conversely, some functions in the generated code are extremely large yet very cold, with both of these
+      61             : // properties being extreme enough to confuse C++ compilers into spending pathological amounts of time
+      62             : // on a futile (the code becomes worse) attempt to optimize the least important parts of code.
+      63             : #if __has_attribute(optnone)
+      64             : #define CXXRTL_EXTREMELY_COLD __attribute__((__optnone__))
+      65             : #elif __has_attribute(optimize)
+      66             : #define CXXRTL_EXTREMELY_COLD __attribute__((__optimize__(0)))
+      67             : #else
+      68             : #define CXXRTL_EXTREMELY_COLD
+      69             : #endif
+      70             : 
+      71             : // CXXRTL uses assert() to check for C++ contract violations (which may result in e.g. undefined behavior
+      72             : // of the simulation code itself), and CXXRTL_ASSERT to check for RTL contract violations (which may at
+      73             : // most result in undefined simulation results).
+      74             : //
+      75             : // Though by default, CXXRTL_ASSERT() expands to assert(), it may be overridden e.g. when integrating
+      76             : // the simulation into another process that should survive violating RTL contracts.
+      77             : #ifndef CXXRTL_ASSERT
+      78             : #ifndef CXXRTL_NDEBUG
+      79             : #define CXXRTL_ASSERT(x) assert(x)
+      80             : #else
+      81             : #define CXXRTL_ASSERT(x)
+      82             : #endif
+      83             : #endif
+      84             : 
+      85             : namespace cxxrtl {
+      86             : 
+      87             : // All arbitrary-width values in CXXRTL are backed by arrays of unsigned integers called chunks. The chunk size
+      88             : // is the same regardless of the value width to simplify manipulating values via FFI interfaces, e.g. driving
+      89             : // and introspecting the simulation in Python.
+      90             : //
+      91             : // It is practical to use chunk sizes between 32 bits and platform register size because when arithmetics on
+      92             : // narrower integer types is legalized by the C++ compiler, it inserts code to clear the high bits of the register.
+      93             : // However, (a) most of our operations do not change those bits in the first place because of invariants that are
+      94             : // invisible to the compiler, (b) we often operate on non-power-of-2 values and have to clear the high bits anyway.
+      95             : // Therefore, using relatively wide chunks and clearing the high bits explicitly and only when we know they may be
+      96             : // clobbered results in simpler generated code.
+      97             : typedef uint32_t chunk_t;
+      98             : typedef uint64_t wide_chunk_t;
+      99             : 
+     100             : template<typename T>
+     101             : struct chunk_traits {
+     102             :         static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value,
+     103             :                       "chunk type must be an unsigned integral type");
+     104             :         using type = T;
+     105             :         static constexpr size_t bits = std::numeric_limits<T>::digits;
+     106             :         static constexpr T mask = std::numeric_limits<T>::max();
+     107             : };
+     108             : 
+     109             : template<class T>
+     110             : struct expr_base;
+     111             : 
+     112             : template<size_t Bits>
+     113             : struct value : public expr_base<value<Bits>> {
+     114             :         static constexpr size_t bits = Bits;
+     115             : 
+     116             :         using chunk = chunk_traits<chunk_t>;
+     117             :         static constexpr chunk::type msb_mask = (Bits % chunk::bits == 0) ? chunk::mask
+     118             :                 : chunk::mask >> (chunk::bits - (Bits % chunk::bits));
+     119             : 
+     120             :         static constexpr size_t chunks = (Bits + chunk::bits - 1) / chunk::bits;
+     121             :         chunk::type data[chunks] = {};
+     122             : 
+     123           3 :         value() = default;
+     124             :         template<typename... Init>
+     125             :         explicit constexpr value(Init ...init) : data{init...} {}
+     126             : 
+     127             :         value(const value<Bits> &) = default;
+     128             :         value<Bits> &operator=(const value<Bits> &) = default;
+     129             : 
+     130             :         value(value<Bits> &&) = default;
+     131             :         value<Bits> &operator=(value<Bits> &&) = default;
+     132             : 
+     133             :         // A (no-op) helper that forces the cast to value<>.
+     134             :         CXXRTL_ALWAYS_INLINE
+     135             :         const value<Bits> &val() const {
+     136             :                 return *this;
+     137             :         }
+     138             : 
+     139             :         std::string str() const {
+     140             :                 std::stringstream ss;
+     141             :                 ss << *this;
+     142             :                 return ss.str();
+     143             :         }
+     144             : 
+     145             :         // Conversion operations.
+     146             :         //
+     147             :         // These functions ensure that a conversion is never out of range, and should be always used, if at all
+     148             :         // possible, instead of direct manipulation of the `data` member. For very large types, .slice() and
+     149             :         // .concat() can be used to split them into more manageable parts.
+     150             :         template<class IntegerT, typename std::enable_if<!std::is_signed<IntegerT>::value, int>::type = 0>
+     151             :         CXXRTL_ALWAYS_INLINE
+     152             :         IntegerT get() const {
+     153             :                 static_assert(std::numeric_limits<IntegerT>::is_integer && !std::numeric_limits<IntegerT>::is_signed,
+     154             :                               "get<T>() requires T to be an unsigned integral type");
+     155             :                 static_assert(std::numeric_limits<IntegerT>::digits >= Bits,
+     156             :                               "get<T>() requires T to be at least as wide as the value is");
+     157             :                 IntegerT result = 0;
+     158             :                 for (size_t n = 0; n < chunks; n++)
+     159             :                         result |= IntegerT(data[n]) << (n * chunk::bits);
+     160             :                 return result;
+     161             :         }
+     162             : 
+     163             :         template<class IntegerT, typename std::enable_if<std::is_signed<IntegerT>::value, int>::type = 0>
+     164             :         CXXRTL_ALWAYS_INLINE
+     165             :         IntegerT get() const {
+     166             :                 auto unsigned_result = get<typename std::make_unsigned<IntegerT>::type>();
+     167             :                 IntegerT result;
+     168             :                 memcpy(&result, &unsigned_result, sizeof(IntegerT));
+     169             :                 return result;
+     170             :         }
+     171             : 
+     172             :         template<class IntegerT, typename std::enable_if<!std::is_signed<IntegerT>::value, int>::type = 0>
+     173             :         CXXRTL_ALWAYS_INLINE
+     174          30 :         void set(IntegerT value) {
+     175             :                 static_assert(std::numeric_limits<IntegerT>::is_integer && !std::numeric_limits<IntegerT>::is_signed,
+     176             :                               "set<T>() requires T to be an unsigned integral type");
+     177             :                 static_assert(std::numeric_limits<IntegerT>::digits >= Bits,
+     178             :                               "set<T>() requires the value to be at least as wide as T is");
+     179           6 :                 for (size_t n = 0; n < chunks; n++)
+     180          36 :                         data[n] = (value >> (n * chunk::bits)) & chunk::mask;
+     181             :         }
+     182             : 
+     183             :         template<class IntegerT, typename std::enable_if<std::is_signed<IntegerT>::value, int>::type = 0>
+     184             :         CXXRTL_ALWAYS_INLINE
+     185             :         void set(IntegerT value) {
+     186             :                 typename std::make_unsigned<IntegerT>::type unsigned_value;
+     187             :                 memcpy(&unsigned_value, &value, sizeof(IntegerT));
+     188             :                 set(unsigned_value);
+     189             :         }
+     190             : 
+     191             :         // Operations with compile-time parameters.
+     192             :         //
+     193             :         // These operations are used to implement slicing, concatenation, and blitting.
+     194             :         // The trunc, zext and sext operations add or remove most significant bits (i.e. on the left);
+     195             :         // the rtrunc and rzext operations add or remove least significant bits (i.e. on the right).
+     196             :         template<size_t NewBits>
+     197             :         CXXRTL_ALWAYS_INLINE
+     198             :         value<NewBits> trunc() const {
+     199             :                 static_assert(NewBits <= Bits, "trunc() may not increase width");
+     200             :                 value<NewBits> result;
+     201             :                 for (size_t n = 0; n < result.chunks; n++)
+     202             :                         result.data[n] = data[n];
+     203             :                 result.data[result.chunks - 1] &= result.msb_mask;
+     204             :                 return result;
+     205             :         }
+     206             : 
+     207             :         template<size_t NewBits>
+     208             :         CXXRTL_ALWAYS_INLINE
+     209          33 :         value<NewBits> zext() const {
+     210             :                 static_assert(NewBits >= Bits, "zext() may not decrease width");
+     211             :                 value<NewBits> result;
+     212          33 :                 for (size_t n = 0; n < chunks; n++)
+     213          33 :                         result.data[n] = data[n];
+     214             :                 return result;
+     215             :         }
+     216             : 
+     217             :         template<size_t NewBits>
+     218             :         CXXRTL_ALWAYS_INLINE
+     219             :         value<NewBits> sext() const {
+     220             :                 static_assert(NewBits >= Bits, "sext() may not decrease width");
+     221             :                 value<NewBits> result;
+     222             :                 for (size_t n = 0; n < chunks; n++)
+     223             :                         result.data[n] = data[n];
+     224             :                 if (is_neg()) {
+     225             :                         result.data[chunks - 1] |= ~msb_mask;
+     226             :                         for (size_t n = chunks; n < result.chunks; n++)
+     227             :                                 result.data[n] = chunk::mask;
+     228             :                         result.data[result.chunks - 1] &= result.msb_mask;
+     229             :                 }
+     230             :                 return result;
+     231             :         }
+     232             : 
+     233             :         template<size_t NewBits>
+     234             :         CXXRTL_ALWAYS_INLINE
+     235             :         value<NewBits> rtrunc() const {
+     236             :                 static_assert(NewBits <= Bits, "rtrunc() may not increase width");
+     237             :                 value<NewBits> result;
+     238             :                 constexpr size_t shift_chunks = (Bits - NewBits) / chunk::bits;
+     239             :                 constexpr size_t shift_bits   = (Bits - NewBits) % chunk::bits;
+     240             :                 chunk::type carry = 0;
+     241             :                 if (shift_chunks + result.chunks < chunks) {
+     242             :                         carry = (shift_bits == 0) ? 0
+     243             :                                 : data[shift_chunks + result.chunks] << (chunk::bits - shift_bits);
+     244             :                 }
+     245             :                 for (size_t n = result.chunks; n > 0; n--) {
+     246             :                         result.data[n - 1] = carry | (data[shift_chunks + n - 1] >> shift_bits);
+     247             :                         carry = (shift_bits == 0) ? 0
+     248             :                                 : data[shift_chunks + n - 1] << (chunk::bits - shift_bits);
+     249             :                 }
+     250             :                 return result;
+     251             :         }
+     252             : 
+     253             :         template<size_t NewBits>
+     254             :         CXXRTL_ALWAYS_INLINE
+     255             :         value<NewBits> rzext() const {
+     256             :                 static_assert(NewBits >= Bits, "rzext() may not decrease width");
+     257             :                 value<NewBits> result;
+     258             :                 constexpr size_t shift_chunks = (NewBits - Bits) / chunk::bits;
+     259             :                 constexpr size_t shift_bits   = (NewBits - Bits) % chunk::bits;
+     260             :                 chunk::type carry = 0;
+     261             :                 for (size_t n = 0; n < chunks; n++) {
+     262             :                         result.data[shift_chunks + n] = (data[n] << shift_bits) | carry;
+     263             :                         carry = (shift_bits == 0) ? 0
+     264             :                                 : data[n] >> (chunk::bits - shift_bits);
+     265             :                 }
+     266             :                 if (shift_chunks + chunks < result.chunks)
+     267             :                         result.data[shift_chunks + chunks] = carry;
+     268             :                 return result;
+     269             :         }
+     270             : 
+     271             :         // Bit blit operation, i.e. a partial read-modify-write.
+     272             :         template<size_t Stop, size_t Start>
+     273             :         CXXRTL_ALWAYS_INLINE
+     274             :         value<Bits> blit(const value<Stop - Start + 1> &source) const {
+     275             :                 static_assert(Stop >= Start, "blit() may not reverse bit order");
+     276             :                 constexpr chunk::type start_mask = ~(chunk::mask << (Start % chunk::bits));
+     277             :                 constexpr chunk::type stop_mask = (Stop % chunk::bits + 1 == chunk::bits) ? 0
+     278             :                         : (chunk::mask << (Stop % chunk::bits + 1));
+     279             :                 value<Bits> masked = *this;
+     280             :                 if (Start / chunk::bits == Stop / chunk::bits) {
+     281             :                         masked.data[Start / chunk::bits] &= stop_mask | start_mask;
+     282             :                 } else {
+     283             :                         masked.data[Start / chunk::bits] &= start_mask;
+     284             :                         for (size_t n = Start / chunk::bits + 1; n < Stop / chunk::bits; n++)
+     285             :                                 masked.data[n] = 0;
+     286             :                         masked.data[Stop / chunk::bits] &= stop_mask;
+     287             :                 }
+     288             :                 value<Bits> shifted = source
+     289             :                         .template rzext<Stop + 1>()
+     290             :                         .template zext<Bits>();
+     291             :                 return masked.bit_or(shifted);
+     292             :         }
+     293             : 
+     294             :         // Helpers for selecting extending or truncating operation depending on whether the result is wider or narrower
+     295             :         // than the operand. In C++17 these can be replaced with `if constexpr`.
+     296             :         template<size_t NewBits, typename = void>
+     297             :         struct zext_cast {
+     298             :                 CXXRTL_ALWAYS_INLINE
+     299          33 :                 value<NewBits> operator()(const value<Bits> &val) {
+     300          33 :                         return val.template zext<NewBits>();
+     301             :                 }
+     302             :         };
+     303             : 
+     304             :         template<size_t NewBits>
+     305             :         struct zext_cast<NewBits, typename std::enable_if<(NewBits < Bits)>::type> {
+     306             :                 CXXRTL_ALWAYS_INLINE
+     307             :                 value<NewBits> operator()(const value<Bits> &val) {
+     308             :                         return val.template trunc<NewBits>();
+     309             :                 }
+     310             :         };
+     311             : 
+     312             :         template<size_t NewBits, typename = void>
+     313             :         struct sext_cast {
+     314             :                 CXXRTL_ALWAYS_INLINE
+     315             :                 value<NewBits> operator()(const value<Bits> &val) {
+     316             :                         return val.template sext<NewBits>();
+     317             :                 }
+     318             :         };
+     319             : 
+     320             :         template<size_t NewBits>
+     321             :         struct sext_cast<NewBits, typename std::enable_if<(NewBits < Bits)>::type> {
+     322             :                 CXXRTL_ALWAYS_INLINE
+     323             :                 value<NewBits> operator()(const value<Bits> &val) {
+     324             :                         return val.template trunc<NewBits>();
+     325             :                 }
+     326             :         };
+     327             : 
+     328             :         template<size_t NewBits>
+     329             :         CXXRTL_ALWAYS_INLINE
+     330          33 :         value<NewBits> zcast() const {
+     331          33 :                 return zext_cast<NewBits>()(*this);
+     332             :         }
+     333             : 
+     334             :         template<size_t NewBits>
+     335             :         CXXRTL_ALWAYS_INLINE
+     336             :         value<NewBits> scast() const {
+     337             :                 return sext_cast<NewBits>()(*this);
+     338             :         }
+     339             : 
+     340             :         // Bit replication is far more efficient than the equivalent concatenation.
+     341             :         template<size_t Count>
+     342             :         CXXRTL_ALWAYS_INLINE
+     343             :         value<Bits * Count> repeat() const {
+     344             :                 static_assert(Bits == 1, "repeat() is implemented only for 1-bit values");
+     345             :                 return *this ? value<Bits * Count>().bit_not() : value<Bits * Count>();
+     346             :         }
+     347             : 
+     348             :         // Operations with run-time parameters (offsets, amounts, etc).
+     349             :         //
+     350             :         // These operations are used for computations.
+     351             :         bool bit(size_t offset) const {
+     352             :                 return data[offset / chunk::bits] & (1 << (offset % chunk::bits));
+     353             :         }
+     354             : 
+     355             :         void set_bit(size_t offset, bool value = true) {
+     356             :                 size_t offset_chunks = offset / chunk::bits;
+     357             :                 size_t offset_bits = offset % chunk::bits;
+     358             :                 data[offset_chunks] &= ~(1 << offset_bits);
+     359             :                 data[offset_chunks] |= value ? 1 << offset_bits : 0;
+     360             :         }
+     361             : 
+     362             :         explicit operator bool() const {
+     363             :                 return !is_zero();
+     364             :         }
+     365             : 
+     366             :         bool is_zero() const {
+     367             :                 for (size_t n = 0; n < chunks; n++)
+     368             :                         if (data[n] != 0)
+     369             :                                 return false;
+     370             :                 return true;
+     371             :         }
+     372             : 
+     373             :         bool is_neg() const {
+     374             :                 return data[chunks - 1] & (1 << ((Bits - 1) % chunk::bits));
+     375             :         }
+     376             : 
+     377             :         bool operator ==(const value<Bits> &other) const {
+     378             :                 for (size_t n = 0; n < chunks; n++)
+     379             :                         if (data[n] != other.data[n])
+     380             :                                 return false;
+     381             :                 return true;
+     382             :         }
+     383             : 
+     384             :         bool operator !=(const value<Bits> &other) const {
+     385             :                 return !(*this == other);
+     386             :         }
+     387             : 
+     388             :         value<Bits> bit_not() const {
+     389             :                 value<Bits> result;
+     390             :                 for (size_t n = 0; n < chunks; n++)
+     391             :                         result.data[n] = ~data[n];
+     392             :                 result.data[chunks - 1] &= msb_mask;
+     393             :                 return result;
+     394             :         }
+     395             : 
+     396             :         value<Bits> bit_and(const value<Bits> &other) const {
+     397             :                 value<Bits> result;
+     398             :                 for (size_t n = 0; n < chunks; n++)
+     399             :                         result.data[n] = data[n] & other.data[n];
+     400             :                 return result;
+     401             :         }
+     402             : 
+     403             :         value<Bits> bit_or(const value<Bits> &other) const {
+     404             :                 value<Bits> result;
+     405             :                 for (size_t n = 0; n < chunks; n++)
+     406             :                         result.data[n] = data[n] | other.data[n];
+     407             :                 return result;
+     408             :         }
+     409             : 
+     410             :         value<Bits> bit_xor(const value<Bits> &other) const {
+     411             :                 value<Bits> result;
+     412             :                 for (size_t n = 0; n < chunks; n++)
+     413             :                         result.data[n] = data[n] ^ other.data[n];
+     414             :                 return result;
+     415             :         }
+     416             : 
+     417             :         value<Bits> update(const value<Bits> &val, const value<Bits> &mask) const {
+     418             :                 return bit_and(mask.bit_not()).bit_or(val.bit_and(mask));
+     419             :         }
+     420             : 
+     421             :         template<size_t AmountBits>
+     422             :         value<Bits> shl(const value<AmountBits> &amount) const {
+     423             :                 // Ensure our early return is correct by prohibiting values larger than 4 Gbit.
+     424             :                 static_assert(Bits <= chunk::mask, "shl() of unreasonably large values is not supported");
+     425             :                 // Detect shifts definitely large than Bits early.
+     426             :                 for (size_t n = 1; n < amount.chunks; n++)
+     427             :                         if (amount.data[n] != 0)
+     428             :                                 return {};
+     429             :                 // Past this point we can use the least significant chunk as the shift size.
+     430             :                 size_t shift_chunks = amount.data[0] / chunk::bits;
+     431             :                 size_t shift_bits   = amount.data[0] % chunk::bits;
+     432             :                 if (shift_chunks >= chunks)
+     433             :                         return {};
+     434             :                 value<Bits> result;
+     435             :                 chunk::type carry = 0;
+     436             :                 for (size_t n = 0; n < chunks - shift_chunks; n++) {
+     437             :                         result.data[shift_chunks + n] = (data[n] << shift_bits) | carry;
+     438             :                         carry = (shift_bits == 0) ? 0
+     439             :                                 : data[n] >> (chunk::bits - shift_bits);
+     440             :                 }
+     441             :                 result.data[result.chunks - 1] &= result.msb_mask;
+     442             :                 return result;
+     443             :         }
+     444             : 
+     445             :         template<size_t AmountBits, bool Signed = false>
+     446             :         value<Bits> shr(const value<AmountBits> &amount) const {
+     447             :                 // Ensure our early return is correct by prohibiting values larger than 4 Gbit.
+     448             :                 static_assert(Bits <= chunk::mask, "shr() of unreasonably large values is not supported");
+     449             :                 // Detect shifts definitely large than Bits early.
+     450             :                 for (size_t n = 1; n < amount.chunks; n++)
+     451             :                         if (amount.data[n] != 0)
+     452             :                                 return (Signed && is_neg()) ? value<Bits>().bit_not() : value<Bits>();
+     453             :                 // Past this point we can use the least significant chunk as the shift size.
+     454             :                 size_t shift_chunks = amount.data[0] / chunk::bits;
+     455             :                 size_t shift_bits   = amount.data[0] % chunk::bits;
+     456             :                 if (shift_chunks >= chunks)
+     457             :                         return (Signed && is_neg()) ? value<Bits>().bit_not() : value<Bits>();
+     458             :                 value<Bits> result;
+     459             :                 chunk::type carry = 0;
+     460             :                 for (size_t n = 0; n < chunks - shift_chunks; n++) {
+     461             :                         result.data[chunks - shift_chunks - 1 - n] = carry | (data[chunks - 1 - n] >> shift_bits);
+     462             :                         carry = (shift_bits == 0) ? 0
+     463             :                                 : data[chunks - 1 - n] << (chunk::bits - shift_bits);
+     464             :                 }
+     465             :                 if (Signed && is_neg()) {
+     466             :                         size_t top_chunk_idx  = amount.data[0] > Bits ? 0 : (Bits - amount.data[0]) / chunk::bits;
+     467             :                         size_t top_chunk_bits = amount.data[0] > Bits ? 0 : (Bits - amount.data[0]) % chunk::bits;
+     468             :                         for (size_t n = top_chunk_idx + 1; n < chunks; n++)
+     469             :                                 result.data[n] = chunk::mask;
+     470             :                         if (amount.data[0] != 0)
+     471             :                                 result.data[top_chunk_idx] |= chunk::mask << top_chunk_bits;
+     472             :                         result.data[result.chunks - 1] &= result.msb_mask;
+     473             :                 }
+     474             :                 return result;
+     475             :         }
+     476             : 
+     477             :         template<size_t AmountBits>
+     478             :         value<Bits> sshr(const value<AmountBits> &amount) const {
+     479             :                 return shr<AmountBits, /*Signed=*/true>(amount);
+     480             :         }
+     481             : 
+     482             :         template<size_t ResultBits, size_t SelBits>
+     483             :         value<ResultBits> bmux(const value<SelBits> &sel) const {
+     484             :                 static_assert(ResultBits << SelBits == Bits, "invalid sizes used in bmux()");
+     485             :                 size_t amount = sel.data[0] * ResultBits;
+     486             :                 size_t shift_chunks = amount / chunk::bits;
+     487             :                 size_t shift_bits   = amount % chunk::bits;
+     488             :                 value<ResultBits> result;
+     489             :                 chunk::type carry = 0;
+     490             :                 if (ResultBits % chunk::bits + shift_bits > chunk::bits)
+     491             :                         carry = data[result.chunks + shift_chunks] << (chunk::bits - shift_bits);
+     492             :                 for (size_t n = 0; n < result.chunks; n++) {
+     493             :                         result.data[result.chunks - 1 - n] = carry | (data[result.chunks + shift_chunks - 1 - n] >> shift_bits);
+     494             :                         carry = (shift_bits == 0) ? 0
+     495             :                                 : data[result.chunks + shift_chunks - 1 - n] << (chunk::bits - shift_bits);
+     496             :                 }
+     497             :                 result.data[result.chunks - 1] &= result.msb_mask;
+     498             :                 return result;
+     499             :         }
+     500             : 
+     501             :         template<size_t ResultBits, size_t SelBits>
+     502             :         value<ResultBits> demux(const value<SelBits> &sel) const {
+     503             :                 static_assert(Bits << SelBits == ResultBits, "invalid sizes used in demux()");
+     504             :                 size_t amount = sel.data[0] * Bits;
+     505             :                 size_t shift_chunks = amount / chunk::bits;
+     506             :                 size_t shift_bits   = amount % chunk::bits;
+     507             :                 value<ResultBits> result;
+     508             :                 chunk::type carry = 0;
+     509             :                 for (size_t n = 0; n < chunks; n++) {
+     510             :                         result.data[shift_chunks + n] = (data[n] << shift_bits) | carry;
+     511             :                         carry = (shift_bits == 0) ? 0
+     512             :                                 : data[n] >> (chunk::bits - shift_bits);
+     513             :                 }
+     514             :                 if (Bits % chunk::bits + shift_bits > chunk::bits)
+     515             :                         result.data[shift_chunks + chunks] = carry;
+     516             :                 return result;
+     517             :         }
+     518             : 
+     519             :         size_t ctpop() const {
+     520             :                 size_t count = 0;
+     521             :                 for (size_t n = 0; n < chunks; n++) {
+     522             :                         // This loop implements the population count idiom as recognized by LLVM and GCC.
+     523             :                         for (chunk::type x = data[n]; x != 0; count++)
+     524             :                                 x = x & (x - 1);
+     525             :                 }
+     526             :                 return count;
+     527             :         }
+     528             : 
+     529             :         size_t ctlz() const {
+     530             :                 size_t count = 0;
+     531             :                 for (size_t n = 0; n < chunks; n++) {
+     532             :                         chunk::type x = data[chunks - 1 - n];
+     533             :                         // First add to `count` as if the chunk is zero
+     534             :                         constexpr size_t msb_chunk_bits = Bits % chunk::bits != 0 ? Bits % chunk::bits : chunk::bits;
+     535             :                         count += (n == 0 ? msb_chunk_bits : chunk::bits);
+     536             :                         // If the chunk isn't zero, correct the `count` value and return
+     537             :                         if (x != 0) {
+     538             :                                 for (; x != 0; count--)
+     539             :                                         x >>= 1;
+     540             :                                 break;
+     541             :                         }
+     542             :                 }
+     543             :                 return count;
+     544             :         }
+     545             : 
+     546             :         template<bool Invert, bool CarryIn>
+     547          33 :         std::pair<value<Bits>, bool /*CarryOut*/> alu(const value<Bits> &other) const {
+     548          33 :                 value<Bits> result;
+     549          33 :                 bool carry = CarryIn;
+     550          66 :                 for (size_t n = 0; n < result.chunks; n++) {
+     551          33 :                         result.data[n] = data[n] + (Invert ? ~other.data[n] : other.data[n]) + carry;
+     552             :                         if (result.chunks - 1 == n)
+     553          33 :                                 result.data[result.chunks - 1] &= result.msb_mask;
+     554          33 :                         carry = (result.data[n] <  data[n]) ||
+     555             :                                 (result.data[n] == data[n] && carry);
+     556             :                 }
+     557          33 :                 return {result, carry};
+     558             :         }
+     559             : 
+     560          33 :         value<Bits> add(const value<Bits> &other) const {
+     561          33 :                 return alu</*Invert=*/false, /*CarryIn=*/false>(other).first;
+     562             :         }
+     563             : 
+     564             :         value<Bits> sub(const value<Bits> &other) const {
+     565             :                 return alu</*Invert=*/true, /*CarryIn=*/true>(other).first;
+     566             :         }
+     567             : 
+     568             :         value<Bits> neg() const {
+     569             :                 return value<Bits>().sub(*this);
+     570             :         }
+     571             : 
+     572             :         bool ucmp(const value<Bits> &other) const {
+     573             :                 bool carry;
+     574             :                 std::tie(std::ignore, carry) = alu</*Invert=*/true, /*CarryIn=*/true>(other);
+     575             :                 return !carry; // a.ucmp(b) ≡ a u< b
+     576             :         }
+     577             : 
+     578             :         bool scmp(const value<Bits> &other) const {
+     579             :                 value<Bits> result;
+     580             :                 bool carry;
+     581             :                 std::tie(result, carry) = alu</*Invert=*/true, /*CarryIn=*/true>(other);
+     582             :                 bool overflow = (is_neg() == !other.is_neg()) && (is_neg() != result.is_neg());
+     583             :                 return result.is_neg() ^ overflow; // a.scmp(b) ≡ a s< b
+     584             :         }
+     585             : 
+     586             :         template<size_t ResultBits>
+     587             :         value<ResultBits> mul(const value<Bits> &other) const {
+     588             :                 value<ResultBits> result;
+     589             :                 wide_chunk_t wide_result[result.chunks + 1] = {};
+     590             :                 for (size_t n = 0; n < chunks; n++) {
+     591             :                         for (size_t m = 0; m < chunks && n + m < result.chunks; m++) {
+     592             :                                 wide_result[n + m] += wide_chunk_t(data[n]) * wide_chunk_t(other.data[m]);
+     593             :                                 wide_result[n + m + 1] += wide_result[n + m] >> chunk::bits;
+     594             :                                 wide_result[n + m] &= chunk::mask;
+     595             :                         }
+     596             :                 }
+     597             :                 for (size_t n = 0; n < result.chunks; n++) {
+     598             :                         result.data[n] = wide_result[n];
+     599             :                 }
+     600             :                 result.data[result.chunks - 1] &= result.msb_mask;
+     601             :                 return result;
+     602             :         }
+     603             : 
+     604             :         std::pair<value<Bits>, value<Bits>> udivmod(value<Bits> divisor) const {
+     605             :                 value<Bits> quotient;
+     606             :                 value<Bits> dividend = *this;
+     607             :                 if (dividend.ucmp(divisor))
+     608             :                         return {/*quotient=*/value<Bits>{0u}, /*remainder=*/dividend};
+     609             :                 int64_t divisor_shift = divisor.ctlz() - dividend.ctlz();
+     610             :                 assert(divisor_shift >= 0);
+     611             :                 divisor = divisor.shl(value<Bits>{(chunk::type) divisor_shift});
+     612             :                 for (size_t step = 0; step <= divisor_shift; step++) {
+     613             :                         quotient = quotient.shl(value<Bits>{1u});
+     614             :                         if (!dividend.ucmp(divisor)) {
+     615             :                                 dividend = dividend.sub(divisor);
+     616             :                                 quotient.set_bit(0, true);
+     617             :                         }
+     618             :                         divisor = divisor.shr(value<Bits>{1u});
+     619             :                 }
+     620             :                 return {quotient, /*remainder=*/dividend};
+     621             :         }
+     622             : 
+     623             :         std::pair<value<Bits>, value<Bits>> sdivmod(const value<Bits> &other) const {
+     624             :                 value<Bits + 1> quotient;
+     625             :                 value<Bits + 1> remainder;
+     626             :                 value<Bits + 1> dividend = sext<Bits + 1>();
+     627             :                 value<Bits + 1> divisor = other.template sext<Bits + 1>();
+     628             :                 if (is_neg()) dividend = dividend.neg();
+     629             :                 if (other.is_neg()) divisor = divisor.neg();
+     630             :                 std::tie(quotient, remainder) = dividend.udivmod(divisor);
+     631             :                 if (is_neg() != other.is_neg()) quotient = quotient.neg();
+     632             :                 if (is_neg()) remainder = remainder.neg();
+     633             :                 return {quotient.template trunc<Bits>(), remainder.template trunc<Bits>()};
+     634             :         }
+     635             : };
+     636             : 
+     637             : // Expression template for a slice, usable as lvalue or rvalue, and composable with other expression templates here.
+     638             : template<class T, size_t Stop, size_t Start>
+     639             : struct slice_expr : public expr_base<slice_expr<T, Stop, Start>> {
+     640             :         static_assert(Stop >= Start, "slice_expr() may not reverse bit order");
+     641             :         static_assert(Start < T::bits && Stop < T::bits, "slice_expr() must be within bounds");
+     642             :         static constexpr size_t bits = Stop - Start + 1;
+     643             : 
+     644             :         T &expr;
+     645             : 
+     646             :         slice_expr(T &expr) : expr(expr) {}
+     647             :         slice_expr(const slice_expr<T, Stop, Start> &) = delete;
+     648             : 
+     649             :         CXXRTL_ALWAYS_INLINE
+     650             :         operator value<bits>() const {
+     651             :                 return static_cast<const value<T::bits> &>(expr)
+     652             :                         .template rtrunc<T::bits - Start>()
+     653             :                         .template trunc<bits>();
+     654             :         }
+     655             : 
+     656             :         CXXRTL_ALWAYS_INLINE
+     657             :         slice_expr<T, Stop, Start> &operator=(const value<bits> &rhs) {
+     658             :                 // Generic partial assignment implemented using a read-modify-write operation on the sliced expression.
+     659             :                 expr = static_cast<const value<T::bits> &>(expr)
+     660             :                         .template blit<Stop, Start>(rhs);
+     661             :                 return *this;
+     662             :         }
+     663             : 
+     664             :         // A helper that forces the cast to value<>, which allows deduction to work.
+     665             :         CXXRTL_ALWAYS_INLINE
+     666             :         value<bits> val() const {
+     667             :                 return static_cast<const value<bits> &>(*this);
+     668             :         }
+     669             : };
+     670             : 
+     671             : // Expression template for a concatenation, usable as lvalue or rvalue, and composable with other expression templates here.
+     672             : template<class T, class U>
+     673             : struct concat_expr : public expr_base<concat_expr<T, U>> {
+     674             :         static constexpr size_t bits = T::bits + U::bits;
+     675             : 
+     676             :         T &ms_expr;
+     677             :         U &ls_expr;
+     678             : 
+     679             :         concat_expr(T &ms_expr, U &ls_expr) : ms_expr(ms_expr), ls_expr(ls_expr) {}
+     680             :         concat_expr(const concat_expr<T, U> &) = delete;
+     681             : 
+     682             :         CXXRTL_ALWAYS_INLINE
+     683             :         operator value<bits>() const {
+     684             :                 value<bits> ms_shifted = static_cast<const value<T::bits> &>(ms_expr)
+     685             :                         .template rzext<bits>();
+     686             :                 value<bits> ls_extended = static_cast<const value<U::bits> &>(ls_expr)
+     687             :                         .template zext<bits>();
+     688             :                 return ms_shifted.bit_or(ls_extended);
+     689             :         }
+     690             : 
+     691             :         CXXRTL_ALWAYS_INLINE
+     692             :         concat_expr<T, U> &operator=(const value<bits> &rhs) {
+     693             :                 ms_expr = rhs.template rtrunc<T::bits>();
+     694             :                 ls_expr = rhs.template trunc<U::bits>();
+     695             :                 return *this;
+     696             :         }
+     697             : 
+     698             :         // A helper that forces the cast to value<>, which allows deduction to work.
+     699             :         CXXRTL_ALWAYS_INLINE
+     700             :         value<bits> val() const {
+     701             :                 return static_cast<const value<bits> &>(*this);
+     702             :         }
+     703             : };
+     704             : 
+     705             : // Base class for expression templates, providing helper methods for operations that are valid on both rvalues and lvalues.
+     706             : //
+     707             : // Note that expression objects (slices and concatenations) constructed in this way should NEVER be captured because
+     708             : // they refer to temporaries that will, in general, only live until the end of the statement. For example, both of
+     709             : // these snippets perform use-after-free:
+     710             : //
+     711             : //    const auto &a = val.slice<7,0>().slice<1>();
+     712             : //    value<1> b = a;
+     713             : //
+     714             : //    auto &&c = val.slice<7,0>().slice<1>();
+     715             : //    c = value<1>{1u};
+     716             : //
+     717             : // An easy way to write code using slices and concatenations safely is to follow two simple rules:
+     718             : //   * Never explicitly name any type except `value<W>` or `const value<W> &`.
+     719             : //   * Never use a `const auto &` or `auto &&` in any such expression.
+     720             : // Then, any code that compiles will be well-defined.
+     721             : template<class T>
+     722             : struct expr_base {
+     723             :         template<size_t Stop, size_t Start = Stop>
+     724             :         CXXRTL_ALWAYS_INLINE
+     725             :         slice_expr<const T, Stop, Start> slice() const {
+     726             :                 return {*static_cast<const T *>(this)};
+     727             :         }
+     728             : 
+     729             :         template<size_t Stop, size_t Start = Stop>
+     730             :         CXXRTL_ALWAYS_INLINE
+     731             :         slice_expr<T, Stop, Start> slice() {
+     732             :                 return {*static_cast<T *>(this)};
+     733             :         }
+     734             : 
+     735             :         template<class U>
+     736             :         CXXRTL_ALWAYS_INLINE
+     737             :         concat_expr<const T, typename std::remove_reference<const U>::type> concat(const U &other) const {
+     738             :                 return {*static_cast<const T *>(this), other};
+     739             :         }
+     740             : 
+     741             :         template<class U>
+     742             :         CXXRTL_ALWAYS_INLINE
+     743             :         concat_expr<T, typename std::remove_reference<U>::type> concat(U &&other) {
+     744             :                 return {*static_cast<T *>(this), other};
+     745             :         }
+     746             : };
+     747             : 
+     748             : template<size_t Bits>
+     749             : std::ostream &operator<<(std::ostream &os, const value<Bits> &val) {
+     750             :         auto old_flags = os.flags(std::ios::right);
+     751             :         auto old_width = os.width(0);
+     752             :         auto old_fill  = os.fill('0');
+     753             :         os << val.bits << '\'' << std::hex;
+     754             :         for (size_t n = val.chunks - 1; n != (size_t)-1; n--) {
+     755             :                 if (n == val.chunks - 1 && Bits % value<Bits>::chunk::bits != 0)
+     756             :                         os.width((Bits % value<Bits>::chunk::bits + 3) / 4);
+     757             :                 else
+     758             :                         os.width((value<Bits>::chunk::bits + 3) / 4);
+     759             :                 os << val.data[n];
+     760             :         }
+     761             :         os.fill(old_fill);
+     762             :         os.width(old_width);
+     763             :         os.flags(old_flags);
+     764             :         return os;
+     765             : }
+     766             : 
+     767             : template<size_t Bits>
+     768             : struct wire {
+     769             :         static constexpr size_t bits = Bits;
+     770             : 
+     771             :         value<Bits> curr;
+     772             :         value<Bits> next;
+     773             : 
+     774             :         wire() = default;
+     775             :         explicit constexpr wire(const value<Bits> &init) : curr(init), next(init) {}
+     776             :         template<typename... Init>
+     777             :         explicit constexpr wire(Init ...init) : curr{init...}, next{init...} {}
+     778             : 
+     779             :         // Copying and copy-assigning values is natural. If, however, a value is replaced with a wire,
+     780             :         // e.g. because a module is built with a different optimization level, then existing code could
+     781             :         // unintentionally copy a wire instead, which would create a subtle but serious bug. To make sure
+     782             :         // this doesn't happen, prohibit copying and copy-assigning wires.
+     783             :         wire(const wire<Bits> &) = delete;
+     784             :         wire<Bits> &operator=(const wire<Bits> &) = delete;
+     785             : 
+     786             :         wire(wire<Bits> &&) = default;
+     787             :         wire<Bits> &operator=(wire<Bits> &&) = default;
+     788             : 
+     789             :         template<class IntegerT>
+     790             :         CXXRTL_ALWAYS_INLINE
+     791             :         IntegerT get() const {
+     792             :                 return curr.template get<IntegerT>();
+     793             :         }
+     794             : 
+     795             :         template<class IntegerT>
+     796             :         CXXRTL_ALWAYS_INLINE
+     797             :         void set(IntegerT other) {
+     798             :                 next.template set<IntegerT>(other);
+     799             :         }
+     800             : 
+     801             :         // This method intentionally takes a mandatory argument (to make it more difficult to misuse in
+     802             :         // black box implementations, leading to missed observer events). It is generic over its argument
+     803             :         // to allow the `on_update` method to be non-virtual.
+     804             :         template<class ObserverT>
+     805             :         bool commit(ObserverT &observer) {
+     806             :                 if (curr != next) {
+     807             :                         observer.on_update(curr.chunks, curr.data, next.data);
+     808             :                         curr = next;
+     809             :                         return true;
+     810             :                 }
+     811             :                 return false;
+     812             :         }
+     813             : };
+     814             : 
+     815             : template<size_t Bits>
+     816             : std::ostream &operator<<(std::ostream &os, const wire<Bits> &val) {
+     817             :         os << val.curr;
+     818             :         return os;
+     819             : }
+     820             : 
+     821             : template<size_t Width>
+     822             : struct memory {
+     823             :         const size_t depth;
+     824             :         std::unique_ptr<value<Width>[]> data;
+     825             : 
+     826             :         explicit memory(size_t depth) : depth(depth), data(new value<Width>[depth]) {}
+     827             : 
+     828             :         memory(const memory<Width> &) = delete;
+     829             :         memory<Width> &operator=(const memory<Width> &) = delete;
+     830             : 
+     831             :         memory(memory<Width> &&) = default;
+     832             :         memory<Width> &operator=(memory<Width> &&other) {
+     833             :                 assert(depth == other.depth);
+     834             :                 data = std::move(other.data);
+     835             :                 write_queue = std::move(other.write_queue);
+     836             :                 return *this;
+     837             :         }
+     838             : 
+     839             :         // An operator for direct memory reads. May be used at any time during the simulation.
+     840             :         const value<Width> &operator [](size_t index) const {
+     841             :                 assert(index < depth);
+     842             :                 return data[index];
+     843             :         }
+     844             : 
+     845             :         // An operator for direct memory writes. May only be used before the simulation is started. If used
+     846             :         // after the simulation is started, the design may malfunction.
+     847             :         value<Width> &operator [](size_t index) {
+     848             :                 assert(index < depth);
+     849             :                 return data[index];
+     850             :         }
+     851             : 
+     852             :         // A simple way to make a writable memory would be to use an array of wires instead of an array of values.
+     853             :         // However, there are two significant downsides to this approach: first, it has large overhead (2× space
+     854             :         // overhead, and O(depth) time overhead during commit); second, it does not simplify handling write port
+     855             :         // priorities. Although in principle write ports could be ordered or conditionally enabled in generated
+     856             :         // code based on their priorities and selected addresses, the feedback arc set problem is computationally
+     857             :         // expensive, and the heuristic based algorithms are not easily modified to guarantee (rather than prefer)
+     858             :         // a particular write port evaluation order.
+     859             :         //
+     860             :         // The approach used here instead is to queue writes into a buffer during the eval phase, then perform
+     861             :         // the writes during the commit phase in the priority order. This approach has low overhead, with both space
+     862             :         // and time proportional to the amount of write ports. Because virtually every memory in a practical design
+     863             :         // has at most two write ports, linear search is used on every write, being the fastest and simplest approach.
+     864             :         struct write {
+     865             :                 size_t index;
+     866             :                 value<Width> val;
+     867             :                 value<Width> mask;
+     868             :                 int priority;
+     869             :         };
+     870             :         std::vector<write> write_queue;
+     871             : 
+     872             :         void update(size_t index, const value<Width> &val, const value<Width> &mask, int priority = 0) {
+     873             :                 assert(index < depth);
+     874             :                 // Queue up the write while keeping the queue sorted by priority.
+     875             :                 write_queue.insert(
+     876             :                         std::upper_bound(write_queue.begin(), write_queue.end(), priority,
+     877             :                                 [](const int a, const write& b) { return a < b.priority; }),
+     878             :                         write { index, val, mask, priority });
+     879             :         }
+     880             : 
+     881             :         // See the note for `wire::commit()`.
+     882             :         template<class ObserverT>
+     883             :         bool commit(ObserverT &observer) {
+     884             :                 bool changed = false;
+     885             :                 for (const write &entry : write_queue) {
+     886             :                         value<Width> elem = data[entry.index];
+     887             :                         elem = elem.update(entry.val, entry.mask);
+     888             :                         if (data[entry.index] != elem) {
+     889             :                                 observer.on_update(value<Width>::chunks, data[0].data, elem.data, entry.index);
+     890             :                                 changed |= true;
+     891             :                         }
+     892             :                         data[entry.index] = elem;
+     893             :                 }
+     894             :                 write_queue.clear();
+     895             :                 return changed;
+     896             :         }
+     897             : };
+     898             : 
+     899          27 : struct metadata {
+     900             :         const enum {
+     901             :                 MISSING = 0,
+     902             :                 UINT    = 1,
+     903             :                 SINT    = 2,
+     904             :                 STRING  = 3,
+     905             :                 DOUBLE  = 4,
+     906             :         } value_type;
+     907             : 
+     908             :         // In debug mode, using the wrong .as_*() function will assert.
+     909             :         // In release mode, using the wrong .as_*() function will safely return a default value.
+     910             :         const uint64_t    uint_value = 0;
+     911             :         const int64_t     sint_value = 0;
+     912             :         const std::string string_value = "";
+     913             :         const double      double_value = 0.0;
+     914             : 
+     915             :         metadata() : value_type(MISSING) {}
+     916           0 :         metadata(uint64_t value) : value_type(UINT), uint_value(value) {}
+     917           0 :         metadata(int64_t value) : value_type(SINT), sint_value(value) {}
+     918           9 :         metadata(const std::string &value) : value_type(STRING), string_value(value) {}
+     919           0 :         metadata(const char *value) : value_type(STRING), string_value(value) {}
+     920           0 :         metadata(double value) : value_type(DOUBLE), double_value(value) {}
+     921             : 
+     922          18 :         metadata(const metadata &) = default;
+     923             :         metadata &operator=(const metadata &) = delete;
+     924             : 
+     925             :         uint64_t as_uint() const {
+     926             :                 assert(value_type == UINT);
+     927             :                 return uint_value;
+     928             :         }
+     929             : 
+     930             :         int64_t as_sint() const {
+     931             :                 assert(value_type == SINT);
+     932             :                 return sint_value;
+     933             :         }
+     934             : 
+     935             :         const std::string &as_string() const {
+     936             :                 assert(value_type == STRING);
+     937             :                 return string_value;
+     938             :         }
+     939             : 
+     940             :         double as_double() const {
+     941             :                 assert(value_type == DOUBLE);
+     942             :                 return double_value;
+     943             :         }
+     944             : 
+     945             :         // Internal CXXRTL use only.
+     946           9 :         static std::map<std::string, metadata> deserialize(const char *ptr) {
+     947           9 :                 std::map<std::string, metadata> result;
+     948           9 :                 std::string name;
+     949             :                 // Grammar:
+     950             :                 // string   ::= [^\0]+ \0
+     951             :                 // metadata ::= [uid] .{8} | s <string>
+     952             :                 // map      ::= ( <string> <metadata> )* \0
+     953          45 :                 for (;;) {
+     954          45 :                         if (*ptr) {
+     955          45 :                                 name += *ptr++;
+     956          18 :                         } else if (!name.empty()) {
+     957           9 :                                 ptr++;
+     958           9 :                                 auto get_u64 = [&]() {
+     959           0 :                                         uint64_t result = 0;
+     960           0 :                                         for (size_t count = 0; count < 8; count++)
+     961           0 :                                                 result = (result << 8) | *ptr++;
+     962           0 :                                         return result;
+     963           9 :                                 };
+     964           9 :                                 char type = *ptr++;
+     965           9 :                                 if (type == 'u') {
+     966           0 :                                         uint64_t value = get_u64();
+     967           0 :                                         result.emplace(name, value);
+     968           9 :                                 } else if (type == 'i') {
+     969           0 :                                         int64_t value = (int64_t)get_u64();
+     970           0 :                                         result.emplace(name, value);
+     971           9 :                                 } else if (type == 'd') {
+     972           0 :                                         double dvalue;
+     973           0 :                                         uint64_t uvalue = get_u64();
+     974           0 :                                         static_assert(sizeof(dvalue) == sizeof(uvalue), "double must be 64 bits in size");
+     975           0 :                                         memcpy(&dvalue, &uvalue, sizeof(dvalue));
+     976           0 :                                         result.emplace(name, dvalue);
+     977           9 :                                 } else if (type == 's') {
+     978           9 :                                         std::string value;
+     979           9 :                                         while (*ptr)
+     980         216 :                                                 value += *ptr++;
+     981           9 :                                         ptr++;
+     982           9 :                                         result.emplace(name, value);
+     983           9 :                                 } else {
+     984           0 :                                         assert(false && "Unknown type specifier");
+     985           9 :                                         return result;
+     986             :                                 }
+     987           9 :                                 name.clear();
+     988             :                         } else {
+     989           9 :                                 return result;
+     990             :                         }
+     991             :                 }
+     992           9 :         }
+     993             : };
+     994             : 
+     995             : typedef std::map<std::string, metadata> metadata_map;
+     996             : 
+     997             : struct performer;
+     998             : 
+     999             : // An object that allows formatting a string lazily.
+    1000             : struct lazy_fmt {
+    1001             :         virtual std::string operator() () const = 0;
+    1002             : };
+    1003             : 
+    1004             : // Flavor of a `$check` cell.
+    1005             : enum class flavor {
+    1006             :         // Corresponds to a `$assert` cell in other flows, and a Verilog `assert ()` statement.
+    1007             :         ASSERT,
+    1008             :         // Corresponds to a `$assume` cell in other flows, and a Verilog `assume ()` statement.
+    1009             :         ASSUME,
+    1010             :         // Corresponds to a `$live` cell in other flows, and a Verilog `assert (eventually)` statement.
+    1011             :         ASSERT_EVENTUALLY,
+    1012             :         // Corresponds to a `$fair` cell in other flows, and a Verilog `assume (eventually)` statement.
+    1013             :         ASSUME_EVENTUALLY,
+    1014             :         // Corresponds to a `$cover` cell in other flows, and a Verilog `cover ()` statement.
+    1015             :         COVER,
+    1016             : };
+    1017             : 
+    1018             : // An object that can be passed to a `eval()` method in order to act on side effects. The default behavior implemented
+    1019             : // below is the same as the behavior of `eval(nullptr)`, except that `-print-output` option of `write_cxxrtl` is not
+    1020             : // taken into account.
+    1021             : struct performer {
+    1022             :         // Called by generated formatting code to evaluate a Verilog `$time` expression.
+    1023             :         virtual int64_t vlog_time() const { return 0; }
+    1024             : 
+    1025             :         // Called by generated formatting code to evaluate a Verilog `$realtime` expression.
+    1026             :         virtual double vlog_realtime() const { return vlog_time(); }
+    1027             : 
+    1028             :         // Called when a `$print` cell is triggered.
+    1029             :         virtual void on_print(const lazy_fmt &formatter, const metadata_map &attributes) {
+    1030             :                 std::cout << formatter();
+    1031             :         }
+    1032             : 
+    1033             :         // Called when a `$check` cell is triggered.
+    1034             :         virtual void on_check(flavor type, bool condition, const lazy_fmt &formatter, const metadata_map &attributes) {
+    1035             :                 if (type == flavor::ASSERT || type == flavor::ASSUME) {
+    1036             :                         if (!condition)
+    1037             :                                 std::cerr << formatter();
+    1038             :                         CXXRTL_ASSERT(condition && "Check failed");
+    1039             :                 }
+    1040             :         }
+    1041             : };
+    1042             : 
+    1043             : // An object that can be passed to a `commit()` method in order to produce a replay log of every state change in
+    1044             : // the simulation. Unlike `performer`, `observer` does not use virtual calls as their overhead is unacceptable, and
+    1045             : // a comparatively heavyweight template-based solution is justified.
+    1046             : struct observer {
+    1047             :         // Called when the `commit()` method for a wire is about to update the `chunks` chunks at `base` with `chunks` chunks
+    1048             :         // at `value` that have a different bit pattern. It is guaranteed that `chunks` is equal to the wire chunk count and
+    1049             :         // `base` points to the first chunk.
+    1050             :         void on_update(size_t chunks, const chunk_t *base, const chunk_t *value) {}
+    1051             : 
+    1052             :         // Called when the `commit()` method for a memory is about to update the `chunks` chunks at `&base[chunks * index]`
+    1053             :         // with `chunks` chunks at `value` that have a different bit pattern. It is guaranteed that `chunks` is equal to
+    1054             :         // the memory element chunk count and `base` points to the first chunk of the first element of the memory.
+    1055             :         void on_update(size_t chunks, const chunk_t *base, const chunk_t *value, size_t index) {}
+    1056             : };
+    1057             : 
+    1058             : // Must be kept in sync with `struct FmtPart` in kernel/fmt.h!
+    1059             : // Default member initializers would make this a non-aggregate-type in C++11, so they are commented out.
+    1060             : struct fmt_part {
+    1061             :         enum {
+    1062             :                 LITERAL   = 0,
+    1063             :                 INTEGER   = 1,
+    1064             :                 STRING    = 2,
+    1065             :                 UNICHAR   = 3,
+    1066             :                 VLOG_TIME = 4,
+    1067             :         } type;
+    1068             : 
+    1069             :         // LITERAL type
+    1070             :         std::string str;
+    1071             : 
+    1072             :         // INTEGER/STRING/UNICHAR types
+    1073             :         // + value<Bits> val;
+    1074             : 
+    1075             :         // INTEGER/STRING/VLOG_TIME types
+    1076             :         enum {
+    1077             :                 RIGHT   = 0,
+    1078             :                 LEFT    = 1,
+    1079             :                 NUMERIC = 2,
+    1080             :         } justify; // = RIGHT;
+    1081             :         char padding; // = '\0';
+    1082             :         size_t width; // = 0;
+    1083             : 
+    1084             :         // INTEGER type
+    1085             :         unsigned base; // = 10;
+    1086             :         bool signed_; // = false;
+    1087             :         enum {
+    1088             :                 MINUS           = 0,
+    1089             :                 PLUS_MINUS      = 1,
+    1090             :                 SPACE_MINUS     = 2,
+    1091             :         } sign; // = MINUS;
+    1092             :         bool hex_upper; // = false;
+    1093             :         bool show_base; // = false;
+    1094             :         bool group; // = false;
+    1095             : 
+    1096             :         // VLOG_TIME type
+    1097             :         bool realtime; // = false;
+    1098             :         // + int64_t itime;
+    1099             :         // + double ftime;
+    1100             : 
+    1101             :         // Format the part as a string.
+    1102             :         //
+    1103             :         // The values of `vlog_time` and `vlog_realtime` are used for Verilog `$time` and `$realtime`, correspondingly.
+    1104             :         template<size_t Bits>
+    1105             :         std::string render(value<Bits> val, performer *performer = nullptr)
+    1106             :         {
+    1107             :                 // We might want to replace some of these bit() calls with direct
+    1108             :                 // chunk access if it turns out to be slow enough to matter.
+    1109             :                 std::string buf;
+    1110             :                 std::string prefix;
+    1111             :                 switch (type) {
+    1112             :                         case LITERAL:
+    1113             :                                 return str;
+    1114             : 
+    1115             :                         case STRING: {
+    1116             :                                 buf.reserve(Bits/8);
+    1117             :                                 for (int i = 0; i < Bits; i += 8) {
+    1118             :                                         char ch = 0;
+    1119             :                                         for (int j = 0; j < 8 && i + j < int(Bits); j++)
+    1120             :                                                 if (val.bit(i + j))
+    1121             :                                                         ch |= 1 << j;
+    1122             :                                         if (ch != 0)
+    1123             :                                                 buf.append({ch});
+    1124             :                                 }
+    1125             :                                 std::reverse(buf.begin(), buf.end());
+    1126             :                                 break;
+    1127             :                         }
+    1128             : 
+    1129             :                         case UNICHAR: {
+    1130             :                                 uint32_t codepoint = val.template get<uint32_t>();
+    1131             :                                 if (codepoint >= 0x10000)
+    1132             :                                         buf += (char)(0xf0 |  (codepoint >> 18));
+    1133             :                                 else if (codepoint >= 0x800)
+    1134             :                                         buf += (char)(0xe0 |  (codepoint >> 12));
+    1135             :                                 else if (codepoint >= 0x80)
+    1136             :                                         buf += (char)(0xc0 |  (codepoint >>  6));
+    1137             :                                 else
+    1138             :                                         buf += (char)codepoint;
+    1139             :                                 if (codepoint >= 0x10000)
+    1140             :                                         buf += (char)(0x80 | ((codepoint >> 12) & 0x3f));
+    1141             :                                 if (codepoint >= 0x800)
+    1142             :                                         buf += (char)(0x80 | ((codepoint >>  6) & 0x3f));
+    1143             :                                 if (codepoint >= 0x80)
+    1144             :                                         buf += (char)(0x80 | ((codepoint >>  0) & 0x3f));
+    1145             :                                 break;
+    1146             :                         }
+    1147             : 
+    1148             :                         case INTEGER: {
+    1149             :                                 bool negative = signed_ && val.is_neg();
+    1150             :                                 if (negative) {
+    1151             :                                         prefix = "-";
+    1152             :                                         val = val.neg();
+    1153             :                                 } else {
+    1154             :                                         switch (sign) {
+    1155             :                                                 case MINUS:       break;
+    1156             :                                                 case PLUS_MINUS:  prefix = "+"; break;
+    1157             :                                                 case SPACE_MINUS: prefix = " "; break;
+    1158             :                                         }
+    1159             :                                 }
+    1160             : 
+    1161             :                                 size_t val_width = Bits;
+    1162             :                                 if (base != 10) {
+    1163             :                                         val_width = 1;
+    1164             :                                         for (size_t index = 0; index < Bits; index++)
+    1165             :                                                 if (val.bit(index))
+    1166             :                                                         val_width = index + 1;
+    1167             :                                 }
+    1168             : 
+    1169             :                                 if (base == 2) {
+    1170             :                                         if (show_base)
+    1171             :                                                 prefix += "0b";
+    1172             :                                         for (size_t index = 0; index < val_width; index++) {
+    1173             :                                                 if (group && index > 0 && index % 4 == 0)
+    1174             :                                                         buf += '_';
+    1175             :                                                 buf += (val.bit(index) ? '1' : '0');
+    1176             :                                         }
+    1177             :                                 } else if (base == 8 || base == 16) {
+    1178             :                                         if (show_base)
+    1179             :                                                 prefix += (base == 16) ? (hex_upper ? "0X" : "0x") : "0o";
+    1180             :                                         size_t step = (base == 16) ? 4 : 3;
+    1181             :                                         for (size_t index = 0; index < val_width; index += step) {
+    1182             :                                                 if (group && index > 0 && index % (4 * step) == 0)
+    1183             :                                                         buf += '_';
+    1184             :                                                 uint8_t value = val.bit(index) | (val.bit(index + 1) << 1) | (val.bit(index + 2) << 2);
+    1185             :                                                 if (step == 4)
+    1186             :                                                         value |= val.bit(index + 3) << 3;
+    1187             :                                                 buf += (hex_upper ? "0123456789ABCDEF" : "0123456789abcdef")[value];
+    1188             :                                         }
+    1189             :                                 } else if (base == 10) {
+    1190             :                                         if (show_base)
+    1191             :                                                 prefix += "0d";
+    1192             :                                         if (val.is_zero())
+    1193             :                                                 buf += '0';
+    1194             :                                         value<(Bits > 4 ? Bits : 4)> xval = val.template zext<(Bits > 4 ? Bits : 4)>();
+    1195             :                                         size_t index = 0;
+    1196             :                                         while (!xval.is_zero()) {
+    1197             :                                                 if (group && index > 0 && index % 3 == 0)
+    1198             :                                                         buf += '_';
+    1199             :                                                 value<(Bits > 4 ? Bits : 4)> quotient, remainder;
+    1200             :                                                 if (Bits >= 4)
+    1201             :                                                         std::tie(quotient, remainder) = xval.udivmod(value<(Bits > 4 ? Bits : 4)>{10u});
+    1202             :                                                 else
+    1203             :                                                         std::tie(quotient, remainder) = std::make_pair(value<(Bits > 4 ? Bits : 4)>{0u}, xval);
+    1204             :                                                 buf += '0' + remainder.template trunc<4>().template get<uint8_t>();
+    1205             :                                                 xval = quotient;
+    1206             :                                                 index++;
+    1207             :                                         }
+    1208             :                                 } else assert(false && "Unsupported base for fmt_part");
+    1209             :                                 if (justify == NUMERIC && group && padding == '0') {
+    1210             :                                         int group_size = base == 10 ? 3 : 4;
+    1211             :                                         while (prefix.size() + buf.size() < width) {
+    1212             :                                                 if (buf.size() % (group_size + 1) == group_size)
+    1213             :                                                         buf += '_';
+    1214             :                                                 buf += '0';
+    1215             :                                         }
+    1216             :                                 }
+    1217             :                                 std::reverse(buf.begin(), buf.end());
+    1218             :                                 break;
+    1219             :                         }
+    1220             : 
+    1221             :                         case VLOG_TIME: {
+    1222             :                                 if (performer) {
+    1223             :                                         buf = realtime ? std::to_string(performer->vlog_realtime()) : std::to_string(performer->vlog_time());
+    1224             :                                 } else {
+    1225             :                                         buf = realtime ? std::to_string(0.0) : std::to_string(0);
+    1226             :                                 }
+    1227             :                                 break;
+    1228             :                         }
+    1229             :                 }
+    1230             : 
+    1231             :                 std::string str;
+    1232             :                 assert(width == 0 || padding != '\0');
+    1233             :                 if (prefix.size() + buf.size() < width) {
+    1234             :                         size_t pad_width = width - prefix.size() - buf.size();
+    1235             :                         switch (justify) {
+    1236             :                                 case LEFT:
+    1237             :                                         str += prefix;
+    1238             :                                         str += buf;
+    1239             :                                         str += std::string(pad_width, padding);
+    1240             :                                         break;
+    1241             :                                 case RIGHT:
+    1242             :                                         str += std::string(pad_width, padding);
+    1243             :                                         str += prefix;
+    1244             :                                         str += buf;
+    1245             :                                         break;
+    1246             :                                 case NUMERIC:
+    1247             :                                         str += prefix;
+    1248             :                                         str += std::string(pad_width, padding);
+    1249             :                                         str += buf;
+    1250             :                                         break;
+    1251             :                                 }
+    1252             :                 } else {
+    1253             :                         str += prefix;
+    1254             :                         str += buf;
+    1255             :                 }
+    1256             :                 return str;
+    1257             :         }
+    1258             : };
+    1259             : 
+    1260             : // Tag class to disambiguate values/wires and their aliases.
+    1261             : struct debug_alias {};
+    1262             : 
+    1263             : // Tag declaration to disambiguate values and debug outlines.
+    1264             : using debug_outline = ::_cxxrtl_outline;
+    1265             : 
+    1266             : // This structure is intended for consumption via foreign function interfaces, like Python's ctypes.
+    1267             : // Because of this it uses a C-style layout that is easy to parse rather than more idiomatic C++.
+    1268             : //
+    1269             : // To avoid violating strict aliasing rules, this structure has to be a subclass of the one used
+    1270             : // in the C API, or it would not be possible to cast between the pointers to these.
+    1271             : //
+    1272             : // The `attrs` member cannot be owned by this structure because a `cxxrtl_object` can be created
+    1273             : // from external C code.
+    1274             : struct debug_item : ::cxxrtl_object {
+    1275             :         // Object types.
+    1276             :         enum : uint32_t {
+    1277             :                 VALUE   = CXXRTL_VALUE,
+    1278             :                 WIRE    = CXXRTL_WIRE,
+    1279             :                 MEMORY  = CXXRTL_MEMORY,
+    1280             :                 ALIAS   = CXXRTL_ALIAS,
+    1281             :                 OUTLINE = CXXRTL_OUTLINE,
+    1282             :         };
+    1283             : 
+    1284             :         // Object flags.
+    1285             :         enum : uint32_t {
+    1286             :                 INPUT  = CXXRTL_INPUT,
+    1287             :                 OUTPUT = CXXRTL_OUTPUT,
+    1288             :                 INOUT  = CXXRTL_INOUT,
+    1289             :                 DRIVEN_SYNC = CXXRTL_DRIVEN_SYNC,
+    1290             :                 DRIVEN_COMB = CXXRTL_DRIVEN_COMB,
+    1291             :                 UNDRIVEN    = CXXRTL_UNDRIVEN,
+    1292             :         };
+    1293             : 
+    1294             :         debug_item(const ::cxxrtl_object &object) : cxxrtl_object(object) {}
+    1295             : 
+    1296             :         template<size_t Bits>
+    1297           9 :         debug_item(value<Bits> &item, size_t lsb_offset = 0, uint32_t flags_ = 0) {
+    1298             :                 static_assert(Bits == 0 || sizeof(item) == value<Bits>::chunks * sizeof(chunk_t),
+    1299             :                               "value<Bits> is not compatible with C layout");
+    1300           9 :                 type    = VALUE;
+    1301           9 :                 flags   = flags_;
+    1302           9 :                 width   = Bits;
+    1303           9 :                 lsb_at  = lsb_offset;
+    1304           9 :                 depth   = 1;
+    1305           9 :                 zero_at = 0;
+    1306           9 :                 curr    = item.data;
+    1307           9 :                 next    = item.data;
+    1308           9 :                 outline = nullptr;
+    1309           9 :                 attrs   = nullptr;
+    1310             :         }
+    1311             : 
+    1312             :         template<size_t Bits>
+    1313             :         debug_item(const value<Bits> &item, size_t lsb_offset = 0) {
+    1314             :                 static_assert(Bits == 0 || sizeof(item) == value<Bits>::chunks * sizeof(chunk_t),
+    1315             :                               "value<Bits> is not compatible with C layout");
+    1316             :                 type    = VALUE;
+    1317             :                 flags   = DRIVEN_COMB;
+    1318             :                 width   = Bits;
+    1319             :                 lsb_at  = lsb_offset;
+    1320             :                 depth   = 1;
+    1321             :                 zero_at = 0;
+    1322             :                 curr    = const_cast<chunk_t*>(item.data);
+    1323             :                 next    = nullptr;
+    1324             :                 outline = nullptr;
+    1325             :                 attrs   = nullptr;
+    1326             :         }
+    1327             : 
+    1328             :         template<size_t Bits>
+    1329             :         debug_item(wire<Bits> &item, size_t lsb_offset = 0, uint32_t flags_ = 0) {
+    1330             :                 static_assert(Bits == 0 ||
+    1331             :                               (sizeof(item.curr) == value<Bits>::chunks * sizeof(chunk_t) &&
+    1332             :                                sizeof(item.next) == value<Bits>::chunks * sizeof(chunk_t)),
+    1333             :                               "wire<Bits> is not compatible with C layout");
+    1334             :                 type    = WIRE;
+    1335             :                 flags   = flags_;
+    1336             :                 width   = Bits;
+    1337             :                 lsb_at  = lsb_offset;
+    1338             :                 depth   = 1;
+    1339             :                 zero_at = 0;
+    1340             :                 curr    = item.curr.data;
+    1341             :                 next    = item.next.data;
+    1342             :                 outline = nullptr;
+    1343             :                 attrs   = nullptr;
+    1344             :         }
+    1345             : 
+    1346             :         template<size_t Width>
+    1347             :         debug_item(memory<Width> &item, size_t zero_offset = 0) {
+    1348             :                 static_assert(Width == 0 || sizeof(item.data[0]) == value<Width>::chunks * sizeof(chunk_t),
+    1349             :                               "memory<Width> is not compatible with C layout");
+    1350             :                 type    = MEMORY;
+    1351             :                 flags   = 0;
+    1352             :                 width   = Width;
+    1353             :                 lsb_at  = 0;
+    1354             :                 depth   = item.depth;
+    1355             :                 zero_at = zero_offset;
+    1356             :                 curr    = item.data ? item.data[0].data : nullptr;
+    1357             :                 next    = nullptr;
+    1358             :                 outline = nullptr;
+    1359             :                 attrs   = nullptr;
+    1360             :         }
+    1361             : 
+    1362             :         template<size_t Bits>
+    1363             :         debug_item(debug_alias, const value<Bits> &item, size_t lsb_offset = 0) {
+    1364             :                 static_assert(Bits == 0 || sizeof(item) == value<Bits>::chunks * sizeof(chunk_t),
+    1365             :                               "value<Bits> is not compatible with C layout");
+    1366             :                 type    = ALIAS;
+    1367             :                 flags   = DRIVEN_COMB;
+    1368             :                 width   = Bits;
+    1369             :                 lsb_at  = lsb_offset;
+    1370             :                 depth   = 1;
+    1371             :                 zero_at = 0;
+    1372             :                 curr    = const_cast<chunk_t*>(item.data);
+    1373             :                 next    = nullptr;
+    1374             :                 outline = nullptr;
+    1375             :                 attrs   = nullptr;
+    1376             :         }
+    1377             : 
+    1378             :         template<size_t Bits>
+    1379             :         debug_item(debug_alias, const wire<Bits> &item, size_t lsb_offset = 0) {
+    1380             :                 static_assert(Bits == 0 ||
+    1381             :                               (sizeof(item.curr) == value<Bits>::chunks * sizeof(chunk_t) &&
+    1382             :                                sizeof(item.next) == value<Bits>::chunks * sizeof(chunk_t)),
+    1383             :                               "wire<Bits> is not compatible with C layout");
+    1384             :                 type    = ALIAS;
+    1385             :                 flags   = DRIVEN_COMB;
+    1386             :                 width   = Bits;
+    1387             :                 lsb_at  = lsb_offset;
+    1388             :                 depth   = 1;
+    1389             :                 zero_at = 0;
+    1390             :                 curr    = const_cast<chunk_t*>(item.curr.data);
+    1391             :                 next    = nullptr;
+    1392             :                 outline = nullptr;
+    1393             :                 attrs   = nullptr;
+    1394             :         }
+    1395             : 
+    1396             :         template<size_t Bits>
+    1397             :         debug_item(debug_outline &group, const value<Bits> &item, size_t lsb_offset = 0) {
+    1398             :                 static_assert(Bits == 0 || sizeof(item) == value<Bits>::chunks * sizeof(chunk_t),
+    1399             :                               "value<Bits> is not compatible with C layout");
+    1400             :                 type    = OUTLINE;
+    1401             :                 flags   = DRIVEN_COMB;
+    1402             :                 width   = Bits;
+    1403             :                 lsb_at  = lsb_offset;
+    1404             :                 depth   = 1;
+    1405             :                 zero_at = 0;
+    1406             :                 curr    = const_cast<chunk_t*>(item.data);
+    1407             :                 next    = nullptr;
+    1408             :                 outline = &group;
+    1409             :                 attrs   = nullptr;
+    1410             :         }
+    1411             : 
+    1412             :         template<size_t Bits, class IntegerT>
+    1413             :         IntegerT get() const {
+    1414             :                 assert(width == Bits && depth == 1);
+    1415             :                 value<Bits> item;
+    1416             :                 std::copy(curr, curr + value<Bits>::chunks, item.data);
+    1417             :                 return item.template get<IntegerT>();
+    1418             :         }
+    1419             : 
+    1420             :         template<size_t Bits, class IntegerT>
+    1421             :         void set(IntegerT other) const {
+    1422             :                 assert(width == Bits && depth == 1);
+    1423             :                 value<Bits> item;
+    1424             :                 item.template set<IntegerT>(other);
+    1425             :                 std::copy(item.data, item.data + value<Bits>::chunks, next);
+    1426             :         }
+    1427             : };
+    1428             : static_assert(std::is_standard_layout<debug_item>::value, "debug_item is not compatible with C layout");
+    1429             : 
+    1430             : } // namespace cxxrtl
+    1431             : 
+    1432           9 : typedef struct _cxxrtl_attr_set {
+    1433             :         cxxrtl::metadata_map map;
+    1434             : } *cxxrtl_attr_set;
+    1435             : 
+    1436             : namespace cxxrtl {
+    1437             : 
+    1438             : // Representation of an attribute set in the C++ interface.
+    1439             : using debug_attrs = ::_cxxrtl_attr_set;
+    1440             : 
+    1441           3 : struct debug_items {
+    1442             :         // Debug items may be composed of multiple parts, but the attributes are shared between all of them.
+    1443             :         // There are additional invariants, not all of which are not checked by this code:
+    1444             :         // - Memories and non-memories cannot be mixed together.
+    1445             :         // - Bit indices (considering `lsb_at` and `width`) must not overlap.
+    1446             :         // - Row indices (considering `depth` and `zero_at`) must be the same.
+    1447             :         // - The `INPUT` and `OUTPUT` flags must be the same for all parts.
+    1448             :         // Other than that, the parts can be quite different, e.g. it is OK to mix a value, a wire, an alias,
+    1449             :         // and an outline, in the debug information for a single name in four parts.
+    1450             :         std::map<std::string, std::vector<debug_item>> table;
+    1451             :         std::map<std::string, std::unique_ptr<debug_attrs>> attrs_table;
+    1452             : 
+    1453           9 :         void add(const std::string &path, debug_item &&item, metadata_map &&item_attrs = {}) {
+    1454           9 :                 assert((path.empty() || path[path.size() - 1] != ' ') && path.find("  ") == std::string::npos);
+    1455           9 :                 std::unique_ptr<debug_attrs> &attrs = attrs_table[path];
+    1456           9 :                 if (attrs.get() == nullptr)
+    1457           9 :                         attrs = std::unique_ptr<debug_attrs>(new debug_attrs);
+    1458          18 :                 for (auto attr : item_attrs)
+    1459          18 :                         attrs->map.insert(attr);
+    1460           9 :                 item.attrs = attrs.get();
+    1461           9 :                 std::vector<debug_item> &parts = table[path];
+    1462           9 :                 parts.emplace_back(item);
+    1463           9 :                 std::sort(parts.begin(), parts.end(),
+    1464           0 :                         [](const debug_item &a, const debug_item &b) {
+    1465           0 :                                 return a.lsb_at < b.lsb_at;
+    1466             :                         });
+    1467           9 :         }
+    1468             : 
+    1469             :         // This overload exists to reduce excessive stack slot allocation in `CXXRTL_EXTREMELY_COLD void debug_info()`.
+    1470             :         template<class... T>
+    1471           9 :         void add(const std::string &base_path, const char *path, const char *serialized_item_attrs, T&&... args) {
+    1472          18 :                 add(base_path + path, debug_item(std::forward<T>(args)...), metadata::deserialize(serialized_item_attrs));
+    1473           9 :         }
+    1474             : 
+    1475             :         size_t count(const std::string &path) const {
+    1476             :                 if (table.count(path) == 0)
+    1477             :                         return 0;
+    1478             :                 return table.at(path).size();
+    1479             :         }
+    1480             : 
+    1481             :         const std::vector<debug_item> &at(const std::string &path) const {
+    1482             :                 return table.at(path);
+    1483             :         }
+    1484             : 
+    1485             :         // Like `at()`, but operates only on single-part debug items.
+    1486             :         const debug_item &operator [](const std::string &path) const {
+    1487             :                 const std::vector<debug_item> &parts = table.at(path);
+    1488             :                 assert(parts.size() == 1);
+    1489             :                 return parts.at(0);
+    1490             :         }
+    1491             : 
+    1492             :         bool is_memory(const std::string &path) const {
+    1493             :                 return at(path).at(0).type == debug_item::MEMORY;
+    1494             :         }
+    1495             : 
+    1496             :         const metadata_map &attrs(const std::string &path) const {
+    1497             :                 return attrs_table.at(path)->map;
+    1498             :         }
+    1499             : };
+    1500             : 
+    1501             : // Only `module` scopes are defined. The type is implicit, since Yosys does not currently support
+    1502             : // any other scope types.
+    1503           3 : struct debug_scope {
+    1504             :         std::string module_name;
+    1505             :         std::unique_ptr<debug_attrs> module_attrs;
+    1506             :         std::unique_ptr<debug_attrs> cell_attrs;
+    1507             : };
+    1508             : 
+    1509             : struct debug_scopes {
+    1510             :         std::map<std::string, debug_scope> table;
+    1511             : 
+    1512           0 :         void add(const std::string &path, const std::string &module_name, metadata_map &&module_attrs, metadata_map &&cell_attrs) {
+    1513           0 :                 assert((path.empty() || path[path.size() - 1] != ' ') && path.find("  ") == std::string::npos);
+    1514           0 :                 assert(table.count(path) == 0);
+    1515           0 :                 debug_scope &scope = table[path];
+    1516           0 :                 scope.module_name = module_name;
+    1517           0 :                 scope.module_attrs = std::unique_ptr<debug_attrs>(new debug_attrs { module_attrs });
+    1518           0 :                 scope.cell_attrs = std::unique_ptr<debug_attrs>(new debug_attrs { cell_attrs });
+    1519           0 :         }
+    1520             : 
+    1521             :         // This overload exists to reduce excessive stack slot allocation in `CXXRTL_EXTREMELY_COLD void debug_info()`.
+    1522             :         void add(const std::string &base_path, const char *path, const char *module_name, const char *serialized_module_attrs, const char *serialized_cell_attrs) {
+    1523             :                 add(base_path + path, module_name, metadata::deserialize(serialized_module_attrs), metadata::deserialize(serialized_cell_attrs));
+    1524             :         }
+    1525             : 
+    1526             :         size_t contains(const std::string &path) const {
+    1527             :                 return table.count(path);
+    1528             :         }
+    1529             : 
+    1530             :         const debug_scope &operator [](const std::string &path) const {
+    1531             :                 return table.at(path);
+    1532             :         }
+    1533             : };
+    1534             : 
+    1535             : // Tag class to disambiguate the default constructor used by the toplevel module that calls `reset()`,
+    1536             : // and the constructor of interior modules that should not call it.
+    1537             : struct interior {};
+    1538             : 
+    1539             : // The core API of the `module` class consists of only four virtual methods: `reset()`, `eval()`,
+    1540             : // `commit`, and `debug_info()`. (The virtual destructor is made necessary by C++.) Every other method
+    1541             : // is a convenience method, and exists solely to simplify some common pattern for C++ API consumers.
+    1542             : // No behavior may be added to such convenience methods that other parts of CXXRTL can rely on, since
+    1543             : // there is no guarantee they will be called (and, for example, other CXXRTL libraries will often call
+    1544             : // the `eval()` and `commit()` directly instead, as well as being exposed in the C API).
+    1545             : struct module {
+    1546           3 :         module() {}
+    1547           3 :         virtual ~module() {}
+    1548             : 
+    1549             :         // Modules with black boxes cannot be copied. Although not all designs include black boxes,
+    1550             :         // delete the copy constructor and copy assignment operator to make sure that any downstream
+    1551             :         // code that manipulates modules doesn't accidentally depend on their availability.
+    1552             :         module(const module &) = delete;
+    1553             :         module &operator=(const module &) = delete;
+    1554             : 
+    1555             :         module(module &&) = default;
+    1556             :         module &operator=(module &&) = default;
+    1557             : 
+    1558             :         virtual void reset() = 0;
+    1559             : 
+    1560             :         // The `eval()` callback object, `performer`, is included in the virtual call signature since
+    1561             :         // the generated code has broadly identical performance properties.
+    1562             :         virtual bool eval(performer *performer = nullptr) = 0;
+    1563             : 
+    1564             :         // The `commit()` callback object, `observer`, is not included in the virtual call signature since
+    1565             :         // the generated code is severely pessimized by it. To observe commit events, the non-virtual
+    1566             :         // `commit(observer *)` overload must be called directly on a `module` subclass.
+    1567             :         virtual bool commit() = 0;
+    1568             : 
+    1569          33 :         size_t step(performer *performer = nullptr) {
+    1570          33 :                 size_t deltas = 0;
+    1571          33 :                 bool converged = false;
+    1572          33 :                 do {
+    1573          33 :                         converged = eval(performer);
+    1574          33 :                         deltas++;
+    1575          66 :                 } while (commit() && !converged);
+    1576          33 :                 return deltas;
+    1577             :         }
+    1578             : 
+    1579             :         virtual void debug_info(debug_items *items, debug_scopes *scopes, std::string path, metadata_map &&cell_attrs = {}) {
+    1580             :                 (void)items, (void)scopes, (void)path, (void)cell_attrs;
+    1581             :         }
+    1582             : 
+    1583             :         // Compatibility method.
+    1584             : #if __has_attribute(deprecated)
+    1585             :         __attribute__((deprecated("Use `debug_info(path, &items, /*scopes=*/nullptr);` instead. (`path` could be \"top \".)")))
+    1586             : #endif
+    1587             :         void debug_info(debug_items &items, std::string path) {
+    1588             :                 debug_info(&items, /*scopes=*/nullptr, path);
+    1589             :         }
+    1590             : };
+    1591             : 
+    1592             : } // namespace cxxrtl
+    1593             : 
+    1594             : // Internal structures used to communicate with the implementation of the C interface.
+    1595             : 
+    1596             : typedef struct _cxxrtl_toplevel {
+    1597             :         std::unique_ptr<cxxrtl::module> module;
+    1598             : } *cxxrtl_toplevel;
+    1599             : 
+    1600             : typedef struct _cxxrtl_outline {
+    1601             :         std::function<void()> eval;
+    1602             : } *cxxrtl_outline;
+    1603             : 
+    1604             : // Definitions of internal Yosys cells. Other than the functions in this namespace, CXXRTL is fully generic
+    1605             : // and indepenent of Yosys implementation details.
+    1606             : //
+    1607             : // The `write_cxxrtl` pass translates internal cells (cells with names that start with `$`) to calls of these
+    1608             : // functions. All of Yosys arithmetic and logical cells perform sign or zero extension on their operands,
+    1609             : // whereas basic operations on arbitrary width values require operands to be of the same width. These functions
+    1610             : // bridge the gap by performing the necessary casts. They are named similar to `cell_A[B]`, where A and B are `u`
+    1611             : // if the corresponding operand is unsigned, and `s` if it is signed.
+    1612             : namespace cxxrtl_yosys {
+    1613             : 
+    1614             : using namespace cxxrtl;
+    1615             : 
+    1616             : // std::max isn't constexpr until C++14 for no particular reason (it's an oversight), so we define our own.
+    1617             : template<class T>
+    1618             : CXXRTL_ALWAYS_INLINE
+    1619             : constexpr T max(const T &a, const T &b) {
+    1620             :         return a > b ? a : b;
+    1621             : }
+    1622             : 
+    1623             : // Logic operations
+    1624             : template<size_t BitsY, size_t BitsA>
+    1625             : CXXRTL_ALWAYS_INLINE
+    1626             : value<BitsY> logic_not(const value<BitsA> &a) {
+    1627             :         return value<BitsY> { a ? 0u : 1u };
+    1628             : }
+    1629             : 
+    1630             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1631             : CXXRTL_ALWAYS_INLINE
+    1632             : value<BitsY> logic_and(const value<BitsA> &a, const value<BitsB> &b) {
+    1633             :         return value<BitsY> { (bool(a) && bool(b)) ? 1u : 0u };
+    1634             : }
+    1635             : 
+    1636             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1637             : CXXRTL_ALWAYS_INLINE
+    1638             : value<BitsY> logic_or(const value<BitsA> &a, const value<BitsB> &b) {
+    1639             :         return value<BitsY> { (bool(a) || bool(b)) ? 1u : 0u };
+    1640             : }
+    1641             : 
+    1642             : // Reduction operations
+    1643             : template<size_t BitsY, size_t BitsA>
+    1644             : CXXRTL_ALWAYS_INLINE
+    1645             : value<BitsY> reduce_and(const value<BitsA> &a) {
+    1646             :         return value<BitsY> { a.bit_not().is_zero() ? 1u : 0u };
+    1647             : }
+    1648             : 
+    1649             : template<size_t BitsY, size_t BitsA>
+    1650             : CXXRTL_ALWAYS_INLINE
+    1651             : value<BitsY> reduce_or(const value<BitsA> &a) {
+    1652             :         return value<BitsY> { a ? 1u : 0u };
+    1653             : }
+    1654             : 
+    1655             : template<size_t BitsY, size_t BitsA>
+    1656             : CXXRTL_ALWAYS_INLINE
+    1657             : value<BitsY> reduce_xor(const value<BitsA> &a) {
+    1658             :         return value<BitsY> { (a.ctpop() % 2) ? 1u : 0u };
+    1659             : }
+    1660             : 
+    1661             : template<size_t BitsY, size_t BitsA>
+    1662             : CXXRTL_ALWAYS_INLINE
+    1663             : value<BitsY> reduce_xnor(const value<BitsA> &a) {
+    1664             :         return value<BitsY> { (a.ctpop() % 2) ? 0u : 1u };
+    1665             : }
+    1666             : 
+    1667             : template<size_t BitsY, size_t BitsA>
+    1668             : CXXRTL_ALWAYS_INLINE
+    1669             : value<BitsY> reduce_bool(const value<BitsA> &a) {
+    1670             :         return value<BitsY> { a ? 1u : 0u };
+    1671             : }
+    1672             : 
+    1673             : // Bitwise operations
+    1674             : template<size_t BitsY, size_t BitsA>
+    1675             : CXXRTL_ALWAYS_INLINE
+    1676             : value<BitsY> not_u(const value<BitsA> &a) {
+    1677             :         return a.template zcast<BitsY>().bit_not();
+    1678             : }
+    1679             : 
+    1680             : template<size_t BitsY, size_t BitsA>
+    1681             : CXXRTL_ALWAYS_INLINE
+    1682             : value<BitsY> not_s(const value<BitsA> &a) {
+    1683             :         return a.template scast<BitsY>().bit_not();
+    1684             : }
+    1685             : 
+    1686             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1687             : CXXRTL_ALWAYS_INLINE
+    1688             : value<BitsY> and_uu(const value<BitsA> &a, const value<BitsB> &b) {
+    1689             :         return a.template zcast<BitsY>().bit_and(b.template zcast<BitsY>());
+    1690             : }
+    1691             : 
+    1692             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1693             : CXXRTL_ALWAYS_INLINE
+    1694             : value<BitsY> and_ss(const value<BitsA> &a, const value<BitsB> &b) {
+    1695             :         return a.template scast<BitsY>().bit_and(b.template scast<BitsY>());
+    1696             : }
+    1697             : 
+    1698             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1699             : CXXRTL_ALWAYS_INLINE
+    1700             : value<BitsY> or_uu(const value<BitsA> &a, const value<BitsB> &b) {
+    1701             :         return a.template zcast<BitsY>().bit_or(b.template zcast<BitsY>());
+    1702             : }
+    1703             : 
+    1704             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1705             : CXXRTL_ALWAYS_INLINE
+    1706             : value<BitsY> or_ss(const value<BitsA> &a, const value<BitsB> &b) {
+    1707             :         return a.template scast<BitsY>().bit_or(b.template scast<BitsY>());
+    1708             : }
+    1709             : 
+    1710             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1711             : CXXRTL_ALWAYS_INLINE
+    1712             : value<BitsY> xor_uu(const value<BitsA> &a, const value<BitsB> &b) {
+    1713             :         return a.template zcast<BitsY>().bit_xor(b.template zcast<BitsY>());
+    1714             : }
+    1715             : 
+    1716             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1717             : CXXRTL_ALWAYS_INLINE
+    1718             : value<BitsY> xor_ss(const value<BitsA> &a, const value<BitsB> &b) {
+    1719             :         return a.template scast<BitsY>().bit_xor(b.template scast<BitsY>());
+    1720             : }
+    1721             : 
+    1722             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1723             : CXXRTL_ALWAYS_INLINE
+    1724             : value<BitsY> xnor_uu(const value<BitsA> &a, const value<BitsB> &b) {
+    1725             :         return a.template zcast<BitsY>().bit_xor(b.template zcast<BitsY>()).bit_not();
+    1726             : }
+    1727             : 
+    1728             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1729             : CXXRTL_ALWAYS_INLINE
+    1730             : value<BitsY> xnor_ss(const value<BitsA> &a, const value<BitsB> &b) {
+    1731             :         return a.template scast<BitsY>().bit_xor(b.template scast<BitsY>()).bit_not();
+    1732             : }
+    1733             : 
+    1734             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1735             : CXXRTL_ALWAYS_INLINE
+    1736             : value<BitsY> shl_uu(const value<BitsA> &a, const value<BitsB> &b) {
+    1737             :         return a.template zcast<BitsY>().shl(b);
+    1738             : }
+    1739             : 
+    1740             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1741             : CXXRTL_ALWAYS_INLINE
+    1742             : value<BitsY> shl_su(const value<BitsA> &a, const value<BitsB> &b) {
+    1743             :         return a.template scast<BitsY>().shl(b);
+    1744             : }
+    1745             : 
+    1746             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1747             : CXXRTL_ALWAYS_INLINE
+    1748             : value<BitsY> sshl_uu(const value<BitsA> &a, const value<BitsB> &b) {
+    1749             :         return a.template zcast<BitsY>().shl(b);
+    1750             : }
+    1751             : 
+    1752             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1753             : CXXRTL_ALWAYS_INLINE
+    1754             : value<BitsY> sshl_su(const value<BitsA> &a, const value<BitsB> &b) {
+    1755             :         return a.template scast<BitsY>().shl(b);
+    1756             : }
+    1757             : 
+    1758             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1759             : CXXRTL_ALWAYS_INLINE
+    1760             : value<BitsY> shr_uu(const value<BitsA> &a, const value<BitsB> &b) {
+    1761             :         return a.shr(b).template zcast<BitsY>();
+    1762             : }
+    1763             : 
+    1764             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1765             : CXXRTL_ALWAYS_INLINE
+    1766             : value<BitsY> shr_su(const value<BitsA> &a, const value<BitsB> &b) {
+    1767             :         return a.shr(b).template scast<BitsY>();
+    1768             : }
+    1769             : 
+    1770             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1771             : CXXRTL_ALWAYS_INLINE
+    1772             : value<BitsY> sshr_uu(const value<BitsA> &a, const value<BitsB> &b) {
+    1773             :         return a.shr(b).template zcast<BitsY>();
+    1774             : }
+    1775             : 
+    1776             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1777             : CXXRTL_ALWAYS_INLINE
+    1778             : value<BitsY> sshr_su(const value<BitsA> &a, const value<BitsB> &b) {
+    1779             :         return a.sshr(b).template scast<BitsY>();
+    1780             : }
+    1781             : 
+    1782             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1783             : CXXRTL_ALWAYS_INLINE
+    1784             : value<BitsY> shift_uu(const value<BitsA> &a, const value<BitsB> &b) {
+    1785             :         return shr_uu<BitsY>(a, b);
+    1786             : }
+    1787             : 
+    1788             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1789             : CXXRTL_ALWAYS_INLINE
+    1790             : value<BitsY> shift_su(const value<BitsA> &a, const value<BitsB> &b) {
+    1791             :         return shr_su<BitsY>(a, b);
+    1792             : }
+    1793             : 
+    1794             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1795             : CXXRTL_ALWAYS_INLINE
+    1796             : value<BitsY> shift_us(const value<BitsA> &a, const value<BitsB> &b) {
+    1797             :         return b.is_neg() ? shl_uu<BitsY>(a, b.template sext<BitsB + 1>().neg()) : shr_uu<BitsY>(a, b);
+    1798             : }
+    1799             : 
+    1800             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1801             : CXXRTL_ALWAYS_INLINE
+    1802             : value<BitsY> shift_ss(const value<BitsA> &a, const value<BitsB> &b) {
+    1803             :         return b.is_neg() ? shl_su<BitsY>(a, b.template sext<BitsB + 1>().neg()) : shr_su<BitsY>(a, b);
+    1804             : }
+    1805             : 
+    1806             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1807             : CXXRTL_ALWAYS_INLINE
+    1808             : value<BitsY> shiftx_uu(const value<BitsA> &a, const value<BitsB> &b) {
+    1809             :         return shift_uu<BitsY>(a, b);
+    1810             : }
+    1811             : 
+    1812             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1813             : CXXRTL_ALWAYS_INLINE
+    1814             : value<BitsY> shiftx_su(const value<BitsA> &a, const value<BitsB> &b) {
+    1815             :         return shift_su<BitsY>(a, b);
+    1816             : }
+    1817             : 
+    1818             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1819             : CXXRTL_ALWAYS_INLINE
+    1820             : value<BitsY> shiftx_us(const value<BitsA> &a, const value<BitsB> &b) {
+    1821             :         return shift_us<BitsY>(a, b);
+    1822             : }
+    1823             : 
+    1824             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1825             : CXXRTL_ALWAYS_INLINE
+    1826             : value<BitsY> shiftx_ss(const value<BitsA> &a, const value<BitsB> &b) {
+    1827             :         return shift_ss<BitsY>(a, b);
+    1828             : }
+    1829             : 
+    1830             : // Comparison operations
+    1831             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1832             : CXXRTL_ALWAYS_INLINE
+    1833             : value<BitsY> eq_uu(const value<BitsA> &a, const value<BitsB> &b) {
+    1834             :         constexpr size_t BitsExt = max(BitsA, BitsB);
+    1835             :         return value<BitsY>{ a.template zext<BitsExt>() == b.template zext<BitsExt>() ? 1u : 0u };
+    1836             : }
+    1837             : 
+    1838             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1839             : CXXRTL_ALWAYS_INLINE
+    1840             : value<BitsY> eq_ss(const value<BitsA> &a, const value<BitsB> &b) {
+    1841             :         constexpr size_t BitsExt = max(BitsA, BitsB);
+    1842             :         return value<BitsY>{ a.template sext<BitsExt>() == b.template sext<BitsExt>() ? 1u : 0u };
+    1843             : }
+    1844             : 
+    1845             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1846             : CXXRTL_ALWAYS_INLINE
+    1847             : value<BitsY> ne_uu(const value<BitsA> &a, const value<BitsB> &b) {
+    1848             :         constexpr size_t BitsExt = max(BitsA, BitsB);
+    1849             :         return value<BitsY>{ a.template zext<BitsExt>() != b.template zext<BitsExt>() ? 1u : 0u };
+    1850             : }
+    1851             : 
+    1852             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1853             : CXXRTL_ALWAYS_INLINE
+    1854             : value<BitsY> ne_ss(const value<BitsA> &a, const value<BitsB> &b) {
+    1855             :         constexpr size_t BitsExt = max(BitsA, BitsB);
+    1856             :         return value<BitsY>{ a.template sext<BitsExt>() != b.template sext<BitsExt>() ? 1u : 0u };
+    1857             : }
+    1858             : 
+    1859             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1860             : CXXRTL_ALWAYS_INLINE
+    1861             : value<BitsY> eqx_uu(const value<BitsA> &a, const value<BitsB> &b) {
+    1862             :         return eq_uu<BitsY>(a, b);
+    1863             : }
+    1864             : 
+    1865             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1866             : CXXRTL_ALWAYS_INLINE
+    1867             : value<BitsY> eqx_ss(const value<BitsA> &a, const value<BitsB> &b) {
+    1868             :         return eq_ss<BitsY>(a, b);
+    1869             : }
+    1870             : 
+    1871             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1872             : CXXRTL_ALWAYS_INLINE
+    1873             : value<BitsY> nex_uu(const value<BitsA> &a, const value<BitsB> &b) {
+    1874             :         return ne_uu<BitsY>(a, b);
+    1875             : }
+    1876             : 
+    1877             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1878             : CXXRTL_ALWAYS_INLINE
+    1879             : value<BitsY> nex_ss(const value<BitsA> &a, const value<BitsB> &b) {
+    1880             :         return ne_ss<BitsY>(a, b);
+    1881             : }
+    1882             : 
+    1883             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1884             : CXXRTL_ALWAYS_INLINE
+    1885             : value<BitsY> gt_uu(const value<BitsA> &a, const value<BitsB> &b) {
+    1886             :         constexpr size_t BitsExt = max(BitsA, BitsB);
+    1887             :         return value<BitsY> { b.template zext<BitsExt>().ucmp(a.template zext<BitsExt>()) ? 1u : 0u };
+    1888             : }
+    1889             : 
+    1890             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1891             : CXXRTL_ALWAYS_INLINE
+    1892             : value<BitsY> gt_ss(const value<BitsA> &a, const value<BitsB> &b) {
+    1893             :         constexpr size_t BitsExt = max(BitsA, BitsB);
+    1894             :         return value<BitsY> { b.template sext<BitsExt>().scmp(a.template sext<BitsExt>()) ? 1u : 0u };
+    1895             : }
+    1896             : 
+    1897             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1898             : CXXRTL_ALWAYS_INLINE
+    1899             : value<BitsY> ge_uu(const value<BitsA> &a, const value<BitsB> &b) {
+    1900             :         constexpr size_t BitsExt = max(BitsA, BitsB);
+    1901             :         return value<BitsY> { !a.template zext<BitsExt>().ucmp(b.template zext<BitsExt>()) ? 1u : 0u };
+    1902             : }
+    1903             : 
+    1904             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1905             : CXXRTL_ALWAYS_INLINE
+    1906             : value<BitsY> ge_ss(const value<BitsA> &a, const value<BitsB> &b) {
+    1907             :         constexpr size_t BitsExt = max(BitsA, BitsB);
+    1908             :         return value<BitsY> { !a.template sext<BitsExt>().scmp(b.template sext<BitsExt>()) ? 1u : 0u };
+    1909             : }
+    1910             : 
+    1911             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1912             : CXXRTL_ALWAYS_INLINE
+    1913             : value<BitsY> lt_uu(const value<BitsA> &a, const value<BitsB> &b) {
+    1914             :         constexpr size_t BitsExt = max(BitsA, BitsB);
+    1915             :         return value<BitsY> { a.template zext<BitsExt>().ucmp(b.template zext<BitsExt>()) ? 1u : 0u };
+    1916             : }
+    1917             : 
+    1918             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1919             : CXXRTL_ALWAYS_INLINE
+    1920             : value<BitsY> lt_ss(const value<BitsA> &a, const value<BitsB> &b) {
+    1921             :         constexpr size_t BitsExt = max(BitsA, BitsB);
+    1922             :         return value<BitsY> { a.template sext<BitsExt>().scmp(b.template sext<BitsExt>()) ? 1u : 0u };
+    1923             : }
+    1924             : 
+    1925             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1926             : CXXRTL_ALWAYS_INLINE
+    1927             : value<BitsY> le_uu(const value<BitsA> &a, const value<BitsB> &b) {
+    1928             :         constexpr size_t BitsExt = max(BitsA, BitsB);
+    1929             :         return value<BitsY> { !b.template zext<BitsExt>().ucmp(a.template zext<BitsExt>()) ? 1u : 0u };
+    1930             : }
+    1931             : 
+    1932             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1933             : CXXRTL_ALWAYS_INLINE
+    1934             : value<BitsY> le_ss(const value<BitsA> &a, const value<BitsB> &b) {
+    1935             :         constexpr size_t BitsExt = max(BitsA, BitsB);
+    1936             :         return value<BitsY> { !b.template sext<BitsExt>().scmp(a.template sext<BitsExt>()) ? 1u : 0u };
+    1937             : }
+    1938             : 
+    1939             : // Arithmetic operations
+    1940             : template<size_t BitsY, size_t BitsA>
+    1941             : CXXRTL_ALWAYS_INLINE
+    1942             : value<BitsY> pos_u(const value<BitsA> &a) {
+    1943             :         return a.template zcast<BitsY>();
+    1944             : }
+    1945             : 
+    1946             : template<size_t BitsY, size_t BitsA>
+    1947             : CXXRTL_ALWAYS_INLINE
+    1948             : value<BitsY> pos_s(const value<BitsA> &a) {
+    1949             :         return a.template scast<BitsY>();
+    1950             : }
+    1951             : 
+    1952             : template<size_t BitsY, size_t BitsA>
+    1953             : CXXRTL_ALWAYS_INLINE
+    1954             : value<BitsY> neg_u(const value<BitsA> &a) {
+    1955             :         return a.template zcast<BitsY>().neg();
+    1956             : }
+    1957             : 
+    1958             : template<size_t BitsY, size_t BitsA>
+    1959             : CXXRTL_ALWAYS_INLINE
+    1960             : value<BitsY> neg_s(const value<BitsA> &a) {
+    1961             :         return a.template scast<BitsY>().neg();
+    1962             : }
+    1963             : 
+    1964             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1965             : CXXRTL_ALWAYS_INLINE
+    1966          33 : value<BitsY> add_uu(const value<BitsA> &a, const value<BitsB> &b) {
+    1967          33 :         return a.template zcast<BitsY>().add(b.template zcast<BitsY>());
+    1968             : }
+    1969             : 
+    1970             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1971             : CXXRTL_ALWAYS_INLINE
+    1972             : value<BitsY> add_ss(const value<BitsA> &a, const value<BitsB> &b) {
+    1973             :         return a.template scast<BitsY>().add(b.template scast<BitsY>());
+    1974             : }
+    1975             : 
+    1976             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1977             : CXXRTL_ALWAYS_INLINE
+    1978             : value<BitsY> sub_uu(const value<BitsA> &a, const value<BitsB> &b) {
+    1979             :         return a.template zcast<BitsY>().sub(b.template zcast<BitsY>());
+    1980             : }
+    1981             : 
+    1982             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1983             : CXXRTL_ALWAYS_INLINE
+    1984             : value<BitsY> sub_ss(const value<BitsA> &a, const value<BitsB> &b) {
+    1985             :         return a.template scast<BitsY>().sub(b.template scast<BitsY>());
+    1986             : }
+    1987             : 
+    1988             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1989             : CXXRTL_ALWAYS_INLINE
+    1990             : value<BitsY> mul_uu(const value<BitsA> &a, const value<BitsB> &b) {
+    1991             :         constexpr size_t BitsM = BitsA >= BitsB ? BitsA : BitsB;
+    1992             :         return a.template zcast<BitsM>().template mul<BitsY>(b.template zcast<BitsM>());
+    1993             : }
+    1994             : 
+    1995             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    1996             : CXXRTL_ALWAYS_INLINE
+    1997             : value<BitsY> mul_ss(const value<BitsA> &a, const value<BitsB> &b) {
+    1998             :         return a.template scast<BitsY>().template mul<BitsY>(b.template scast<BitsY>());
+    1999             : }
+    2000             : 
+    2001             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    2002             : CXXRTL_ALWAYS_INLINE
+    2003             : std::pair<value<BitsY>, value<BitsY>> divmod_uu(const value<BitsA> &a, const value<BitsB> &b) {
+    2004             :         constexpr size_t Bits = max(BitsY, max(BitsA, BitsB));
+    2005             :         value<Bits> quotient;
+    2006             :         value<Bits> remainder;
+    2007             :         value<Bits> dividend = a.template zext<Bits>();
+    2008             :         value<Bits> divisor = b.template zext<Bits>();
+    2009             :         std::tie(quotient, remainder) = dividend.udivmod(divisor);
+    2010             :         return {quotient.template trunc<BitsY>(), remainder.template trunc<BitsY>()};
+    2011             : }
+    2012             : 
+    2013             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    2014             : CXXRTL_ALWAYS_INLINE
+    2015             : std::pair<value<BitsY>, value<BitsY>> divmod_ss(const value<BitsA> &a, const value<BitsB> &b) {
+    2016             :         constexpr size_t Bits = max(BitsY, max(BitsA, BitsB));
+    2017             :         value<Bits> quotient;
+    2018             :         value<Bits> remainder;
+    2019             :         value<Bits> dividend = a.template sext<Bits>();
+    2020             :         value<Bits> divisor = b.template sext<Bits>();
+    2021             :         std::tie(quotient, remainder) = dividend.sdivmod(divisor);
+    2022             :         return {quotient.template trunc<BitsY>(), remainder.template trunc<BitsY>()};
+    2023             : }
+    2024             : 
+    2025             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    2026             : CXXRTL_ALWAYS_INLINE
+    2027             : value<BitsY> div_uu(const value<BitsA> &a, const value<BitsB> &b) {
+    2028             :         return divmod_uu<BitsY>(a, b).first;
+    2029             : }
+    2030             : 
+    2031             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    2032             : CXXRTL_ALWAYS_INLINE
+    2033             : value<BitsY> div_ss(const value<BitsA> &a, const value<BitsB> &b) {
+    2034             :         return divmod_ss<BitsY>(a, b).first;
+    2035             : }
+    2036             : 
+    2037             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    2038             : CXXRTL_ALWAYS_INLINE
+    2039             : value<BitsY> mod_uu(const value<BitsA> &a, const value<BitsB> &b) {
+    2040             :         return divmod_uu<BitsY>(a, b).second;
+    2041             : }
+    2042             : 
+    2043             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    2044             : CXXRTL_ALWAYS_INLINE
+    2045             : value<BitsY> mod_ss(const value<BitsA> &a, const value<BitsB> &b) {
+    2046             :         return divmod_ss<BitsY>(a, b).second;
+    2047             : }
+    2048             : 
+    2049             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    2050             : CXXRTL_ALWAYS_INLINE
+    2051             : value<BitsY> modfloor_uu(const value<BitsA> &a, const value<BitsB> &b) {
+    2052             :         return divmod_uu<BitsY>(a, b).second;
+    2053             : }
+    2054             : 
+    2055             : // GHDL Modfloor operator. Returns r=a mod b, such that r has the same sign as b and
+    2056             : // a=b*N+r where N is some integer
+    2057             : // In practical terms, when a and b have different signs and the remainder returned by divmod_ss is not 0
+    2058             : // then return the remainder + b
+    2059             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    2060             : CXXRTL_ALWAYS_INLINE
+    2061             : value<BitsY> modfloor_ss(const value<BitsA> &a, const value<BitsB> &b) {
+    2062             :         value<BitsY> r;
+    2063             :         r = divmod_ss<BitsY>(a, b).second;
+    2064             :         if((b.is_neg() != a.is_neg()) && !r.is_zero())
+    2065             :                 return add_ss<BitsY>(b, r);
+    2066             :         return r;
+    2067             : }
+    2068             : 
+    2069             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    2070             : CXXRTL_ALWAYS_INLINE
+    2071             : value<BitsY> divfloor_uu(const value<BitsA> &a, const value<BitsB> &b) {
+    2072             :         return divmod_uu<BitsY>(a, b).first;
+    2073             : }
+    2074             : 
+    2075             : // Divfloor. Similar to above: returns q=a//b, where q has the sign of a*b and a=b*q+N.
+    2076             : // In other words, returns (truncating) a/b, except if a and b have different signs
+    2077             : // and there's non-zero remainder, subtract one more towards floor.
+    2078             : template<size_t BitsY, size_t BitsA, size_t BitsB>
+    2079             : CXXRTL_ALWAYS_INLINE
+    2080             : value<BitsY> divfloor_ss(const value<BitsA> &a, const value<BitsB> &b) {
+    2081             :         value<BitsY> q, r;
+    2082             :         std::tie(q, r) = divmod_ss<BitsY>(a, b);
+    2083             :         if ((b.is_neg() != a.is_neg()) && !r.is_zero())
+    2084             :                 return sub_uu<BitsY>(q, value<1> { 1u });
+    2085             :         return q;
+    2086             : 
+    2087             : }
+    2088             : 
+    2089             : // Memory helper
+    2090             : struct memory_index {
+    2091             :         bool valid;
+    2092             :         size_t index;
+    2093             : 
+    2094             :         template<size_t BitsAddr>
+    2095             :         memory_index(const value<BitsAddr> &addr, size_t offset, size_t depth) {
+    2096             :                 static_assert(value<BitsAddr>::chunks <= 1, "memory address is too wide");
+    2097             :                 size_t offset_index = addr.data[0];
+    2098             : 
+    2099             :                 valid = (offset_index >= offset && offset_index < offset + depth);
+    2100             :                 index = offset_index - offset;
+    2101             :         }
+    2102             : };
+    2103             : 
+    2104             : } // namespace cxxrtl_yosys
+    2105             : 
+    2106             : #endif
+
+
+
+ + + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl_vcd.h.func-sort-c.html b/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl_vcd.h.func-sort-c.html new file mode 100644 index 00000000000..cf6db54ca95 --- /dev/null +++ b/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl_vcd.h.func-sort-c.html @@ -0,0 +1,136 @@ + + + + + + + LCOV - vcd_harness.info - /home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl_vcd.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl - cxxrtl_vcd.h (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:11216070.0 %
Date:1980-01-01 00:00:00Functions:151693.8 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN6cxxrtl10vcd_writer11emit_vectorERKNS0_8variableE0
_ZN6cxxrtl10vcd_writer14emit_timescaleEjRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE3
_ZN6cxxrtl10vcd_writer19emit_enddefinitionsEv3
_ZN6cxxrtl10vcd_writer3addIZNS0_20add_without_memoriesERKNS_11debug_itemsEEUlRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_10debug_itemEE_EEvS4_RKT_3
_ZN6cxxrtl10vcd_writer15split_hierarchyERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE9
_ZN6cxxrtl10vcd_writer17register_variableEmPjbP15_cxxrtl_outline9
_ZN6cxxrtl10vcd_writer3addERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_10debug_itemEb9
_ZN6cxxrtl10vcd_writer8emit_varERKNS0_8variableERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESB_mb9
_ZN6cxxrtl10vcd_writer9emit_nameERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE9
_ZN6cxxrtl10vcd_writer10emit_scopeERKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS7_EE12
_ZN6cxxrtl10vcd_writer14reset_outlinesEv33
_ZN6cxxrtl10vcd_writer6sampleEm33
_ZN6cxxrtl10vcd_writer9emit_timeEm33
_ZN6cxxrtl10vcd_writer11emit_scalarERKNS0_8variableE51
_ZN6cxxrtl10vcd_writer10emit_identEm60
_ZN6cxxrtl10vcd_writer13test_variableERKNS0_8variableE99
+
+
+ + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl_vcd.h.func.html b/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl_vcd.h.func.html new file mode 100644 index 00000000000..5ceeb75a190 --- /dev/null +++ b/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl_vcd.h.func.html @@ -0,0 +1,136 @@ + + + + + + + LCOV - vcd_harness.info - /home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl_vcd.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl - cxxrtl_vcd.h (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:11216070.0 %
Date:1980-01-01 00:00:00Functions:151693.8 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN6cxxrtl10vcd_writer10emit_identEm60
_ZN6cxxrtl10vcd_writer10emit_scopeERKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS7_EE12
_ZN6cxxrtl10vcd_writer11emit_scalarERKNS0_8variableE51
_ZN6cxxrtl10vcd_writer11emit_vectorERKNS0_8variableE0
_ZN6cxxrtl10vcd_writer13test_variableERKNS0_8variableE99
_ZN6cxxrtl10vcd_writer14emit_timescaleEjRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE3
_ZN6cxxrtl10vcd_writer14reset_outlinesEv33
_ZN6cxxrtl10vcd_writer15split_hierarchyERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE9
_ZN6cxxrtl10vcd_writer17register_variableEmPjbP15_cxxrtl_outline9
_ZN6cxxrtl10vcd_writer19emit_enddefinitionsEv3
_ZN6cxxrtl10vcd_writer3addERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_10debug_itemEb9
_ZN6cxxrtl10vcd_writer3addIZNS0_20add_without_memoriesERKNS_11debug_itemsEEUlRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_10debug_itemEE_EEvS4_RKT_3
_ZN6cxxrtl10vcd_writer6sampleEm33
_ZN6cxxrtl10vcd_writer8emit_varERKNS0_8variableERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESB_mb9
_ZN6cxxrtl10vcd_writer9emit_nameERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE9
_ZN6cxxrtl10vcd_writer9emit_timeEm33
+
+
+ + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl_vcd.h.gcov.html b/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl_vcd.h.gcov.html new file mode 100644 index 00000000000..79fb13319cd --- /dev/null +++ b/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl_vcd.h.gcov.html @@ -0,0 +1,351 @@ + + + + + + + LCOV - vcd_harness.info - /home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl_vcd.h + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl - cxxrtl_vcd.h (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:11216070.0 %
Date:1980-01-01 00:00:00Functions:151693.8 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : /*
+       2             :  *  yosys -- Yosys Open SYnthesis Suite
+       3             :  *
+       4             :  *  Copyright (C) 2020  whitequark <whitequark@whitequark.org>
+       5             :  *
+       6             :  *  Permission to use, copy, modify, and/or distribute this software for any
+       7             :  *  purpose with or without fee is hereby granted.
+       8             :  *
+       9             :  *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+      10             :  *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+      11             :  *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+      12             :  *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+      13             :  *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+      14             :  *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+      15             :  *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+      16             :  *
+      17             :  */
+      18             : 
+      19             : #ifndef CXXRTL_VCD_H
+      20             : #define CXXRTL_VCD_H
+      21             : 
+      22             : #include <cxxrtl/cxxrtl.h>
+      23             : 
+      24             : namespace cxxrtl {
+      25             : 
+      26             : class vcd_writer {
+      27             :         struct variable {
+      28             :                 size_t ident;
+      29             :                 size_t width;
+      30             :                 chunk_t *curr;
+      31             :                 size_t cache_offset;
+      32             :                 debug_outline *outline;
+      33             :                 bool *outline_warm;
+      34             :         };
+      35             : 
+      36             :         std::vector<std::string> current_scope;
+      37             :         std::map<debug_outline*, bool> outlines;
+      38             :         std::vector<variable> variables;
+      39             :         std::vector<chunk_t> cache;
+      40             :         std::map<chunk_t*, size_t> aliases;
+      41             :         bool streaming = false;
+      42             : 
+      43           3 :         void emit_timescale(unsigned number, const std::string &unit) {
+      44           3 :                 assert(!streaming);
+      45           3 :                 assert(number == 1 || number == 10 || number == 100);
+      46           3 :                 assert(unit == "s" || unit == "ms" || unit == "us" ||
+      47             :                        unit == "ns" || unit == "ps" || unit == "fs");
+      48          12 :                 buffer += "$timescale " + std::to_string(number) + " " + unit + " $end\n";
+      49           3 :         }
+      50             : 
+      51          12 :         void emit_scope(const std::vector<std::string> &scope) {
+      52          12 :                 assert(!streaming);
+      53          12 :                 while (current_scope.size() > scope.size() ||
+      54          12 :                        (current_scope.size() > 0 &&
+      55           0 :                         current_scope[current_scope.size() - 1] != scope[current_scope.size() - 1])) {
+      56           0 :                         buffer += "$upscope $end\n";
+      57           0 :                         current_scope.pop_back();
+      58             :                 }
+      59          12 :                 while (current_scope.size() < scope.size()) {
+      60           0 :                         buffer += "$scope module " + scope[current_scope.size()] + " $end\n";
+      61           0 :                         current_scope.push_back(scope[current_scope.size()]);
+      62             :                 }
+      63          12 :         }
+      64             : 
+      65          60 :         void emit_ident(size_t ident) {
+      66          60 :                 do {
+      67          60 :                         buffer += '!' + ident % 94; // "base94"
+      68          60 :                         ident /= 94;
+      69          60 :                 } while (ident != 0);
+      70          60 :         }
+      71             : 
+      72           9 :         void emit_name(const std::string &name) {
+      73          24 :                 for (char c : name) {
+      74          15 :                         if (c == ':') {
+      75             :                                 // Due to a bug, GTKWave cannot parse a colon in the variable name, causing the VCD file
+      76             :                                 // to be unreadable. It cannot be escaped either, so replace it with the sideways colon.
+      77           0 :                                 buffer += "..";
+      78             :                         } else {
+      79          30 :                                 buffer += c;
+      80             :                         }
+      81             :                 }
+      82           9 :         }
+      83             : 
+      84           9 :         void emit_var(const variable &var, const std::string &type, const std::string &name,
+      85             :                       size_t lsb_at, bool multipart) {
+      86           9 :                 assert(!streaming);
+      87          36 :                 buffer += "$var " + type + " " + std::to_string(var.width) + " ";
+      88           9 :                 emit_ident(var.ident);
+      89           9 :                 buffer += " ";
+      90           9 :                 emit_name(name);
+      91           9 :                 if (multipart || name.back() == ']' || lsb_at != 0) {
+      92           0 :                         if (var.width == 1)
+      93           0 :                                 buffer += " [" + std::to_string(lsb_at) + "]";
+      94             :                         else
+      95           0 :                                 buffer += " [" + std::to_string(lsb_at + var.width - 1) + ":" + std::to_string(lsb_at) + "]";
+      96             :                 }
+      97           9 :                 buffer += " $end\n";
+      98           9 :         }
+      99             : 
+     100           3 :         void emit_enddefinitions() {
+     101           3 :                 assert(!streaming);
+     102           3 :                 buffer += "$enddefinitions $end\n";
+     103           3 :                 streaming = true;
+     104           3 :         }
+     105             : 
+     106          33 :         void emit_time(uint64_t timestamp) {
+     107          33 :                 assert(streaming);
+     108          99 :                 buffer += "#" + std::to_string(timestamp) + "\n";
+     109          33 :         }
+     110             : 
+     111          51 :         void emit_scalar(const variable &var) {
+     112          51 :                 assert(streaming);
+     113          51 :                 assert(var.width == 1);
+     114          78 :                 buffer += (*var.curr ? '1' : '0');
+     115          51 :                 emit_ident(var.ident);
+     116          51 :                 buffer += '\n';
+     117          51 :         }
+     118             : 
+     119           0 :         void emit_vector(const variable &var) {
+     120           0 :                 assert(streaming);
+     121           0 :                 buffer += 'b';
+     122           0 :                 for (size_t bit = var.width - 1; bit != (size_t)-1; bit--) {
+     123           0 :                         bool bit_curr = var.curr[bit / (8 * sizeof(chunk_t))] & (1 << (bit % (8 * sizeof(chunk_t))));
+     124           0 :                         buffer += (bit_curr ? '1' : '0');
+     125             :                 }
+     126           0 :                 buffer += ' ';
+     127           0 :                 emit_ident(var.ident);
+     128           0 :                 buffer += '\n';
+     129           0 :         }
+     130             : 
+     131          33 :         void reset_outlines() {
+     132          66 :                 for (auto &outline_it : outlines)
+     133          33 :                         outline_it.second = /*warm=*/(outline_it.first == nullptr);
+     134          33 :         }
+     135             : 
+     136           9 :         variable &register_variable(size_t width, chunk_t *curr, bool constant = false, debug_outline *outline = nullptr) {
+     137           9 :                 if (aliases.count(curr)) {
+     138           0 :                         return variables[aliases[curr]];
+     139             :                 } else {
+     140           9 :                         auto outline_it = outlines.emplace(outline, /*warm=*/(outline == nullptr)).first;
+     141           9 :                         const size_t chunks = (width + (sizeof(chunk_t) * 8 - 1)) / (sizeof(chunk_t) * 8);
+     142           9 :                         aliases[curr] = variables.size();
+     143           9 :                         if (constant) {
+     144           0 :                                 variables.emplace_back(variable { variables.size(), width, curr, (size_t)-1, outline_it->first, &outline_it->second });
+     145             :                         } else {
+     146           9 :                                 variables.emplace_back(variable { variables.size(), width, curr, cache.size(), outline_it->first, &outline_it->second });
+     147           9 :                                 cache.insert(cache.end(), &curr[0], &curr[chunks]);
+     148             :                         }
+     149           9 :                         return variables.back();
+     150             :                 }
+     151             :         }
+     152             : 
+     153          99 :         bool test_variable(const variable &var) {
+     154          99 :                 if (var.cache_offset == (size_t)-1)
+     155             :                         return false; // constant
+     156          99 :                 if (!*var.outline_warm) {
+     157           0 :                         var.outline->eval();
+     158           0 :                         *var.outline_warm = true;
+     159             :                 }
+     160          99 :                 const size_t chunks = (var.width + (sizeof(chunk_t) * 8 - 1)) / (sizeof(chunk_t) * 8);
+     161          99 :                 if (std::equal(&var.curr[0], &var.curr[chunks], &cache[var.cache_offset])) {
+     162             :                         return false;
+     163             :                 } else {
+     164          42 :                         std::copy(&var.curr[0], &var.curr[chunks], &cache[var.cache_offset]);
+     165          42 :                         return true;
+     166             :                 }
+     167             :         }
+     168             : 
+     169           9 :         static std::vector<std::string> split_hierarchy(const std::string &hier_name) {
+     170           9 :                 std::vector<std::string> hierarchy;
+     171           9 :                 size_t prev = 0;
+     172           9 :                 while (true) {
+     173           9 :                         size_t curr = hier_name.find_first_of(' ', prev);
+     174           9 :                         if (curr == std::string::npos) {
+     175          18 :                                 hierarchy.push_back(hier_name.substr(prev));
+     176           9 :                                 break;
+     177             :                         } else {
+     178           0 :                                 hierarchy.push_back(hier_name.substr(prev, curr - prev));
+     179           0 :                                 prev = curr + 1;
+     180             :                         }
+     181           0 :                 }
+     182           9 :                 return hierarchy;
+     183           0 :         }
+     184             : 
+     185             : public:
+     186             :         std::string buffer;
+     187             : 
+     188           3 :         void timescale(unsigned number, const std::string &unit) {
+     189           3 :                 emit_timescale(number, unit);
+     190           3 :         }
+     191             : 
+     192           9 :         void add(const std::string &hier_name, const debug_item &item, bool multipart = false) {
+     193           9 :                 std::vector<std::string> scope = split_hierarchy(hier_name);
+     194           9 :                 std::string name = scope.back();
+     195           9 :                 scope.pop_back();
+     196             : 
+     197           9 :                 emit_scope(scope);
+     198           9 :                 switch (item.type) {
+     199             :                         // Not the best naming but oh well...
+     200           9 :                         case debug_item::VALUE:
+     201          18 :                                 emit_var(register_variable(item.width, item.curr, /*constant=*/item.next == nullptr),
+     202           9 :                                          "wire", name, item.lsb_at, multipart);
+     203           9 :                                 break;
+     204           0 :                         case debug_item::WIRE:
+     205           0 :                                 emit_var(register_variable(item.width, item.curr),
+     206           0 :                                          "reg", name, item.lsb_at, multipart);
+     207           0 :                                 break;
+     208           0 :                         case debug_item::MEMORY: {
+     209           0 :                                 const size_t stride = (item.width + (sizeof(chunk_t) * 8 - 1)) / (sizeof(chunk_t) * 8);
+     210           0 :                                 for (size_t index = 0; index < item.depth; index++) {
+     211           0 :                                         chunk_t *nth_curr = &item.curr[stride * index];
+     212           0 :                                         std::string nth_name = name + '[' + std::to_string(index) + ']';
+     213           0 :                                         emit_var(register_variable(item.width, nth_curr),
+     214           0 :                                                  "reg", nth_name, item.lsb_at, multipart);
+     215           0 :                                 }
+     216             :                                 break;
+     217             :                         }
+     218           0 :                         case debug_item::ALIAS:
+     219             :                                 // Like VALUE, but, even though `item.next == nullptr` always holds, the underlying value
+     220             :                                 // can actually change, and must be tracked. In most cases the VCD identifier will be
+     221             :                                 // unified with the aliased reg, but we should handle the case where only the alias is
+     222             :                                 // added to the VCD writer, too.
+     223           0 :                                 emit_var(register_variable(item.width, item.curr),
+     224           0 :                                          "wire", name, item.lsb_at, multipart);
+     225           0 :                                 break;
+     226           0 :                         case debug_item::OUTLINE:
+     227           0 :                                 emit_var(register_variable(item.width, item.curr, /*constant=*/false, item.outline),
+     228           0 :                                          "wire", name, item.lsb_at, multipart);
+     229           0 :                                 break;
+     230             :                 }
+     231           9 :         }
+     232             : 
+     233             :         template<class Filter>
+     234           3 :         void add(const debug_items &items, const Filter &filter) {
+     235             :                 // `debug_items` is a map, so the items are already sorted in an order optimal for emitting
+     236             :                 // VCD scope sections.
+     237          12 :                 for (auto &it : items.table)
+     238          18 :                         for (auto &part : it.second)
+     239           9 :                                 if (filter(it.first, part))
+     240           9 :                                         add(it.first, part, it.second.size() > 1);
+     241           3 :         }
+     242             : 
+     243             :         void add(const debug_items &items) {
+     244             :                 this->add(items, [](const std::string &, const debug_item &) {
+     245             :                         return true;
+     246             :                 });
+     247             :         }
+     248             : 
+     249           3 :         void add_without_memories(const debug_items &items) {
+     250           3 :                 this->add(items, [](const std::string &, const debug_item &item) {
+     251           9 :                         return item.type != debug_item::MEMORY;
+     252             :                 });
+     253             :         }
+     254             : 
+     255          33 :         void sample(uint64_t timestamp) {
+     256          33 :                 bool first_sample = !streaming;
+     257          33 :                 if (first_sample) {
+     258           3 :                         emit_scope({});
+     259           3 :                         emit_enddefinitions();
+     260             :                 }
+     261          33 :                 reset_outlines();
+     262          33 :                 emit_time(timestamp);
+     263         132 :                 for (auto var : variables)
+     264          99 :                         if (test_variable(var) || first_sample) {
+     265          51 :                                 if (var.width == 1)
+     266          51 :                                         emit_scalar(var);
+     267             :                                 else
+     268           0 :                                         emit_vector(var);
+     269             :                         }
+     270          33 :         }
+     271             : };
+     272             : 
+     273             : }
+     274             : 
+     275             : #endif
+
+
+
+ + + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/index-sort-f.html b/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/index-sort-f.html new file mode 100644 index 00000000000..c99c203f1d4 --- /dev/null +++ b/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/index-sort-f.html @@ -0,0 +1,103 @@ + + + + + + + LCOV - vcd_harness.info - /home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - /home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtlHitTotalCoverage
Test:vcd_harness.infoLines:20227872.7 %
Date:1980-01-01 00:00:00Functions:222588.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
cxxrtl.h +
76.3%76.3%
+
76.3 %90 / 11877.8 %7 / 9
cxxrtl_vcd.h +
70.0%70.0%
+
70.0 %112 / 16093.8 %15 / 16
+
+
+ + + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/index-sort-l.html b/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/index-sort-l.html new file mode 100644 index 00000000000..540500d9b36 --- /dev/null +++ b/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/index-sort-l.html @@ -0,0 +1,103 @@ + + + + + + + LCOV - vcd_harness.info - /home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - /home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtlHitTotalCoverage
Test:vcd_harness.infoLines:20227872.7 %
Date:1980-01-01 00:00:00Functions:222588.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
cxxrtl_vcd.h +
70.0%70.0%
+
70.0 %112 / 16093.8 %15 / 16
cxxrtl.h +
76.3%76.3%
+
76.3 %90 / 11877.8 %7 / 9
+
+
+ + + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/index.html b/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/index.html new file mode 100644 index 00000000000..cb7c4a6f2f4 --- /dev/null +++ b/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/index.html @@ -0,0 +1,103 @@ + + + + + + + LCOV - vcd_harness.info - /home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - /home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtlHitTotalCoverage
Test:vcd_harness.infoLines:20227872.7 %
Date:1980-01-01 00:00:00Functions:222588.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
cxxrtl.h +
76.3%76.3%
+
76.3 %90 / 11877.8 %7 / 9
cxxrtl_vcd.h +
70.0%70.0%
+
70.0 %112 / 16093.8 %15 / 16
+
+
+ + + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/index-sort-f.html b/tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/index-sort-f.html new file mode 100644 index 00000000000..d2049083e2e --- /dev/null +++ b/tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/index-sort-f.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - vcd_harness.info - /home/roland/my_yosys/backends/functional/cxx_runtime + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - /home/roland/my_yosys/backends/functional/cxx_runtimeHitTotalCoverage
Test:vcd_harness.infoLines:88100.0 %
Date:1980-01-01 00:00:00Functions:00-
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
sim.h +
100.0%
+
100.0 %8 / 8-0 / 0
+
+
+ + + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/index-sort-l.html b/tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/index-sort-l.html new file mode 100644 index 00000000000..9b62553938b --- /dev/null +++ b/tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/index-sort-l.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - vcd_harness.info - /home/roland/my_yosys/backends/functional/cxx_runtime + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - /home/roland/my_yosys/backends/functional/cxx_runtimeHitTotalCoverage
Test:vcd_harness.infoLines:88100.0 %
Date:1980-01-01 00:00:00Functions:00-
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
sim.h +
100.0%
+
100.0 %8 / 8-0 / 0
+
+
+ + + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/index.html b/tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/index.html new file mode 100644 index 00000000000..fdffcc1bd9d --- /dev/null +++ b/tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/index.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - vcd_harness.info - /home/roland/my_yosys/backends/functional/cxx_runtime + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - /home/roland/my_yosys/backends/functional/cxx_runtimeHitTotalCoverage
Test:vcd_harness.infoLines:88100.0 %
Date:1980-01-01 00:00:00Functions:00-
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
sim.h +
100.0%
+
100.0 %8 / 8-0 / 0
+
+
+ + + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/sim.h.func-sort-c.html b/tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/sim.h.func-sort-c.html new file mode 100644 index 00000000000..f4433ccc8b5 --- /dev/null +++ b/tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/sim.h.func-sort-c.html @@ -0,0 +1,72 @@ + + + + + + + LCOV - vcd_harness.info - /home/roland/my_yosys/backends/functional/cxx_runtime/sim.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - home/roland/my_yosys/backends/functional/cxx_runtime - sim.h (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:88100.0 %
Date:1980-01-01 00:00:00Functions:00-
+
+ +
+ + + + + + +

Function Name Sort by function nameHit count Sort by hit count
+
+
+ + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/sim.h.func.html b/tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/sim.h.func.html new file mode 100644 index 00000000000..27443d08173 --- /dev/null +++ b/tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/sim.h.func.html @@ -0,0 +1,72 @@ + + + + + + + LCOV - vcd_harness.info - /home/roland/my_yosys/backends/functional/cxx_runtime/sim.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - home/roland/my_yosys/backends/functional/cxx_runtime - sim.h (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:88100.0 %
Date:1980-01-01 00:00:00Functions:00-
+
+ +
+ + + + + + +

Function Name Sort by function nameHit count Sort by hit count
+
+
+ + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/sim.h.gcov.html b/tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/sim.h.gcov.html new file mode 100644 index 00000000000..7f21dcee36c --- /dev/null +++ b/tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/sim.h.gcov.html @@ -0,0 +1,444 @@ + + + + + + + LCOV - vcd_harness.info - /home/roland/my_yosys/backends/functional/cxx_runtime/sim.h + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - home/roland/my_yosys/backends/functional/cxx_runtime - sim.h (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:88100.0 %
Date:1980-01-01 00:00:00Functions:00-
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : /*
+       2             :  *  yosys -- Yosys Open SYnthesis Suite
+       3             :  *
+       4             :  *  Copyright (C) 2024  Emily Schmidt <emily@yosyshq.com>
+       5             :  *
+       6             :  *  Permission to use, copy, modify, and/or distribute this software for any
+       7             :  *  purpose with or without fee is hereby granted, provided that the above
+       8             :  *  copyright notice and this permission notice appear in all copies.
+       9             :  *
+      10             :  *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+      11             :  *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+      12             :  *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+      13             :  *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+      14             :  *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+      15             :  *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+      16             :  *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+      17             :  *
+      18             :  */
+      19             : 
+      20             : #ifndef SIM_H
+      21             : #define SIM_H
+      22             : 
+      23             : #include <array>
+      24             : #include <cstdint>
+      25             : #include <cassert>
+      26             : 
+      27             : template<size_t n>
+      28             : using Signal = std::array<bool, n>;
+      29             : 
+      30             : template<size_t n, size_t m>
+      31             : Signal<n> slice(Signal<m> const& a, size_t offset)
+      32             : {
+      33             :     Signal<n> ret;
+      34             : 
+      35             :     std::copy(a.begin() + offset, a.begin() + offset + n, ret.begin());
+      36             :     return ret;
+      37             : }
+      38             : 
+      39             : template<size_t n>
+      40          30 : Signal<n> $const(uint32_t val)
+      41             : {
+      42             :     size_t i;
+      43             :     Signal<n> ret;
+      44             : 
+      45          30 :     for(i = 0; i < n; i++)
+      46             :         if(i < 32)
+      47          33 :             ret[i] = val & (1<<i);
+      48             :         else
+      49             :             ret[i] = false;
+      50             :     return ret;
+      51             : }
+      52             : 
+      53             : template<size_t n>
+      54             : Signal<n> $const(std::initializer_list<uint32_t> vals)
+      55             : {
+      56             :     size_t k, i;
+      57             :     Signal<n> ret;
+      58             : 
+      59             :     k = 0;
+      60             :     for (auto val : vals) {
+      61             :         for(i = 0; i < 32; i++)
+      62             :             if(i + k < n)
+      63             :                 ret[i + k] = val & (1<<i);
+      64             :         k += 32;
+      65             :     }
+      66             :     for(; k < n; k++)
+      67             :         ret[k] = false;
+      68             :     return ret;
+      69             : }
+      70             : 
+      71             : template<size_t n>
+      72             : bool as_bool(Signal<n> sig)
+      73             : {
+      74             :     for(int i = 0; i < n; i++)
+      75             :         if(sig[i])
+      76             :             return true;
+      77             :     return false;
+      78             : }
+      79             : 
+      80             : template<size_t n>
+      81             : uint32_t as_int(Signal<n> sig)
+      82             : {
+      83             :     uint32_t ret = 0;
+      84             :     for(int i = 0; i < n; i++)
+      85             :         if(sig[i] && i < 32)
+      86             :             ret |= 1<<i;
+      87             :     return ret;
+      88             : }
+      89             : 
+      90             : template<size_t n>
+      91             : Signal<n> $mux(Signal<n> const& a, Signal<n> const &b, Signal<1> const &s)
+      92             : {
+      93             :     return s[0] ? b : a;
+      94             : }
+      95             : 
+      96             : template<size_t n>
+      97             : Signal<n> $not(Signal<n> const& a)
+      98             : {
+      99             :     Signal<n> ret;
+     100             :     for(size_t i = 0; i < n; i++)
+     101             :         ret[i] = !a[i];
+     102             :     return ret;
+     103             : }
+     104             : 
+     105             : template<size_t n>
+     106             : Signal<n> $neg(Signal<n> const& a)
+     107             : {
+     108             :     Signal<n> ret;
+     109             :     bool carry = true;
+     110             :     for(size_t i = 0; i < n; i++) {
+     111             :         int r = !a[i] + carry;
+     112             :         ret[i] = (r & 1) != 0;
+     113             :         carry = (r >> 1) != 0;
+     114             :     }
+     115             :     return ret;
+     116             : }
+     117             : 
+     118             : template<size_t n>
+     119             : Signal<1> $reduce_or(Signal<n> const& a)
+     120             : {
+     121             :     return { as_bool(a) };
+     122             : }
+     123             : 
+     124             : template<size_t n>
+     125             : Signal<1> $reduce_and(Signal<n> const& a)
+     126             : {
+     127             :     for(size_t i = 0; i < n; i++)
+     128             :         if(!a[i])
+     129             :             return { false };
+     130             :     return { true };
+     131             : }
+     132             : 
+     133             : template<size_t n>
+     134             : Signal<1> $reduce_bool(Signal<n> const& a)
+     135             : {
+     136             :     return { as_bool(a) };
+     137             : }
+     138             : 
+     139             : template<size_t n>
+     140             : Signal<1> $logic_and(Signal<n> const& a, Signal<n> const& b)
+     141             : {
+     142             :     return { as_bool(a) && as_bool(b) };
+     143             : }
+     144             : 
+     145             : template<size_t n>
+     146             : Signal<1> $logic_or(Signal<n> const& a, Signal<n> const& b)
+     147             : {
+     148             :     return { as_bool(a) || as_bool(b) };
+     149             : }
+     150             : 
+     151             : template<size_t n>
+     152             : Signal<1> $logic_not(Signal<n> const& a)
+     153             : {
+     154             :     return { !as_bool(a) };
+     155             : }
+     156             : 
+     157             : template<size_t n>
+     158          30 : Signal<n> $add(Signal<n> const& a, Signal<n> const &b)
+     159             : {
+     160             :     Signal<n> ret;
+     161             :     size_t i;
+     162             :     int x = 0;
+     163          30 :     for(i = 0; i < n; i++){
+     164          30 :         x += (int)a[i] + (int)b[i];
+     165          30 :         ret[i] = x & 1;
+     166          30 :         x >>= 1;
+     167             :     }
+     168             :     return ret;
+     169             : }
+     170             : template<size_t n>
+     171             : Signal<n> $sub(Signal<n> const& a, Signal<n> const &b)
+     172             : {
+     173             :     Signal<n> ret;
+     174             :     int x = 1;
+     175             :     for(size_t i = 0; i < n; i++){
+     176             :         x += (int)a[i] + (int)!b[i];
+     177             :         ret[i] = x & 1;
+     178             :         x >>= 1;
+     179             :     }
+     180             :     return ret;
+     181             : }
+     182             : 
+     183             : template<size_t n>
+     184             : Signal<1> $uge(Signal<n> const& a, Signal<n> const &b)
+     185             : {
+     186             :     for(size_t i = n; i-- != 0; )
+     187             :         if(a[i] != b[i])
+     188             :             return { a[i] };
+     189             :     return { true };
+     190             : }
+     191             : 
+     192             : template<size_t n>
+     193             : Signal<1> $ugt(Signal<n> const& a, Signal<n> const &b)
+     194             : {
+     195             :     for(size_t i = n; i-- != 0; )
+     196             :         if(a[i] != b[i])
+     197             :             return { a[i] };
+     198             :     return { false };
+     199             : }
+     200             : 
+     201             : template<size_t n>
+     202             : Signal<1> $ge(Signal<n> const& a, Signal<n> const &b)
+     203             : {
+     204             :     if(a[n-1] != b[n-1])
+     205             :         return { b[n-1] };
+     206             :     return $uge(a, b);
+     207             : }
+     208             : 
+     209             : template<size_t n>
+     210             : Signal<1> $gt(Signal<n> const& a, Signal<n> const &b)
+     211             : {
+     212             :     if(a[n-1] != b[n-1])
+     213             :         return { b[n-1] };
+     214             :     return $ugt(a, b);
+     215             : }
+     216             : 
+     217             : template<size_t n> Signal<1> $ule(Signal<n> const& a, Signal<n> const &b) { return $uge(b, a); }
+     218             : template<size_t n> Signal<1> $ult(Signal<n> const& a, Signal<n> const &b) { return $ugt(b, a); }
+     219             : template<size_t n> Signal<1> $le(Signal<n> const& a, Signal<n> const &b) { return $ge(b, a); }
+     220             : template<size_t n> Signal<1> $lt(Signal<n> const& a, Signal<n> const &b) { return $gt(b, a); }
+     221             : 
+     222             : template<size_t n>
+     223             : Signal<n> $and(Signal<n> const& a, Signal<n> const &b)
+     224             : {
+     225             :     Signal<n> ret;
+     226             :     for(size_t i = 0; i < n; i++)
+     227             :         ret[i] = a[i] && b[i];
+     228             :     return ret;
+     229             : }
+     230             : 
+     231             : template<size_t n>
+     232             : Signal<n> $or(Signal<n> const& a, Signal<n> const &b)
+     233             : {
+     234             :     Signal<n> ret;
+     235             :     for(size_t i = 0; i < n; i++)
+     236             :         ret[i] = a[i] || b[i];
+     237             :     return ret;
+     238             : }
+     239             : 
+     240             : template<size_t n>
+     241             : Signal<n> $xor(Signal<n> const& a, Signal<n> const &b)
+     242             : {
+     243             :     Signal<n> ret;
+     244             :     for(size_t i = 0; i < n; i++)
+     245             :         ret[i] = a[i] != b[i];
+     246             :     return ret;
+     247             : }
+     248             : 
+     249             : template<size_t n, size_t na, size_t nb>
+     250             : Signal<n> $shl(Signal<na> const& a, Signal<nb> const &b)
+     251             : {
+     252             :     if(nb >= sizeof(int) * 8 - 1)
+     253             :         for(size_t i = sizeof(int) * 8 - 1; i < nb; i++)
+     254             :             assert(!b[i]);
+     255             :     size_t amount = as_int(b);
+     256             :     Signal<n> ret = $const<n>(0);
+     257             :     if(amount < n){
+     258             :         if(amount + na > n)
+     259             :             std::copy(a.begin(), a.begin() + (n - amount), ret.begin() + amount);
+     260             :         else
+     261             :             std::copy(a.begin(), a.end(), ret.begin() + amount);
+     262             :     }
+     263             :     return ret;
+     264             : }
+     265             : 
+     266             : template<size_t n, size_t nb>
+     267             : Signal<n> $shr(Signal<n> const& a, Signal<nb> const &b)
+     268             : {
+     269             :     if(nb >= sizeof(int) * 8 - 1)
+     270             :         for(size_t i = sizeof(int) * 8 - 1; i < nb; i++)
+     271             :             assert(!b[i]);
+     272             :     size_t amount = as_int(b);
+     273             :     Signal<n> ret;
+     274             :     for (size_t i = 0; i < n; i++) {
+     275             :         if(i + amount < n)
+     276             :             ret[i] = a[i + amount];
+     277             :         else
+     278             :             ret[i] = false;
+     279             :     }
+     280             :     return ret;
+     281             : }
+     282             : 
+     283             : template<size_t n, size_t nb>
+     284             : Signal<n> $asr(Signal<n> const& a, Signal<nb> const &b)
+     285             : {
+     286             :     if(nb >= sizeof(int) * 8 - 1)
+     287             :         for(size_t i = sizeof(int) * 8 - 1; i < nb; i++)
+     288             :             assert(!b[i]);
+     289             :     size_t amount = as_int(b);
+     290             :     Signal<n> ret;
+     291             :     for (size_t i = 0; i < n; i++) {
+     292             :         if(i + amount < n)
+     293             :             ret[i] = a[i + amount];
+     294             :         else
+     295             :             ret[i] = a[n - 1];
+     296             :     }
+     297             :     return ret;
+     298             : }
+     299             : 
+     300             : template<size_t n>
+     301             : Signal<1> $eq(Signal<n> const& a, Signal<n> const &b)
+     302             : {
+     303             :     for(size_t i = 0; i < n; i++)
+     304             :         if(a[i] != b[i])
+     305             :             return { false };
+     306             :     return { true };
+     307             : }
+     308             : 
+     309             : template<size_t n>
+     310             : Signal<1> $ne(Signal<n> const& a, Signal<n> const &b)
+     311             : {
+     312             :     for(size_t i = 0; i < n; i++)
+     313             :         if(a[i] != b[i])
+     314             :             return { true };
+     315             :     return { false };
+     316             : }
+     317             : 
+     318             : template<size_t n, size_t ns>
+     319             : Signal<n> $pmux(Signal<n> const& a, Signal<n*ns> const &b, Signal<ns> const &s)
+     320             : {
+     321             :     bool found;
+     322             :     Signal<n> ret;
+     323             : 
+     324             :     found = false;
+     325             :     ret = a;
+     326             :     for(size_t i = 0; i < ns; i++){
+     327             :         if(s[i]){
+     328             :             if(found)
+     329             :                 return $const<n>(0);
+     330             :             found = true;
+     331             :             ret = slice<n>(b, n * i);
+     332             :         }
+     333             :     }
+     334             :     return ret;
+     335             : }
+     336             : 
+     337             : template<size_t n, size_t m>
+     338             : Signal<n+m> concat(Signal<n> const& a, Signal<m> const& b)
+     339             : {
+     340             :     Signal<n + m> ret;
+     341             :     std::copy(a.begin(), a.end(), ret.begin());
+     342             :     std::copy(b.begin(), b.end(), ret.begin() + n);
+     343             :     return ret;
+     344             : }
+     345             : 
+     346             : template<size_t n, size_t m>
+     347             : Signal<n> $zero_extend(Signal<m> const& a)
+     348             : {
+     349             :     assert(n >= m);
+     350             :     Signal<n> ret;
+     351             :     std::copy(a.begin(), a.end(), ret.begin());
+     352             :     for(size_t i = m; i < n; i++)
+     353             :         ret[i] = false;
+     354             :     return ret;
+     355             : }
+     356             : 
+     357             : template<size_t n, size_t m>
+     358             : Signal<n> $sign_extend(Signal<m> const& a)
+     359             : {
+     360             :     assert(n >= m);
+     361             :     Signal<n> ret;
+     362             :     std::copy(a.begin(), a.end(), ret.begin());
+     363             :     for(size_t i = m; i < n; i++)
+     364             :         ret[i] = a[m-1];
+     365             :     return ret;
+     366             : }
+     367             : 
+     368             : #endif
+
+
+
+ + + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_cxxrtl.cc.func-sort-c.html b/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_cxxrtl.cc.func-sort-c.html new file mode 100644 index 00000000000..e325523d6be --- /dev/null +++ b/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_cxxrtl.cc.func-sort-c.html @@ -0,0 +1,100 @@ + + + + + + + LCOV - vcd_harness.info - /home/roland/my_yosys/tests/functional/and_cxxrtl.cc - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - home/roland/my_yosys/tests/functional - and_cxxrtl.cc (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:222975.9 %
Date:1980-01-01 00:00:00Functions:5771.4 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN13cxxrtl_design7p_Adder10debug_evalEv0
cxxrtl_design_create0
_ZN13cxxrtl_design7p_Adder10debug_infoEPN6cxxrtl11debug_itemsEPNS1_12debug_scopesENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEOSt3mapISB_NS1_8metadataESt4lessISB_ESaISt4pairIKSB_SD_EEE3
_ZN13cxxrtl_design7p_Adder5resetEv3
_ZN13cxxrtl_design7p_AdderC2Ev3
_ZN13cxxrtl_design7p_Adder4evalEPN6cxxrtl9performerE33
_ZN13cxxrtl_design7p_Adder6commitEv33
+
+
+ + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_cxxrtl.cc.func.html b/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_cxxrtl.cc.func.html new file mode 100644 index 00000000000..61a536bc000 --- /dev/null +++ b/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_cxxrtl.cc.func.html @@ -0,0 +1,100 @@ + + + + + + + LCOV - vcd_harness.info - /home/roland/my_yosys/tests/functional/and_cxxrtl.cc - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - home/roland/my_yosys/tests/functional - and_cxxrtl.cc (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:222975.9 %
Date:1980-01-01 00:00:00Functions:5771.4 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN13cxxrtl_design7p_Adder10debug_evalEv0
_ZN13cxxrtl_design7p_Adder10debug_infoEPN6cxxrtl11debug_itemsEPNS1_12debug_scopesENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEOSt3mapISB_NS1_8metadataESt4lessISB_ESaISt4pairIKSB_SD_EEE3
_ZN13cxxrtl_design7p_Adder4evalEPN6cxxrtl9performerE33
_ZN13cxxrtl_design7p_Adder5resetEv3
_ZN13cxxrtl_design7p_Adder6commitEv33
_ZN13cxxrtl_design7p_AdderC2Ev3
cxxrtl_design_create0
+
+
+ + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_cxxrtl.cc.gcov.html b/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_cxxrtl.cc.gcov.html new file mode 100644 index 00000000000..83033d50085 --- /dev/null +++ b/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_cxxrtl.cc.gcov.html @@ -0,0 +1,161 @@ + + + + + + + LCOV - vcd_harness.info - /home/roland/my_yosys/tests/functional/and_cxxrtl.cc + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - home/roland/my_yosys/tests/functional - and_cxxrtl.cc (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:222975.9 %
Date:1980-01-01 00:00:00Functions:5771.4 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : #include <cxxrtl/cxxrtl.h>
+       2             : 
+       3             : #if defined(CXXRTL_INCLUDE_CAPI_IMPL) || \
+       4             :     defined(CXXRTL_INCLUDE_VCD_CAPI_IMPL)
+       5             : #include <cxxrtl/capi/cxxrtl_capi.cc>
+       6             : #endif
+       7             : 
+       8             : #if defined(CXXRTL_INCLUDE_VCD_CAPI_IMPL)
+       9             : #include <cxxrtl/capi/cxxrtl_capi_vcd.cc>
+      10             : #endif
+      11             : 
+      12             : using namespace cxxrtl_yosys;
+      13             : 
+      14             : namespace cxxrtl_design {
+      15             : 
+      16             : // \top: 1
+      17             : // \src: verilog/and.v:1.1-9.10
+      18           3 : struct p_Adder : public module {
+      19             :         // \src: verilog/and.v:4.14-4.17
+      20             :         /*output*/ value<1> p_sum;
+      21             :         // \src: verilog/and.v:3.14-3.15
+      22             :         /*input*/ value<1> p_b;
+      23             :         // \src: verilog/and.v:2.14-2.15
+      24             :         /*input*/ value<1> p_a;
+      25             :         p_Adder(interior) {}
+      26           3 :         p_Adder() {
+      27           3 :                 reset();
+      28           3 :         };
+      29             : 
+      30             :         void reset() override;
+      31             : 
+      32             :         bool eval(performer *performer = nullptr) override;
+      33             : 
+      34             :         template<class ObserverT>
+      35             :         bool commit(ObserverT &observer) {
+      36          33 :                 bool changed = false;
+      37             :                 return changed;
+      38             :         }
+      39             : 
+      40          33 :         bool commit() override {
+      41          33 :                 observer observer;
+      42          33 :                 return commit<>(observer);
+      43             :         }
+      44             : 
+      45             :         void debug_eval();
+      46             : 
+      47             :         void debug_info(debug_items *items, debug_scopes *scopes, std::string path, metadata_map &&cell_attrs = {}) override;
+      48             : }; // struct p_Adder
+      49             : 
+      50           3 : void p_Adder::reset() {
+      51           3 : }
+      52             : 
+      53          33 : bool p_Adder::eval(performer *performer) {
+      54          33 :         bool converged = true;
+      55             :         // \src: verilog/and.v:7.17-7.22
+      56             :         // cell $add$verilog/and.v:7$1
+      57          33 :         p_sum = add_uu<1>(p_a, p_b);
+      58          33 :         return converged;
+      59             : }
+      60             : 
+      61           0 : void p_Adder::debug_eval() {
+      62           0 : }
+      63             : 
+      64             : CXXRTL_EXTREMELY_COLD
+      65           3 : void p_Adder::debug_info(debug_items *items, debug_scopes *scopes, std::string path, metadata_map &&cell_attrs) {
+      66           3 :         assert(path.empty() || path[path.size() - 1] == ' ');
+      67           3 :         if (scopes) {
+      68           0 :                 scopes->add(path.empty() ? path : path.substr(0, path.size() - 1), "Adder", metadata_map({
+      69           0 :                         { "top", UINT64_C(1) },
+      70             :                         { "src", "verilog/and.v:1.1-9.10" },
+      71           0 :                 }), std::move(cell_attrs));
+      72             :         }
+      73           3 :         if (items) {
+      74           3 :                 items->add(path, "sum", "src\000sverilog/and.v:4.14-4.17\000", p_sum, 0, debug_item::OUTPUT|debug_item::DRIVEN_COMB);
+      75           3 :                 items->add(path, "b", "src\000sverilog/and.v:3.14-3.15\000", p_b, 0, debug_item::INPUT|debug_item::UNDRIVEN);
+      76           3 :                 items->add(path, "a", "src\000sverilog/and.v:2.14-2.15\000", p_a, 0, debug_item::INPUT|debug_item::UNDRIVEN);
+      77             :         }
+      78           3 : }
+      79             : 
+      80             : } // namespace cxxrtl_design
+      81             : 
+      82             : extern "C"
+      83           0 : cxxrtl_toplevel cxxrtl_design_create() {
+      84           0 :         return new _cxxrtl_toplevel { std::unique_ptr<cxxrtl_design::p_Adder>(new cxxrtl_design::p_Adder) };
+      85             : }
+
+
+
+ + + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_functional_cxx.cc.func-sort-c.html b/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_functional_cxx.cc.func-sort-c.html new file mode 100644 index 00000000000..1ff7fb0d449 --- /dev/null +++ b/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_functional_cxx.cc.func-sort-c.html @@ -0,0 +1,84 @@ + + + + + + + LCOV - vcd_harness.info - /home/roland/my_yosys/tests/functional/and_functional_cxx.cc - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - home/roland/my_yosys/tests/functional - and_functional_cxx.cc (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:1313100.0 %
Date:1980-01-01 00:00:00Functions:33100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN12Adder_Inputs4dumpI10DumpHeaderEEvRT_3
_Z5AdderRK12Adder_InputsR13Adder_OutputsRK11Adder_StateRS4_30
_ZN12Adder_Inputs4dumpI4DumpEEvRT_33
+
+
+ + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_functional_cxx.cc.func.html b/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_functional_cxx.cc.func.html new file mode 100644 index 00000000000..8a02bda164c --- /dev/null +++ b/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_functional_cxx.cc.func.html @@ -0,0 +1,84 @@ + + + + + + + LCOV - vcd_harness.info - /home/roland/my_yosys/tests/functional/and_functional_cxx.cc - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - home/roland/my_yosys/tests/functional - and_functional_cxx.cc (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:1313100.0 %
Date:1980-01-01 00:00:00Functions:33100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_Z5AdderRK12Adder_InputsR13Adder_OutputsRK11Adder_StateRS4_30
_ZN12Adder_Inputs4dumpI10DumpHeaderEEvRT_3
_ZN12Adder_Inputs4dumpI4DumpEEvRT_33
+
+
+ + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_functional_cxx.cc.gcov.html b/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_functional_cxx.cc.gcov.html new file mode 100644 index 00000000000..57e77268202 --- /dev/null +++ b/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_functional_cxx.cc.gcov.html @@ -0,0 +1,108 @@ + + + + + + + LCOV - vcd_harness.info - /home/roland/my_yosys/tests/functional/and_functional_cxx.cc + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - home/roland/my_yosys/tests/functional - and_functional_cxx.cc (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:1313100.0 %
Date:1980-01-01 00:00:00Functions:33100.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : #include "sim.h"
+       2             : struct Adder_Inputs {
+       3             :         Signal<1> b;
+       4             :         Signal<1> a;
+       5             : 
+       6          36 :         template <typename T> void dump(T &out) {
+       7          36 :                 out("b", b);
+       8          36 :                 out("a", a);
+       9          36 :         }
+      10             : };
+      11             : 
+      12             : struct Adder_Outputs {
+      13             :         Signal<1> sum;
+      14             : 
+      15          36 :         template <typename T> void dump(T &out) {
+      16          36 :                 out("sum", sum);
+      17          36 :         }
+      18             : };
+      19             : 
+      20             : struct Adder_State {
+      21             : 
+      22             :         template <typename T> void dump(T &out) {
+      23             :         }
+      24             : };
+      25             : 
+      26          30 : void Adder(Adder_Inputs const &input, Adder_Outputs &output, Adder_State const &current_state, Adder_State &next_state)
+      27             : {
+      28          30 :         Signal<1> b = input.b;
+      29          30 :         Signal<1> a = input.a;
+      30          30 :         Signal<1> $add$verilog_and_v_7$1$_Y = $add(a, b); //
+      31          30 :         output.sum = $add$verilog_and_v_7$1$_Y;
+      32          30 : }
+
+
+
+ + + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/index-sort-f.html b/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/index-sort-f.html new file mode 100644 index 00000000000..476b5417b52 --- /dev/null +++ b/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/index-sort-f.html @@ -0,0 +1,113 @@ + + + + + + + LCOV - vcd_harness.info - /home/roland/my_yosys/tests/functional + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - /home/roland/my_yosys/tests/functionalHitTotalCoverage
Test:vcd_harness.infoLines:10511293.8 %
Date:1980-01-01 00:00:00Functions:111384.6 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
and_cxxrtl.cc +
75.9%75.9%
+
75.9 %22 / 2971.4 %5 / 7
vcd_harness.cpp +
100.0%
+
100.0 %70 / 70100.0 %3 / 3
and_functional_cxx.cc +
100.0%
+
100.0 %13 / 13100.0 %3 / 3
+
+
+ + + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/index-sort-l.html b/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/index-sort-l.html new file mode 100644 index 00000000000..aad1a23666d --- /dev/null +++ b/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/index-sort-l.html @@ -0,0 +1,113 @@ + + + + + + + LCOV - vcd_harness.info - /home/roland/my_yosys/tests/functional + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - /home/roland/my_yosys/tests/functionalHitTotalCoverage
Test:vcd_harness.infoLines:10511293.8 %
Date:1980-01-01 00:00:00Functions:111384.6 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
and_cxxrtl.cc +
75.9%75.9%
+
75.9 %22 / 2971.4 %5 / 7
and_functional_cxx.cc +
100.0%
+
100.0 %13 / 13100.0 %3 / 3
vcd_harness.cpp +
100.0%
+
100.0 %70 / 70100.0 %3 / 3
+
+
+ + + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/index.html b/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/index.html new file mode 100644 index 00000000000..548ec95fffd --- /dev/null +++ b/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/index.html @@ -0,0 +1,113 @@ + + + + + + + LCOV - vcd_harness.info - /home/roland/my_yosys/tests/functional + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - /home/roland/my_yosys/tests/functionalHitTotalCoverage
Test:vcd_harness.infoLines:10511293.8 %
Date:1980-01-01 00:00:00Functions:111384.6 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
and_cxxrtl.cc +
75.9%75.9%
+
75.9 %22 / 2971.4 %5 / 7
and_functional_cxx.cc +
100.0%
+
100.0 %13 / 13100.0 %3 / 3
vcd_harness.cpp +
100.0%
+
100.0 %70 / 70100.0 %3 / 3
+
+
+ + + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/vcd_harness.cpp.func-sort-c.html b/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/vcd_harness.cpp.func-sort-c.html new file mode 100644 index 00000000000..07fdc01e640 --- /dev/null +++ b/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/vcd_harness.cpp.func-sort-c.html @@ -0,0 +1,84 @@ + + + + + + + LCOV - vcd_harness.info - /home/roland/my_yosys/tests/functional/vcd_harness.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - home/roland/my_yosys/tests/functional - vcd_harness.cpp (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:7070100.0 %
Date:1980-01-01 00:00:00Functions:33100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
main3
_ZN10DumpHeaderclILm1EEEvPKcSt5arrayIbXT_EE9
_ZN4DumpclILm1EEEvPKcSt5arrayIbXT_EE99
+
+
+ + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/vcd_harness.cpp.func.html b/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/vcd_harness.cpp.func.html new file mode 100644 index 00000000000..6a9159b0109 --- /dev/null +++ b/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/vcd_harness.cpp.func.html @@ -0,0 +1,84 @@ + + + + + + + LCOV - vcd_harness.info - /home/roland/my_yosys/tests/functional/vcd_harness.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - home/roland/my_yosys/tests/functional - vcd_harness.cpp (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:7070100.0 %
Date:1980-01-01 00:00:00Functions:33100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN10DumpHeaderclILm1EEEvPKcSt5arrayIbXT_EE9
_ZN4DumpclILm1EEEvPKcSt5arrayIbXT_EE99
main3
+
+
+ + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/vcd_harness.cpp.gcov.html b/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/vcd_harness.cpp.gcov.html new file mode 100644 index 00000000000..805ab98d73e --- /dev/null +++ b/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/vcd_harness.cpp.gcov.html @@ -0,0 +1,216 @@ + + + + + + + LCOV - vcd_harness.info - /home/roland/my_yosys/tests/functional/vcd_harness.cpp + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - home/roland/my_yosys/tests/functional - vcd_harness.cpp (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:7070100.0 %
Date:1980-01-01 00:00:00Functions:33100.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : #include <cstdio>
+       2             : #include <iostream>
+       3             : #include <fstream>
+       4             : #include <random>
+       5             : 
+       6             : #include <cxxrtl/cxxrtl_vcd.h>
+       7             : 
+       8             : #include "and_cxxrtl.cc"
+       9             : #include "and_functional_cxx.cc"
+      10             : 
+      11             : struct DumpHeader {
+      12             :     std::ofstream &ofs;
+      13           3 :     DumpHeader(std::ofstream &ofs) : ofs(ofs) {}
+      14             :     template <size_t n>
+      15           9 :     void operator()(const char *name, Signal<n> value) {
+      16           9 :         ofs << "$var wire " << n << " " << name[0] << " " << name << " $end\n";
+      17           9 :     }
+      18             : };
+      19             : 
+      20             : struct Dump {
+      21             :     std::ofstream &ofs;
+      22          33 :     Dump(std::ofstream &ofs) : ofs(ofs) {}
+      23             :     template <size_t n>
+      24          99 :     void operator()(const char *name, Signal<n> value) {
+      25             :         // Bit
+      26             :         if (n == 1) {
+      27         156 :             ofs << (value[0] ? '1' : '0');
+      28          99 :             ofs << name[0] << "\n";
+      29             :             return;
+      30             :         }
+      31             :         // vector (multi-bit) signals
+      32             :         ofs << "b";
+      33             :         for (size_t i = n; i-- > 0;)
+      34             :             ofs << (value[i] ? '1' : '0');
+      35             :         ofs << " " << name[0] << "\n";
+      36             :     }
+      37             : };
+      38             : 
+      39           3 : int main(int argc, char **argv)
+      40             : {
+      41           3 :     constexpr int steps = 10;
+      42           3 :     constexpr int number_timescale = 1;
+      43           3 :     const std::string units_timescale = "us";
+      44           3 :     Adder_Inputs inputs;
+      45           3 :     Adder_Outputs outputs;
+      46           3 :     Adder_State state;
+      47           3 :     Adder_State next_state;
+      48             : 
+      49           3 :     std::ofstream vcd_file("functional_cxx.vcd");
+      50             : 
+      51           3 :     vcd_file << "$timescale " << number_timescale << " " << units_timescale << " $end\n"; //$scope module logic $end\n";
+      52           3 :     {
+      53           3 :         DumpHeader d(vcd_file);
+      54           3 :         inputs.dump(d);
+      55           3 :         outputs.dump(d);
+      56             :         // vcd_file << "$scope module state $end\n";
+      57           3 :         state.dump(d);
+      58             :     }
+      59           3 :     vcd_file << "$enddefinitions $end\n$dumpvars\n";
+      60             : 
+      61           3 :     cxxrtl_design::p_Adder top;
+      62             : 
+      63             :     // debug_items maps the hierarchical names of signals and memories in the design
+      64             :     // to a cxxrtl_object (a value, a wire, or a memory)
+      65           3 :     cxxrtl::debug_items all_debug_items;
+      66           3 :     cxxrtl::debug_scope debug_scope;
+      67             :     // Load the debug items of the top down the whole design hierarchy
+      68           6 :     top.debug_info(&all_debug_items, nullptr, "");
+      69             : 
+      70             :     // vcd_writer is the CXXRTL object that's responsible for creating a string with
+      71             :     // the VCD file contents.
+      72           3 :     cxxrtl::vcd_writer vcd;
+      73           3 :     vcd.timescale(number_timescale, units_timescale);
+      74             : 
+      75             :     // Here we tell the vcd writer to dump all the signals of the design, except for the
+      76             :     // memories, to the VCD file.
+      77             :     //
+      78             :     // It's not necessary to load all debug objects to the VCD. There is, for example,
+      79             :     // a  vcd.add(<debug items>, <filter>)) method which allows creating your custom filter to decide
+      80             :     // what to add and what not.
+      81           3 :     vcd.add_without_memories(all_debug_items);
+      82             : 
+      83           3 :     std::ofstream waves("cxxrtl.vcd");
+      84             : 
+      85           3 :     top.p_a.set<bool>(false);
+      86           3 :     top.p_b.set<bool>(false);
+      87           3 :     top.step();
+      88             : 
+      89             :     // We need to manually tell the VCD writer when to sample and write out the traced items.
+      90             :     // This is only a slight inconvenience and allows for complete flexibility.
+      91             :     // E.g. you could only start waveform tracing when an internal signal has reached some specific
+      92             :     // value etc.
+      93           3 :     vcd.sample(0);
+      94           3 :     vcd_file << "#0\n";
+      95           3 :     inputs.a = $const<1>(false);
+      96           3 :     inputs.b = $const<1>(false);
+      97           3 :     {
+      98           3 :         Dump d(vcd_file);
+      99           3 :         inputs.dump(d);
+     100           3 :         outputs.dump(d);
+     101           3 :         state.dump(d);
+     102             :     }
+     103             : 
+     104             :     // Initialize random number generator
+     105           3 :     std::random_device rd;
+     106           3 :     std::mt19937 gen(rd());
+     107           3 :     std::bernoulli_distribution dist(0.5); // 50% chance for true or false
+     108             :     
+     109          33 :     for (int step = 0; step < steps; ++step) {
+     110          30 :       const bool a_value = dist(gen);
+     111          30 :       const bool b_value = dist(gen);
+     112             : 
+     113             :         // cxxrtl
+     114          30 :         top.p_a.set<bool>(a_value);
+     115          30 :         top.p_b.set<bool>(b_value);
+     116          30 :         top.step();
+     117          30 :         vcd.sample(step + 1);
+     118             : 
+     119          30 :         waves << vcd.buffer;
+     120          30 :         vcd.buffer.clear();
+     121             : 
+     122             :         // Functional backend cxx
+     123          30 :         vcd_file << "#" << (step + 1) << "\n";
+     124          30 :         inputs.a = $const<1>(a_value);
+     125          30 :         inputs.b = $const<1>(b_value);
+     126          30 :         Adder(inputs, outputs, state, next_state);
+     127          30 :         {
+     128          30 :             Dump d(vcd_file);
+     129          30 :             inputs.dump(d);
+     130          30 :             outputs.dump(d);
+     131          30 :             state.dump(d);
+     132             :         }
+     133          30 :         state = next_state;
+     134             :     }
+     135             : 
+     136           3 :     vcd_file.close();
+     137           3 :     waves.close();
+     138             : 
+     139           3 :     return 0;
+     140           3 : }
+
+
+
+ + + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/index-sort-f.html b/tests/functional/coverage_report/index-sort-f.html new file mode 100644 index 00000000000..e83963227e1 --- /dev/null +++ b/tests/functional/coverage_report/index-sort-f.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - vcd_harness.info + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top levelHitTotalCoverage
Test:vcd_harness.infoLines:10511293.8 %
Date:1980-01-01 00:00:00Functions:111384.6 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Directory Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
functional +
93.8%93.8%
+
93.8 %105 / 11284.6 %11 / 13
+
+
+ + + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/index-sort-l.html b/tests/functional/coverage_report/index-sort-l.html new file mode 100644 index 00000000000..ddc964eb34a --- /dev/null +++ b/tests/functional/coverage_report/index-sort-l.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - vcd_harness.info + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top levelHitTotalCoverage
Test:vcd_harness.infoLines:10511293.8 %
Date:1980-01-01 00:00:00Functions:111384.6 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Directory Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
functional +
93.8%93.8%
+
93.8 %105 / 11284.6 %11 / 13
+
+
+ + + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/index.html b/tests/functional/coverage_report/index.html new file mode 100644 index 00000000000..65d715c439e --- /dev/null +++ b/tests/functional/coverage_report/index.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - vcd_harness.info + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top levelHitTotalCoverage
Test:vcd_harness.infoLines:10511293.8 %
Date:1980-01-01 00:00:00Functions:111384.6 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Directory Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
functional +
93.8%93.8%
+
93.8 %105 / 11284.6 %11 / 13
+
+
+ + + + +
Generated by: LCOV version 1.0
+
+ + + diff --git a/tests/functional/coverage_report/nix/store/B0S2LKF593R3585038WS4JD3LYLF2WDX-glibc-2.38-44-dev/include/bits/string_fortified.h.gcov.html b/tests/functional/coverage_report/nix/store/B0S2LKF593R3585038WS4JD3LYLF2WDX-glibc-2.38-44-dev/include/bits/string_fortified.h.gcov.html new file mode 100644 index 00000000000..7c9e3ccdcd7 --- /dev/null +++ b/tests/functional/coverage_report/nix/store/B0S2LKF593R3585038WS4JD3LYLF2WDX-glibc-2.38-44-dev/include/bits/string_fortified.h.gcov.html @@ -0,0 +1,54 @@ + + + + + + + LCOV - vcd_harness.info - /nix/store/B0S2LKF593R3585038WS4JD3LYLF2WDX-glibc-2.38-44-dev/include/bits/string_fortified.h + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - nix/store/B0S2LKF593R3585038WS4JD3LYLF2WDX-glibc-2.38-44-dev/include/bits - string_fortified.h (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:020.0 %
Date:1980-01-01 00:00:00Functions:00-
+
+ diff --git a/tests/functional/coverage_report/ruby.png b/tests/functional/coverage_report/ruby.png new file mode 100644 index 0000000000000000000000000000000000000000..991b6d4ec9e78be165e3ef757eed1aada287364d GIT binary patch literal 141 zcmeAS@N?(olHy`uVBq!ia0vp^j3CU&3?x-=hn)ga>?NMQuI!iC1^FceV#7`HfI^%F z9+AZi4BSE>%y{W;-5;PJOS+@4BLl<6e(pbstUx|nfKQ0)e^Y%R^MdiLxj>4`)5S5Q b;#P73kj=!v_*DHKNFRfztDnm{r-UW|iOwIS literal 0 HcmV?d00001 diff --git a/tests/functional/coverage_report/snow.png b/tests/functional/coverage_report/snow.png new file mode 100644 index 0000000000000000000000000000000000000000..2cdae107fceec6e7f02ac7acb4a34a82a540caa5 GIT binary patch literal 141 zcmeAS@N?(olHy`uVBq!ia0vp^j3CU&3?x-=hn)ga>?NMQuI!iC1^MM!lvI6;R0X`wF|Ns97GD8ntt^-nBo-U3d c6}OTTfNUlP#;5A{K>8RwUHx3vIVCg!071?oo&W#< literal 0 HcmV?d00001 diff --git a/tests/functional/coverage_report/updown.png b/tests/functional/coverage_report/updown.png new file mode 100644 index 0000000000000000000000000000000000000000..aa56a238b3e6c435265250f9266cd1b8caba0f20 GIT binary patch literal 117 zcmeAS@N?(olHy`uVBq!ia0vp^AT}Qd8;}%R+`Ae`*?77*hG?8mPH5^{)z4*}Q$iB}huR`+ literal 0 HcmV?d00001 diff --git a/tests/functional/coverage_report/vcd_harness.info b/tests/functional/coverage_report/vcd_harness.info new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/functional/generate_coverage.sh b/tests/functional/generate_coverage.sh new file mode 100755 index 00000000000..016e22ea269 --- /dev/null +++ b/tests/functional/generate_coverage.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +# Ensure you have compiled with coverage flags +# g++ -o vcd_harness -fprofile-arcs -ftest-coverage vcd_harness.cpp + +# Define the directory two levels below the current directory +coverage_dir="../../" + +# Create directory for coverage report +mkdir -p coverage_report + +# Capture coverage data from the specified directory, excluding external libraries +lcov --capture --directory "$coverage_dir" --output-file coverage_report/vcd_harness.info --no-external + +# Generate HTML report +genhtml coverage_report/vcd_harness.info --output-directory coverage_report + +# Open the HTML report in the default web browser +xdg-open coverage_report/index.html diff --git a/tests/functional/run-test.sh b/tests/functional/run-test.sh index 3e9de003fc2..09ee5e0f9a3 100755 --- a/tests/functional/run-test.sh +++ b/tests/functional/run-test.sh @@ -2,19 +2,29 @@ set -ex -../../yosys -p "read_verilog verilog/and.v; write_cxxrtl and_cxxrtl.cc; write_functional_cxx and_functional_cxx.cc" -${CXX:-g++} -g -fprofile-arcs -ftest-coverage vcd_harness.cpp -I ../../backends/functional/cxx_runtime/ -I ../../backends/cxxrtl/runtime/ -o vcd_harness -# Generate VCD files cxxrtl.vcd and functional_cxx.vcd -./vcd_harness -# Run vcdiff and capture the output -output=$(vcdiff cxxrtl.vcd functional_cxx.vcd) +# Loop through all Verilog files in the verilog directory +for verilog_file in verilog/*.v; do + # Run yosys to process each Verilog file + ../../yosys -p "read_verilog $verilog_file; write_cxxrtl my_module_cxxrtl.cc; write_functional_cxx my_module_functional_cxx.cc" -# Check if there is any output -if [ -n "$output" ]; then - echo "Differences detected:" - echo "$output" - exit 1 -else - echo "No differences detected." - exit 0 -fi + # Compile the generated C++ files with vcd_harness.cpp + ${CXX:-g++} -g -fprofile-arcs -ftest-coverage vcd_harness.cpp -I ../../backends/functional/cxx_runtime/ -I ../../backends/cxxrtl/runtime/ -o vcd_harness + + # Generate VCD files cxxrtl.vcd and functional_cxx.vcd + ./vcd_harness + + # Run vcdiff and capture the output + output=$(vcdiff cxxrtl.vcd functional_cxx.vcd) + + # Check if there is any output + if [ -n "$output" ]; then + echo "Differences detected in $verilog_file:" + echo "$output" + exit 1 + else + echo "No differences detected in $verilog_file." + fi +done + +# If all files are processed without differences +exit 0 diff --git a/tests/functional/vcd_harness.cpp b/tests/functional/vcd_harness.cpp index dc3ad3b9c2b..76d078b7103 100644 --- a/tests/functional/vcd_harness.cpp +++ b/tests/functional/vcd_harness.cpp @@ -5,8 +5,8 @@ #include -#include "and_cxxrtl.cc" -#include "and_functional_cxx.cc" +#include "my_module_cxxrtl.cc" +#include "my_module_functional_cxx.cc" struct DumpHeader { std::ofstream &ofs; @@ -41,10 +41,10 @@ int main(int argc, char **argv) constexpr int steps = 10; constexpr int number_timescale = 1; const std::string units_timescale = "us"; - Adder_Inputs inputs; - Adder_Outputs outputs; - Adder_State state; - Adder_State next_state; + my_module_Inputs inputs; + my_module_Outputs outputs; + my_module_State state; + my_module_State next_state; std::ofstream vcd_file("functional_cxx.vcd"); @@ -58,7 +58,7 @@ int main(int argc, char **argv) } vcd_file << "$enddefinitions $end\n$dumpvars\n"; - cxxrtl_design::p_Adder top; + cxxrtl_design::p_my__module top; // debug_items maps the hierarchical names of signals and memories in the design // to a cxxrtl_object (a value, a wire, or a memory) @@ -123,7 +123,7 @@ int main(int argc, char **argv) vcd_file << "#" << (step + 1) << "\n"; inputs.a = $const<1>(a_value); inputs.b = $const<1>(b_value); - Adder(inputs, outputs, state, next_state); + my_module(inputs, outputs, state, next_state); { Dump d(vcd_file); inputs.dump(d); diff --git a/tests/functional/verilog/add.v b/tests/functional/verilog/add.v new file mode 100644 index 00000000000..95bae7b3544 --- /dev/null +++ b/tests/functional/verilog/add.v @@ -0,0 +1,9 @@ +module my_module( + input a, + input b, + output sum + ); + // Perform addition + assign sum = a + b; + +endmodule diff --git a/tests/functional/verilog/and.v b/tests/functional/verilog/and.v index 11cf481e96b..ae07de221ff 100644 --- a/tests/functional/verilog/and.v +++ b/tests/functional/verilog/and.v @@ -1,9 +1,9 @@ -module Adder( - input a, - input b, - output sum - ); - // Perform addition - assign sum = a + b; +module my_module( + input a, + input b, + output y +); + // Perform AND + assign y = a & b; endmodule diff --git a/tests/functional/verilog/my_module_div.v b/tests/functional/verilog/my_module_div.v new file mode 100755 index 00000000000..d9a5d372a40 --- /dev/null +++ b/tests/functional/verilog/my_module_div.v @@ -0,0 +1,9 @@ +module my_module( + input a, + input b, + output y +); + // Perform operation + assign y = a / b; + +endmodule diff --git a/tests/functional/verilog/my_module_eqx.v b/tests/functional/verilog/my_module_eqx.v new file mode 100755 index 00000000000..09a2d9dd680 --- /dev/null +++ b/tests/functional/verilog/my_module_eqx.v @@ -0,0 +1,9 @@ +module my_module( + input a, + input b, + output y +); + // Perform operation + assign y = a === b; + +endmodule diff --git a/tests/functional/verilog/my_module_ge.v b/tests/functional/verilog/my_module_ge.v new file mode 100755 index 00000000000..8fcfc8b7f6d --- /dev/null +++ b/tests/functional/verilog/my_module_ge.v @@ -0,0 +1,9 @@ +module my_module( + input a, + input b, + output y +); + // Perform operation + assign y = a >= b; + +endmodule diff --git a/tests/functional/verilog/my_module_gt.v b/tests/functional/verilog/my_module_gt.v new file mode 100755 index 00000000000..5667db3e746 --- /dev/null +++ b/tests/functional/verilog/my_module_gt.v @@ -0,0 +1,9 @@ +module my_module( + input a, + input b, + output y +); + // Perform operation + assign y = a > b; + +endmodule diff --git a/tests/functional/verilog/my_module_le.v b/tests/functional/verilog/my_module_le.v new file mode 100755 index 00000000000..a4b7c482089 --- /dev/null +++ b/tests/functional/verilog/my_module_le.v @@ -0,0 +1,9 @@ +module my_module( + input a, + input b, + output y +); + // Perform operation + assign y = a <= b; + +endmodule diff --git a/tests/functional/verilog/my_module_logic_and.v b/tests/functional/verilog/my_module_logic_and.v new file mode 100755 index 00000000000..3028d8361da --- /dev/null +++ b/tests/functional/verilog/my_module_logic_and.v @@ -0,0 +1,9 @@ +module my_module( + input a, + input b, + output y +); + // Perform operation + assign y = a && b; + +endmodule diff --git a/tests/functional/verilog/my_module_logic_or.v b/tests/functional/verilog/my_module_logic_or.v new file mode 100755 index 00000000000..ca37346d91f --- /dev/null +++ b/tests/functional/verilog/my_module_logic_or.v @@ -0,0 +1,9 @@ +module my_module( + input a, + input b, + output y +); + // Perform operation + assign y = a || b; + +endmodule diff --git a/tests/functional/verilog/my_module_lt.v b/tests/functional/verilog/my_module_lt.v new file mode 100755 index 00000000000..c702433d4f8 --- /dev/null +++ b/tests/functional/verilog/my_module_lt.v @@ -0,0 +1,9 @@ +module my_module( + input a, + input b, + output y +); + // Perform operation + assign y = a < b; + +endmodule diff --git a/tests/functional/verilog/my_module_mod.v b/tests/functional/verilog/my_module_mod.v new file mode 100755 index 00000000000..84c8c91884f --- /dev/null +++ b/tests/functional/verilog/my_module_mod.v @@ -0,0 +1,9 @@ +module my_module( + input a, + input b, + output y +); + // Perform operation + assign y = a % b; + +endmodule diff --git a/tests/functional/verilog/my_module_mul.v b/tests/functional/verilog/my_module_mul.v new file mode 100755 index 00000000000..8eff36abce1 --- /dev/null +++ b/tests/functional/verilog/my_module_mul.v @@ -0,0 +1,9 @@ +module my_module( + input a, + input b, + output y +); + // Perform operation + assign y = a * b; + +endmodule diff --git a/tests/functional/verilog/my_module_ne.v b/tests/functional/verilog/my_module_ne.v new file mode 100755 index 00000000000..c4e0dc1c916 --- /dev/null +++ b/tests/functional/verilog/my_module_ne.v @@ -0,0 +1,9 @@ +module my_module( + input a, + input b, + output y +); + // Perform operation + assign y = a != b; + +endmodule diff --git a/tests/functional/verilog/my_module_nex.v b/tests/functional/verilog/my_module_nex.v new file mode 100755 index 00000000000..630dce4e915 --- /dev/null +++ b/tests/functional/verilog/my_module_nex.v @@ -0,0 +1,9 @@ +module my_module( + input a, + input b, + output y +); + // Perform operation + assign y = a !== b; + +endmodule diff --git a/tests/functional/verilog/my_module_or.v b/tests/functional/verilog/my_module_or.v new file mode 100755 index 00000000000..ada39ee49ce --- /dev/null +++ b/tests/functional/verilog/my_module_or.v @@ -0,0 +1,9 @@ +module my_module( + input a, + input b, + output y +); + // Perform operation + assign y = a | b; + +endmodule diff --git a/tests/functional/verilog/my_module_pow.v b/tests/functional/verilog/my_module_pow.v new file mode 100755 index 00000000000..d9f09638510 --- /dev/null +++ b/tests/functional/verilog/my_module_pow.v @@ -0,0 +1,9 @@ +module my_module( + input a, + input b, + output y +); + // Perform operation + assign y = a ** b; + +endmodule diff --git a/tests/functional/verilog/my_module_shl.v b/tests/functional/verilog/my_module_shl.v new file mode 100755 index 00000000000..66a435ad474 --- /dev/null +++ b/tests/functional/verilog/my_module_shl.v @@ -0,0 +1,9 @@ +module my_module( + input a, + input b, + output y +); + // Perform operation + assign y = a << b; + +endmodule diff --git a/tests/functional/verilog/my_module_shr.v b/tests/functional/verilog/my_module_shr.v new file mode 100755 index 00000000000..791a2ab423a --- /dev/null +++ b/tests/functional/verilog/my_module_shr.v @@ -0,0 +1,9 @@ +module my_module( + input a, + input b, + output y +); + // Perform operation + assign y = a >> b; + +endmodule diff --git a/tests/functional/verilog/my_module_sshl.v b/tests/functional/verilog/my_module_sshl.v new file mode 100755 index 00000000000..8a2f5fe5e95 --- /dev/null +++ b/tests/functional/verilog/my_module_sshl.v @@ -0,0 +1,9 @@ +module my_module( + input a, + input b, + output y +); + // Perform operation + assign y = a <<< b; + +endmodule diff --git a/tests/functional/verilog/my_module_sshr.v b/tests/functional/verilog/my_module_sshr.v new file mode 100755 index 00000000000..9fc46102305 --- /dev/null +++ b/tests/functional/verilog/my_module_sshr.v @@ -0,0 +1,9 @@ +module my_module( + input a, + input b, + output y +); + // Perform operation + assign y = a >>> b; + +endmodule diff --git a/tests/functional/verilog/my_module_sub.v b/tests/functional/verilog/my_module_sub.v new file mode 100755 index 00000000000..2f4e4380e89 --- /dev/null +++ b/tests/functional/verilog/my_module_sub.v @@ -0,0 +1,9 @@ +module my_module( + input a, + input b, + output y +); + // Perform operation + assign y = a - b; + +endmodule diff --git a/tests/functional/verilog/my_module_xnor.v b/tests/functional/verilog/my_module_xnor.v new file mode 100755 index 00000000000..4f1b0148ddb --- /dev/null +++ b/tests/functional/verilog/my_module_xnor.v @@ -0,0 +1,9 @@ +module my_module( + input a, + input b, + output y +); + // Perform operation + assign y = a ~^ b; + +endmodule diff --git a/tests/functional/verilog/my_module_xor.v b/tests/functional/verilog/my_module_xor.v new file mode 100755 index 00000000000..6e241186f97 --- /dev/null +++ b/tests/functional/verilog/my_module_xor.v @@ -0,0 +1,9 @@ +module my_module( + input a, + input b, + output y +); + // Perform operation + assign y = a ^ b; + +endmodule From 59e6c947275220d5f60a585ca25a15db492bbf76 Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Sat, 25 May 2024 11:51:00 +0200 Subject: [PATCH 18/51] Check the return code of yosys and of vcd_harness --- tests/functional/run-test.sh | 56 ++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/tests/functional/run-test.sh b/tests/functional/run-test.sh index 09ee5e0f9a3..b427ee32d12 100755 --- a/tests/functional/run-test.sh +++ b/tests/functional/run-test.sh @@ -2,29 +2,49 @@ set -ex +# Initialize an array to store the names of failing Verilog files +failing_files=() + # Loop through all Verilog files in the verilog directory for verilog_file in verilog/*.v; do # Run yosys to process each Verilog file - ../../yosys -p "read_verilog $verilog_file; write_cxxrtl my_module_cxxrtl.cc; write_functional_cxx my_module_functional_cxx.cc" - - # Compile the generated C++ files with vcd_harness.cpp - ${CXX:-g++} -g -fprofile-arcs -ftest-coverage vcd_harness.cpp -I ../../backends/functional/cxx_runtime/ -I ../../backends/cxxrtl/runtime/ -o vcd_harness - - # Generate VCD files cxxrtl.vcd and functional_cxx.vcd - ./vcd_harness - - # Run vcdiff and capture the output - output=$(vcdiff cxxrtl.vcd functional_cxx.vcd) + if ../../yosys -p "read_verilog $verilog_file; write_cxxrtl my_module_cxxrtl.cc; write_functional_cxx my_module_functional_cxx.cc"; then + echo "Yosys processed $verilog_file successfully." + + # Compile the generated C++ files with vcd_harness.cpp + ${CXX:-g++} -g -fprofile-arcs -ftest-coverage vcd_harness.cpp -I ../../backends/functional/cxx_runtime/ -I ../../backends/cxxrtl/runtime/ -o vcd_harness + + # Generate VCD files cxxrtl.vcd and functional_cxx.vcd + if ./vcd_harness; then + # Run vcdiff and capture the output + output=$(vcdiff cxxrtl.vcd functional_cxx.vcd) - # Check if there is any output - if [ -n "$output" ]; then - echo "Differences detected in $verilog_file:" - echo "$output" - exit 1 + # Check if there is any output + if [ -n "$output" ]; then + echo "Differences detected in $verilog_file:" + echo "$output" + failing_files+=("$verilog_file") + else + echo "No differences detected in $verilog_file." + fi + else + echo "Failed to generate VCD files for $verilog_file." + failing_files+=("$verilog_file") + fi else - echo "No differences detected in $verilog_file." + echo "Yosys failed to process $verilog_file." + failing_files+=("$verilog_file") fi done -# If all files are processed without differences -exit 0 +# Check if the array of failing files is empty +if [ ${#failing_files[@]} -eq 0 ]; then + echo "All files passed." + exit 0 +else + echo "The following files failed:" + for file in "${failing_files[@]}"; do + echo "$file" + done + exit 1 +fi From 83d98c59aa6d99408d52fe6af72667d9f3a100cb Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Sat, 25 May 2024 12:16:58 +0200 Subject: [PATCH 19/51] Specify VCD names to dump --- tests/functional/.gitignore | 3 +-- tests/functional/run-test.sh | 6 +++-- tests/functional/vcd_harness.cpp | 40 ++++++++++++-------------------- 3 files changed, 20 insertions(+), 29 deletions(-) diff --git a/tests/functional/.gitignore b/tests/functional/.gitignore index 6ee14e70604..543226b49dc 100644 --- a/tests/functional/.gitignore +++ b/tests/functional/.gitignore @@ -1,5 +1,4 @@ my_module_cxxrtl.cc my_module_functional_cxx.cc vcd_harness -cxxrtl.vcd -functional_cxx.vcd \ No newline at end of file +*.vcd \ No newline at end of file diff --git a/tests/functional/run-test.sh b/tests/functional/run-test.sh index b427ee32d12..978ae53b919 100755 --- a/tests/functional/run-test.sh +++ b/tests/functional/run-test.sh @@ -7,6 +7,8 @@ failing_files=() # Loop through all Verilog files in the verilog directory for verilog_file in verilog/*.v; do + # Extract the base name without extension + base_name=$(basename "$verilog_file" .v) # Run yosys to process each Verilog file if ../../yosys -p "read_verilog $verilog_file; write_cxxrtl my_module_cxxrtl.cc; write_functional_cxx my_module_functional_cxx.cc"; then echo "Yosys processed $verilog_file successfully." @@ -15,9 +17,9 @@ for verilog_file in verilog/*.v; do ${CXX:-g++} -g -fprofile-arcs -ftest-coverage vcd_harness.cpp -I ../../backends/functional/cxx_runtime/ -I ../../backends/cxxrtl/runtime/ -o vcd_harness # Generate VCD files cxxrtl.vcd and functional_cxx.vcd - if ./vcd_harness; then + if ./vcd_harness ${base_name}_functional_cxx.vcd ${base_name}_cxxrtl.vcd ; then # Run vcdiff and capture the output - output=$(vcdiff cxxrtl.vcd functional_cxx.vcd) + output=$(vcdiff ${base_name}_functional_cxx.vcd ${base_name}_cxxrtl.vcd) # Check if there is any output if [ -n "$output" ]; then diff --git a/tests/functional/vcd_harness.cpp b/tests/functional/vcd_harness.cpp index 76d078b7103..17297962f1d 100644 --- a/tests/functional/vcd_harness.cpp +++ b/tests/functional/vcd_harness.cpp @@ -38,6 +38,14 @@ struct Dump { int main(int argc, char **argv) { + if (argc != 3) { + std::cerr << "Usage: " << argv[0] << " \n"; + return 1; + } + + const std::string functional_vcd_filename = argv[1]; + const std::string cxxrtl_vcd_filename = argv[2]; + constexpr int steps = 10; constexpr int number_timescale = 1; const std::string units_timescale = "us"; @@ -46,50 +54,33 @@ int main(int argc, char **argv) my_module_State state; my_module_State next_state; - std::ofstream vcd_file("functional_cxx.vcd"); + std::ofstream vcd_file(functional_vcd_filename); - vcd_file << "$timescale " << number_timescale << " " << units_timescale << " $end\n"; //$scope module logic $end\n"; + vcd_file << "$timescale " << number_timescale << " " << units_timescale << " $end\n"; { DumpHeader d(vcd_file); inputs.dump(d); outputs.dump(d); - // vcd_file << "$scope module state $end\n"; state.dump(d); } vcd_file << "$enddefinitions $end\n$dumpvars\n"; cxxrtl_design::p_my__module top; - // debug_items maps the hierarchical names of signals and memories in the design - // to a cxxrtl_object (a value, a wire, or a memory) cxxrtl::debug_items all_debug_items; cxxrtl::debug_scope debug_scope; - // Load the debug items of the top down the whole design hierarchy top.debug_info(&all_debug_items, nullptr, ""); - // vcd_writer is the CXXRTL object that's responsible for creating a string with - // the VCD file contents. cxxrtl::vcd_writer vcd; vcd.timescale(number_timescale, units_timescale); - - // Here we tell the vcd writer to dump all the signals of the design, except for the - // memories, to the VCD file. - // - // It's not necessary to load all debug objects to the VCD. There is, for example, - // a vcd.add(, )) method which allows creating your custom filter to decide - // what to add and what not. vcd.add_without_memories(all_debug_items); - std::ofstream waves("cxxrtl.vcd"); + std::ofstream waves(cxxrtl_vcd_filename); top.p_a.set(false); top.p_b.set(false); top.step(); - // We need to manually tell the VCD writer when to sample and write out the traced items. - // This is only a slight inconvenience and allows for complete flexibility. - // E.g. you could only start waveform tracing when an internal signal has reached some specific - // value etc. vcd.sample(0); vcd_file << "#0\n"; inputs.a = $const<1>(false); @@ -101,14 +92,13 @@ int main(int argc, char **argv) state.dump(d); } - // Initialize random number generator std::random_device rd; std::mt19937 gen(rd()); - std::bernoulli_distribution dist(0.5); // 50% chance for true or false - + std::bernoulli_distribution dist(0.5); + for (int step = 0; step < steps; ++step) { - const bool a_value = dist(gen); - const bool b_value = dist(gen); + const bool a_value = dist(gen); + const bool b_value = dist(gen); // cxxrtl top.p_a.set(a_value); From 905db0a17a13a1d92ff32be962ad6e759a251274 Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Sat, 25 May 2024 12:26:04 +0200 Subject: [PATCH 20/51] Print type of error --- tests/functional/run-test.sh | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/tests/functional/run-test.sh b/tests/functional/run-test.sh index 978ae53b919..7dc842a797a 100755 --- a/tests/functional/run-test.sh +++ b/tests/functional/run-test.sh @@ -2,13 +2,14 @@ set -ex -# Initialize an array to store the names of failing Verilog files -failing_files=() +# Initialize an array to store the names of failing Verilog files and their failure types +declare -A failing_files # Loop through all Verilog files in the verilog directory for verilog_file in verilog/*.v; do # Extract the base name without extension base_name=$(basename "$verilog_file" .v) + # Run yosys to process each Verilog file if ../../yosys -p "read_verilog $verilog_file; write_cxxrtl my_module_cxxrtl.cc; write_functional_cxx my_module_functional_cxx.cc"; then echo "Yosys processed $verilog_file successfully." @@ -16,7 +17,7 @@ for verilog_file in verilog/*.v; do # Compile the generated C++ files with vcd_harness.cpp ${CXX:-g++} -g -fprofile-arcs -ftest-coverage vcd_harness.cpp -I ../../backends/functional/cxx_runtime/ -I ../../backends/cxxrtl/runtime/ -o vcd_harness - # Generate VCD files cxxrtl.vcd and functional_cxx.vcd + # Generate VCD files with base_name if ./vcd_harness ${base_name}_functional_cxx.vcd ${base_name}_cxxrtl.vcd ; then # Run vcdiff and capture the output output=$(vcdiff ${base_name}_functional_cxx.vcd ${base_name}_cxxrtl.vcd) @@ -25,17 +26,17 @@ for verilog_file in verilog/*.v; do if [ -n "$output" ]; then echo "Differences detected in $verilog_file:" echo "$output" - failing_files+=("$verilog_file") + failing_files["$verilog_file"]="Differences detected" else echo "No differences detected in $verilog_file." fi else echo "Failed to generate VCD files for $verilog_file." - failing_files+=("$verilog_file") + failing_files["$verilog_file"]="VCD generation failure" fi else echo "Yosys failed to process $verilog_file." - failing_files+=("$verilog_file") + failing_files["$verilog_file"]="Yosys failure" fi done @@ -45,8 +46,8 @@ if [ ${#failing_files[@]} -eq 0 ]; then exit 0 else echo "The following files failed:" - for file in "${failing_files[@]}"; do - echo "$file" + for file in "${!failing_files[@]}"; do + echo "$file: ${failing_files[$file]}" done exit 1 fi From 7cbbcaf246126ff66ff64809f7efa833ce9fc60c Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Mon, 27 May 2024 18:12:13 +0200 Subject: [PATCH 21/51] Dump first state only after module is initialized --- tests/functional/vcd_harness.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tests/functional/vcd_harness.cpp b/tests/functional/vcd_harness.cpp index 17297962f1d..b12bc54e311 100644 --- a/tests/functional/vcd_harness.cpp +++ b/tests/functional/vcd_harness.cpp @@ -85,13 +85,14 @@ int main(int argc, char **argv) vcd_file << "#0\n"; inputs.a = $const<1>(false); inputs.b = $const<1>(false); + my_module(inputs, outputs, state, next_state); { - Dump d(vcd_file); - inputs.dump(d); - outputs.dump(d); - state.dump(d); + Dump d(vcd_file); + inputs.dump(d); + outputs.dump(d); + state.dump(d); } - + std::random_device rd; std::mt19937 gen(rd()); std::bernoulli_distribution dist(0.5); @@ -113,6 +114,7 @@ int main(int argc, char **argv) vcd_file << "#" << (step + 1) << "\n"; inputs.a = $const<1>(a_value); inputs.b = $const<1>(b_value); + my_module(inputs, outputs, state, next_state); { Dump d(vcd_file); @@ -120,6 +122,7 @@ int main(int argc, char **argv) outputs.dump(d); state.dump(d); } + state = next_state; } From c18d99c250e936301c21b784a41b6b8afe0d07d0 Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Mon, 27 May 2024 22:15:00 +0200 Subject: [PATCH 22/51] Implement and test $mul. Use return, not exit in tests --- backends/functional/cxx.cc | 3 +- backends/functional/cxx_runtime/sim.h | 14 ++ backends/functional/smtlib.cc | 3 +- kernel/graphtools.h | 6 + tests/functional/{ => multi_bit}/run-test.sh | 7 +- tests/functional/multi_bit/vcd_harness.cpp | 133 ++++++++++++++++++ tests/functional/multi_bit/verilog/and.v | 9 ++ tests/functional/single_bit/run-test.sh | 69 +++++++++ .../{ => single_bit}/vcd_harness.cpp | 0 .../functional/{ => single_bit}/verilog/add.v | 0 .../functional/{ => single_bit}/verilog/and.v | 0 .../{ => single_bit}/verilog/my_module_div.v | 0 .../{ => single_bit}/verilog/my_module_eqx.v | 0 .../{ => single_bit}/verilog/my_module_ge.v | 0 .../{ => single_bit}/verilog/my_module_gt.v | 0 .../{ => single_bit}/verilog/my_module_le.v | 0 .../verilog/my_module_logic_and.v | 0 .../verilog/my_module_logic_or.v | 0 .../{ => single_bit}/verilog/my_module_lt.v | 0 .../{ => single_bit}/verilog/my_module_mod.v | 0 .../{ => single_bit}/verilog/my_module_mul.v | 0 .../{ => single_bit}/verilog/my_module_ne.v | 0 .../{ => single_bit}/verilog/my_module_nex.v | 0 .../{ => single_bit}/verilog/my_module_or.v | 0 .../{ => single_bit}/verilog/my_module_pow.v | 0 .../{ => single_bit}/verilog/my_module_shl.v | 0 .../{ => single_bit}/verilog/my_module_shr.v | 0 .../{ => single_bit}/verilog/my_module_sshl.v | 0 .../{ => single_bit}/verilog/my_module_sshr.v | 0 .../{ => single_bit}/verilog/my_module_sub.v | 0 .../{ => single_bit}/verilog/my_module_xnor.v | 0 .../{ => single_bit}/verilog/my_module_xor.v | 0 tests/verismith/yosys_all.toml | 33 +++++ 33 files changed, 273 insertions(+), 4 deletions(-) rename tests/functional/{ => multi_bit}/run-test.sh (84%) create mode 100644 tests/functional/multi_bit/vcd_harness.cpp create mode 100644 tests/functional/multi_bit/verilog/and.v create mode 100755 tests/functional/single_bit/run-test.sh rename tests/functional/{ => single_bit}/vcd_harness.cpp (100%) rename tests/functional/{ => single_bit}/verilog/add.v (100%) rename tests/functional/{ => single_bit}/verilog/and.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_div.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_eqx.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_ge.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_gt.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_le.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_logic_and.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_logic_or.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_lt.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_mod.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_mul.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_ne.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_nex.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_or.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_pow.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_shl.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_shr.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_sshl.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_sshr.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_sub.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_xnor.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_xor.v (100%) create mode 100644 tests/verismith/yosys_all.toml diff --git a/backends/functional/cxx.cc b/backends/functional/cxx.cc index a1060c58d79..5623e795bc1 100644 --- a/backends/functional/cxx.cc +++ b/backends/functional/cxx.cc @@ -189,7 +189,8 @@ class CxxComputeGraphFactory { T logical_shift_left(T a, T b, int y_width, int) { return graph.add(CxxFunction(ID($shl), y_width, {{ID(WIDTH), y_width}}), 0, std::array{a, b}); } T logical_shift_right(T a, T b, int y_width, int) { return graph.add(CxxFunction(ID($shr), y_width, {{ID(WIDTH), y_width}}), 0, std::array{a, b}); } T arithmetic_shift_right(T a, T b, int y_width, int) { return graph.add(CxxFunction(ID($asr), y_width, {{ID(WIDTH), y_width}}), 0, std::array{a, b}); } - + T mul(T a, T b, int width) {return graph.add(CxxFunction(ID($mul), width), 0, std::array{a, b}); } + T constant(RTLIL::Const value) { return graph.add(CxxFunction(ID($$const), value.size(), {{ID(value), value}}), 0); } diff --git a/backends/functional/cxx_runtime/sim.h b/backends/functional/cxx_runtime/sim.h index 829266da0e6..0cbbe9831a1 100644 --- a/backends/functional/cxx_runtime/sim.h +++ b/backends/functional/cxx_runtime/sim.h @@ -365,4 +365,18 @@ Signal $sign_extend(Signal const& a) return ret; } +template +Signal $mul(Signal const& a, Signal const& b) +{ + Signal ret = $const(0); + + for(size_t i = 0; i < n; i++) { + if(b[i]) { + Signal shifted_a = $shl($zero_extend(a), $const(i)); + ret = $add(ret, shifted_a); + } + } + return ret; +} + #endif diff --git a/backends/functional/smtlib.cc b/backends/functional/smtlib.cc index cd11111b9d8..2811d0bea7e 100644 --- a/backends/functional/smtlib.cc +++ b/backends/functional/smtlib.cc @@ -367,7 +367,8 @@ class SmtlibComputeGraphFactory { T logical_shift_left(T a, T b, int y_width, int b_width) { return shift("bvshl", a, b, y_width, b_width); } T logical_shift_right(T a, T b, int y_width, int b_width) { return shift("bvlshl", a, b, y_width, b_width); } T arithmetic_shift_right(T a, T b, int y_width, int b_width) { return shift("bvashr", a, b, y_width, b_width, true); } - + T mul(T a, T b, int width) { return node(SExpr {"bvmul", Arg(1), Arg(2)}, width, {a, b}); } + T constant(RTLIL::Const value) { return node(SExpr(value), value.size(), {}); } T input(IdString name, int width) { module.input_struct.insert(name, width); diff --git a/kernel/graphtools.h b/kernel/graphtools.h index adf4764c201..1c6b927739d 100644 --- a/kernel/graphtools.h +++ b/kernel/graphtools.h @@ -183,6 +183,12 @@ class CellSimplifier { int offset = parameters.at(ID(OFFSET)).as_int(); T a = inputs.at(ID(A)); return factory.slice(a, a_width, offset, y_width); + }else if(cellType == ID($mul)){ + bool is_signed = a_signed && b_signed; + int width = a_width + b_width; + T a = extend(inputs.at(ID(A)), a_width, width, is_signed); + T b = extend(inputs.at(ID(B)), b_width, width, is_signed); + return extend(factory.mul(a, b, width), width, y_width, is_signed); }else{ log_error("unhandled cell in CellSimplifier %s\n", cellType.c_str()); } diff --git a/tests/functional/run-test.sh b/tests/functional/multi_bit/run-test.sh similarity index 84% rename from tests/functional/run-test.sh rename to tests/functional/multi_bit/run-test.sh index 7dc842a797a..421630d5be5 100755 --- a/tests/functional/run-test.sh +++ b/tests/functional/multi_bit/run-test.sh @@ -2,6 +2,9 @@ set -ex +# Define the common variable for the relative path +BASE_PATH="../../../" + # Initialize an array to store the names of failing Verilog files and their failure types declare -A failing_files @@ -11,11 +14,11 @@ for verilog_file in verilog/*.v; do base_name=$(basename "$verilog_file" .v) # Run yosys to process each Verilog file - if ../../yosys -p "read_verilog $verilog_file; write_cxxrtl my_module_cxxrtl.cc; write_functional_cxx my_module_functional_cxx.cc"; then + if ${BASE_PATH}yosys -p "read_verilog $verilog_file; write_cxxrtl my_module_cxxrtl.cc; write_functional_cxx my_module_functional_cxx.cc"; then echo "Yosys processed $verilog_file successfully." # Compile the generated C++ files with vcd_harness.cpp - ${CXX:-g++} -g -fprofile-arcs -ftest-coverage vcd_harness.cpp -I ../../backends/functional/cxx_runtime/ -I ../../backends/cxxrtl/runtime/ -o vcd_harness + ${CXX:-g++} -g -fprofile-arcs -ftest-coverage vcd_harness.cpp -I ${BASE_PATH}backends/functional/cxx_runtime/ -I ${BASE_PATH}backends/cxxrtl/runtime/ -o vcd_harness # Generate VCD files with base_name if ./vcd_harness ${base_name}_functional_cxx.vcd ${base_name}_cxxrtl.vcd ; then diff --git a/tests/functional/multi_bit/vcd_harness.cpp b/tests/functional/multi_bit/vcd_harness.cpp new file mode 100644 index 00000000000..bb8cca6fc8d --- /dev/null +++ b/tests/functional/multi_bit/vcd_harness.cpp @@ -0,0 +1,133 @@ +#include +#include +#include +#include + +#include + +#include "my_module_cxxrtl.cc" +#include "my_module_functional_cxx.cc" + +struct DumpHeader { + std::ofstream &ofs; + DumpHeader(std::ofstream &ofs) : ofs(ofs) {} + template + void operator()(const char *name, Signal value) { + ofs << "$var wire " << n << " " << name[0] << " " << name << " $end\n"; + } +}; + +struct Dump { + std::ofstream &ofs; + Dump(std::ofstream &ofs) : ofs(ofs) {} + template + void operator()(const char *name, Signal value) { + // Bit + if (n == 1) { + ofs << (value[0] ? '1' : '0'); + ofs << name[0] << "\n"; + return; + } + // vector (multi-bit) signals + ofs << "b"; + for (size_t i = n; i-- > 0;) + ofs << (value[i] ? '1' : '0'); + ofs << " " << name[0] << "\n"; + } +}; + +int main(int argc, char **argv) +{ + if (argc != 3) { + std::cerr << "Usage: " << argv[0] << " \n"; + return 1; + } + + const std::string functional_vcd_filename = argv[1]; + const std::string cxxrtl_vcd_filename = argv[2]; + + constexpr int steps = 10; + constexpr int number_timescale = 1; + const std::string units_timescale = "us"; + my_module_Inputs inputs; + my_module_Outputs outputs; + my_module_State state; + my_module_State next_state; + + std::ofstream vcd_file(functional_vcd_filename); + + vcd_file << "$timescale " << number_timescale << " " << units_timescale << " $end\n"; + { + DumpHeader d(vcd_file); + inputs.dump(d); + outputs.dump(d); + state.dump(d); + } + vcd_file << "$enddefinitions $end\n$dumpvars\n"; + + cxxrtl_design::p_my__module top; + + cxxrtl::debug_items all_debug_items; + cxxrtl::debug_scope debug_scope; + top.debug_info(&all_debug_items, nullptr, ""); + + cxxrtl::vcd_writer vcd; + vcd.timescale(number_timescale, units_timescale); + vcd.add_without_memories(all_debug_items); + + std::ofstream waves(cxxrtl_vcd_filename); + + top.p_a.set<8>(false); + top.p_b.set<8>(false); + top.step(); + + vcd.sample(0); + vcd_file << "#0\n"; + inputs.a = $const<8>(false); + inputs.b = $const<8>(false); + my_module(inputs, outputs, state, next_state); + { + Dump d(vcd_file); + inputs.dump(d); + outputs.dump(d); + state.dump(d); + } + + std::random_device rd; + std::mt19937 gen(rd()); + std::bernoulli_distribution dist(0.5); + + for (int step = 0; step < steps; ++step) { + const bool a_value = dist(gen); + const bool b_value = dist(gen); + + // cxxrtl + top.p_a.set(a_value); + top.p_b.set(b_value); + top.step(); + vcd.sample(step + 1); + + waves << vcd.buffer; + vcd.buffer.clear(); + + // Functional backend cxx + vcd_file << "#" << (step + 1) << "\n"; + inputs.a = $const<8>(a_value); + inputs.b = $const<8>(b_value); + + my_module(inputs, outputs, state, next_state); + { + Dump d(vcd_file); + inputs.dump(d); + outputs.dump(d); + state.dump(d); + } + + state = next_state; + } + + vcd_file.close(); + waves.close(); + + return 0; +} diff --git a/tests/functional/multi_bit/verilog/and.v b/tests/functional/multi_bit/verilog/and.v new file mode 100644 index 00000000000..be20c778e65 --- /dev/null +++ b/tests/functional/multi_bit/verilog/and.v @@ -0,0 +1,9 @@ +module my_module( + input [7:0] a, + input [7:0] b, + output [7:0] y +); + // Perform bitwise AND + assign y = a & b; + +endmodule diff --git a/tests/functional/single_bit/run-test.sh b/tests/functional/single_bit/run-test.sh new file mode 100755 index 00000000000..ff5636f93f9 --- /dev/null +++ b/tests/functional/single_bit/run-test.sh @@ -0,0 +1,69 @@ +#!/bin/bash + +# Initialize an array to store the names of failing Verilog files and their failure types +declare -A failing_files + +# Function to run the test on a given Verilog file +run_test() { + # Define the common variable for the relative path + BASE_PATH="../../../" + + local verilog_file=$1 + + # Extract the base name without extension + local base_name=$(basename "$verilog_file" .v) + + # Run yosys to process each Verilog file + if ${BASE_PATH}yosys -p "read_verilog $verilog_file; write_cxxrtl my_module_cxxrtl.cc; write_functional_cxx my_module_functional_cxx.cc"; then + echo "Yosys processed $verilog_file successfully." + + # Compile the generated C++ files with vcd_harness.cpp + ${CXX:-g++} -g -fprofile-arcs -ftest-coverage vcd_harness.cpp -I ${BASE_PATH}backends/functional/cxx_runtime/ -I ${BASE_PATH}backends/cxxrtl/runtime/ -o vcd_harness + + # Generate VCD files with base_name + if ./vcd_harness ${base_name}_functional_cxx.vcd ${base_name}_cxxrtl.vcd ; then + # Run vcdiff and capture the output + local output=$(vcdiff ${base_name}_functional_cxx.vcd ${base_name}_cxxrtl.vcd) + + # Check if there is any output + if [ -n "$output" ]; then + echo "Differences detected in $verilog_file:" + echo "$output" + failing_files["$verilog_file"]="Differences detected" + else + echo "No differences detected in $verilog_file." + fi + else + echo "Failed to generate VCD files for $verilog_file." + failing_files["$verilog_file"]="VCD generation failure" + fi + else + echo "Yosys failed to process $verilog_file." + failing_files["$verilog_file"]="Yosys failure" + fi +} + +# Main function to run all tests +run_all_tests() { + # Loop through all Verilog files in the verilog directory + for verilog_file in verilog/*.v; do + run_test "$verilog_file" + done + + # Check if the array of failing files is empty + if [ ${#failing_files[@]} -eq 0 ]; then + echo "All files passed." + return 0 + else + echo "The following files failed:" + for file in "${!failing_files[@]}"; do + echo "$file: ${failing_files[$file]}" + done + return 1 + fi +} + +# If the script is being sourced, do not execute the tests +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + run_all_tests +fi diff --git a/tests/functional/vcd_harness.cpp b/tests/functional/single_bit/vcd_harness.cpp similarity index 100% rename from tests/functional/vcd_harness.cpp rename to tests/functional/single_bit/vcd_harness.cpp diff --git a/tests/functional/verilog/add.v b/tests/functional/single_bit/verilog/add.v similarity index 100% rename from tests/functional/verilog/add.v rename to tests/functional/single_bit/verilog/add.v diff --git a/tests/functional/verilog/and.v b/tests/functional/single_bit/verilog/and.v similarity index 100% rename from tests/functional/verilog/and.v rename to tests/functional/single_bit/verilog/and.v diff --git a/tests/functional/verilog/my_module_div.v b/tests/functional/single_bit/verilog/my_module_div.v similarity index 100% rename from tests/functional/verilog/my_module_div.v rename to tests/functional/single_bit/verilog/my_module_div.v diff --git a/tests/functional/verilog/my_module_eqx.v b/tests/functional/single_bit/verilog/my_module_eqx.v similarity index 100% rename from tests/functional/verilog/my_module_eqx.v rename to tests/functional/single_bit/verilog/my_module_eqx.v diff --git a/tests/functional/verilog/my_module_ge.v b/tests/functional/single_bit/verilog/my_module_ge.v similarity index 100% rename from tests/functional/verilog/my_module_ge.v rename to tests/functional/single_bit/verilog/my_module_ge.v diff --git a/tests/functional/verilog/my_module_gt.v b/tests/functional/single_bit/verilog/my_module_gt.v similarity index 100% rename from tests/functional/verilog/my_module_gt.v rename to tests/functional/single_bit/verilog/my_module_gt.v diff --git a/tests/functional/verilog/my_module_le.v b/tests/functional/single_bit/verilog/my_module_le.v similarity index 100% rename from tests/functional/verilog/my_module_le.v rename to tests/functional/single_bit/verilog/my_module_le.v diff --git a/tests/functional/verilog/my_module_logic_and.v b/tests/functional/single_bit/verilog/my_module_logic_and.v similarity index 100% rename from tests/functional/verilog/my_module_logic_and.v rename to tests/functional/single_bit/verilog/my_module_logic_and.v diff --git a/tests/functional/verilog/my_module_logic_or.v b/tests/functional/single_bit/verilog/my_module_logic_or.v similarity index 100% rename from tests/functional/verilog/my_module_logic_or.v rename to tests/functional/single_bit/verilog/my_module_logic_or.v diff --git a/tests/functional/verilog/my_module_lt.v b/tests/functional/single_bit/verilog/my_module_lt.v similarity index 100% rename from tests/functional/verilog/my_module_lt.v rename to tests/functional/single_bit/verilog/my_module_lt.v diff --git a/tests/functional/verilog/my_module_mod.v b/tests/functional/single_bit/verilog/my_module_mod.v similarity index 100% rename from tests/functional/verilog/my_module_mod.v rename to tests/functional/single_bit/verilog/my_module_mod.v diff --git a/tests/functional/verilog/my_module_mul.v b/tests/functional/single_bit/verilog/my_module_mul.v similarity index 100% rename from tests/functional/verilog/my_module_mul.v rename to tests/functional/single_bit/verilog/my_module_mul.v diff --git a/tests/functional/verilog/my_module_ne.v b/tests/functional/single_bit/verilog/my_module_ne.v similarity index 100% rename from tests/functional/verilog/my_module_ne.v rename to tests/functional/single_bit/verilog/my_module_ne.v diff --git a/tests/functional/verilog/my_module_nex.v b/tests/functional/single_bit/verilog/my_module_nex.v similarity index 100% rename from tests/functional/verilog/my_module_nex.v rename to tests/functional/single_bit/verilog/my_module_nex.v diff --git a/tests/functional/verilog/my_module_or.v b/tests/functional/single_bit/verilog/my_module_or.v similarity index 100% rename from tests/functional/verilog/my_module_or.v rename to tests/functional/single_bit/verilog/my_module_or.v diff --git a/tests/functional/verilog/my_module_pow.v b/tests/functional/single_bit/verilog/my_module_pow.v similarity index 100% rename from tests/functional/verilog/my_module_pow.v rename to tests/functional/single_bit/verilog/my_module_pow.v diff --git a/tests/functional/verilog/my_module_shl.v b/tests/functional/single_bit/verilog/my_module_shl.v similarity index 100% rename from tests/functional/verilog/my_module_shl.v rename to tests/functional/single_bit/verilog/my_module_shl.v diff --git a/tests/functional/verilog/my_module_shr.v b/tests/functional/single_bit/verilog/my_module_shr.v similarity index 100% rename from tests/functional/verilog/my_module_shr.v rename to tests/functional/single_bit/verilog/my_module_shr.v diff --git a/tests/functional/verilog/my_module_sshl.v b/tests/functional/single_bit/verilog/my_module_sshl.v similarity index 100% rename from tests/functional/verilog/my_module_sshl.v rename to tests/functional/single_bit/verilog/my_module_sshl.v diff --git a/tests/functional/verilog/my_module_sshr.v b/tests/functional/single_bit/verilog/my_module_sshr.v similarity index 100% rename from tests/functional/verilog/my_module_sshr.v rename to tests/functional/single_bit/verilog/my_module_sshr.v diff --git a/tests/functional/verilog/my_module_sub.v b/tests/functional/single_bit/verilog/my_module_sub.v similarity index 100% rename from tests/functional/verilog/my_module_sub.v rename to tests/functional/single_bit/verilog/my_module_sub.v diff --git a/tests/functional/verilog/my_module_xnor.v b/tests/functional/single_bit/verilog/my_module_xnor.v similarity index 100% rename from tests/functional/verilog/my_module_xnor.v rename to tests/functional/single_bit/verilog/my_module_xnor.v diff --git a/tests/functional/verilog/my_module_xor.v b/tests/functional/single_bit/verilog/my_module_xor.v similarity index 100% rename from tests/functional/verilog/my_module_xor.v rename to tests/functional/single_bit/verilog/my_module_xor.v diff --git a/tests/verismith/yosys_all.toml b/tests/verismith/yosys_all.toml new file mode 100644 index 00000000000..a60a8371db5 --- /dev/null +++ b/tests/verismith/yosys_all.toml @@ -0,0 +1,33 @@ +[probability] + expr.binary = 5 + expr.concatenation = 5 + expr.number = 1 + expr.rangeselect = 5 + expr.signed = 5 + expr.string = 0 + expr.ternary = 5 + expr.unary = 5 + expr.unsigned = 5 + expr.variable = 5 + moditem.assign = 2 + moditem.combinational = 0 + moditem.instantiation = 0 + moditem.sequential = 3 + statement.blocking = 0 + statement.conditional = 1 + statement.forloop = 0 + statement.nonblocking = 2 + +[property] + module.depth = 2 + module.max = 5 + size = 20 + statement.depth = 7 + sample.method = "hat" + sample.size = 10 + +[[synthesiser]] + name = "yosys" + description = "yosys_nix" + output = "yosys_nix.v" + bin = "/nix/store/fzqckbn2ajj6illgrbcja6fj8qzrbacb-yosys/bin/" \ No newline at end of file From 4bfb50e56edaf421fe787dce66818c48315bbca3 Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Tue, 28 May 2024 06:11:27 +0200 Subject: [PATCH 23/51] vcdiff gives error output on stderr --- tests/functional/single_bit/run-test.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/functional/single_bit/run-test.sh b/tests/functional/single_bit/run-test.sh index ff5636f93f9..4d5d8747f6e 100755 --- a/tests/functional/single_bit/run-test.sh +++ b/tests/functional/single_bit/run-test.sh @@ -21,9 +21,9 @@ run_test() { ${CXX:-g++} -g -fprofile-arcs -ftest-coverage vcd_harness.cpp -I ${BASE_PATH}backends/functional/cxx_runtime/ -I ${BASE_PATH}backends/cxxrtl/runtime/ -o vcd_harness # Generate VCD files with base_name - if ./vcd_harness ${base_name}_functional_cxx.vcd ${base_name}_cxxrtl.vcd ; then + if ./vcd_harness ${base_name}_functional_cxx.vcd ${base_name}_cxxrtl.vcd; then # Run vcdiff and capture the output - local output=$(vcdiff ${base_name}_functional_cxx.vcd ${base_name}_cxxrtl.vcd) + local output=$(vcdiff ${base_name}_functional_cxx.vcd ${base_name}_cxxrtl.vcd 2>&1) # Check if there is any output if [ -n "$output" ]; then From 44e073fee9656119c12b8dc2a8d88d76954e2e7c Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Tue, 28 May 2024 11:52:50 +0200 Subject: [PATCH 24/51] Compare with sim -sim-cmp, not vcdiff --- backends/functional/cxx.cc | 2 +- tests/functional/single_bit/run-test.sh | 20 +++++++++----------- tests/functional/single_bit/vcd_harness.cpp | 1 + 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/backends/functional/cxx.cc b/backends/functional/cxx.cc index 5623e795bc1..a4153035dad 100644 --- a/backends/functional/cxx.cc +++ b/backends/functional/cxx.cc @@ -189,7 +189,7 @@ class CxxComputeGraphFactory { T logical_shift_left(T a, T b, int y_width, int) { return graph.add(CxxFunction(ID($shl), y_width, {{ID(WIDTH), y_width}}), 0, std::array{a, b}); } T logical_shift_right(T a, T b, int y_width, int) { return graph.add(CxxFunction(ID($shr), y_width, {{ID(WIDTH), y_width}}), 0, std::array{a, b}); } T arithmetic_shift_right(T a, T b, int y_width, int) { return graph.add(CxxFunction(ID($asr), y_width, {{ID(WIDTH), y_width}}), 0, std::array{a, b}); } - T mul(T a, T b, int width) {return graph.add(CxxFunction(ID($mul), width), 0, std::array{a, b}); } + T mul(T a, T b, int width) { return graph.add(CxxFunction(ID($mul), width), 0, std::array{a, b}); } T constant(RTLIL::Const value) { return graph.add(CxxFunction(ID($$const), value.size(), {{ID(value), value}}), 0); diff --git a/tests/functional/single_bit/run-test.sh b/tests/functional/single_bit/run-test.sh index 4d5d8747f6e..2eba8367483 100755 --- a/tests/functional/single_bit/run-test.sh +++ b/tests/functional/single_bit/run-test.sh @@ -22,17 +22,15 @@ run_test() { # Generate VCD files with base_name if ./vcd_harness ${base_name}_functional_cxx.vcd ${base_name}_cxxrtl.vcd; then - # Run vcdiff and capture the output - local output=$(vcdiff ${base_name}_functional_cxx.vcd ${base_name}_cxxrtl.vcd 2>&1) - - # Check if there is any output - if [ -n "$output" ]; then - echo "Differences detected in $verilog_file:" - echo "$output" - failing_files["$verilog_file"]="Differences detected" - else - echo "No differences detected in $verilog_file." - fi + + # Run yosys to process each Verilog file + if ${BASE_PATH}yosys -p "read_verilog $verilog_file; sim -r ${base_name}_functional_cxx.vcd -scope my_module -timescale 1us -sim-cmp"; then + echo "Yosys sim $verilog_file successfully." + else + echo "Yosys simulation of $verilog_file failed. There is a discrepancy with functional cxx" + failing_files["$verilog_file"]="Yosys sim failure" + fi + else echo "Failed to generate VCD files for $verilog_file." failing_files["$verilog_file"]="VCD generation failure" diff --git a/tests/functional/single_bit/vcd_harness.cpp b/tests/functional/single_bit/vcd_harness.cpp index b12bc54e311..7e474eea985 100644 --- a/tests/functional/single_bit/vcd_harness.cpp +++ b/tests/functional/single_bit/vcd_harness.cpp @@ -57,6 +57,7 @@ int main(int argc, char **argv) std::ofstream vcd_file(functional_vcd_filename); vcd_file << "$timescale " << number_timescale << " " << units_timescale << " $end\n"; + vcd_file << "$scope module my_module $end\n"; { DumpHeader d(vcd_file); inputs.dump(d); From 1628ac38c51c82b388267c73e0f4cc05b7e8cd13 Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Tue, 28 May 2024 12:20:39 +0200 Subject: [PATCH 25/51] Copy test to cxxrtl to not forget --- tests/cxxrtl/sim_test.sh | 67 +++++++++ .../vcd_harness.cpp => cxxrtl/vcd_harness.cc} | 0 tests/functional/single_bit/vcd_harness.cc | 134 ++++++++++++++++++ 3 files changed, 201 insertions(+) create mode 100755 tests/cxxrtl/sim_test.sh rename tests/{functional/single_bit/vcd_harness.cpp => cxxrtl/vcd_harness.cc} (100%) create mode 100644 tests/functional/single_bit/vcd_harness.cc diff --git a/tests/cxxrtl/sim_test.sh b/tests/cxxrtl/sim_test.sh new file mode 100755 index 00000000000..2eba8367483 --- /dev/null +++ b/tests/cxxrtl/sim_test.sh @@ -0,0 +1,67 @@ +#!/bin/bash + +# Initialize an array to store the names of failing Verilog files and their failure types +declare -A failing_files + +# Function to run the test on a given Verilog file +run_test() { + # Define the common variable for the relative path + BASE_PATH="../../../" + + local verilog_file=$1 + + # Extract the base name without extension + local base_name=$(basename "$verilog_file" .v) + + # Run yosys to process each Verilog file + if ${BASE_PATH}yosys -p "read_verilog $verilog_file; write_cxxrtl my_module_cxxrtl.cc; write_functional_cxx my_module_functional_cxx.cc"; then + echo "Yosys processed $verilog_file successfully." + + # Compile the generated C++ files with vcd_harness.cpp + ${CXX:-g++} -g -fprofile-arcs -ftest-coverage vcd_harness.cpp -I ${BASE_PATH}backends/functional/cxx_runtime/ -I ${BASE_PATH}backends/cxxrtl/runtime/ -o vcd_harness + + # Generate VCD files with base_name + if ./vcd_harness ${base_name}_functional_cxx.vcd ${base_name}_cxxrtl.vcd; then + + # Run yosys to process each Verilog file + if ${BASE_PATH}yosys -p "read_verilog $verilog_file; sim -r ${base_name}_functional_cxx.vcd -scope my_module -timescale 1us -sim-cmp"; then + echo "Yosys sim $verilog_file successfully." + else + echo "Yosys simulation of $verilog_file failed. There is a discrepancy with functional cxx" + failing_files["$verilog_file"]="Yosys sim failure" + fi + + else + echo "Failed to generate VCD files for $verilog_file." + failing_files["$verilog_file"]="VCD generation failure" + fi + else + echo "Yosys failed to process $verilog_file." + failing_files["$verilog_file"]="Yosys failure" + fi +} + +# Main function to run all tests +run_all_tests() { + # Loop through all Verilog files in the verilog directory + for verilog_file in verilog/*.v; do + run_test "$verilog_file" + done + + # Check if the array of failing files is empty + if [ ${#failing_files[@]} -eq 0 ]; then + echo "All files passed." + return 0 + else + echo "The following files failed:" + for file in "${!failing_files[@]}"; do + echo "$file: ${failing_files[$file]}" + done + return 1 + fi +} + +# If the script is being sourced, do not execute the tests +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + run_all_tests +fi diff --git a/tests/functional/single_bit/vcd_harness.cpp b/tests/cxxrtl/vcd_harness.cc similarity index 100% rename from tests/functional/single_bit/vcd_harness.cpp rename to tests/cxxrtl/vcd_harness.cc diff --git a/tests/functional/single_bit/vcd_harness.cc b/tests/functional/single_bit/vcd_harness.cc new file mode 100644 index 00000000000..7e474eea985 --- /dev/null +++ b/tests/functional/single_bit/vcd_harness.cc @@ -0,0 +1,134 @@ +#include +#include +#include +#include + +#include + +#include "my_module_cxxrtl.cc" +#include "my_module_functional_cxx.cc" + +struct DumpHeader { + std::ofstream &ofs; + DumpHeader(std::ofstream &ofs) : ofs(ofs) {} + template + void operator()(const char *name, Signal value) { + ofs << "$var wire " << n << " " << name[0] << " " << name << " $end\n"; + } +}; + +struct Dump { + std::ofstream &ofs; + Dump(std::ofstream &ofs) : ofs(ofs) {} + template + void operator()(const char *name, Signal value) { + // Bit + if (n == 1) { + ofs << (value[0] ? '1' : '0'); + ofs << name[0] << "\n"; + return; + } + // vector (multi-bit) signals + ofs << "b"; + for (size_t i = n; i-- > 0;) + ofs << (value[i] ? '1' : '0'); + ofs << " " << name[0] << "\n"; + } +}; + +int main(int argc, char **argv) +{ + if (argc != 3) { + std::cerr << "Usage: " << argv[0] << " \n"; + return 1; + } + + const std::string functional_vcd_filename = argv[1]; + const std::string cxxrtl_vcd_filename = argv[2]; + + constexpr int steps = 10; + constexpr int number_timescale = 1; + const std::string units_timescale = "us"; + my_module_Inputs inputs; + my_module_Outputs outputs; + my_module_State state; + my_module_State next_state; + + std::ofstream vcd_file(functional_vcd_filename); + + vcd_file << "$timescale " << number_timescale << " " << units_timescale << " $end\n"; + vcd_file << "$scope module my_module $end\n"; + { + DumpHeader d(vcd_file); + inputs.dump(d); + outputs.dump(d); + state.dump(d); + } + vcd_file << "$enddefinitions $end\n$dumpvars\n"; + + cxxrtl_design::p_my__module top; + + cxxrtl::debug_items all_debug_items; + cxxrtl::debug_scope debug_scope; + top.debug_info(&all_debug_items, nullptr, ""); + + cxxrtl::vcd_writer vcd; + vcd.timescale(number_timescale, units_timescale); + vcd.add_without_memories(all_debug_items); + + std::ofstream waves(cxxrtl_vcd_filename); + + top.p_a.set(false); + top.p_b.set(false); + top.step(); + + vcd.sample(0); + vcd_file << "#0\n"; + inputs.a = $const<1>(false); + inputs.b = $const<1>(false); + my_module(inputs, outputs, state, next_state); + { + Dump d(vcd_file); + inputs.dump(d); + outputs.dump(d); + state.dump(d); + } + + std::random_device rd; + std::mt19937 gen(rd()); + std::bernoulli_distribution dist(0.5); + + for (int step = 0; step < steps; ++step) { + const bool a_value = dist(gen); + const bool b_value = dist(gen); + + // cxxrtl + top.p_a.set(a_value); + top.p_b.set(b_value); + top.step(); + vcd.sample(step + 1); + + waves << vcd.buffer; + vcd.buffer.clear(); + + // Functional backend cxx + vcd_file << "#" << (step + 1) << "\n"; + inputs.a = $const<1>(a_value); + inputs.b = $const<1>(b_value); + + my_module(inputs, outputs, state, next_state); + { + Dump d(vcd_file); + inputs.dump(d); + outputs.dump(d); + state.dump(d); + } + + state = next_state; + } + + vcd_file.close(); + waves.close(); + + return 0; +} From 4b5c366bf40afd08d55732836a7afb7bef07ce11 Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Tue, 28 May 2024 12:25:21 +0200 Subject: [PATCH 26/51] Remove cxxrtl from functional backend C++ testing, using yosys sim -sim-cmp instead --- tests/functional/single_bit/run-test.sh | 6 ++-- tests/functional/single_bit/vcd_harness.cc | 36 ++-------------------- 2 files changed, 5 insertions(+), 37 deletions(-) diff --git a/tests/functional/single_bit/run-test.sh b/tests/functional/single_bit/run-test.sh index 2eba8367483..d71a2c90fb8 100755 --- a/tests/functional/single_bit/run-test.sh +++ b/tests/functional/single_bit/run-test.sh @@ -14,14 +14,14 @@ run_test() { local base_name=$(basename "$verilog_file" .v) # Run yosys to process each Verilog file - if ${BASE_PATH}yosys -p "read_verilog $verilog_file; write_cxxrtl my_module_cxxrtl.cc; write_functional_cxx my_module_functional_cxx.cc"; then + if ${BASE_PATH}yosys -p "read_verilog $verilog_file; write_functional_cxx my_module_functional_cxx.cc"; then echo "Yosys processed $verilog_file successfully." # Compile the generated C++ files with vcd_harness.cpp - ${CXX:-g++} -g -fprofile-arcs -ftest-coverage vcd_harness.cpp -I ${BASE_PATH}backends/functional/cxx_runtime/ -I ${BASE_PATH}backends/cxxrtl/runtime/ -o vcd_harness + ${CXX:-g++} -g -fprofile-arcs -ftest-coverage vcd_harness.cc -I ${BASE_PATH}backends/functional/cxx_runtime/ -o vcd_harness # Generate VCD files with base_name - if ./vcd_harness ${base_name}_functional_cxx.vcd ${base_name}_cxxrtl.vcd; then + if ./vcd_harness ${base_name}_functional_cxx.vcd; then # Run yosys to process each Verilog file if ${BASE_PATH}yosys -p "read_verilog $verilog_file; sim -r ${base_name}_functional_cxx.vcd -scope my_module -timescale 1us -sim-cmp"; then diff --git a/tests/functional/single_bit/vcd_harness.cc b/tests/functional/single_bit/vcd_harness.cc index 7e474eea985..2086ef6fdcd 100644 --- a/tests/functional/single_bit/vcd_harness.cc +++ b/tests/functional/single_bit/vcd_harness.cc @@ -3,9 +3,6 @@ #include #include -#include - -#include "my_module_cxxrtl.cc" #include "my_module_functional_cxx.cc" struct DumpHeader { @@ -38,13 +35,12 @@ struct Dump { int main(int argc, char **argv) { - if (argc != 3) { - std::cerr << "Usage: " << argv[0] << " \n"; + if (argc != 2) { + std::cerr << "Usage: " << argv[0] << " \n"; return 1; } const std::string functional_vcd_filename = argv[1]; - const std::string cxxrtl_vcd_filename = argv[2]; constexpr int steps = 10; constexpr int number_timescale = 1; @@ -65,24 +61,6 @@ int main(int argc, char **argv) state.dump(d); } vcd_file << "$enddefinitions $end\n$dumpvars\n"; - - cxxrtl_design::p_my__module top; - - cxxrtl::debug_items all_debug_items; - cxxrtl::debug_scope debug_scope; - top.debug_info(&all_debug_items, nullptr, ""); - - cxxrtl::vcd_writer vcd; - vcd.timescale(number_timescale, units_timescale); - vcd.add_without_memories(all_debug_items); - - std::ofstream waves(cxxrtl_vcd_filename); - - top.p_a.set(false); - top.p_b.set(false); - top.step(); - - vcd.sample(0); vcd_file << "#0\n"; inputs.a = $const<1>(false); inputs.b = $const<1>(false); @@ -102,15 +80,6 @@ int main(int argc, char **argv) const bool a_value = dist(gen); const bool b_value = dist(gen); - // cxxrtl - top.p_a.set(a_value); - top.p_b.set(b_value); - top.step(); - vcd.sample(step + 1); - - waves << vcd.buffer; - vcd.buffer.clear(); - // Functional backend cxx vcd_file << "#" << (step + 1) << "\n"; inputs.a = $const<1>(a_value); @@ -128,7 +97,6 @@ int main(int argc, char **argv) } vcd_file.close(); - waves.close(); return 0; } From 89d9339907424805be1bf89f812741999b7789a3 Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Tue, 28 May 2024 12:32:07 +0200 Subject: [PATCH 27/51] WIP --- tests/functional/multi_bit/run-test.sh | 75 +++++++++++-------- .../{vcd_harness.cpp => vcd_harness.cc} | 41 ++-------- 2 files changed, 48 insertions(+), 68 deletions(-) rename tests/functional/multi_bit/{vcd_harness.cpp => vcd_harness.cc} (72%) diff --git a/tests/functional/multi_bit/run-test.sh b/tests/functional/multi_bit/run-test.sh index 421630d5be5..d71a2c90fb8 100755 --- a/tests/functional/multi_bit/run-test.sh +++ b/tests/functional/multi_bit/run-test.sh @@ -1,38 +1,36 @@ #!/bin/bash -set -ex - -# Define the common variable for the relative path -BASE_PATH="../../../" - # Initialize an array to store the names of failing Verilog files and their failure types declare -A failing_files -# Loop through all Verilog files in the verilog directory -for verilog_file in verilog/*.v; do +# Function to run the test on a given Verilog file +run_test() { + # Define the common variable for the relative path + BASE_PATH="../../../" + + local verilog_file=$1 + # Extract the base name without extension - base_name=$(basename "$verilog_file" .v) + local base_name=$(basename "$verilog_file" .v) # Run yosys to process each Verilog file - if ${BASE_PATH}yosys -p "read_verilog $verilog_file; write_cxxrtl my_module_cxxrtl.cc; write_functional_cxx my_module_functional_cxx.cc"; then + if ${BASE_PATH}yosys -p "read_verilog $verilog_file; write_functional_cxx my_module_functional_cxx.cc"; then echo "Yosys processed $verilog_file successfully." # Compile the generated C++ files with vcd_harness.cpp - ${CXX:-g++} -g -fprofile-arcs -ftest-coverage vcd_harness.cpp -I ${BASE_PATH}backends/functional/cxx_runtime/ -I ${BASE_PATH}backends/cxxrtl/runtime/ -o vcd_harness + ${CXX:-g++} -g -fprofile-arcs -ftest-coverage vcd_harness.cc -I ${BASE_PATH}backends/functional/cxx_runtime/ -o vcd_harness # Generate VCD files with base_name - if ./vcd_harness ${base_name}_functional_cxx.vcd ${base_name}_cxxrtl.vcd ; then - # Run vcdiff and capture the output - output=$(vcdiff ${base_name}_functional_cxx.vcd ${base_name}_cxxrtl.vcd) - - # Check if there is any output - if [ -n "$output" ]; then - echo "Differences detected in $verilog_file:" - echo "$output" - failing_files["$verilog_file"]="Differences detected" - else - echo "No differences detected in $verilog_file." - fi + if ./vcd_harness ${base_name}_functional_cxx.vcd; then + + # Run yosys to process each Verilog file + if ${BASE_PATH}yosys -p "read_verilog $verilog_file; sim -r ${base_name}_functional_cxx.vcd -scope my_module -timescale 1us -sim-cmp"; then + echo "Yosys sim $verilog_file successfully." + else + echo "Yosys simulation of $verilog_file failed. There is a discrepancy with functional cxx" + failing_files["$verilog_file"]="Yosys sim failure" + fi + else echo "Failed to generate VCD files for $verilog_file." failing_files["$verilog_file"]="VCD generation failure" @@ -41,16 +39,29 @@ for verilog_file in verilog/*.v; do echo "Yosys failed to process $verilog_file." failing_files["$verilog_file"]="Yosys failure" fi -done +} -# Check if the array of failing files is empty -if [ ${#failing_files[@]} -eq 0 ]; then - echo "All files passed." - exit 0 -else - echo "The following files failed:" - for file in "${!failing_files[@]}"; do - echo "$file: ${failing_files[$file]}" +# Main function to run all tests +run_all_tests() { + # Loop through all Verilog files in the verilog directory + for verilog_file in verilog/*.v; do + run_test "$verilog_file" done - exit 1 + + # Check if the array of failing files is empty + if [ ${#failing_files[@]} -eq 0 ]; then + echo "All files passed." + return 0 + else + echo "The following files failed:" + for file in "${!failing_files[@]}"; do + echo "$file: ${failing_files[$file]}" + done + return 1 + fi +} + +# If the script is being sourced, do not execute the tests +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + run_all_tests fi diff --git a/tests/functional/multi_bit/vcd_harness.cpp b/tests/functional/multi_bit/vcd_harness.cc similarity index 72% rename from tests/functional/multi_bit/vcd_harness.cpp rename to tests/functional/multi_bit/vcd_harness.cc index bb8cca6fc8d..8c7e0ed4c96 100644 --- a/tests/functional/multi_bit/vcd_harness.cpp +++ b/tests/functional/multi_bit/vcd_harness.cc @@ -3,9 +3,6 @@ #include #include -#include - -#include "my_module_cxxrtl.cc" #include "my_module_functional_cxx.cc" struct DumpHeader { @@ -38,13 +35,12 @@ struct Dump { int main(int argc, char **argv) { - if (argc != 3) { - std::cerr << "Usage: " << argv[0] << " \n"; + if (argc != 2) { + std::cerr << "Usage: " << argv[0] << " \n"; return 1; } const std::string functional_vcd_filename = argv[1]; - const std::string cxxrtl_vcd_filename = argv[2]; constexpr int steps = 10; constexpr int number_timescale = 1; @@ -57,6 +53,7 @@ int main(int argc, char **argv) std::ofstream vcd_file(functional_vcd_filename); vcd_file << "$timescale " << number_timescale << " " << units_timescale << " $end\n"; + vcd_file << "$scope module my_module $end\n"; { DumpHeader d(vcd_file); inputs.dump(d); @@ -64,24 +61,6 @@ int main(int argc, char **argv) state.dump(d); } vcd_file << "$enddefinitions $end\n$dumpvars\n"; - - cxxrtl_design::p_my__module top; - - cxxrtl::debug_items all_debug_items; - cxxrtl::debug_scope debug_scope; - top.debug_info(&all_debug_items, nullptr, ""); - - cxxrtl::vcd_writer vcd; - vcd.timescale(number_timescale, units_timescale); - vcd.add_without_memories(all_debug_items); - - std::ofstream waves(cxxrtl_vcd_filename); - - top.p_a.set<8>(false); - top.p_b.set<8>(false); - top.step(); - - vcd.sample(0); vcd_file << "#0\n"; inputs.a = $const<8>(false); inputs.b = $const<8>(false); @@ -101,19 +80,10 @@ int main(int argc, char **argv) const bool a_value = dist(gen); const bool b_value = dist(gen); - // cxxrtl - top.p_a.set(a_value); - top.p_b.set(b_value); - top.step(); - vcd.sample(step + 1); - - waves << vcd.buffer; - vcd.buffer.clear(); - // Functional backend cxx vcd_file << "#" << (step + 1) << "\n"; - inputs.a = $const<8>(a_value); - inputs.b = $const<8>(b_value); + inputs.a = $const<1>(a_value); + inputs.b = $const<1>(b_value); my_module(inputs, outputs, state, next_state); { @@ -127,7 +97,6 @@ int main(int argc, char **argv) } vcd_file.close(); - waves.close(); return 0; } From ec6c48b75d3cf57234b6ac62cf93a5c4fbaa5e71 Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Tue, 28 May 2024 12:42:59 +0200 Subject: [PATCH 28/51] Multi bit testing infrastructure works --- tests/functional/multi_bit/vcd_harness.cc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/functional/multi_bit/vcd_harness.cc b/tests/functional/multi_bit/vcd_harness.cc index 8c7e0ed4c96..901e8de1f78 100644 --- a/tests/functional/multi_bit/vcd_harness.cc +++ b/tests/functional/multi_bit/vcd_harness.cc @@ -2,6 +2,7 @@ #include #include #include +#include #include "my_module_functional_cxx.cc" @@ -74,16 +75,16 @@ int main(int argc, char **argv) std::random_device rd; std::mt19937 gen(rd()); - std::bernoulli_distribution dist(0.5); + std::uniform_int_distribution dist(0, 255); for (int step = 0; step < steps; ++step) { - const bool a_value = dist(gen); - const bool b_value = dist(gen); + const uint8_t a_value = dist(gen); + const uint8_t b_value = dist(gen); // Functional backend cxx vcd_file << "#" << (step + 1) << "\n"; - inputs.a = $const<1>(a_value); - inputs.b = $const<1>(b_value); + inputs.a = $const<8>(a_value); + inputs.b = $const<8>(b_value); my_module(inputs, outputs, state, next_state); { From f64c19bcd22eb7a3d9f4f76182a49b760afdb936 Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Tue, 28 May 2024 12:54:46 +0200 Subject: [PATCH 29/51] Change permissions of verilog files --- tests/functional/single_bit/verilog/my_module_div.v | 0 tests/functional/single_bit/verilog/my_module_eqx.v | 0 tests/functional/single_bit/verilog/my_module_ge.v | 0 tests/functional/single_bit/verilog/my_module_gt.v | 0 tests/functional/single_bit/verilog/my_module_le.v | 0 tests/functional/single_bit/verilog/my_module_logic_and.v | 0 tests/functional/single_bit/verilog/my_module_logic_or.v | 0 tests/functional/single_bit/verilog/my_module_lt.v | 0 tests/functional/single_bit/verilog/my_module_mod.v | 0 tests/functional/single_bit/verilog/my_module_mul.v | 0 tests/functional/single_bit/verilog/my_module_ne.v | 0 tests/functional/single_bit/verilog/my_module_nex.v | 0 tests/functional/single_bit/verilog/my_module_or.v | 0 tests/functional/single_bit/verilog/my_module_pow.v | 0 tests/functional/single_bit/verilog/my_module_shl.v | 0 tests/functional/single_bit/verilog/my_module_shr.v | 0 tests/functional/single_bit/verilog/my_module_sshl.v | 0 tests/functional/single_bit/verilog/my_module_sshr.v | 0 tests/functional/single_bit/verilog/my_module_sub.v | 0 tests/functional/single_bit/verilog/my_module_xnor.v | 0 tests/functional/single_bit/verilog/my_module_xor.v | 0 21 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 tests/functional/single_bit/verilog/my_module_div.v mode change 100755 => 100644 tests/functional/single_bit/verilog/my_module_eqx.v mode change 100755 => 100644 tests/functional/single_bit/verilog/my_module_ge.v mode change 100755 => 100644 tests/functional/single_bit/verilog/my_module_gt.v mode change 100755 => 100644 tests/functional/single_bit/verilog/my_module_le.v mode change 100755 => 100644 tests/functional/single_bit/verilog/my_module_logic_and.v mode change 100755 => 100644 tests/functional/single_bit/verilog/my_module_logic_or.v mode change 100755 => 100644 tests/functional/single_bit/verilog/my_module_lt.v mode change 100755 => 100644 tests/functional/single_bit/verilog/my_module_mod.v mode change 100755 => 100644 tests/functional/single_bit/verilog/my_module_mul.v mode change 100755 => 100644 tests/functional/single_bit/verilog/my_module_ne.v mode change 100755 => 100644 tests/functional/single_bit/verilog/my_module_nex.v mode change 100755 => 100644 tests/functional/single_bit/verilog/my_module_or.v mode change 100755 => 100644 tests/functional/single_bit/verilog/my_module_pow.v mode change 100755 => 100644 tests/functional/single_bit/verilog/my_module_shl.v mode change 100755 => 100644 tests/functional/single_bit/verilog/my_module_shr.v mode change 100755 => 100644 tests/functional/single_bit/verilog/my_module_sshl.v mode change 100755 => 100644 tests/functional/single_bit/verilog/my_module_sshr.v mode change 100755 => 100644 tests/functional/single_bit/verilog/my_module_sub.v mode change 100755 => 100644 tests/functional/single_bit/verilog/my_module_xnor.v mode change 100755 => 100644 tests/functional/single_bit/verilog/my_module_xor.v diff --git a/tests/functional/single_bit/verilog/my_module_div.v b/tests/functional/single_bit/verilog/my_module_div.v old mode 100755 new mode 100644 diff --git a/tests/functional/single_bit/verilog/my_module_eqx.v b/tests/functional/single_bit/verilog/my_module_eqx.v old mode 100755 new mode 100644 diff --git a/tests/functional/single_bit/verilog/my_module_ge.v b/tests/functional/single_bit/verilog/my_module_ge.v old mode 100755 new mode 100644 diff --git a/tests/functional/single_bit/verilog/my_module_gt.v b/tests/functional/single_bit/verilog/my_module_gt.v old mode 100755 new mode 100644 diff --git a/tests/functional/single_bit/verilog/my_module_le.v b/tests/functional/single_bit/verilog/my_module_le.v old mode 100755 new mode 100644 diff --git a/tests/functional/single_bit/verilog/my_module_logic_and.v b/tests/functional/single_bit/verilog/my_module_logic_and.v old mode 100755 new mode 100644 diff --git a/tests/functional/single_bit/verilog/my_module_logic_or.v b/tests/functional/single_bit/verilog/my_module_logic_or.v old mode 100755 new mode 100644 diff --git a/tests/functional/single_bit/verilog/my_module_lt.v b/tests/functional/single_bit/verilog/my_module_lt.v old mode 100755 new mode 100644 diff --git a/tests/functional/single_bit/verilog/my_module_mod.v b/tests/functional/single_bit/verilog/my_module_mod.v old mode 100755 new mode 100644 diff --git a/tests/functional/single_bit/verilog/my_module_mul.v b/tests/functional/single_bit/verilog/my_module_mul.v old mode 100755 new mode 100644 diff --git a/tests/functional/single_bit/verilog/my_module_ne.v b/tests/functional/single_bit/verilog/my_module_ne.v old mode 100755 new mode 100644 diff --git a/tests/functional/single_bit/verilog/my_module_nex.v b/tests/functional/single_bit/verilog/my_module_nex.v old mode 100755 new mode 100644 diff --git a/tests/functional/single_bit/verilog/my_module_or.v b/tests/functional/single_bit/verilog/my_module_or.v old mode 100755 new mode 100644 diff --git a/tests/functional/single_bit/verilog/my_module_pow.v b/tests/functional/single_bit/verilog/my_module_pow.v old mode 100755 new mode 100644 diff --git a/tests/functional/single_bit/verilog/my_module_shl.v b/tests/functional/single_bit/verilog/my_module_shl.v old mode 100755 new mode 100644 diff --git a/tests/functional/single_bit/verilog/my_module_shr.v b/tests/functional/single_bit/verilog/my_module_shr.v old mode 100755 new mode 100644 diff --git a/tests/functional/single_bit/verilog/my_module_sshl.v b/tests/functional/single_bit/verilog/my_module_sshl.v old mode 100755 new mode 100644 diff --git a/tests/functional/single_bit/verilog/my_module_sshr.v b/tests/functional/single_bit/verilog/my_module_sshr.v old mode 100755 new mode 100644 diff --git a/tests/functional/single_bit/verilog/my_module_sub.v b/tests/functional/single_bit/verilog/my_module_sub.v old mode 100755 new mode 100644 diff --git a/tests/functional/single_bit/verilog/my_module_xnor.v b/tests/functional/single_bit/verilog/my_module_xnor.v old mode 100755 new mode 100644 diff --git a/tests/functional/single_bit/verilog/my_module_xor.v b/tests/functional/single_bit/verilog/my_module_xor.v old mode 100755 new mode 100644 From c0b8e6c90c287c6b22beb8ca9004411a43b8963a Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Tue, 28 May 2024 12:55:44 +0200 Subject: [PATCH 30/51] Rename verilog files for consistency --- tests/functional/single_bit/verilog/{add.v => my_module_add.v} | 0 tests/functional/single_bit/verilog/{and.v => my_module_and.v} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename tests/functional/single_bit/verilog/{add.v => my_module_add.v} (100%) rename tests/functional/single_bit/verilog/{and.v => my_module_and.v} (100%) diff --git a/tests/functional/single_bit/verilog/add.v b/tests/functional/single_bit/verilog/my_module_add.v similarity index 100% rename from tests/functional/single_bit/verilog/add.v rename to tests/functional/single_bit/verilog/my_module_add.v diff --git a/tests/functional/single_bit/verilog/and.v b/tests/functional/single_bit/verilog/my_module_and.v similarity index 100% rename from tests/functional/single_bit/verilog/and.v rename to tests/functional/single_bit/verilog/my_module_and.v From 37d7175252ac6f3e908fe7c45d51e24d49b3ce5b Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Tue, 28 May 2024 12:56:08 +0200 Subject: [PATCH 31/51] Rename verilog files for consistency --- tests/functional/multi_bit/verilog/{and.v => my_module_and.v} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/functional/multi_bit/verilog/{and.v => my_module_and.v} (100%) diff --git a/tests/functional/multi_bit/verilog/and.v b/tests/functional/multi_bit/verilog/my_module_and.v similarity index 100% rename from tests/functional/multi_bit/verilog/and.v rename to tests/functional/multi_bit/verilog/my_module_and.v From 94171a46c66ee224dbc3f15d87305c280ff315c1 Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Tue, 28 May 2024 13:22:32 +0200 Subject: [PATCH 32/51] Add some 8 bit tests for functional C++ backend --- tests/functional/multi_bit/verilog/my_module_add.v | 9 +++++++++ tests/functional/multi_bit/verilog/my_module_div.v | 9 +++++++++ tests/functional/multi_bit/verilog/my_module_logic_and.v | 9 +++++++++ tests/functional/multi_bit/verilog/my_module_logic_or.v | 9 +++++++++ tests/functional/multi_bit/verilog/my_module_mod.v | 9 +++++++++ tests/functional/multi_bit/verilog/my_module_mul.v | 9 +++++++++ tests/functional/multi_bit/verilog/my_module_or.v | 9 +++++++++ tests/functional/multi_bit/verilog/my_module_sub.v | 9 +++++++++ tests/functional/multi_bit/verilog/my_module_xor.v | 9 +++++++++ 9 files changed, 81 insertions(+) create mode 100644 tests/functional/multi_bit/verilog/my_module_add.v create mode 100644 tests/functional/multi_bit/verilog/my_module_div.v create mode 100644 tests/functional/multi_bit/verilog/my_module_logic_and.v create mode 100644 tests/functional/multi_bit/verilog/my_module_logic_or.v create mode 100644 tests/functional/multi_bit/verilog/my_module_mod.v create mode 100644 tests/functional/multi_bit/verilog/my_module_mul.v create mode 100644 tests/functional/multi_bit/verilog/my_module_or.v create mode 100644 tests/functional/multi_bit/verilog/my_module_sub.v create mode 100644 tests/functional/multi_bit/verilog/my_module_xor.v diff --git a/tests/functional/multi_bit/verilog/my_module_add.v b/tests/functional/multi_bit/verilog/my_module_add.v new file mode 100644 index 00000000000..b9c42165a16 --- /dev/null +++ b/tests/functional/multi_bit/verilog/my_module_add.v @@ -0,0 +1,9 @@ +module my_module( + input [7:0] a, + input [7:0] b, + output [7:0] y +); + // Perform operation + assign y = a + b; + +endmodule diff --git a/tests/functional/multi_bit/verilog/my_module_div.v b/tests/functional/multi_bit/verilog/my_module_div.v new file mode 100644 index 00000000000..9d36fd3d7c3 --- /dev/null +++ b/tests/functional/multi_bit/verilog/my_module_div.v @@ -0,0 +1,9 @@ +module my_module( + input [7:0] a, + input [7:0] b, + output [7:0] y +); + // Perform operation + assign y = a / b; + +endmodule diff --git a/tests/functional/multi_bit/verilog/my_module_logic_and.v b/tests/functional/multi_bit/verilog/my_module_logic_and.v new file mode 100644 index 00000000000..3c5245c9c15 --- /dev/null +++ b/tests/functional/multi_bit/verilog/my_module_logic_and.v @@ -0,0 +1,9 @@ +module my_module( + input [7:0] a, + input [7:0] b, + output [7:0] y +); + // Perform operation + assign y = a && b; + +endmodule diff --git a/tests/functional/multi_bit/verilog/my_module_logic_or.v b/tests/functional/multi_bit/verilog/my_module_logic_or.v new file mode 100644 index 00000000000..679babd9b2c --- /dev/null +++ b/tests/functional/multi_bit/verilog/my_module_logic_or.v @@ -0,0 +1,9 @@ +module my_module( + input [7:0] a, + input [7:0] b, + output [7:0] y +); + // Perform operation + assign y = a || b; + +endmodule diff --git a/tests/functional/multi_bit/verilog/my_module_mod.v b/tests/functional/multi_bit/verilog/my_module_mod.v new file mode 100644 index 00000000000..7a0b5705c6e --- /dev/null +++ b/tests/functional/multi_bit/verilog/my_module_mod.v @@ -0,0 +1,9 @@ +module my_module( + input [7:0] a, + input [7:0] b, + output [7:0] y +); + // Perform operation + assign y = a % b; + +endmodule diff --git a/tests/functional/multi_bit/verilog/my_module_mul.v b/tests/functional/multi_bit/verilog/my_module_mul.v new file mode 100644 index 00000000000..8244f4a8ec8 --- /dev/null +++ b/tests/functional/multi_bit/verilog/my_module_mul.v @@ -0,0 +1,9 @@ +module my_module( + input [7:0] a, + input [7:0] b, + output [7:0] y +); + // Perform operation + assign y = a * b; + +endmodule diff --git a/tests/functional/multi_bit/verilog/my_module_or.v b/tests/functional/multi_bit/verilog/my_module_or.v new file mode 100644 index 00000000000..f8b459af70b --- /dev/null +++ b/tests/functional/multi_bit/verilog/my_module_or.v @@ -0,0 +1,9 @@ +module my_module( + input [7:0] a, + input [7:0] b, + output [7:0] y +); + // Perform operation + assign y = a | b; + +endmodule diff --git a/tests/functional/multi_bit/verilog/my_module_sub.v b/tests/functional/multi_bit/verilog/my_module_sub.v new file mode 100644 index 00000000000..0c5b52073dd --- /dev/null +++ b/tests/functional/multi_bit/verilog/my_module_sub.v @@ -0,0 +1,9 @@ +module my_module( + input [7:0] a, + input [7:0] b, + output [7:0] y +); + // Perform operation + assign y = a - b; + +endmodule diff --git a/tests/functional/multi_bit/verilog/my_module_xor.v b/tests/functional/multi_bit/verilog/my_module_xor.v new file mode 100644 index 00000000000..4d7ab43890f --- /dev/null +++ b/tests/functional/multi_bit/verilog/my_module_xor.v @@ -0,0 +1,9 @@ +module my_module( + input [7:0] a, + input [7:0] b, + output [7:0] y +); + // Perform operation + assign y = a ^ b; + +endmodule From 1ce9a9795091db09b8358413f5b99445c2f154e3 Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Tue, 28 May 2024 14:56:16 +0200 Subject: [PATCH 33/51] Initial, failing implementation of div and mod cells --- backends/functional/cxx.cc | 2 ++ backends/functional/cxx_runtime/sim.h | 30 +++++++++++++++++++++++++ backends/functional/smtlib.cc | 2 ++ kernel/graphtools.h | 12 ++++++++++ tests/functional/single_bit/run-test.sh | 3 ++- 5 files changed, 48 insertions(+), 1 deletion(-) diff --git a/backends/functional/cxx.cc b/backends/functional/cxx.cc index a4153035dad..f0ceb5d76d4 100644 --- a/backends/functional/cxx.cc +++ b/backends/functional/cxx.cc @@ -190,6 +190,8 @@ class CxxComputeGraphFactory { T logical_shift_right(T a, T b, int y_width, int) { return graph.add(CxxFunction(ID($shr), y_width, {{ID(WIDTH), y_width}}), 0, std::array{a, b}); } T arithmetic_shift_right(T a, T b, int y_width, int) { return graph.add(CxxFunction(ID($asr), y_width, {{ID(WIDTH), y_width}}), 0, std::array{a, b}); } T mul(T a, T b, int width) { return graph.add(CxxFunction(ID($mul), width), 0, std::array{a, b}); } + T mod(T a, T b, int width) { return graph.add(CxxFunction(ID($mod), width), 0, std::array{a, b}); } + T div(T a, T b, int width) { return graph.add(CxxFunction(ID($div), width), 0, std::array{a, b}); } T constant(RTLIL::Const value) { return graph.add(CxxFunction(ID($$const), value.size(), {{ID(value), value}}), 0); diff --git a/backends/functional/cxx_runtime/sim.h b/backends/functional/cxx_runtime/sim.h index 0cbbe9831a1..e6e1c2f953a 100644 --- a/backends/functional/cxx_runtime/sim.h +++ b/backends/functional/cxx_runtime/sim.h @@ -379,4 +379,34 @@ Signal $mul(Signal const& a, Signal const& b) return ret; } +template +Signal $div(Signal const& a, Signal const& b) +{ + Signal quotient = $const(0); + Signal remainder = a; + Signal divisor = b; + + for(int i = n - 1; i >= 0; i--) { + if(as_int(remainder) >= (as_int(divisor) << i)) { + remainder = $sub(remainder, $shl(divisor, $const(i))); + quotient[i] = true; + } + } + return quotient; +} + +template +Signal $mod(Signal const& a, Signal const& b) +{ + Signal remainder = a; + Signal divisor = b; + + for(int i = n - 1; i >= 0; i--) { + if(as_int(remainder) >= (as_int(divisor) << i)) { + remainder = $sub(remainder, $shl(divisor, $const(i))); + } + } + return remainder; +} + #endif diff --git a/backends/functional/smtlib.cc b/backends/functional/smtlib.cc index 2811d0bea7e..30883577215 100644 --- a/backends/functional/smtlib.cc +++ b/backends/functional/smtlib.cc @@ -368,6 +368,8 @@ class SmtlibComputeGraphFactory { T logical_shift_right(T a, T b, int y_width, int b_width) { return shift("bvlshl", a, b, y_width, b_width); } T arithmetic_shift_right(T a, T b, int y_width, int b_width) { return shift("bvashr", a, b, y_width, b_width, true); } T mul(T a, T b, int width) { return node(SExpr {"bvmul", Arg(1), Arg(2)}, width, {a, b}); } + T div(T a, T b, int width) { return node(SExpr {"bvudiv", Arg(1), Arg(2)}, width, {a, b}); } + T mod(T a, T b, int width) { return node(SExpr {"bvurem", Arg(1), Arg(2)}, width, {a, b}); } T constant(RTLIL::Const value) { return node(SExpr(value), value.size(), {}); } T input(IdString name, int width) { diff --git a/kernel/graphtools.h b/kernel/graphtools.h index 1c6b927739d..907a2b1cf4a 100644 --- a/kernel/graphtools.h +++ b/kernel/graphtools.h @@ -189,6 +189,18 @@ class CellSimplifier { T a = extend(inputs.at(ID(A)), a_width, width, is_signed); T b = extend(inputs.at(ID(B)), b_width, width, is_signed); return extend(factory.mul(a, b, width), width, y_width, is_signed); + }else if(cellType == ID($div)){ + bool is_signed = a_signed && b_signed; + int width = max(a_width, b_width); + T a = extend(inputs.at(ID(A)), a_width, width, is_signed); + T b = extend(inputs.at(ID(B)), b_width, width, is_signed); + return extend(factory.div(a, b, width), width, y_width, is_signed); + }else if(cellType == ID($mod)){ + bool is_signed = a_signed && b_signed; + int width = max(a_width, b_width); + T a = extend(inputs.at(ID(A)), a_width, width, is_signed); + T b = extend(inputs.at(ID(B)), b_width, width, is_signed); + return extend(factory.mod(a, b, width), width, y_width, is_signed); }else{ log_error("unhandled cell in CellSimplifier %s\n", cellType.c_str()); } diff --git a/tests/functional/single_bit/run-test.sh b/tests/functional/single_bit/run-test.sh index d71a2c90fb8..7fe74cc47d4 100755 --- a/tests/functional/single_bit/run-test.sh +++ b/tests/functional/single_bit/run-test.sh @@ -24,7 +24,8 @@ run_test() { if ./vcd_harness ${base_name}_functional_cxx.vcd; then # Run yosys to process each Verilog file - if ${BASE_PATH}yosys -p "read_verilog $verilog_file; sim -r ${base_name}_functional_cxx.vcd -scope my_module -timescale 1us -sim-cmp"; then + if ${BASE_PATH}yosys -p "read_verilog $verilog_file; sim -r ${base_name}_functional_cxx.vcd -scope my_module -vcd ${base_name}_yosys_sim.vcd -timescale 1us -sim-cmp"; then + # ${BASE_PATH}yosys -p "read_verilog $verilog_file; sim -vcd ${base_name}_yosys_sim.vcd -r ${base_name}_functional_cxx.vcd -scope my_module -timescale 1us" echo "Yosys sim $verilog_file successfully." else echo "Yosys simulation of $verilog_file failed. There is a discrepancy with functional cxx" From cdf4b1ffc91abd73b22ff539fcec786b8927ebca Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Tue, 28 May 2024 14:59:49 +0200 Subject: [PATCH 34/51] Added Functional backend C++ tests to make test --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index a4c8680b8c8..544f91128ff 100644 --- a/Makefile +++ b/Makefile @@ -849,6 +849,8 @@ endif +cd tests/xprop && bash run-test.sh $(SEEDOPT) +cd tests/fmt && bash run-test.sh +cd tests/cxxrtl && bash run-test.sh + +cd tests/functional/single_bit && bash run-test.sh + +cd tests/functional/multi_bit && bash run-test.sh @echo "" @echo " Passed \"make test\"." @echo "" From b8dc9c546434cd727c771e1f93be14e8909209a3 Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Tue, 28 May 2024 19:36:03 +0200 Subject: [PATCH 35/51] Create vcd file from sim if -sim-cmp fails --- tests/functional/single_bit/run-test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functional/single_bit/run-test.sh b/tests/functional/single_bit/run-test.sh index 7fe74cc47d4..685dc7a4691 100755 --- a/tests/functional/single_bit/run-test.sh +++ b/tests/functional/single_bit/run-test.sh @@ -25,9 +25,9 @@ run_test() { # Run yosys to process each Verilog file if ${BASE_PATH}yosys -p "read_verilog $verilog_file; sim -r ${base_name}_functional_cxx.vcd -scope my_module -vcd ${base_name}_yosys_sim.vcd -timescale 1us -sim-cmp"; then - # ${BASE_PATH}yosys -p "read_verilog $verilog_file; sim -vcd ${base_name}_yosys_sim.vcd -r ${base_name}_functional_cxx.vcd -scope my_module -timescale 1us" echo "Yosys sim $verilog_file successfully." else + ${BASE_PATH}yosys -p "read_verilog $verilog_file; sim -vcd ${base_name}_yosys_sim.vcd -r ${base_name}_functional_cxx.vcd -scope my_module -timescale 1us" echo "Yosys simulation of $verilog_file failed. There is a discrepancy with functional cxx" failing_files["$verilog_file"]="Yosys sim failure" fi From 54536afb158d661053e4b1845b0e978d6732d106 Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Tue, 28 May 2024 23:15:03 +0200 Subject: [PATCH 36/51] Remove coverage --- dsn | 204 + flake.nix | 2 +- .../vcd_harness.info => sim.vcd | 0 test_and.v | 108 + tests/functional/coverage_report/amber.png | Bin 141 -> 0 bytes tests/functional/coverage_report/emerald.png | Bin 141 -> 0 bytes .../functional/and_cxxrtl.cc.func-sort-c.html | 100 - .../functional/and_cxxrtl.cc.func.html | 100 - .../functional/and_cxxrtl.cc.gcov.html | 161 - .../and_functional_cxx.cc.func-sort-c.html | 84 - .../and_functional_cxx.cc.func.html | 84 - .../and_functional_cxx.cc.gcov.html | 108 - .../functional/index-sort-f.html | 113 - .../functional/index-sort-l.html | 113 - .../coverage_report/functional/index.html | 113 - .../vcd_harness.cpp.func-sort-c.html | 84 - .../functional/vcd_harness.cpp.func.html | 84 - .../functional/vcd_harness.cpp.gcov.html | 216 - tests/functional/coverage_report/gcov.css | 519 - tests/functional/coverage_report/glass.png | Bin 167 -> 0 bytes .../runtime/cxxrtl/cxxrtl.h.func-sort-c.html | 108 - .../cxxrtl/runtime/cxxrtl/cxxrtl.h.func.html | 108 - .../cxxrtl/runtime/cxxrtl/cxxrtl.h.gcov.html | 2182 ---- .../cxxrtl/cxxrtl_vcd.h.func-sort-c.html | 136 - .../runtime/cxxrtl/cxxrtl_vcd.h.func.html | 136 - .../runtime/cxxrtl/cxxrtl_vcd.h.gcov.html | 351 - .../cxxrtl/runtime/cxxrtl/index-sort-f.html | 103 - .../cxxrtl/runtime/cxxrtl/index-sort-l.html | 103 - .../backends/cxxrtl/runtime/cxxrtl/index.html | 103 - .../functional/cxx_runtime/index-sort-f.html | 93 - .../functional/cxx_runtime/index-sort-l.html | 93 - .../functional/cxx_runtime/index.html | 93 - .../cxx_runtime/sim.h.func-sort-c.html | 72 - .../functional/cxx_runtime/sim.h.func.html | 72 - .../functional/cxx_runtime/sim.h.gcov.html | 444 - .../functional/and_cxxrtl.cc.func-sort-c.html | 100 - .../tests/functional/and_cxxrtl.cc.func.html | 100 - .../tests/functional/and_cxxrtl.cc.gcov.html | 161 - .../and_functional_cxx.cc.func-sort-c.html | 84 - .../and_functional_cxx.cc.func.html | 84 - .../and_functional_cxx.cc.gcov.html | 108 - .../tests/functional/index-sort-f.html | 113 - .../tests/functional/index-sort-l.html | 113 - .../my_yosys/tests/functional/index.html | 113 - .../vcd_harness.cpp.func-sort-c.html | 84 - .../functional/vcd_harness.cpp.func.html | 84 - .../functional/vcd_harness.cpp.gcov.html | 216 - .../coverage_report/index-sort-f.html | 93 - .../coverage_report/index-sort-l.html | 93 - tests/functional/coverage_report/index.html | 93 - .../include/bits/string_fortified.h.gcov.html | 54 - tests/functional/coverage_report/ruby.png | Bin 141 -> 0 bytes tests/functional/coverage_report/snow.png | Bin 141 -> 0 bytes tests/functional/coverage_report/updown.png | Bin 117 -> 0 bytes tests/functional/smt/and.smt2 | 23 + tests/functional/smt/test_smt.rkt | 22 + vvp.vcd | 10489 ++++++++++++++++ 57 files changed, 10847 insertions(+), 7770 deletions(-) create mode 100755 dsn rename tests/functional/coverage_report/vcd_harness.info => sim.vcd (100%) create mode 100644 test_and.v delete mode 100644 tests/functional/coverage_report/amber.png delete mode 100644 tests/functional/coverage_report/emerald.png delete mode 100644 tests/functional/coverage_report/functional/and_cxxrtl.cc.func-sort-c.html delete mode 100644 tests/functional/coverage_report/functional/and_cxxrtl.cc.func.html delete mode 100644 tests/functional/coverage_report/functional/and_cxxrtl.cc.gcov.html delete mode 100644 tests/functional/coverage_report/functional/and_functional_cxx.cc.func-sort-c.html delete mode 100644 tests/functional/coverage_report/functional/and_functional_cxx.cc.func.html delete mode 100644 tests/functional/coverage_report/functional/and_functional_cxx.cc.gcov.html delete mode 100644 tests/functional/coverage_report/functional/index-sort-f.html delete mode 100644 tests/functional/coverage_report/functional/index-sort-l.html delete mode 100644 tests/functional/coverage_report/functional/index.html delete mode 100644 tests/functional/coverage_report/functional/vcd_harness.cpp.func-sort-c.html delete mode 100644 tests/functional/coverage_report/functional/vcd_harness.cpp.func.html delete mode 100644 tests/functional/coverage_report/functional/vcd_harness.cpp.gcov.html delete mode 100644 tests/functional/coverage_report/gcov.css delete mode 100644 tests/functional/coverage_report/glass.png delete mode 100644 tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h.func-sort-c.html delete mode 100644 tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h.func.html delete mode 100644 tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h.gcov.html delete mode 100644 tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl_vcd.h.func-sort-c.html delete mode 100644 tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl_vcd.h.func.html delete mode 100644 tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl_vcd.h.gcov.html delete mode 100644 tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/index-sort-f.html delete mode 100644 tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/index-sort-l.html delete mode 100644 tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/index.html delete mode 100644 tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/index-sort-f.html delete mode 100644 tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/index-sort-l.html delete mode 100644 tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/index.html delete mode 100644 tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/sim.h.func-sort-c.html delete mode 100644 tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/sim.h.func.html delete mode 100644 tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/sim.h.gcov.html delete mode 100644 tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_cxxrtl.cc.func-sort-c.html delete mode 100644 tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_cxxrtl.cc.func.html delete mode 100644 tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_cxxrtl.cc.gcov.html delete mode 100644 tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_functional_cxx.cc.func-sort-c.html delete mode 100644 tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_functional_cxx.cc.func.html delete mode 100644 tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_functional_cxx.cc.gcov.html delete mode 100644 tests/functional/coverage_report/home/roland/my_yosys/tests/functional/index-sort-f.html delete mode 100644 tests/functional/coverage_report/home/roland/my_yosys/tests/functional/index-sort-l.html delete mode 100644 tests/functional/coverage_report/home/roland/my_yosys/tests/functional/index.html delete mode 100644 tests/functional/coverage_report/home/roland/my_yosys/tests/functional/vcd_harness.cpp.func-sort-c.html delete mode 100644 tests/functional/coverage_report/home/roland/my_yosys/tests/functional/vcd_harness.cpp.func.html delete mode 100644 tests/functional/coverage_report/home/roland/my_yosys/tests/functional/vcd_harness.cpp.gcov.html delete mode 100644 tests/functional/coverage_report/index-sort-f.html delete mode 100644 tests/functional/coverage_report/index-sort-l.html delete mode 100644 tests/functional/coverage_report/index.html delete mode 100644 tests/functional/coverage_report/nix/store/B0S2LKF593R3585038WS4JD3LYLF2WDX-glibc-2.38-44-dev/include/bits/string_fortified.h.gcov.html delete mode 100644 tests/functional/coverage_report/ruby.png delete mode 100644 tests/functional/coverage_report/snow.png delete mode 100644 tests/functional/coverage_report/updown.png create mode 100644 tests/functional/smt/and.smt2 create mode 100644 tests/functional/smt/test_smt.rkt create mode 100644 vvp.vcd diff --git a/dsn b/dsn new file mode 100755 index 00000000000..cb44c419cb6 --- /dev/null +++ b/dsn @@ -0,0 +1,204 @@ +#! /nix/store/7f3kcbzgv0m5nk1z24lg38127yg4r90k-iverilog-12.0/bin/vvp +:ivl_version "12.0 (stable)"; +:ivl_delay_selection "TYPICAL"; +:vpi_time_precision + 0; +:vpi_module "/nix/store/7f3kcbzgv0m5nk1z24lg38127yg4r90k-iverilog-12.0/lib/ivl/system.vpi"; +:vpi_module "/nix/store/7f3kcbzgv0m5nk1z24lg38127yg4r90k-iverilog-12.0/lib/ivl/vhdl_sys.vpi"; +:vpi_module "/nix/store/7f3kcbzgv0m5nk1z24lg38127yg4r90k-iverilog-12.0/lib/ivl/vhdl_textio.vpi"; +:vpi_module "/nix/store/7f3kcbzgv0m5nk1z24lg38127yg4r90k-iverilog-12.0/lib/ivl/v2005_math.vpi"; +:vpi_module "/nix/store/7f3kcbzgv0m5nk1z24lg38127yg4r90k-iverilog-12.0/lib/ivl/va_math.vpi"; +S_0x703640 .scope module, "testbench" "testbench" 2 4; + .timescale 0 0; +v0x74c7f0_0 .var/i "file", 31 0; +v0x74c8d0_0 .var "filename", 1023 0; +v0x74c9b0_0 .var/i "i", 31 0; +v0x74ca70_0 .var "sig_my_module_a", 0 0; +v0x74cb60_0 .var "sig_my_module_b", 0 0; +v0x74cc50_0 .net "sig_my_module_y", 0 0, L_0x74d160; 1 drivers +v0x74cd20_0 .var "xorshift128_t", 31 0; +v0x74cde0_0 .var "xorshift128_w", 31 0; +v0x74cec0_0 .var "xorshift128_x", 31 0; +v0x74cfa0_0 .var "xorshift128_y", 31 0; +v0x74d080_0 .var "xorshift128_z", 31 0; +S_0x6efef0 .scope task, "my_module_print_header" "my_module_print_header" 2 69, 2 69 0, S_0x703640; + .timescale 0 0; +TD_testbench.my_module_print_header ; + %vpi_call 2 71 "$fdisplay", v0x74c7f0_0, "#OUT#" {0 0 0}; + %vpi_call 2 72 "$fdisplay", v0x74c7f0_0, "#OUT# A sig_my_module_a" {0 0 0}; + %vpi_call 2 73 "$fdisplay", v0x74c7f0_0, "#OUT# B sig_my_module_b" {0 0 0}; + %vpi_call 2 74 "$fdisplay", v0x74c7f0_0, "#OUT# C sig_my_module_y" {0 0 0}; + %vpi_call 2 75 "$fdisplay", v0x74c7f0_0, "#OUT#" {0 0 0}; + %vpi_call 2 76 "$fdisplay", v0x74c7f0_0, "#OUT# AB # C" {0 0 0}; + %end; +S_0x701c90 .scope task, "my_module_print_status" "my_module_print_status" 2 63, 2 63 0, S_0x703640; + .timescale 0 0; +TD_testbench.my_module_print_status ; + %load/vec4 v0x74ca70_0; + %load/vec4 v0x74cb60_0; + %concat/vec4; draw_concat_vec4 + %load/vec4 v0x74cc50_0; + %vpi_call 2 65 "$fdisplay", v0x74c7f0_0, "#OUT# %b %b %b %t %d", S<1,vec4,u2>, 1'bx, S<0,vec4,u1>, $time, v0x74c9b0_0 {2 0 0}; + %end; +S_0x701e70 .scope task, "my_module_reset" "my_module_reset" 2 36, 2 36 0, S_0x703640; + .timescale 0 0; +TD_testbench.my_module_reset ; + %pushi/vec4 0, 0, 1; + %assign/vec4 v0x74ca70_0, 2; + %pushi/vec4 0, 0, 1; + %assign/vec4 v0x74cb60_0, 4; + %delay 100, 0; + %pushi/vec4 1, 0, 1; + %assign/vec4 v0x74ca70_0, 2; + %pushi/vec4 1, 0, 1; + %assign/vec4 v0x74cb60_0, 4; + %delay 100, 0; + %delay 0, 0; + %end; +S_0x733630 .scope task, "my_module_test" "my_module_test" 2 80, 2 80 0, S_0x703640; + .timescale 0 0; +TD_testbench.my_module_test ; + %vpi_call 2 82 "$fdisplay", v0x74c7f0_0, "#OUT#\012#OUT# ==== my_module ====" {0 0 0}; + %fork TD_testbench.my_module_reset, S_0x701e70; + %join; + %pushi/vec4 0, 0, 32; + %store/vec4 v0x74c9b0_0, 0, 32; +T_3.0 ; + %load/vec4 v0x74c9b0_0; + %cmpi/s 1000, 0, 32; + %jmp/0xz T_3.1, 5; + %load/vec4 v0x74c9b0_0; + %pushi/vec4 20, 0, 32; + %mod/s; + %cmpi/e 0, 0, 32; + %jmp/0xz T_3.2, 4; + %fork TD_testbench.my_module_print_header, S_0x6efef0; + %join; +T_3.2 ; + %delay 100, 0; + %fork TD_testbench.my_module_update_data, S_0x71fde0; + %join; + %delay 100, 0; + %fork TD_testbench.my_module_update_clock, S_0x733810; + %join; + %delay 100, 0; + %fork TD_testbench.my_module_print_status, S_0x701c90; + %join; + %load/vec4 v0x74c9b0_0; + %addi 1, 0, 32; + %store/vec4 v0x74c9b0_0, 0, 32; + %jmp T_3.0; +T_3.1 ; + %end; +S_0x733810 .scope task, "my_module_update_clock" "my_module_update_clock" 2 58, 2 58 0, S_0x703640; + .timescale 0 0; +TD_testbench.my_module_update_clock ; + %end; +S_0x71fde0 .scope task, "my_module_update_data" "my_module_update_data" 2 48, 2 48 0, S_0x703640; + .timescale 0 0; +TD_testbench.my_module_update_data ; + %fork TD_testbench.xorshift128, S_0x74c610; + %join; + %load/vec4 v0x74cec0_0; + %load/vec4 v0x74cfa0_0; + %concat/vec4; draw_concat_vec4 + %load/vec4 v0x74d080_0; + %concat/vec4; draw_concat_vec4 + %load/vec4 v0x74cde0_0; + %concat/vec4; draw_concat_vec4 + %pad/u 1; + %assign/vec4 v0x74ca70_0, 2; + %fork TD_testbench.xorshift128, S_0x74c610; + %join; + %load/vec4 v0x74cec0_0; + %load/vec4 v0x74cfa0_0; + %concat/vec4; draw_concat_vec4 + %load/vec4 v0x74d080_0; + %concat/vec4; draw_concat_vec4 + %load/vec4 v0x74cde0_0; + %concat/vec4; draw_concat_vec4 + %pad/u 1; + %assign/vec4 v0x74cb60_0, 4; + %delay 100, 0; + %end; +S_0x71ffc0 .scope module, "uut_my_module" "my_module" 2 30, 3 1 0, S_0x703640; + .timescale 0 0; + .port_info 0 /INPUT 1 "a"; + .port_info 1 /INPUT 1 "b"; + .port_info 2 /OUTPUT 1 "y"; +L_0x74d160 .functor AND 1, v0x74ca70_0, v0x74cb60_0, C4<1>, C4<1>; +v0x7201f0_0 .net "a", 0 0, v0x74ca70_0; 1 drivers +v0x74c430_0 .net "b", 0 0, v0x74cb60_0; 1 drivers +v0x74c4f0_0 .net "y", 0 0, L_0x74d160; alias, 1 drivers +S_0x74c610 .scope task, "xorshift128" "xorshift128" 2 17, 2 17 0, S_0x703640; + .timescale 0 0; +TD_testbench.xorshift128 ; + %load/vec4 v0x74cec0_0; + %load/vec4 v0x74cec0_0; + %ix/load 4, 11, 0; + %flag_set/imm 4, 0; + %shiftl 4; + %xor; + %store/vec4 v0x74cd20_0, 0, 32; + %load/vec4 v0x74cfa0_0; + %store/vec4 v0x74cec0_0, 0, 32; + %load/vec4 v0x74d080_0; + %store/vec4 v0x74cfa0_0, 0, 32; + %load/vec4 v0x74cde0_0; + %store/vec4 v0x74d080_0, 0, 32; + %load/vec4 v0x74cde0_0; + %load/vec4 v0x74cde0_0; + %ix/load 4, 19, 0; + %flag_set/imm 4, 0; + %shiftr 4; + %xor; + %load/vec4 v0x74cd20_0; + %xor; + %load/vec4 v0x74cd20_0; + %ix/load 4, 8, 0; + %flag_set/imm 4, 0; + %shiftr 4; + %xor; + %store/vec4 v0x74cde0_0, 0, 32; + %end; + .scope S_0x703640; +T_7 ; + %pushi/vec4 123456789, 0, 32; + %store/vec4 v0x74cec0_0, 0, 32; + %pushi/vec4 362436069, 0, 32; + %store/vec4 v0x74cfa0_0, 0, 32; + %pushi/vec4 521288629, 0, 32; + %store/vec4 v0x74d080_0, 0, 32; + %pushi/vec4 1716911459, 0, 32; + %store/vec4 v0x74cde0_0, 0, 32; + %end; + .thread T_7; + .scope S_0x703640; +T_8 ; + %vpi_func 2 94 "$value$plusargs" 32, "VCD=%s", v0x74c8d0_0 {0 0 0}; + %cmpi/ne 0, 0, 32; + %jmp/0xz T_8.0, 4; + %vpi_call 2 95 "$dumpfile", v0x74c8d0_0 {0 0 0}; + %vpi_call 2 96 "$dumpvars", 32'sb00000000000000000000000000000000, S_0x703640 {0 0 0}; +T_8.0 ; + %vpi_func 2 98 "$value$plusargs" 32, "OUT=%s", v0x74c8d0_0 {0 0 0}; + %cmpi/ne 0, 0, 32; + %jmp/0xz T_8.2, 4; + %vpi_func 2 99 "$fopen" 32, v0x74c8d0_0 {0 0 0}; + %store/vec4 v0x74c7f0_0, 0, 32; + %jmp T_8.3; +T_8.2 ; + %vpi_func 2 101 "$fopen" 32, "/dev/stdout" {0 0 0}; + %store/vec4 v0x74c7f0_0, 0, 32; +T_8.3 ; + %fork TD_testbench.my_module_test, S_0x733630; + %join; + %vpi_call 2 104 "$fclose", v0x74c7f0_0 {0 0 0}; + %vpi_call 2 105 "$finish" {0 0 0}; + %end; + .thread T_8; +# The file index is used to find the file name in the following table. +:file_names 4; + "N/A"; + ""; + "test_and.v"; + "tests/functional/single_bit/verilog/my_module_and.v"; diff --git a/flake.nix b/flake.nix index 6ed167dab80..90c646aa9a6 100644 --- a/flake.nix +++ b/flake.nix @@ -66,7 +66,7 @@ defaultPackage = yosys; packages.vcdiff = vcdiff; devShell = pkgs.mkShell { - buildInputs = with pkgs; [ clang bison flex libffi tcl readline python3 llvmPackages.libcxxClang zlib git gtest abc-verifier gtkwave vcdiff lcov ]; + buildInputs = with pkgs; [ clang bison flex libffi tcl readline python3 llvmPackages.libcxxClang zlib git gtest abc-verifier gtkwave vcdiff lcov racket verilog ]; }; } ); diff --git a/tests/functional/coverage_report/vcd_harness.info b/sim.vcd similarity index 100% rename from tests/functional/coverage_report/vcd_harness.info rename to sim.vcd diff --git a/test_and.v b/test_and.v new file mode 100644 index 00000000000..3799f2a16c2 --- /dev/null +++ b/test_and.v @@ -0,0 +1,108 @@ +`ifndef outfile + `define outfile "/dev/stdout" +`endif +module testbench; + +integer i; +integer file; + +reg [1023:0] filename; + +reg [31:0] xorshift128_x = 123456789; +reg [31:0] xorshift128_y = 362436069; +reg [31:0] xorshift128_z = 521288629; +reg [31:0] xorshift128_w = 1716918015; // <-- seed value +reg [31:0] xorshift128_t; + +task xorshift128; +begin + xorshift128_t = xorshift128_x ^ (xorshift128_x << 11); + xorshift128_x = xorshift128_y; + xorshift128_y = xorshift128_z; + xorshift128_z = xorshift128_w; + xorshift128_w = xorshift128_w ^ (xorshift128_w >> 19) ^ xorshift128_t ^ (xorshift128_t >> 8); +end +endtask + +wire [0:0] sig_my_module_y; +reg [0:0] sig_my_module_b; +reg [0:0] sig_my_module_a; +my_module uut_my_module( + .y(sig_my_module_y), + .b(sig_my_module_b), + .a(sig_my_module_a) +); + +task my_module_reset; +begin + sig_my_module_a <= #2 0; + sig_my_module_b <= #4 0; + #100; + sig_my_module_a <= #2 ~0; + sig_my_module_b <= #4 ~0; + #100; + #0; +end +endtask + +task my_module_update_data; +begin + xorshift128; + sig_my_module_a <= #2 { xorshift128_x, xorshift128_y, xorshift128_z, xorshift128_w }; + xorshift128; + sig_my_module_b <= #4 { xorshift128_x, xorshift128_y, xorshift128_z, xorshift128_w }; + #100; +end +endtask + +task my_module_update_clock; +begin +end +endtask + +task my_module_print_status; +begin + $fdisplay(file, "#OUT# %b %b %b %t %d", { sig_my_module_a, sig_my_module_b }, { 1'bx }, { sig_my_module_y }, $time, i); +end +endtask + +task my_module_print_header; +begin + $fdisplay(file, "#OUT#"); + $fdisplay(file, "#OUT# A sig_my_module_a"); + $fdisplay(file, "#OUT# B sig_my_module_b"); + $fdisplay(file, "#OUT# C sig_my_module_y"); + $fdisplay(file, "#OUT#"); + $fdisplay(file, {"#OUT# ", "A", "B", " ", "#", " ", "C"}); +end +endtask + +task my_module_test; +begin + $fdisplay(file, "#OUT#\n#OUT# ==== my_module ===="); + my_module_reset; + for (i=0; i<1000; i=i+1) begin + if (i % 20 == 0) my_module_print_header; + #100; my_module_update_data; + #100; my_module_update_clock; + #100; my_module_print_status; + end +end +endtask + +initial begin + if ($value$plusargs("VCD=%s", filename)) begin + $dumpfile(filename); + $dumpvars(0, testbench); + end + if ($value$plusargs("OUT=%s", filename)) begin + file = $fopen(filename); + end else begin + file = $fopen(`outfile); + end + my_module_test; + $fclose(file); + $finish; +end + +endmodule diff --git a/tests/functional/coverage_report/amber.png b/tests/functional/coverage_report/amber.png deleted file mode 100644 index 2cab170d8359081983a4e343848dfe06bc490f12..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 141 zcmeAS@N?(olHy`uVBq!ia0vp^j3CU&3?x-=hn)ga>?NMQuI!iC1^G2tW}LqE04T&+ z;1OBOz`!j8!i<;h*8KqrvZOouIx;Y9?C1WI$O`1M1^9%x{(levWG?NMQuI!iC1^Jb!lvI6;R0X`wF(yt=9xVZRt1vCRixIA4P dLn>}1Cji+@42)0J?}79&c)I$ztaD0e0sy@GAL0N2 diff --git a/tests/functional/coverage_report/functional/and_cxxrtl.cc.func-sort-c.html b/tests/functional/coverage_report/functional/and_cxxrtl.cc.func-sort-c.html deleted file mode 100644 index e8c04ffebc6..00000000000 --- a/tests/functional/coverage_report/functional/and_cxxrtl.cc.func-sort-c.html +++ /dev/null @@ -1,100 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - functional/and_cxxrtl.cc - functions - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - functional - and_cxxrtl.cc (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:222975.9 %
Date:1980-01-01 00:00:00Functions:5771.4 %
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Function Name Sort by function nameHit count Sort by hit count
_ZN13cxxrtl_design7p_Adder10debug_evalEv0
cxxrtl_design_create0
_ZN13cxxrtl_design7p_Adder10debug_infoEPN6cxxrtl11debug_itemsEPNS1_12debug_scopesENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEOSt3mapISB_NS1_8metadataESt4lessISB_ESaISt4pairIKSB_SD_EEE3
_ZN13cxxrtl_design7p_Adder5resetEv3
_ZN13cxxrtl_design7p_AdderC2Ev3
_ZN13cxxrtl_design7p_Adder4evalEPN6cxxrtl9performerE33
_ZN13cxxrtl_design7p_Adder6commitEv33
-
-
- - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/functional/and_cxxrtl.cc.func.html b/tests/functional/coverage_report/functional/and_cxxrtl.cc.func.html deleted file mode 100644 index c7717a2dc84..00000000000 --- a/tests/functional/coverage_report/functional/and_cxxrtl.cc.func.html +++ /dev/null @@ -1,100 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - functional/and_cxxrtl.cc - functions - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - functional - and_cxxrtl.cc (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:222975.9 %
Date:1980-01-01 00:00:00Functions:5771.4 %
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Function Name Sort by function nameHit count Sort by hit count
_ZN13cxxrtl_design7p_Adder10debug_evalEv0
_ZN13cxxrtl_design7p_Adder10debug_infoEPN6cxxrtl11debug_itemsEPNS1_12debug_scopesENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEOSt3mapISB_NS1_8metadataESt4lessISB_ESaISt4pairIKSB_SD_EEE3
_ZN13cxxrtl_design7p_Adder4evalEPN6cxxrtl9performerE33
_ZN13cxxrtl_design7p_Adder5resetEv3
_ZN13cxxrtl_design7p_Adder6commitEv33
_ZN13cxxrtl_design7p_AdderC2Ev3
cxxrtl_design_create0
-
-
- - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/functional/and_cxxrtl.cc.gcov.html b/tests/functional/coverage_report/functional/and_cxxrtl.cc.gcov.html deleted file mode 100644 index 796a2e71920..00000000000 --- a/tests/functional/coverage_report/functional/and_cxxrtl.cc.gcov.html +++ /dev/null @@ -1,161 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - functional/and_cxxrtl.cc - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - functional - and_cxxrtl.cc (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:222975.9 %
Date:1980-01-01 00:00:00Functions:5771.4 %
-
- - - - - - - - -

-
          Line data    Source code
-
-       1             : #include <cxxrtl/cxxrtl.h>
-       2             : 
-       3             : #if defined(CXXRTL_INCLUDE_CAPI_IMPL) || \
-       4             :     defined(CXXRTL_INCLUDE_VCD_CAPI_IMPL)
-       5             : #include <cxxrtl/capi/cxxrtl_capi.cc>
-       6             : #endif
-       7             : 
-       8             : #if defined(CXXRTL_INCLUDE_VCD_CAPI_IMPL)
-       9             : #include <cxxrtl/capi/cxxrtl_capi_vcd.cc>
-      10             : #endif
-      11             : 
-      12             : using namespace cxxrtl_yosys;
-      13             : 
-      14             : namespace cxxrtl_design {
-      15             : 
-      16             : // \top: 1
-      17             : // \src: verilog/and.v:1.1-9.10
-      18           3 : struct p_Adder : public module {
-      19             :         // \src: verilog/and.v:4.14-4.17
-      20             :         /*output*/ value<1> p_sum;
-      21             :         // \src: verilog/and.v:3.14-3.15
-      22             :         /*input*/ value<1> p_b;
-      23             :         // \src: verilog/and.v:2.14-2.15
-      24             :         /*input*/ value<1> p_a;
-      25             :         p_Adder(interior) {}
-      26           3 :         p_Adder() {
-      27           3 :                 reset();
-      28           3 :         };
-      29             : 
-      30             :         void reset() override;
-      31             : 
-      32             :         bool eval(performer *performer = nullptr) override;
-      33             : 
-      34             :         template<class ObserverT>
-      35             :         bool commit(ObserverT &observer) {
-      36          33 :                 bool changed = false;
-      37             :                 return changed;
-      38             :         }
-      39             : 
-      40          33 :         bool commit() override {
-      41          33 :                 observer observer;
-      42          33 :                 return commit<>(observer);
-      43             :         }
-      44             : 
-      45             :         void debug_eval();
-      46             : 
-      47             :         void debug_info(debug_items *items, debug_scopes *scopes, std::string path, metadata_map &&cell_attrs = {}) override;
-      48             : }; // struct p_Adder
-      49             : 
-      50           3 : void p_Adder::reset() {
-      51           3 : }
-      52             : 
-      53          33 : bool p_Adder::eval(performer *performer) {
-      54          33 :         bool converged = true;
-      55             :         // \src: verilog/and.v:7.17-7.22
-      56             :         // cell $add$verilog/and.v:7$1
-      57          33 :         p_sum = add_uu<1>(p_a, p_b);
-      58          33 :         return converged;
-      59             : }
-      60             : 
-      61           0 : void p_Adder::debug_eval() {
-      62           0 : }
-      63             : 
-      64             : CXXRTL_EXTREMELY_COLD
-      65           3 : void p_Adder::debug_info(debug_items *items, debug_scopes *scopes, std::string path, metadata_map &&cell_attrs) {
-      66           3 :         assert(path.empty() || path[path.size() - 1] == ' ');
-      67           3 :         if (scopes) {
-      68           0 :                 scopes->add(path.empty() ? path : path.substr(0, path.size() - 1), "Adder", metadata_map({
-      69           0 :                         { "top", UINT64_C(1) },
-      70             :                         { "src", "verilog/and.v:1.1-9.10" },
-      71           0 :                 }), std::move(cell_attrs));
-      72             :         }
-      73           3 :         if (items) {
-      74           3 :                 items->add(path, "sum", "src\000sverilog/and.v:4.14-4.17\000", p_sum, 0, debug_item::OUTPUT|debug_item::DRIVEN_COMB);
-      75           3 :                 items->add(path, "b", "src\000sverilog/and.v:3.14-3.15\000", p_b, 0, debug_item::INPUT|debug_item::UNDRIVEN);
-      76           3 :                 items->add(path, "a", "src\000sverilog/and.v:2.14-2.15\000", p_a, 0, debug_item::INPUT|debug_item::UNDRIVEN);
-      77             :         }
-      78           3 : }
-      79             : 
-      80             : } // namespace cxxrtl_design
-      81             : 
-      82             : extern "C"
-      83           0 : cxxrtl_toplevel cxxrtl_design_create() {
-      84           0 :         return new _cxxrtl_toplevel { std::unique_ptr<cxxrtl_design::p_Adder>(new cxxrtl_design::p_Adder) };
-      85             : }
-
-
-
- - - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/functional/and_functional_cxx.cc.func-sort-c.html b/tests/functional/coverage_report/functional/and_functional_cxx.cc.func-sort-c.html deleted file mode 100644 index 5c1ad8cc617..00000000000 --- a/tests/functional/coverage_report/functional/and_functional_cxx.cc.func-sort-c.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - functional/and_functional_cxx.cc - functions - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - functional - and_functional_cxx.cc (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:1313100.0 %
Date:1980-01-01 00:00:00Functions:33100.0 %
-
- -
- - - - - - - - - - - - - - - - - - -

Function Name Sort by function nameHit count Sort by hit count
_ZN12Adder_Inputs4dumpI10DumpHeaderEEvRT_3
_Z5AdderRK12Adder_InputsR13Adder_OutputsRK11Adder_StateRS4_30
_ZN12Adder_Inputs4dumpI4DumpEEvRT_33
-
-
- - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/functional/and_functional_cxx.cc.func.html b/tests/functional/coverage_report/functional/and_functional_cxx.cc.func.html deleted file mode 100644 index bd54f13143e..00000000000 --- a/tests/functional/coverage_report/functional/and_functional_cxx.cc.func.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - functional/and_functional_cxx.cc - functions - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - functional - and_functional_cxx.cc (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:1313100.0 %
Date:1980-01-01 00:00:00Functions:33100.0 %
-
- -
- - - - - - - - - - - - - - - - - - -

Function Name Sort by function nameHit count Sort by hit count
_Z5AdderRK12Adder_InputsR13Adder_OutputsRK11Adder_StateRS4_30
_ZN12Adder_Inputs4dumpI10DumpHeaderEEvRT_3
_ZN12Adder_Inputs4dumpI4DumpEEvRT_33
-
-
- - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/functional/and_functional_cxx.cc.gcov.html b/tests/functional/coverage_report/functional/and_functional_cxx.cc.gcov.html deleted file mode 100644 index 46ae8931131..00000000000 --- a/tests/functional/coverage_report/functional/and_functional_cxx.cc.gcov.html +++ /dev/null @@ -1,108 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - functional/and_functional_cxx.cc - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - functional - and_functional_cxx.cc (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:1313100.0 %
Date:1980-01-01 00:00:00Functions:33100.0 %
-
- - - - - - - - -

-
          Line data    Source code
-
-       1             : #include "sim.h"
-       2             : struct Adder_Inputs {
-       3             :         Signal<1> b;
-       4             :         Signal<1> a;
-       5             : 
-       6          36 :         template <typename T> void dump(T &out) {
-       7          36 :                 out("b", b);
-       8          36 :                 out("a", a);
-       9          36 :         }
-      10             : };
-      11             : 
-      12             : struct Adder_Outputs {
-      13             :         Signal<1> sum;
-      14             : 
-      15          36 :         template <typename T> void dump(T &out) {
-      16          36 :                 out("sum", sum);
-      17          36 :         }
-      18             : };
-      19             : 
-      20             : struct Adder_State {
-      21             : 
-      22             :         template <typename T> void dump(T &out) {
-      23             :         }
-      24             : };
-      25             : 
-      26          30 : void Adder(Adder_Inputs const &input, Adder_Outputs &output, Adder_State const &current_state, Adder_State &next_state)
-      27             : {
-      28          30 :         Signal<1> b = input.b;
-      29          30 :         Signal<1> a = input.a;
-      30          30 :         Signal<1> $add$verilog_and_v_7$1$_Y = $add(a, b); //
-      31          30 :         output.sum = $add$verilog_and_v_7$1$_Y;
-      32          30 : }
-
-
-
- - - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/functional/index-sort-f.html b/tests/functional/coverage_report/functional/index-sort-f.html deleted file mode 100644 index c6f3150f801..00000000000 --- a/tests/functional/coverage_report/functional/index-sort-f.html +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - functional - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - functionalHitTotalCoverage
Test:vcd_harness.infoLines:10511293.8 %
Date:1980-01-01 00:00:00Functions:111384.6 %
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
and_cxxrtl.cc -
75.9%75.9%
-
75.9 %22 / 2971.4 %5 / 7
and_functional_cxx.cc -
100.0%
-
100.0 %13 / 13100.0 %3 / 3
vcd_harness.cpp -
100.0%
-
100.0 %70 / 70100.0 %3 / 3
-
-
- - - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/functional/index-sort-l.html b/tests/functional/coverage_report/functional/index-sort-l.html deleted file mode 100644 index 85e33c02ae9..00000000000 --- a/tests/functional/coverage_report/functional/index-sort-l.html +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - functional - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - functionalHitTotalCoverage
Test:vcd_harness.infoLines:10511293.8 %
Date:1980-01-01 00:00:00Functions:111384.6 %
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
and_cxxrtl.cc -
75.9%75.9%
-
75.9 %22 / 2971.4 %5 / 7
and_functional_cxx.cc -
100.0%
-
100.0 %13 / 13100.0 %3 / 3
vcd_harness.cpp -
100.0%
-
100.0 %70 / 70100.0 %3 / 3
-
-
- - - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/functional/index.html b/tests/functional/coverage_report/functional/index.html deleted file mode 100644 index 3b31f9d7e6e..00000000000 --- a/tests/functional/coverage_report/functional/index.html +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - functional - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - functionalHitTotalCoverage
Test:vcd_harness.infoLines:10511293.8 %
Date:1980-01-01 00:00:00Functions:111384.6 %
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
and_cxxrtl.cc -
75.9%75.9%
-
75.9 %22 / 2971.4 %5 / 7
and_functional_cxx.cc -
100.0%
-
100.0 %13 / 13100.0 %3 / 3
vcd_harness.cpp -
100.0%
-
100.0 %70 / 70100.0 %3 / 3
-
-
- - - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/functional/vcd_harness.cpp.func-sort-c.html b/tests/functional/coverage_report/functional/vcd_harness.cpp.func-sort-c.html deleted file mode 100644 index 36a518367b0..00000000000 --- a/tests/functional/coverage_report/functional/vcd_harness.cpp.func-sort-c.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - functional/vcd_harness.cpp - functions - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - functional - vcd_harness.cpp (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:7070100.0 %
Date:1980-01-01 00:00:00Functions:33100.0 %
-
- -
- - - - - - - - - - - - - - - - - - -

Function Name Sort by function nameHit count Sort by hit count
main3
_ZN10DumpHeaderclILm1EEEvPKcSt5arrayIbXT_EE9
_ZN4DumpclILm1EEEvPKcSt5arrayIbXT_EE99
-
-
- - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/functional/vcd_harness.cpp.func.html b/tests/functional/coverage_report/functional/vcd_harness.cpp.func.html deleted file mode 100644 index 351dd96a848..00000000000 --- a/tests/functional/coverage_report/functional/vcd_harness.cpp.func.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - functional/vcd_harness.cpp - functions - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - functional - vcd_harness.cpp (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:7070100.0 %
Date:1980-01-01 00:00:00Functions:33100.0 %
-
- -
- - - - - - - - - - - - - - - - - - -

Function Name Sort by function nameHit count Sort by hit count
_ZN10DumpHeaderclILm1EEEvPKcSt5arrayIbXT_EE9
_ZN4DumpclILm1EEEvPKcSt5arrayIbXT_EE99
main3
-
-
- - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/functional/vcd_harness.cpp.gcov.html b/tests/functional/coverage_report/functional/vcd_harness.cpp.gcov.html deleted file mode 100644 index d5c0afbc10c..00000000000 --- a/tests/functional/coverage_report/functional/vcd_harness.cpp.gcov.html +++ /dev/null @@ -1,216 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - functional/vcd_harness.cpp - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - functional - vcd_harness.cpp (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:7070100.0 %
Date:1980-01-01 00:00:00Functions:33100.0 %
-
- - - - - - - - -

-
          Line data    Source code
-
-       1             : #include <cstdio>
-       2             : #include <iostream>
-       3             : #include <fstream>
-       4             : #include <random>
-       5             : 
-       6             : #include <cxxrtl/cxxrtl_vcd.h>
-       7             : 
-       8             : #include "and_cxxrtl.cc"
-       9             : #include "and_functional_cxx.cc"
-      10             : 
-      11             : struct DumpHeader {
-      12             :     std::ofstream &ofs;
-      13           3 :     DumpHeader(std::ofstream &ofs) : ofs(ofs) {}
-      14             :     template <size_t n>
-      15           9 :     void operator()(const char *name, Signal<n> value) {
-      16           9 :         ofs << "$var wire " << n << " " << name[0] << " " << name << " $end\n";
-      17           9 :     }
-      18             : };
-      19             : 
-      20             : struct Dump {
-      21             :     std::ofstream &ofs;
-      22          33 :     Dump(std::ofstream &ofs) : ofs(ofs) {}
-      23             :     template <size_t n>
-      24          99 :     void operator()(const char *name, Signal<n> value) {
-      25             :         // Bit
-      26             :         if (n == 1) {
-      27         156 :             ofs << (value[0] ? '1' : '0');
-      28          99 :             ofs << name[0] << "\n";
-      29             :             return;
-      30             :         }
-      31             :         // vector (multi-bit) signals
-      32             :         ofs << "b";
-      33             :         for (size_t i = n; i-- > 0;)
-      34             :             ofs << (value[i] ? '1' : '0');
-      35             :         ofs << " " << name[0] << "\n";
-      36             :     }
-      37             : };
-      38             : 
-      39           3 : int main(int argc, char **argv)
-      40             : {
-      41           3 :     constexpr int steps = 10;
-      42           3 :     constexpr int number_timescale = 1;
-      43           3 :     const std::string units_timescale = "us";
-      44           3 :     Adder_Inputs inputs;
-      45           3 :     Adder_Outputs outputs;
-      46           3 :     Adder_State state;
-      47           3 :     Adder_State next_state;
-      48             : 
-      49           3 :     std::ofstream vcd_file("functional_cxx.vcd");
-      50             : 
-      51           3 :     vcd_file << "$timescale " << number_timescale << " " << units_timescale << " $end\n"; //$scope module logic $end\n";
-      52           3 :     {
-      53           3 :         DumpHeader d(vcd_file);
-      54           3 :         inputs.dump(d);
-      55           3 :         outputs.dump(d);
-      56             :         // vcd_file << "$scope module state $end\n";
-      57           3 :         state.dump(d);
-      58             :     }
-      59           3 :     vcd_file << "$enddefinitions $end\n$dumpvars\n";
-      60             : 
-      61           3 :     cxxrtl_design::p_Adder top;
-      62             : 
-      63             :     // debug_items maps the hierarchical names of signals and memories in the design
-      64             :     // to a cxxrtl_object (a value, a wire, or a memory)
-      65           3 :     cxxrtl::debug_items all_debug_items;
-      66           3 :     cxxrtl::debug_scope debug_scope;
-      67             :     // Load the debug items of the top down the whole design hierarchy
-      68           6 :     top.debug_info(&all_debug_items, nullptr, "");
-      69             : 
-      70             :     // vcd_writer is the CXXRTL object that's responsible for creating a string with
-      71             :     // the VCD file contents.
-      72           3 :     cxxrtl::vcd_writer vcd;
-      73           3 :     vcd.timescale(number_timescale, units_timescale);
-      74             : 
-      75             :     // Here we tell the vcd writer to dump all the signals of the design, except for the
-      76             :     // memories, to the VCD file.
-      77             :     //
-      78             :     // It's not necessary to load all debug objects to the VCD. There is, for example,
-      79             :     // a  vcd.add(<debug items>, <filter>)) method which allows creating your custom filter to decide
-      80             :     // what to add and what not.
-      81           3 :     vcd.add_without_memories(all_debug_items);
-      82             : 
-      83           3 :     std::ofstream waves("cxxrtl.vcd");
-      84             : 
-      85           3 :     top.p_a.set<bool>(false);
-      86           3 :     top.p_b.set<bool>(false);
-      87           3 :     top.step();
-      88             : 
-      89             :     // We need to manually tell the VCD writer when to sample and write out the traced items.
-      90             :     // This is only a slight inconvenience and allows for complete flexibility.
-      91             :     // E.g. you could only start waveform tracing when an internal signal has reached some specific
-      92             :     // value etc.
-      93           3 :     vcd.sample(0);
-      94           3 :     vcd_file << "#0\n";
-      95           3 :     inputs.a = $const<1>(false);
-      96           3 :     inputs.b = $const<1>(false);
-      97           3 :     {
-      98           3 :         Dump d(vcd_file);
-      99           3 :         inputs.dump(d);
-     100           3 :         outputs.dump(d);
-     101           3 :         state.dump(d);
-     102             :     }
-     103             : 
-     104             :     // Initialize random number generator
-     105           3 :     std::random_device rd;
-     106           3 :     std::mt19937 gen(rd());
-     107           3 :     std::bernoulli_distribution dist(0.5); // 50% chance for true or false
-     108             :     
-     109          33 :     for (int step = 0; step < steps; ++step) {
-     110          30 :       const bool a_value = dist(gen);
-     111          30 :       const bool b_value = dist(gen);
-     112             : 
-     113             :         // cxxrtl
-     114          30 :         top.p_a.set<bool>(a_value);
-     115          30 :         top.p_b.set<bool>(b_value);
-     116          30 :         top.step();
-     117          30 :         vcd.sample(step + 1);
-     118             : 
-     119          30 :         waves << vcd.buffer;
-     120          30 :         vcd.buffer.clear();
-     121             : 
-     122             :         // Functional backend cxx
-     123          30 :         vcd_file << "#" << (step + 1) << "\n";
-     124          30 :         inputs.a = $const<1>(a_value);
-     125          30 :         inputs.b = $const<1>(b_value);
-     126          30 :         Adder(inputs, outputs, state, next_state);
-     127          30 :         {
-     128          30 :             Dump d(vcd_file);
-     129          30 :             inputs.dump(d);
-     130          30 :             outputs.dump(d);
-     131          30 :             state.dump(d);
-     132             :         }
-     133          30 :         state = next_state;
-     134             :     }
-     135             : 
-     136           3 :     vcd_file.close();
-     137           3 :     waves.close();
-     138             : 
-     139           3 :     return 0;
-     140           3 : }
-
-
-
- - - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/gcov.css b/tests/functional/coverage_report/gcov.css deleted file mode 100644 index 0fcdff13cea..00000000000 --- a/tests/functional/coverage_report/gcov.css +++ /dev/null @@ -1,519 +0,0 @@ -/* All views: initial background and text color */ -body -{ - color: #000000; - background-color: #ffffff; -} - -/* All views: standard link format*/ -a:link -{ - color: #284fa8; - text-decoration: underline; -} - -/* All views: standard link - visited format */ -a:visited -{ - color: #00cb40; - text-decoration: underline; -} - -/* All views: standard link - activated format */ -a:active -{ - color: #ff0040; - text-decoration: underline; -} - -/* All views: main title format */ -td.title -{ - text-align: center; - padding-bottom: 10px; - font-family: sans-serif; - font-size: 20pt; - font-style: italic; - font-weight: bold; -} - -/* All views: header item format */ -td.headerItem -{ - text-align: right; - padding-right: 6px; - font-family: sans-serif; - font-weight: bold; - vertical-align: top; - white-space: nowrap; -} - -/* All views: header item value format */ -td.headerValue -{ - text-align: left; - color: #284fa8; - font-family: sans-serif; - font-weight: bold; - white-space: nowrap; -} - -/* All views: header item coverage table heading */ -td.headerCovTableHead -{ - text-align: center; - padding-right: 6px; - padding-left: 6px; - padding-bottom: 0px; - font-family: sans-serif; - font-size: 80%; - white-space: nowrap; -} - -/* All views: header item coverage table entry */ -td.headerCovTableEntry -{ - text-align: right; - color: #284fa8; - font-family: sans-serif; - font-weight: bold; - white-space: nowrap; - padding-left: 12px; - padding-right: 4px; - background-color: #dae7fe; -} - -/* All views: header item coverage table entry for high coverage rate */ -td.headerCovTableEntryHi -{ - text-align: right; - color: #000000; - font-family: sans-serif; - font-weight: bold; - white-space: nowrap; - padding-left: 12px; - padding-right: 4px; - background-color: #a7fc9d; -} - -/* All views: header item coverage table entry for medium coverage rate */ -td.headerCovTableEntryMed -{ - text-align: right; - color: #000000; - font-family: sans-serif; - font-weight: bold; - white-space: nowrap; - padding-left: 12px; - padding-right: 4px; - background-color: #ffea20; -} - -/* All views: header item coverage table entry for ow coverage rate */ -td.headerCovTableEntryLo -{ - text-align: right; - color: #000000; - font-family: sans-serif; - font-weight: bold; - white-space: nowrap; - padding-left: 12px; - padding-right: 4px; - background-color: #ff0000; -} - -/* All views: header legend value for legend entry */ -td.headerValueLeg -{ - text-align: left; - color: #000000; - font-family: sans-serif; - font-size: 80%; - white-space: nowrap; - padding-top: 4px; -} - -/* All views: color of horizontal ruler */ -td.ruler -{ - background-color: #6688d4; -} - -/* All views: version string format */ -td.versionInfo -{ - text-align: center; - padding-top: 2px; - font-family: sans-serif; - font-style: italic; -} - -/* Directory view/File view (all)/Test case descriptions: - table headline format */ -td.tableHead -{ - text-align: center; - color: #ffffff; - background-color: #6688d4; - font-family: sans-serif; - font-size: 120%; - font-weight: bold; - white-space: nowrap; - padding-left: 4px; - padding-right: 4px; -} - -span.tableHeadSort -{ - padding-right: 4px; -} - -/* Directory view/File view (all): filename entry format */ -td.coverFile -{ - text-align: left; - padding-left: 10px; - padding-right: 20px; - color: #284fa8; - background-color: #dae7fe; - font-family: monospace; -} - -/* Directory view/File view (all): bar-graph entry format*/ -td.coverBar -{ - padding-left: 10px; - padding-right: 10px; - background-color: #dae7fe; -} - -/* Directory view/File view (all): bar-graph outline color */ -td.coverBarOutline -{ - background-color: #000000; -} - -/* Directory view/File view (all): percentage entry for files with - high coverage rate */ -td.coverPerHi -{ - text-align: right; - padding-left: 10px; - padding-right: 10px; - background-color: #a7fc9d; - font-weight: bold; - font-family: sans-serif; -} - -/* Directory view/File view (all): line count entry for files with - high coverage rate */ -td.coverNumHi -{ - text-align: right; - padding-left: 10px; - padding-right: 10px; - background-color: #a7fc9d; - white-space: nowrap; - font-family: sans-serif; -} - -/* Directory view/File view (all): percentage entry for files with - medium coverage rate */ -td.coverPerMed -{ - text-align: right; - padding-left: 10px; - padding-right: 10px; - background-color: #ffea20; - font-weight: bold; - font-family: sans-serif; -} - -/* Directory view/File view (all): line count entry for files with - medium coverage rate */ -td.coverNumMed -{ - text-align: right; - padding-left: 10px; - padding-right: 10px; - background-color: #ffea20; - white-space: nowrap; - font-family: sans-serif; -} - -/* Directory view/File view (all): percentage entry for files with - low coverage rate */ -td.coverPerLo -{ - text-align: right; - padding-left: 10px; - padding-right: 10px; - background-color: #ff0000; - font-weight: bold; - font-family: sans-serif; -} - -/* Directory view/File view (all): line count entry for files with - low coverage rate */ -td.coverNumLo -{ - text-align: right; - padding-left: 10px; - padding-right: 10px; - background-color: #ff0000; - white-space: nowrap; - font-family: sans-serif; -} - -/* File view (all): "show/hide details" link format */ -a.detail:link -{ - color: #B8D0FF; - font-size:80%; -} - -/* File view (all): "show/hide details" link - visited format */ -a.detail:visited -{ - color: #B8D0FF; - font-size:80%; -} - -/* File view (all): "show/hide details" link - activated format */ -a.detail:active -{ - color: #ffffff; - font-size:80%; -} - -/* File view (detail): test name entry */ -td.testName -{ - text-align: right; - padding-right: 10px; - background-color: #dae7fe; - font-family: sans-serif; -} - -/* File view (detail): test percentage entry */ -td.testPer -{ - text-align: right; - padding-left: 10px; - padding-right: 10px; - background-color: #dae7fe; - font-family: sans-serif; -} - -/* File view (detail): test lines count entry */ -td.testNum -{ - text-align: right; - padding-left: 10px; - padding-right: 10px; - background-color: #dae7fe; - font-family: sans-serif; -} - -/* Test case descriptions: test name format*/ -dt -{ - font-family: sans-serif; - font-weight: bold; -} - -/* Test case descriptions: description table body */ -td.testDescription -{ - padding-top: 10px; - padding-left: 30px; - padding-bottom: 10px; - padding-right: 30px; - background-color: #dae7fe; -} - -/* Source code view: function entry */ -td.coverFn -{ - text-align: left; - padding-left: 10px; - padding-right: 20px; - color: #284fa8; - background-color: #dae7fe; - font-family: monospace; -} - -/* Source code view: function entry zero count*/ -td.coverFnLo -{ - text-align: right; - padding-left: 10px; - padding-right: 10px; - background-color: #ff0000; - font-weight: bold; - font-family: sans-serif; -} - -/* Source code view: function entry nonzero count*/ -td.coverFnHi -{ - text-align: right; - padding-left: 10px; - padding-right: 10px; - background-color: #dae7fe; - font-weight: bold; - font-family: sans-serif; -} - -/* Source code view: source code format */ -pre.source -{ - font-family: monospace; - white-space: pre; - margin-top: 2px; -} - -/* Source code view: line number format */ -span.lineNum -{ - background-color: #efe383; -} - -/* Source code view: format for lines which were executed */ -td.lineCov, -span.lineCov -{ - background-color: #cad7fe; -} - -/* Source code view: format for Cov legend */ -span.coverLegendCov -{ - padding-left: 10px; - padding-right: 10px; - padding-bottom: 2px; - background-color: #cad7fe; -} - -/* Source code view: format for lines which were not executed */ -td.lineNoCov, -span.lineNoCov -{ - background-color: #ff6230; -} - -/* Source code view: format for NoCov legend */ -span.coverLegendNoCov -{ - padding-left: 10px; - padding-right: 10px; - padding-bottom: 2px; - background-color: #ff6230; -} - -/* Source code view (function table): standard link - visited format */ -td.lineNoCov > a:visited, -td.lineCov > a:visited -{ - color: #000000; - text-decoration: underline; -} - -/* Source code view: format for lines which were executed only in a - previous version */ -span.lineDiffCov -{ - background-color: #b5f7af; -} - -/* Source code view: format for branches which were executed - * and taken */ -span.branchCov -{ - background-color: #cad7fe; -} - -/* Source code view: format for branches which were executed - * but not taken */ -span.branchNoCov -{ - background-color: #ff6230; -} - -/* Source code view: format for branches which were not executed */ -span.branchNoExec -{ - background-color: #ff6230; -} - -/* Source code view: format for the source code heading line */ -pre.sourceHeading -{ - white-space: pre; - font-family: monospace; - font-weight: bold; - margin: 0px; -} - -/* All views: header legend value for low rate */ -td.headerValueLegL -{ - font-family: sans-serif; - text-align: center; - white-space: nowrap; - padding-left: 4px; - padding-right: 2px; - background-color: #ff0000; - font-size: 80%; -} - -/* All views: header legend value for med rate */ -td.headerValueLegM -{ - font-family: sans-serif; - text-align: center; - white-space: nowrap; - padding-left: 2px; - padding-right: 2px; - background-color: #ffea20; - font-size: 80%; -} - -/* All views: header legend value for hi rate */ -td.headerValueLegH -{ - font-family: sans-serif; - text-align: center; - white-space: nowrap; - padding-left: 2px; - padding-right: 4px; - background-color: #a7fc9d; - font-size: 80%; -} - -/* All views except source code view: legend format for low coverage */ -span.coverLegendCovLo -{ - padding-left: 10px; - padding-right: 10px; - padding-top: 2px; - background-color: #ff0000; -} - -/* All views except source code view: legend format for med coverage */ -span.coverLegendCovMed -{ - padding-left: 10px; - padding-right: 10px; - padding-top: 2px; - background-color: #ffea20; -} - -/* All views except source code view: legend format for hi coverage */ -span.coverLegendCovHi -{ - padding-left: 10px; - padding-right: 10px; - padding-top: 2px; - background-color: #a7fc9d; -} diff --git a/tests/functional/coverage_report/glass.png b/tests/functional/coverage_report/glass.png deleted file mode 100644 index e1abc00680a3093c49fdb775ae6bdb6764c95af2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 167 zcmeAS@N?(olHy`uVBq!ia0vp^j3CU&3?x-=hn)gaEa{HEjtmSN`?>!lvI6;R0X`wF z|Ns97GD8ntt^-nxB|(0{3=Yq3q=7g|-tI089jvk*Kn`btM`SSr1Gf+eGhVt|_XjA* zUgGKN%6^Gmn4d%Ph(nkFP>9RZ#WAE}PI3Z}&BVayv3^M*kj3EX>gTe~DWM4f=_Dpv diff --git a/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h.func-sort-c.html b/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h.func-sort-c.html deleted file mode 100644 index b16f35764ec..00000000000 --- a/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h.func-sort-c.html +++ /dev/null @@ -1,108 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - /home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h - functions - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl - cxxrtl.h (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:9011876.3 %
Date:1980-01-01 00:00:00Functions:7977.8 %
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Function Name Sort by function nameHit count Sort by hit count
_ZN6cxxrtl12debug_scopes3addERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES8_OSt3mapIS6_NS_8metadataESt4lessIS6_ESaISt4pairIS7_SA_EEESH_0
_ZZN6cxxrtl8metadata11deserializeB5cxx11EPKcENKUlvE_clEv0
_ZN6cxxrtl11debug_items3addERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEONS_10debug_itemEOSt3mapIS6_NS_8metadataESt4lessIS6_ESaISt4pairIS7_SC_EEE9
_ZN6cxxrtl11debug_items3addIJRNS_5valueILm1EEEijEEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEPKcSE_DpOT_9
_ZN6cxxrtl8metadata11deserializeB5cxx11EPKc9
_ZN6cxxrtl8metadataC2ERKS0_18
_ZN6cxxrtl6module4stepEPNS_9performerE33
_ZNK6cxxrtl5valueILm1EE3addERKS1_33
_ZNK6cxxrtl5valueILm1EE3aluILb0ELb0EEESt4pairIS1_bERKS1_33
-
-
- - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h.func.html b/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h.func.html deleted file mode 100644 index c7d08356953..00000000000 --- a/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h.func.html +++ /dev/null @@ -1,108 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - /home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h - functions - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl - cxxrtl.h (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:9011876.3 %
Date:1980-01-01 00:00:00Functions:7977.8 %
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Function Name Sort by function nameHit count Sort by hit count
_ZN6cxxrtl11debug_items3addERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEONS_10debug_itemEOSt3mapIS6_NS_8metadataESt4lessIS6_ESaISt4pairIS7_SC_EEE9
_ZN6cxxrtl11debug_items3addIJRNS_5valueILm1EEEijEEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEPKcSE_DpOT_9
_ZN6cxxrtl12debug_scopes3addERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES8_OSt3mapIS6_NS_8metadataESt4lessIS6_ESaISt4pairIS7_SA_EEESH_0
_ZN6cxxrtl6module4stepEPNS_9performerE33
_ZN6cxxrtl8metadata11deserializeB5cxx11EPKc9
_ZN6cxxrtl8metadataC2ERKS0_18
_ZNK6cxxrtl5valueILm1EE3addERKS1_33
_ZNK6cxxrtl5valueILm1EE3aluILb0ELb0EEESt4pairIS1_bERKS1_33
_ZZN6cxxrtl8metadata11deserializeB5cxx11EPKcENKUlvE_clEv0
-
-
- - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h.gcov.html b/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h.gcov.html deleted file mode 100644 index 699d0521133..00000000000 --- a/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h.gcov.html +++ /dev/null @@ -1,2182 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - /home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl - cxxrtl.h (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:9011876.3 %
Date:1980-01-01 00:00:00Functions:7977.8 %
-
- - - - - - - - -

-
          Line data    Source code
-
-       1             : /*
-       2             :  *  yosys -- Yosys Open SYnthesis Suite
-       3             :  *
-       4             :  *  Copyright (C) 2019-2020  whitequark <whitequark@whitequark.org>
-       5             :  *
-       6             :  *  Permission to use, copy, modify, and/or distribute this software for any
-       7             :  *  purpose with or without fee is hereby granted.
-       8             :  *
-       9             :  *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-      10             :  *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-      11             :  *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-      12             :  *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-      13             :  *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-      14             :  *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-      15             :  *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-      16             :  *
-      17             :  */
-      18             : 
-      19             : // This file is included by the designs generated with `write_cxxrtl`. It is not used in Yosys itself.
-      20             : //
-      21             : // The CXXRTL support library implements compile time specialized arbitrary width arithmetics, as well as provides
-      22             : // composite lvalues made out of bit slices and concatenations of lvalues. This allows the `write_cxxrtl` pass
-      23             : // to perform a straightforward translation of RTLIL structures to readable C++, relying on the C++ compiler
-      24             : // to unwrap the abstraction and generate efficient code.
-      25             : 
-      26             : #ifndef CXXRTL_H
-      27             : #define CXXRTL_H
-      28             : 
-      29             : #include <cstddef>
-      30             : #include <cstdint>
-      31             : #include <cstring>
-      32             : #include <cassert>
-      33             : #include <limits>
-      34             : #include <type_traits>
-      35             : #include <tuple>
-      36             : #include <vector>
-      37             : #include <map>
-      38             : #include <algorithm>
-      39             : #include <memory>
-      40             : #include <functional>
-      41             : #include <sstream>
-      42             : #include <iostream>
-      43             : 
-      44             : // `cxxrtl::debug_item` has to inherit from `cxxrtl_object` to satisfy strict aliasing requirements.
-      45             : #include <cxxrtl/capi/cxxrtl_capi.h>
-      46             : 
-      47             : #ifndef __has_attribute
-      48             : #       define __has_attribute(x) 0
-      49             : #endif
-      50             : 
-      51             : // CXXRTL essentially uses the C++ compiler as a hygienic macro engine that feeds an instruction selector.
-      52             : // It generates a lot of specialized template functions with relatively large bodies that, when inlined
-      53             : // into the caller and (for those with loops) unrolled, often expose many new optimization opportunities.
-      54             : // Because of this, most of the CXXRTL runtime must be always inlined for best performance.
-      55             : #if __has_attribute(always_inline)
-      56             : #define CXXRTL_ALWAYS_INLINE inline __attribute__((__always_inline__))
-      57             : #else
-      58             : #define CXXRTL_ALWAYS_INLINE inline
-      59             : #endif
-      60             : // Conversely, some functions in the generated code are extremely large yet very cold, with both of these
-      61             : // properties being extreme enough to confuse C++ compilers into spending pathological amounts of time
-      62             : // on a futile (the code becomes worse) attempt to optimize the least important parts of code.
-      63             : #if __has_attribute(optnone)
-      64             : #define CXXRTL_EXTREMELY_COLD __attribute__((__optnone__))
-      65             : #elif __has_attribute(optimize)
-      66             : #define CXXRTL_EXTREMELY_COLD __attribute__((__optimize__(0)))
-      67             : #else
-      68             : #define CXXRTL_EXTREMELY_COLD
-      69             : #endif
-      70             : 
-      71             : // CXXRTL uses assert() to check for C++ contract violations (which may result in e.g. undefined behavior
-      72             : // of the simulation code itself), and CXXRTL_ASSERT to check for RTL contract violations (which may at
-      73             : // most result in undefined simulation results).
-      74             : //
-      75             : // Though by default, CXXRTL_ASSERT() expands to assert(), it may be overridden e.g. when integrating
-      76             : // the simulation into another process that should survive violating RTL contracts.
-      77             : #ifndef CXXRTL_ASSERT
-      78             : #ifndef CXXRTL_NDEBUG
-      79             : #define CXXRTL_ASSERT(x) assert(x)
-      80             : #else
-      81             : #define CXXRTL_ASSERT(x)
-      82             : #endif
-      83             : #endif
-      84             : 
-      85             : namespace cxxrtl {
-      86             : 
-      87             : // All arbitrary-width values in CXXRTL are backed by arrays of unsigned integers called chunks. The chunk size
-      88             : // is the same regardless of the value width to simplify manipulating values via FFI interfaces, e.g. driving
-      89             : // and introspecting the simulation in Python.
-      90             : //
-      91             : // It is practical to use chunk sizes between 32 bits and platform register size because when arithmetics on
-      92             : // narrower integer types is legalized by the C++ compiler, it inserts code to clear the high bits of the register.
-      93             : // However, (a) most of our operations do not change those bits in the first place because of invariants that are
-      94             : // invisible to the compiler, (b) we often operate on non-power-of-2 values and have to clear the high bits anyway.
-      95             : // Therefore, using relatively wide chunks and clearing the high bits explicitly and only when we know they may be
-      96             : // clobbered results in simpler generated code.
-      97             : typedef uint32_t chunk_t;
-      98             : typedef uint64_t wide_chunk_t;
-      99             : 
-     100             : template<typename T>
-     101             : struct chunk_traits {
-     102             :         static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value,
-     103             :                       "chunk type must be an unsigned integral type");
-     104             :         using type = T;
-     105             :         static constexpr size_t bits = std::numeric_limits<T>::digits;
-     106             :         static constexpr T mask = std::numeric_limits<T>::max();
-     107             : };
-     108             : 
-     109             : template<class T>
-     110             : struct expr_base;
-     111             : 
-     112             : template<size_t Bits>
-     113             : struct value : public expr_base<value<Bits>> {
-     114             :         static constexpr size_t bits = Bits;
-     115             : 
-     116             :         using chunk = chunk_traits<chunk_t>;
-     117             :         static constexpr chunk::type msb_mask = (Bits % chunk::bits == 0) ? chunk::mask
-     118             :                 : chunk::mask >> (chunk::bits - (Bits % chunk::bits));
-     119             : 
-     120             :         static constexpr size_t chunks = (Bits + chunk::bits - 1) / chunk::bits;
-     121             :         chunk::type data[chunks] = {};
-     122             : 
-     123           3 :         value() = default;
-     124             :         template<typename... Init>
-     125             :         explicit constexpr value(Init ...init) : data{init...} {}
-     126             : 
-     127             :         value(const value<Bits> &) = default;
-     128             :         value<Bits> &operator=(const value<Bits> &) = default;
-     129             : 
-     130             :         value(value<Bits> &&) = default;
-     131             :         value<Bits> &operator=(value<Bits> &&) = default;
-     132             : 
-     133             :         // A (no-op) helper that forces the cast to value<>.
-     134             :         CXXRTL_ALWAYS_INLINE
-     135             :         const value<Bits> &val() const {
-     136             :                 return *this;
-     137             :         }
-     138             : 
-     139             :         std::string str() const {
-     140             :                 std::stringstream ss;
-     141             :                 ss << *this;
-     142             :                 return ss.str();
-     143             :         }
-     144             : 
-     145             :         // Conversion operations.
-     146             :         //
-     147             :         // These functions ensure that a conversion is never out of range, and should be always used, if at all
-     148             :         // possible, instead of direct manipulation of the `data` member. For very large types, .slice() and
-     149             :         // .concat() can be used to split them into more manageable parts.
-     150             :         template<class IntegerT, typename std::enable_if<!std::is_signed<IntegerT>::value, int>::type = 0>
-     151             :         CXXRTL_ALWAYS_INLINE
-     152             :         IntegerT get() const {
-     153             :                 static_assert(std::numeric_limits<IntegerT>::is_integer && !std::numeric_limits<IntegerT>::is_signed,
-     154             :                               "get<T>() requires T to be an unsigned integral type");
-     155             :                 static_assert(std::numeric_limits<IntegerT>::digits >= Bits,
-     156             :                               "get<T>() requires T to be at least as wide as the value is");
-     157             :                 IntegerT result = 0;
-     158             :                 for (size_t n = 0; n < chunks; n++)
-     159             :                         result |= IntegerT(data[n]) << (n * chunk::bits);
-     160             :                 return result;
-     161             :         }
-     162             : 
-     163             :         template<class IntegerT, typename std::enable_if<std::is_signed<IntegerT>::value, int>::type = 0>
-     164             :         CXXRTL_ALWAYS_INLINE
-     165             :         IntegerT get() const {
-     166             :                 auto unsigned_result = get<typename std::make_unsigned<IntegerT>::type>();
-     167             :                 IntegerT result;
-     168             :                 memcpy(&result, &unsigned_result, sizeof(IntegerT));
-     169             :                 return result;
-     170             :         }
-     171             : 
-     172             :         template<class IntegerT, typename std::enable_if<!std::is_signed<IntegerT>::value, int>::type = 0>
-     173             :         CXXRTL_ALWAYS_INLINE
-     174          30 :         void set(IntegerT value) {
-     175             :                 static_assert(std::numeric_limits<IntegerT>::is_integer && !std::numeric_limits<IntegerT>::is_signed,
-     176             :                               "set<T>() requires T to be an unsigned integral type");
-     177             :                 static_assert(std::numeric_limits<IntegerT>::digits >= Bits,
-     178             :                               "set<T>() requires the value to be at least as wide as T is");
-     179           6 :                 for (size_t n = 0; n < chunks; n++)
-     180          36 :                         data[n] = (value >> (n * chunk::bits)) & chunk::mask;
-     181             :         }
-     182             : 
-     183             :         template<class IntegerT, typename std::enable_if<std::is_signed<IntegerT>::value, int>::type = 0>
-     184             :         CXXRTL_ALWAYS_INLINE
-     185             :         void set(IntegerT value) {
-     186             :                 typename std::make_unsigned<IntegerT>::type unsigned_value;
-     187             :                 memcpy(&unsigned_value, &value, sizeof(IntegerT));
-     188             :                 set(unsigned_value);
-     189             :         }
-     190             : 
-     191             :         // Operations with compile-time parameters.
-     192             :         //
-     193             :         // These operations are used to implement slicing, concatenation, and blitting.
-     194             :         // The trunc, zext and sext operations add or remove most significant bits (i.e. on the left);
-     195             :         // the rtrunc and rzext operations add or remove least significant bits (i.e. on the right).
-     196             :         template<size_t NewBits>
-     197             :         CXXRTL_ALWAYS_INLINE
-     198             :         value<NewBits> trunc() const {
-     199             :                 static_assert(NewBits <= Bits, "trunc() may not increase width");
-     200             :                 value<NewBits> result;
-     201             :                 for (size_t n = 0; n < result.chunks; n++)
-     202             :                         result.data[n] = data[n];
-     203             :                 result.data[result.chunks - 1] &= result.msb_mask;
-     204             :                 return result;
-     205             :         }
-     206             : 
-     207             :         template<size_t NewBits>
-     208             :         CXXRTL_ALWAYS_INLINE
-     209          33 :         value<NewBits> zext() const {
-     210             :                 static_assert(NewBits >= Bits, "zext() may not decrease width");
-     211             :                 value<NewBits> result;
-     212          33 :                 for (size_t n = 0; n < chunks; n++)
-     213          33 :                         result.data[n] = data[n];
-     214             :                 return result;
-     215             :         }
-     216             : 
-     217             :         template<size_t NewBits>
-     218             :         CXXRTL_ALWAYS_INLINE
-     219             :         value<NewBits> sext() const {
-     220             :                 static_assert(NewBits >= Bits, "sext() may not decrease width");
-     221             :                 value<NewBits> result;
-     222             :                 for (size_t n = 0; n < chunks; n++)
-     223             :                         result.data[n] = data[n];
-     224             :                 if (is_neg()) {
-     225             :                         result.data[chunks - 1] |= ~msb_mask;
-     226             :                         for (size_t n = chunks; n < result.chunks; n++)
-     227             :                                 result.data[n] = chunk::mask;
-     228             :                         result.data[result.chunks - 1] &= result.msb_mask;
-     229             :                 }
-     230             :                 return result;
-     231             :         }
-     232             : 
-     233             :         template<size_t NewBits>
-     234             :         CXXRTL_ALWAYS_INLINE
-     235             :         value<NewBits> rtrunc() const {
-     236             :                 static_assert(NewBits <= Bits, "rtrunc() may not increase width");
-     237             :                 value<NewBits> result;
-     238             :                 constexpr size_t shift_chunks = (Bits - NewBits) / chunk::bits;
-     239             :                 constexpr size_t shift_bits   = (Bits - NewBits) % chunk::bits;
-     240             :                 chunk::type carry = 0;
-     241             :                 if (shift_chunks + result.chunks < chunks) {
-     242             :                         carry = (shift_bits == 0) ? 0
-     243             :                                 : data[shift_chunks + result.chunks] << (chunk::bits - shift_bits);
-     244             :                 }
-     245             :                 for (size_t n = result.chunks; n > 0; n--) {
-     246             :                         result.data[n - 1] = carry | (data[shift_chunks + n - 1] >> shift_bits);
-     247             :                         carry = (shift_bits == 0) ? 0
-     248             :                                 : data[shift_chunks + n - 1] << (chunk::bits - shift_bits);
-     249             :                 }
-     250             :                 return result;
-     251             :         }
-     252             : 
-     253             :         template<size_t NewBits>
-     254             :         CXXRTL_ALWAYS_INLINE
-     255             :         value<NewBits> rzext() const {
-     256             :                 static_assert(NewBits >= Bits, "rzext() may not decrease width");
-     257             :                 value<NewBits> result;
-     258             :                 constexpr size_t shift_chunks = (NewBits - Bits) / chunk::bits;
-     259             :                 constexpr size_t shift_bits   = (NewBits - Bits) % chunk::bits;
-     260             :                 chunk::type carry = 0;
-     261             :                 for (size_t n = 0; n < chunks; n++) {
-     262             :                         result.data[shift_chunks + n] = (data[n] << shift_bits) | carry;
-     263             :                         carry = (shift_bits == 0) ? 0
-     264             :                                 : data[n] >> (chunk::bits - shift_bits);
-     265             :                 }
-     266             :                 if (shift_chunks + chunks < result.chunks)
-     267             :                         result.data[shift_chunks + chunks] = carry;
-     268             :                 return result;
-     269             :         }
-     270             : 
-     271             :         // Bit blit operation, i.e. a partial read-modify-write.
-     272             :         template<size_t Stop, size_t Start>
-     273             :         CXXRTL_ALWAYS_INLINE
-     274             :         value<Bits> blit(const value<Stop - Start + 1> &source) const {
-     275             :                 static_assert(Stop >= Start, "blit() may not reverse bit order");
-     276             :                 constexpr chunk::type start_mask = ~(chunk::mask << (Start % chunk::bits));
-     277             :                 constexpr chunk::type stop_mask = (Stop % chunk::bits + 1 == chunk::bits) ? 0
-     278             :                         : (chunk::mask << (Stop % chunk::bits + 1));
-     279             :                 value<Bits> masked = *this;
-     280             :                 if (Start / chunk::bits == Stop / chunk::bits) {
-     281             :                         masked.data[Start / chunk::bits] &= stop_mask | start_mask;
-     282             :                 } else {
-     283             :                         masked.data[Start / chunk::bits] &= start_mask;
-     284             :                         for (size_t n = Start / chunk::bits + 1; n < Stop / chunk::bits; n++)
-     285             :                                 masked.data[n] = 0;
-     286             :                         masked.data[Stop / chunk::bits] &= stop_mask;
-     287             :                 }
-     288             :                 value<Bits> shifted = source
-     289             :                         .template rzext<Stop + 1>()
-     290             :                         .template zext<Bits>();
-     291             :                 return masked.bit_or(shifted);
-     292             :         }
-     293             : 
-     294             :         // Helpers for selecting extending or truncating operation depending on whether the result is wider or narrower
-     295             :         // than the operand. In C++17 these can be replaced with `if constexpr`.
-     296             :         template<size_t NewBits, typename = void>
-     297             :         struct zext_cast {
-     298             :                 CXXRTL_ALWAYS_INLINE
-     299          33 :                 value<NewBits> operator()(const value<Bits> &val) {
-     300          33 :                         return val.template zext<NewBits>();
-     301             :                 }
-     302             :         };
-     303             : 
-     304             :         template<size_t NewBits>
-     305             :         struct zext_cast<NewBits, typename std::enable_if<(NewBits < Bits)>::type> {
-     306             :                 CXXRTL_ALWAYS_INLINE
-     307             :                 value<NewBits> operator()(const value<Bits> &val) {
-     308             :                         return val.template trunc<NewBits>();
-     309             :                 }
-     310             :         };
-     311             : 
-     312             :         template<size_t NewBits, typename = void>
-     313             :         struct sext_cast {
-     314             :                 CXXRTL_ALWAYS_INLINE
-     315             :                 value<NewBits> operator()(const value<Bits> &val) {
-     316             :                         return val.template sext<NewBits>();
-     317             :                 }
-     318             :         };
-     319             : 
-     320             :         template<size_t NewBits>
-     321             :         struct sext_cast<NewBits, typename std::enable_if<(NewBits < Bits)>::type> {
-     322             :                 CXXRTL_ALWAYS_INLINE
-     323             :                 value<NewBits> operator()(const value<Bits> &val) {
-     324             :                         return val.template trunc<NewBits>();
-     325             :                 }
-     326             :         };
-     327             : 
-     328             :         template<size_t NewBits>
-     329             :         CXXRTL_ALWAYS_INLINE
-     330          33 :         value<NewBits> zcast() const {
-     331          33 :                 return zext_cast<NewBits>()(*this);
-     332             :         }
-     333             : 
-     334             :         template<size_t NewBits>
-     335             :         CXXRTL_ALWAYS_INLINE
-     336             :         value<NewBits> scast() const {
-     337             :                 return sext_cast<NewBits>()(*this);
-     338             :         }
-     339             : 
-     340             :         // Bit replication is far more efficient than the equivalent concatenation.
-     341             :         template<size_t Count>
-     342             :         CXXRTL_ALWAYS_INLINE
-     343             :         value<Bits * Count> repeat() const {
-     344             :                 static_assert(Bits == 1, "repeat() is implemented only for 1-bit values");
-     345             :                 return *this ? value<Bits * Count>().bit_not() : value<Bits * Count>();
-     346             :         }
-     347             : 
-     348             :         // Operations with run-time parameters (offsets, amounts, etc).
-     349             :         //
-     350             :         // These operations are used for computations.
-     351             :         bool bit(size_t offset) const {
-     352             :                 return data[offset / chunk::bits] & (1 << (offset % chunk::bits));
-     353             :         }
-     354             : 
-     355             :         void set_bit(size_t offset, bool value = true) {
-     356             :                 size_t offset_chunks = offset / chunk::bits;
-     357             :                 size_t offset_bits = offset % chunk::bits;
-     358             :                 data[offset_chunks] &= ~(1 << offset_bits);
-     359             :                 data[offset_chunks] |= value ? 1 << offset_bits : 0;
-     360             :         }
-     361             : 
-     362             :         explicit operator bool() const {
-     363             :                 return !is_zero();
-     364             :         }
-     365             : 
-     366             :         bool is_zero() const {
-     367             :                 for (size_t n = 0; n < chunks; n++)
-     368             :                         if (data[n] != 0)
-     369             :                                 return false;
-     370             :                 return true;
-     371             :         }
-     372             : 
-     373             :         bool is_neg() const {
-     374             :                 return data[chunks - 1] & (1 << ((Bits - 1) % chunk::bits));
-     375             :         }
-     376             : 
-     377             :         bool operator ==(const value<Bits> &other) const {
-     378             :                 for (size_t n = 0; n < chunks; n++)
-     379             :                         if (data[n] != other.data[n])
-     380             :                                 return false;
-     381             :                 return true;
-     382             :         }
-     383             : 
-     384             :         bool operator !=(const value<Bits> &other) const {
-     385             :                 return !(*this == other);
-     386             :         }
-     387             : 
-     388             :         value<Bits> bit_not() const {
-     389             :                 value<Bits> result;
-     390             :                 for (size_t n = 0; n < chunks; n++)
-     391             :                         result.data[n] = ~data[n];
-     392             :                 result.data[chunks - 1] &= msb_mask;
-     393             :                 return result;
-     394             :         }
-     395             : 
-     396             :         value<Bits> bit_and(const value<Bits> &other) const {
-     397             :                 value<Bits> result;
-     398             :                 for (size_t n = 0; n < chunks; n++)
-     399             :                         result.data[n] = data[n] & other.data[n];
-     400             :                 return result;
-     401             :         }
-     402             : 
-     403             :         value<Bits> bit_or(const value<Bits> &other) const {
-     404             :                 value<Bits> result;
-     405             :                 for (size_t n = 0; n < chunks; n++)
-     406             :                         result.data[n] = data[n] | other.data[n];
-     407             :                 return result;
-     408             :         }
-     409             : 
-     410             :         value<Bits> bit_xor(const value<Bits> &other) const {
-     411             :                 value<Bits> result;
-     412             :                 for (size_t n = 0; n < chunks; n++)
-     413             :                         result.data[n] = data[n] ^ other.data[n];
-     414             :                 return result;
-     415             :         }
-     416             : 
-     417             :         value<Bits> update(const value<Bits> &val, const value<Bits> &mask) const {
-     418             :                 return bit_and(mask.bit_not()).bit_or(val.bit_and(mask));
-     419             :         }
-     420             : 
-     421             :         template<size_t AmountBits>
-     422             :         value<Bits> shl(const value<AmountBits> &amount) const {
-     423             :                 // Ensure our early return is correct by prohibiting values larger than 4 Gbit.
-     424             :                 static_assert(Bits <= chunk::mask, "shl() of unreasonably large values is not supported");
-     425             :                 // Detect shifts definitely large than Bits early.
-     426             :                 for (size_t n = 1; n < amount.chunks; n++)
-     427             :                         if (amount.data[n] != 0)
-     428             :                                 return {};
-     429             :                 // Past this point we can use the least significant chunk as the shift size.
-     430             :                 size_t shift_chunks = amount.data[0] / chunk::bits;
-     431             :                 size_t shift_bits   = amount.data[0] % chunk::bits;
-     432             :                 if (shift_chunks >= chunks)
-     433             :                         return {};
-     434             :                 value<Bits> result;
-     435             :                 chunk::type carry = 0;
-     436             :                 for (size_t n = 0; n < chunks - shift_chunks; n++) {
-     437             :                         result.data[shift_chunks + n] = (data[n] << shift_bits) | carry;
-     438             :                         carry = (shift_bits == 0) ? 0
-     439             :                                 : data[n] >> (chunk::bits - shift_bits);
-     440             :                 }
-     441             :                 result.data[result.chunks - 1] &= result.msb_mask;
-     442             :                 return result;
-     443             :         }
-     444             : 
-     445             :         template<size_t AmountBits, bool Signed = false>
-     446             :         value<Bits> shr(const value<AmountBits> &amount) const {
-     447             :                 // Ensure our early return is correct by prohibiting values larger than 4 Gbit.
-     448             :                 static_assert(Bits <= chunk::mask, "shr() of unreasonably large values is not supported");
-     449             :                 // Detect shifts definitely large than Bits early.
-     450             :                 for (size_t n = 1; n < amount.chunks; n++)
-     451             :                         if (amount.data[n] != 0)
-     452             :                                 return (Signed && is_neg()) ? value<Bits>().bit_not() : value<Bits>();
-     453             :                 // Past this point we can use the least significant chunk as the shift size.
-     454             :                 size_t shift_chunks = amount.data[0] / chunk::bits;
-     455             :                 size_t shift_bits   = amount.data[0] % chunk::bits;
-     456             :                 if (shift_chunks >= chunks)
-     457             :                         return (Signed && is_neg()) ? value<Bits>().bit_not() : value<Bits>();
-     458             :                 value<Bits> result;
-     459             :                 chunk::type carry = 0;
-     460             :                 for (size_t n = 0; n < chunks - shift_chunks; n++) {
-     461             :                         result.data[chunks - shift_chunks - 1 - n] = carry | (data[chunks - 1 - n] >> shift_bits);
-     462             :                         carry = (shift_bits == 0) ? 0
-     463             :                                 : data[chunks - 1 - n] << (chunk::bits - shift_bits);
-     464             :                 }
-     465             :                 if (Signed && is_neg()) {
-     466             :                         size_t top_chunk_idx  = amount.data[0] > Bits ? 0 : (Bits - amount.data[0]) / chunk::bits;
-     467             :                         size_t top_chunk_bits = amount.data[0] > Bits ? 0 : (Bits - amount.data[0]) % chunk::bits;
-     468             :                         for (size_t n = top_chunk_idx + 1; n < chunks; n++)
-     469             :                                 result.data[n] = chunk::mask;
-     470             :                         if (amount.data[0] != 0)
-     471             :                                 result.data[top_chunk_idx] |= chunk::mask << top_chunk_bits;
-     472             :                         result.data[result.chunks - 1] &= result.msb_mask;
-     473             :                 }
-     474             :                 return result;
-     475             :         }
-     476             : 
-     477             :         template<size_t AmountBits>
-     478             :         value<Bits> sshr(const value<AmountBits> &amount) const {
-     479             :                 return shr<AmountBits, /*Signed=*/true>(amount);
-     480             :         }
-     481             : 
-     482             :         template<size_t ResultBits, size_t SelBits>
-     483             :         value<ResultBits> bmux(const value<SelBits> &sel) const {
-     484             :                 static_assert(ResultBits << SelBits == Bits, "invalid sizes used in bmux()");
-     485             :                 size_t amount = sel.data[0] * ResultBits;
-     486             :                 size_t shift_chunks = amount / chunk::bits;
-     487             :                 size_t shift_bits   = amount % chunk::bits;
-     488             :                 value<ResultBits> result;
-     489             :                 chunk::type carry = 0;
-     490             :                 if (ResultBits % chunk::bits + shift_bits > chunk::bits)
-     491             :                         carry = data[result.chunks + shift_chunks] << (chunk::bits - shift_bits);
-     492             :                 for (size_t n = 0; n < result.chunks; n++) {
-     493             :                         result.data[result.chunks - 1 - n] = carry | (data[result.chunks + shift_chunks - 1 - n] >> shift_bits);
-     494             :                         carry = (shift_bits == 0) ? 0
-     495             :                                 : data[result.chunks + shift_chunks - 1 - n] << (chunk::bits - shift_bits);
-     496             :                 }
-     497             :                 result.data[result.chunks - 1] &= result.msb_mask;
-     498             :                 return result;
-     499             :         }
-     500             : 
-     501             :         template<size_t ResultBits, size_t SelBits>
-     502             :         value<ResultBits> demux(const value<SelBits> &sel) const {
-     503             :                 static_assert(Bits << SelBits == ResultBits, "invalid sizes used in demux()");
-     504             :                 size_t amount = sel.data[0] * Bits;
-     505             :                 size_t shift_chunks = amount / chunk::bits;
-     506             :                 size_t shift_bits   = amount % chunk::bits;
-     507             :                 value<ResultBits> result;
-     508             :                 chunk::type carry = 0;
-     509             :                 for (size_t n = 0; n < chunks; n++) {
-     510             :                         result.data[shift_chunks + n] = (data[n] << shift_bits) | carry;
-     511             :                         carry = (shift_bits == 0) ? 0
-     512             :                                 : data[n] >> (chunk::bits - shift_bits);
-     513             :                 }
-     514             :                 if (Bits % chunk::bits + shift_bits > chunk::bits)
-     515             :                         result.data[shift_chunks + chunks] = carry;
-     516             :                 return result;
-     517             :         }
-     518             : 
-     519             :         size_t ctpop() const {
-     520             :                 size_t count = 0;
-     521             :                 for (size_t n = 0; n < chunks; n++) {
-     522             :                         // This loop implements the population count idiom as recognized by LLVM and GCC.
-     523             :                         for (chunk::type x = data[n]; x != 0; count++)
-     524             :                                 x = x & (x - 1);
-     525             :                 }
-     526             :                 return count;
-     527             :         }
-     528             : 
-     529             :         size_t ctlz() const {
-     530             :                 size_t count = 0;
-     531             :                 for (size_t n = 0; n < chunks; n++) {
-     532             :                         chunk::type x = data[chunks - 1 - n];
-     533             :                         // First add to `count` as if the chunk is zero
-     534             :                         constexpr size_t msb_chunk_bits = Bits % chunk::bits != 0 ? Bits % chunk::bits : chunk::bits;
-     535             :                         count += (n == 0 ? msb_chunk_bits : chunk::bits);
-     536             :                         // If the chunk isn't zero, correct the `count` value and return
-     537             :                         if (x != 0) {
-     538             :                                 for (; x != 0; count--)
-     539             :                                         x >>= 1;
-     540             :                                 break;
-     541             :                         }
-     542             :                 }
-     543             :                 return count;
-     544             :         }
-     545             : 
-     546             :         template<bool Invert, bool CarryIn>
-     547          33 :         std::pair<value<Bits>, bool /*CarryOut*/> alu(const value<Bits> &other) const {
-     548          33 :                 value<Bits> result;
-     549          33 :                 bool carry = CarryIn;
-     550          66 :                 for (size_t n = 0; n < result.chunks; n++) {
-     551          33 :                         result.data[n] = data[n] + (Invert ? ~other.data[n] : other.data[n]) + carry;
-     552             :                         if (result.chunks - 1 == n)
-     553          33 :                                 result.data[result.chunks - 1] &= result.msb_mask;
-     554          33 :                         carry = (result.data[n] <  data[n]) ||
-     555             :                                 (result.data[n] == data[n] && carry);
-     556             :                 }
-     557          33 :                 return {result, carry};
-     558             :         }
-     559             : 
-     560          33 :         value<Bits> add(const value<Bits> &other) const {
-     561          33 :                 return alu</*Invert=*/false, /*CarryIn=*/false>(other).first;
-     562             :         }
-     563             : 
-     564             :         value<Bits> sub(const value<Bits> &other) const {
-     565             :                 return alu</*Invert=*/true, /*CarryIn=*/true>(other).first;
-     566             :         }
-     567             : 
-     568             :         value<Bits> neg() const {
-     569             :                 return value<Bits>().sub(*this);
-     570             :         }
-     571             : 
-     572             :         bool ucmp(const value<Bits> &other) const {
-     573             :                 bool carry;
-     574             :                 std::tie(std::ignore, carry) = alu</*Invert=*/true, /*CarryIn=*/true>(other);
-     575             :                 return !carry; // a.ucmp(b) ≡ a u< b
-     576             :         }
-     577             : 
-     578             :         bool scmp(const value<Bits> &other) const {
-     579             :                 value<Bits> result;
-     580             :                 bool carry;
-     581             :                 std::tie(result, carry) = alu</*Invert=*/true, /*CarryIn=*/true>(other);
-     582             :                 bool overflow = (is_neg() == !other.is_neg()) && (is_neg() != result.is_neg());
-     583             :                 return result.is_neg() ^ overflow; // a.scmp(b) ≡ a s< b
-     584             :         }
-     585             : 
-     586             :         template<size_t ResultBits>
-     587             :         value<ResultBits> mul(const value<Bits> &other) const {
-     588             :                 value<ResultBits> result;
-     589             :                 wide_chunk_t wide_result[result.chunks + 1] = {};
-     590             :                 for (size_t n = 0; n < chunks; n++) {
-     591             :                         for (size_t m = 0; m < chunks && n + m < result.chunks; m++) {
-     592             :                                 wide_result[n + m] += wide_chunk_t(data[n]) * wide_chunk_t(other.data[m]);
-     593             :                                 wide_result[n + m + 1] += wide_result[n + m] >> chunk::bits;
-     594             :                                 wide_result[n + m] &= chunk::mask;
-     595             :                         }
-     596             :                 }
-     597             :                 for (size_t n = 0; n < result.chunks; n++) {
-     598             :                         result.data[n] = wide_result[n];
-     599             :                 }
-     600             :                 result.data[result.chunks - 1] &= result.msb_mask;
-     601             :                 return result;
-     602             :         }
-     603             : 
-     604             :         std::pair<value<Bits>, value<Bits>> udivmod(value<Bits> divisor) const {
-     605             :                 value<Bits> quotient;
-     606             :                 value<Bits> dividend = *this;
-     607             :                 if (dividend.ucmp(divisor))
-     608             :                         return {/*quotient=*/value<Bits>{0u}, /*remainder=*/dividend};
-     609             :                 int64_t divisor_shift = divisor.ctlz() - dividend.ctlz();
-     610             :                 assert(divisor_shift >= 0);
-     611             :                 divisor = divisor.shl(value<Bits>{(chunk::type) divisor_shift});
-     612             :                 for (size_t step = 0; step <= divisor_shift; step++) {
-     613             :                         quotient = quotient.shl(value<Bits>{1u});
-     614             :                         if (!dividend.ucmp(divisor)) {
-     615             :                                 dividend = dividend.sub(divisor);
-     616             :                                 quotient.set_bit(0, true);
-     617             :                         }
-     618             :                         divisor = divisor.shr(value<Bits>{1u});
-     619             :                 }
-     620             :                 return {quotient, /*remainder=*/dividend};
-     621             :         }
-     622             : 
-     623             :         std::pair<value<Bits>, value<Bits>> sdivmod(const value<Bits> &other) const {
-     624             :                 value<Bits + 1> quotient;
-     625             :                 value<Bits + 1> remainder;
-     626             :                 value<Bits + 1> dividend = sext<Bits + 1>();
-     627             :                 value<Bits + 1> divisor = other.template sext<Bits + 1>();
-     628             :                 if (is_neg()) dividend = dividend.neg();
-     629             :                 if (other.is_neg()) divisor = divisor.neg();
-     630             :                 std::tie(quotient, remainder) = dividend.udivmod(divisor);
-     631             :                 if (is_neg() != other.is_neg()) quotient = quotient.neg();
-     632             :                 if (is_neg()) remainder = remainder.neg();
-     633             :                 return {quotient.template trunc<Bits>(), remainder.template trunc<Bits>()};
-     634             :         }
-     635             : };
-     636             : 
-     637             : // Expression template for a slice, usable as lvalue or rvalue, and composable with other expression templates here.
-     638             : template<class T, size_t Stop, size_t Start>
-     639             : struct slice_expr : public expr_base<slice_expr<T, Stop, Start>> {
-     640             :         static_assert(Stop >= Start, "slice_expr() may not reverse bit order");
-     641             :         static_assert(Start < T::bits && Stop < T::bits, "slice_expr() must be within bounds");
-     642             :         static constexpr size_t bits = Stop - Start + 1;
-     643             : 
-     644             :         T &expr;
-     645             : 
-     646             :         slice_expr(T &expr) : expr(expr) {}
-     647             :         slice_expr(const slice_expr<T, Stop, Start> &) = delete;
-     648             : 
-     649             :         CXXRTL_ALWAYS_INLINE
-     650             :         operator value<bits>() const {
-     651             :                 return static_cast<const value<T::bits> &>(expr)
-     652             :                         .template rtrunc<T::bits - Start>()
-     653             :                         .template trunc<bits>();
-     654             :         }
-     655             : 
-     656             :         CXXRTL_ALWAYS_INLINE
-     657             :         slice_expr<T, Stop, Start> &operator=(const value<bits> &rhs) {
-     658             :                 // Generic partial assignment implemented using a read-modify-write operation on the sliced expression.
-     659             :                 expr = static_cast<const value<T::bits> &>(expr)
-     660             :                         .template blit<Stop, Start>(rhs);
-     661             :                 return *this;
-     662             :         }
-     663             : 
-     664             :         // A helper that forces the cast to value<>, which allows deduction to work.
-     665             :         CXXRTL_ALWAYS_INLINE
-     666             :         value<bits> val() const {
-     667             :                 return static_cast<const value<bits> &>(*this);
-     668             :         }
-     669             : };
-     670             : 
-     671             : // Expression template for a concatenation, usable as lvalue or rvalue, and composable with other expression templates here.
-     672             : template<class T, class U>
-     673             : struct concat_expr : public expr_base<concat_expr<T, U>> {
-     674             :         static constexpr size_t bits = T::bits + U::bits;
-     675             : 
-     676             :         T &ms_expr;
-     677             :         U &ls_expr;
-     678             : 
-     679             :         concat_expr(T &ms_expr, U &ls_expr) : ms_expr(ms_expr), ls_expr(ls_expr) {}
-     680             :         concat_expr(const concat_expr<T, U> &) = delete;
-     681             : 
-     682             :         CXXRTL_ALWAYS_INLINE
-     683             :         operator value<bits>() const {
-     684             :                 value<bits> ms_shifted = static_cast<const value<T::bits> &>(ms_expr)
-     685             :                         .template rzext<bits>();
-     686             :                 value<bits> ls_extended = static_cast<const value<U::bits> &>(ls_expr)
-     687             :                         .template zext<bits>();
-     688             :                 return ms_shifted.bit_or(ls_extended);
-     689             :         }
-     690             : 
-     691             :         CXXRTL_ALWAYS_INLINE
-     692             :         concat_expr<T, U> &operator=(const value<bits> &rhs) {
-     693             :                 ms_expr = rhs.template rtrunc<T::bits>();
-     694             :                 ls_expr = rhs.template trunc<U::bits>();
-     695             :                 return *this;
-     696             :         }
-     697             : 
-     698             :         // A helper that forces the cast to value<>, which allows deduction to work.
-     699             :         CXXRTL_ALWAYS_INLINE
-     700             :         value<bits> val() const {
-     701             :                 return static_cast<const value<bits> &>(*this);
-     702             :         }
-     703             : };
-     704             : 
-     705             : // Base class for expression templates, providing helper methods for operations that are valid on both rvalues and lvalues.
-     706             : //
-     707             : // Note that expression objects (slices and concatenations) constructed in this way should NEVER be captured because
-     708             : // they refer to temporaries that will, in general, only live until the end of the statement. For example, both of
-     709             : // these snippets perform use-after-free:
-     710             : //
-     711             : //    const auto &a = val.slice<7,0>().slice<1>();
-     712             : //    value<1> b = a;
-     713             : //
-     714             : //    auto &&c = val.slice<7,0>().slice<1>();
-     715             : //    c = value<1>{1u};
-     716             : //
-     717             : // An easy way to write code using slices and concatenations safely is to follow two simple rules:
-     718             : //   * Never explicitly name any type except `value<W>` or `const value<W> &`.
-     719             : //   * Never use a `const auto &` or `auto &&` in any such expression.
-     720             : // Then, any code that compiles will be well-defined.
-     721             : template<class T>
-     722             : struct expr_base {
-     723             :         template<size_t Stop, size_t Start = Stop>
-     724             :         CXXRTL_ALWAYS_INLINE
-     725             :         slice_expr<const T, Stop, Start> slice() const {
-     726             :                 return {*static_cast<const T *>(this)};
-     727             :         }
-     728             : 
-     729             :         template<size_t Stop, size_t Start = Stop>
-     730             :         CXXRTL_ALWAYS_INLINE
-     731             :         slice_expr<T, Stop, Start> slice() {
-     732             :                 return {*static_cast<T *>(this)};
-     733             :         }
-     734             : 
-     735             :         template<class U>
-     736             :         CXXRTL_ALWAYS_INLINE
-     737             :         concat_expr<const T, typename std::remove_reference<const U>::type> concat(const U &other) const {
-     738             :                 return {*static_cast<const T *>(this), other};
-     739             :         }
-     740             : 
-     741             :         template<class U>
-     742             :         CXXRTL_ALWAYS_INLINE
-     743             :         concat_expr<T, typename std::remove_reference<U>::type> concat(U &&other) {
-     744             :                 return {*static_cast<T *>(this), other};
-     745             :         }
-     746             : };
-     747             : 
-     748             : template<size_t Bits>
-     749             : std::ostream &operator<<(std::ostream &os, const value<Bits> &val) {
-     750             :         auto old_flags = os.flags(std::ios::right);
-     751             :         auto old_width = os.width(0);
-     752             :         auto old_fill  = os.fill('0');
-     753             :         os << val.bits << '\'' << std::hex;
-     754             :         for (size_t n = val.chunks - 1; n != (size_t)-1; n--) {
-     755             :                 if (n == val.chunks - 1 && Bits % value<Bits>::chunk::bits != 0)
-     756             :                         os.width((Bits % value<Bits>::chunk::bits + 3) / 4);
-     757             :                 else
-     758             :                         os.width((value<Bits>::chunk::bits + 3) / 4);
-     759             :                 os << val.data[n];
-     760             :         }
-     761             :         os.fill(old_fill);
-     762             :         os.width(old_width);
-     763             :         os.flags(old_flags);
-     764             :         return os;
-     765             : }
-     766             : 
-     767             : template<size_t Bits>
-     768             : struct wire {
-     769             :         static constexpr size_t bits = Bits;
-     770             : 
-     771             :         value<Bits> curr;
-     772             :         value<Bits> next;
-     773             : 
-     774             :         wire() = default;
-     775             :         explicit constexpr wire(const value<Bits> &init) : curr(init), next(init) {}
-     776             :         template<typename... Init>
-     777             :         explicit constexpr wire(Init ...init) : curr{init...}, next{init...} {}
-     778             : 
-     779             :         // Copying and copy-assigning values is natural. If, however, a value is replaced with a wire,
-     780             :         // e.g. because a module is built with a different optimization level, then existing code could
-     781             :         // unintentionally copy a wire instead, which would create a subtle but serious bug. To make sure
-     782             :         // this doesn't happen, prohibit copying and copy-assigning wires.
-     783             :         wire(const wire<Bits> &) = delete;
-     784             :         wire<Bits> &operator=(const wire<Bits> &) = delete;
-     785             : 
-     786             :         wire(wire<Bits> &&) = default;
-     787             :         wire<Bits> &operator=(wire<Bits> &&) = default;
-     788             : 
-     789             :         template<class IntegerT>
-     790             :         CXXRTL_ALWAYS_INLINE
-     791             :         IntegerT get() const {
-     792             :                 return curr.template get<IntegerT>();
-     793             :         }
-     794             : 
-     795             :         template<class IntegerT>
-     796             :         CXXRTL_ALWAYS_INLINE
-     797             :         void set(IntegerT other) {
-     798             :                 next.template set<IntegerT>(other);
-     799             :         }
-     800             : 
-     801             :         // This method intentionally takes a mandatory argument (to make it more difficult to misuse in
-     802             :         // black box implementations, leading to missed observer events). It is generic over its argument
-     803             :         // to allow the `on_update` method to be non-virtual.
-     804             :         template<class ObserverT>
-     805             :         bool commit(ObserverT &observer) {
-     806             :                 if (curr != next) {
-     807             :                         observer.on_update(curr.chunks, curr.data, next.data);
-     808             :                         curr = next;
-     809             :                         return true;
-     810             :                 }
-     811             :                 return false;
-     812             :         }
-     813             : };
-     814             : 
-     815             : template<size_t Bits>
-     816             : std::ostream &operator<<(std::ostream &os, const wire<Bits> &val) {
-     817             :         os << val.curr;
-     818             :         return os;
-     819             : }
-     820             : 
-     821             : template<size_t Width>
-     822             : struct memory {
-     823             :         const size_t depth;
-     824             :         std::unique_ptr<value<Width>[]> data;
-     825             : 
-     826             :         explicit memory(size_t depth) : depth(depth), data(new value<Width>[depth]) {}
-     827             : 
-     828             :         memory(const memory<Width> &) = delete;
-     829             :         memory<Width> &operator=(const memory<Width> &) = delete;
-     830             : 
-     831             :         memory(memory<Width> &&) = default;
-     832             :         memory<Width> &operator=(memory<Width> &&other) {
-     833             :                 assert(depth == other.depth);
-     834             :                 data = std::move(other.data);
-     835             :                 write_queue = std::move(other.write_queue);
-     836             :                 return *this;
-     837             :         }
-     838             : 
-     839             :         // An operator for direct memory reads. May be used at any time during the simulation.
-     840             :         const value<Width> &operator [](size_t index) const {
-     841             :                 assert(index < depth);
-     842             :                 return data[index];
-     843             :         }
-     844             : 
-     845             :         // An operator for direct memory writes. May only be used before the simulation is started. If used
-     846             :         // after the simulation is started, the design may malfunction.
-     847             :         value<Width> &operator [](size_t index) {
-     848             :                 assert(index < depth);
-     849             :                 return data[index];
-     850             :         }
-     851             : 
-     852             :         // A simple way to make a writable memory would be to use an array of wires instead of an array of values.
-     853             :         // However, there are two significant downsides to this approach: first, it has large overhead (2× space
-     854             :         // overhead, and O(depth) time overhead during commit); second, it does not simplify handling write port
-     855             :         // priorities. Although in principle write ports could be ordered or conditionally enabled in generated
-     856             :         // code based on their priorities and selected addresses, the feedback arc set problem is computationally
-     857             :         // expensive, and the heuristic based algorithms are not easily modified to guarantee (rather than prefer)
-     858             :         // a particular write port evaluation order.
-     859             :         //
-     860             :         // The approach used here instead is to queue writes into a buffer during the eval phase, then perform
-     861             :         // the writes during the commit phase in the priority order. This approach has low overhead, with both space
-     862             :         // and time proportional to the amount of write ports. Because virtually every memory in a practical design
-     863             :         // has at most two write ports, linear search is used on every write, being the fastest and simplest approach.
-     864             :         struct write {
-     865             :                 size_t index;
-     866             :                 value<Width> val;
-     867             :                 value<Width> mask;
-     868             :                 int priority;
-     869             :         };
-     870             :         std::vector<write> write_queue;
-     871             : 
-     872             :         void update(size_t index, const value<Width> &val, const value<Width> &mask, int priority = 0) {
-     873             :                 assert(index < depth);
-     874             :                 // Queue up the write while keeping the queue sorted by priority.
-     875             :                 write_queue.insert(
-     876             :                         std::upper_bound(write_queue.begin(), write_queue.end(), priority,
-     877             :                                 [](const int a, const write& b) { return a < b.priority; }),
-     878             :                         write { index, val, mask, priority });
-     879             :         }
-     880             : 
-     881             :         // See the note for `wire::commit()`.
-     882             :         template<class ObserverT>
-     883             :         bool commit(ObserverT &observer) {
-     884             :                 bool changed = false;
-     885             :                 for (const write &entry : write_queue) {
-     886             :                         value<Width> elem = data[entry.index];
-     887             :                         elem = elem.update(entry.val, entry.mask);
-     888             :                         if (data[entry.index] != elem) {
-     889             :                                 observer.on_update(value<Width>::chunks, data[0].data, elem.data, entry.index);
-     890             :                                 changed |= true;
-     891             :                         }
-     892             :                         data[entry.index] = elem;
-     893             :                 }
-     894             :                 write_queue.clear();
-     895             :                 return changed;
-     896             :         }
-     897             : };
-     898             : 
-     899          27 : struct metadata {
-     900             :         const enum {
-     901             :                 MISSING = 0,
-     902             :                 UINT    = 1,
-     903             :                 SINT    = 2,
-     904             :                 STRING  = 3,
-     905             :                 DOUBLE  = 4,
-     906             :         } value_type;
-     907             : 
-     908             :         // In debug mode, using the wrong .as_*() function will assert.
-     909             :         // In release mode, using the wrong .as_*() function will safely return a default value.
-     910             :         const uint64_t    uint_value = 0;
-     911             :         const int64_t     sint_value = 0;
-     912             :         const std::string string_value = "";
-     913             :         const double      double_value = 0.0;
-     914             : 
-     915             :         metadata() : value_type(MISSING) {}
-     916           0 :         metadata(uint64_t value) : value_type(UINT), uint_value(value) {}
-     917           0 :         metadata(int64_t value) : value_type(SINT), sint_value(value) {}
-     918           9 :         metadata(const std::string &value) : value_type(STRING), string_value(value) {}
-     919           0 :         metadata(const char *value) : value_type(STRING), string_value(value) {}
-     920           0 :         metadata(double value) : value_type(DOUBLE), double_value(value) {}
-     921             : 
-     922          18 :         metadata(const metadata &) = default;
-     923             :         metadata &operator=(const metadata &) = delete;
-     924             : 
-     925             :         uint64_t as_uint() const {
-     926             :                 assert(value_type == UINT);
-     927             :                 return uint_value;
-     928             :         }
-     929             : 
-     930             :         int64_t as_sint() const {
-     931             :                 assert(value_type == SINT);
-     932             :                 return sint_value;
-     933             :         }
-     934             : 
-     935             :         const std::string &as_string() const {
-     936             :                 assert(value_type == STRING);
-     937             :                 return string_value;
-     938             :         }
-     939             : 
-     940             :         double as_double() const {
-     941             :                 assert(value_type == DOUBLE);
-     942             :                 return double_value;
-     943             :         }
-     944             : 
-     945             :         // Internal CXXRTL use only.
-     946           9 :         static std::map<std::string, metadata> deserialize(const char *ptr) {
-     947           9 :                 std::map<std::string, metadata> result;
-     948           9 :                 std::string name;
-     949             :                 // Grammar:
-     950             :                 // string   ::= [^\0]+ \0
-     951             :                 // metadata ::= [uid] .{8} | s <string>
-     952             :                 // map      ::= ( <string> <metadata> )* \0
-     953          45 :                 for (;;) {
-     954          45 :                         if (*ptr) {
-     955          45 :                                 name += *ptr++;
-     956          18 :                         } else if (!name.empty()) {
-     957           9 :                                 ptr++;
-     958           9 :                                 auto get_u64 = [&]() {
-     959           0 :                                         uint64_t result = 0;
-     960           0 :                                         for (size_t count = 0; count < 8; count++)
-     961           0 :                                                 result = (result << 8) | *ptr++;
-     962           0 :                                         return result;
-     963           9 :                                 };
-     964           9 :                                 char type = *ptr++;
-     965           9 :                                 if (type == 'u') {
-     966           0 :                                         uint64_t value = get_u64();
-     967           0 :                                         result.emplace(name, value);
-     968           9 :                                 } else if (type == 'i') {
-     969           0 :                                         int64_t value = (int64_t)get_u64();
-     970           0 :                                         result.emplace(name, value);
-     971           9 :                                 } else if (type == 'd') {
-     972           0 :                                         double dvalue;
-     973           0 :                                         uint64_t uvalue = get_u64();
-     974           0 :                                         static_assert(sizeof(dvalue) == sizeof(uvalue), "double must be 64 bits in size");
-     975           0 :                                         memcpy(&dvalue, &uvalue, sizeof(dvalue));
-     976           0 :                                         result.emplace(name, dvalue);
-     977           9 :                                 } else if (type == 's') {
-     978           9 :                                         std::string value;
-     979           9 :                                         while (*ptr)
-     980         216 :                                                 value += *ptr++;
-     981           9 :                                         ptr++;
-     982           9 :                                         result.emplace(name, value);
-     983           9 :                                 } else {
-     984           0 :                                         assert(false && "Unknown type specifier");
-     985           9 :                                         return result;
-     986             :                                 }
-     987           9 :                                 name.clear();
-     988             :                         } else {
-     989           9 :                                 return result;
-     990             :                         }
-     991             :                 }
-     992           9 :         }
-     993             : };
-     994             : 
-     995             : typedef std::map<std::string, metadata> metadata_map;
-     996             : 
-     997             : struct performer;
-     998             : 
-     999             : // An object that allows formatting a string lazily.
-    1000             : struct lazy_fmt {
-    1001             :         virtual std::string operator() () const = 0;
-    1002             : };
-    1003             : 
-    1004             : // Flavor of a `$check` cell.
-    1005             : enum class flavor {
-    1006             :         // Corresponds to a `$assert` cell in other flows, and a Verilog `assert ()` statement.
-    1007             :         ASSERT,
-    1008             :         // Corresponds to a `$assume` cell in other flows, and a Verilog `assume ()` statement.
-    1009             :         ASSUME,
-    1010             :         // Corresponds to a `$live` cell in other flows, and a Verilog `assert (eventually)` statement.
-    1011             :         ASSERT_EVENTUALLY,
-    1012             :         // Corresponds to a `$fair` cell in other flows, and a Verilog `assume (eventually)` statement.
-    1013             :         ASSUME_EVENTUALLY,
-    1014             :         // Corresponds to a `$cover` cell in other flows, and a Verilog `cover ()` statement.
-    1015             :         COVER,
-    1016             : };
-    1017             : 
-    1018             : // An object that can be passed to a `eval()` method in order to act on side effects. The default behavior implemented
-    1019             : // below is the same as the behavior of `eval(nullptr)`, except that `-print-output` option of `write_cxxrtl` is not
-    1020             : // taken into account.
-    1021             : struct performer {
-    1022             :         // Called by generated formatting code to evaluate a Verilog `$time` expression.
-    1023             :         virtual int64_t vlog_time() const { return 0; }
-    1024             : 
-    1025             :         // Called by generated formatting code to evaluate a Verilog `$realtime` expression.
-    1026             :         virtual double vlog_realtime() const { return vlog_time(); }
-    1027             : 
-    1028             :         // Called when a `$print` cell is triggered.
-    1029             :         virtual void on_print(const lazy_fmt &formatter, const metadata_map &attributes) {
-    1030             :                 std::cout << formatter();
-    1031             :         }
-    1032             : 
-    1033             :         // Called when a `$check` cell is triggered.
-    1034             :         virtual void on_check(flavor type, bool condition, const lazy_fmt &formatter, const metadata_map &attributes) {
-    1035             :                 if (type == flavor::ASSERT || type == flavor::ASSUME) {
-    1036             :                         if (!condition)
-    1037             :                                 std::cerr << formatter();
-    1038             :                         CXXRTL_ASSERT(condition && "Check failed");
-    1039             :                 }
-    1040             :         }
-    1041             : };
-    1042             : 
-    1043             : // An object that can be passed to a `commit()` method in order to produce a replay log of every state change in
-    1044             : // the simulation. Unlike `performer`, `observer` does not use virtual calls as their overhead is unacceptable, and
-    1045             : // a comparatively heavyweight template-based solution is justified.
-    1046             : struct observer {
-    1047             :         // Called when the `commit()` method for a wire is about to update the `chunks` chunks at `base` with `chunks` chunks
-    1048             :         // at `value` that have a different bit pattern. It is guaranteed that `chunks` is equal to the wire chunk count and
-    1049             :         // `base` points to the first chunk.
-    1050             :         void on_update(size_t chunks, const chunk_t *base, const chunk_t *value) {}
-    1051             : 
-    1052             :         // Called when the `commit()` method for a memory is about to update the `chunks` chunks at `&base[chunks * index]`
-    1053             :         // with `chunks` chunks at `value` that have a different bit pattern. It is guaranteed that `chunks` is equal to
-    1054             :         // the memory element chunk count and `base` points to the first chunk of the first element of the memory.
-    1055             :         void on_update(size_t chunks, const chunk_t *base, const chunk_t *value, size_t index) {}
-    1056             : };
-    1057             : 
-    1058             : // Must be kept in sync with `struct FmtPart` in kernel/fmt.h!
-    1059             : // Default member initializers would make this a non-aggregate-type in C++11, so they are commented out.
-    1060             : struct fmt_part {
-    1061             :         enum {
-    1062             :                 LITERAL   = 0,
-    1063             :                 INTEGER   = 1,
-    1064             :                 STRING    = 2,
-    1065             :                 UNICHAR   = 3,
-    1066             :                 VLOG_TIME = 4,
-    1067             :         } type;
-    1068             : 
-    1069             :         // LITERAL type
-    1070             :         std::string str;
-    1071             : 
-    1072             :         // INTEGER/STRING/UNICHAR types
-    1073             :         // + value<Bits> val;
-    1074             : 
-    1075             :         // INTEGER/STRING/VLOG_TIME types
-    1076             :         enum {
-    1077             :                 RIGHT   = 0,
-    1078             :                 LEFT    = 1,
-    1079             :                 NUMERIC = 2,
-    1080             :         } justify; // = RIGHT;
-    1081             :         char padding; // = '\0';
-    1082             :         size_t width; // = 0;
-    1083             : 
-    1084             :         // INTEGER type
-    1085             :         unsigned base; // = 10;
-    1086             :         bool signed_; // = false;
-    1087             :         enum {
-    1088             :                 MINUS           = 0,
-    1089             :                 PLUS_MINUS      = 1,
-    1090             :                 SPACE_MINUS     = 2,
-    1091             :         } sign; // = MINUS;
-    1092             :         bool hex_upper; // = false;
-    1093             :         bool show_base; // = false;
-    1094             :         bool group; // = false;
-    1095             : 
-    1096             :         // VLOG_TIME type
-    1097             :         bool realtime; // = false;
-    1098             :         // + int64_t itime;
-    1099             :         // + double ftime;
-    1100             : 
-    1101             :         // Format the part as a string.
-    1102             :         //
-    1103             :         // The values of `vlog_time` and `vlog_realtime` are used for Verilog `$time` and `$realtime`, correspondingly.
-    1104             :         template<size_t Bits>
-    1105             :         std::string render(value<Bits> val, performer *performer = nullptr)
-    1106             :         {
-    1107             :                 // We might want to replace some of these bit() calls with direct
-    1108             :                 // chunk access if it turns out to be slow enough to matter.
-    1109             :                 std::string buf;
-    1110             :                 std::string prefix;
-    1111             :                 switch (type) {
-    1112             :                         case LITERAL:
-    1113             :                                 return str;
-    1114             : 
-    1115             :                         case STRING: {
-    1116             :                                 buf.reserve(Bits/8);
-    1117             :                                 for (int i = 0; i < Bits; i += 8) {
-    1118             :                                         char ch = 0;
-    1119             :                                         for (int j = 0; j < 8 && i + j < int(Bits); j++)
-    1120             :                                                 if (val.bit(i + j))
-    1121             :                                                         ch |= 1 << j;
-    1122             :                                         if (ch != 0)
-    1123             :                                                 buf.append({ch});
-    1124             :                                 }
-    1125             :                                 std::reverse(buf.begin(), buf.end());
-    1126             :                                 break;
-    1127             :                         }
-    1128             : 
-    1129             :                         case UNICHAR: {
-    1130             :                                 uint32_t codepoint = val.template get<uint32_t>();
-    1131             :                                 if (codepoint >= 0x10000)
-    1132             :                                         buf += (char)(0xf0 |  (codepoint >> 18));
-    1133             :                                 else if (codepoint >= 0x800)
-    1134             :                                         buf += (char)(0xe0 |  (codepoint >> 12));
-    1135             :                                 else if (codepoint >= 0x80)
-    1136             :                                         buf += (char)(0xc0 |  (codepoint >>  6));
-    1137             :                                 else
-    1138             :                                         buf += (char)codepoint;
-    1139             :                                 if (codepoint >= 0x10000)
-    1140             :                                         buf += (char)(0x80 | ((codepoint >> 12) & 0x3f));
-    1141             :                                 if (codepoint >= 0x800)
-    1142             :                                         buf += (char)(0x80 | ((codepoint >>  6) & 0x3f));
-    1143             :                                 if (codepoint >= 0x80)
-    1144             :                                         buf += (char)(0x80 | ((codepoint >>  0) & 0x3f));
-    1145             :                                 break;
-    1146             :                         }
-    1147             : 
-    1148             :                         case INTEGER: {
-    1149             :                                 bool negative = signed_ && val.is_neg();
-    1150             :                                 if (negative) {
-    1151             :                                         prefix = "-";
-    1152             :                                         val = val.neg();
-    1153             :                                 } else {
-    1154             :                                         switch (sign) {
-    1155             :                                                 case MINUS:       break;
-    1156             :                                                 case PLUS_MINUS:  prefix = "+"; break;
-    1157             :                                                 case SPACE_MINUS: prefix = " "; break;
-    1158             :                                         }
-    1159             :                                 }
-    1160             : 
-    1161             :                                 size_t val_width = Bits;
-    1162             :                                 if (base != 10) {
-    1163             :                                         val_width = 1;
-    1164             :                                         for (size_t index = 0; index < Bits; index++)
-    1165             :                                                 if (val.bit(index))
-    1166             :                                                         val_width = index + 1;
-    1167             :                                 }
-    1168             : 
-    1169             :                                 if (base == 2) {
-    1170             :                                         if (show_base)
-    1171             :                                                 prefix += "0b";
-    1172             :                                         for (size_t index = 0; index < val_width; index++) {
-    1173             :                                                 if (group && index > 0 && index % 4 == 0)
-    1174             :                                                         buf += '_';
-    1175             :                                                 buf += (val.bit(index) ? '1' : '0');
-    1176             :                                         }
-    1177             :                                 } else if (base == 8 || base == 16) {
-    1178             :                                         if (show_base)
-    1179             :                                                 prefix += (base == 16) ? (hex_upper ? "0X" : "0x") : "0o";
-    1180             :                                         size_t step = (base == 16) ? 4 : 3;
-    1181             :                                         for (size_t index = 0; index < val_width; index += step) {
-    1182             :                                                 if (group && index > 0 && index % (4 * step) == 0)
-    1183             :                                                         buf += '_';
-    1184             :                                                 uint8_t value = val.bit(index) | (val.bit(index + 1) << 1) | (val.bit(index + 2) << 2);
-    1185             :                                                 if (step == 4)
-    1186             :                                                         value |= val.bit(index + 3) << 3;
-    1187             :                                                 buf += (hex_upper ? "0123456789ABCDEF" : "0123456789abcdef")[value];
-    1188             :                                         }
-    1189             :                                 } else if (base == 10) {
-    1190             :                                         if (show_base)
-    1191             :                                                 prefix += "0d";
-    1192             :                                         if (val.is_zero())
-    1193             :                                                 buf += '0';
-    1194             :                                         value<(Bits > 4 ? Bits : 4)> xval = val.template zext<(Bits > 4 ? Bits : 4)>();
-    1195             :                                         size_t index = 0;
-    1196             :                                         while (!xval.is_zero()) {
-    1197             :                                                 if (group && index > 0 && index % 3 == 0)
-    1198             :                                                         buf += '_';
-    1199             :                                                 value<(Bits > 4 ? Bits : 4)> quotient, remainder;
-    1200             :                                                 if (Bits >= 4)
-    1201             :                                                         std::tie(quotient, remainder) = xval.udivmod(value<(Bits > 4 ? Bits : 4)>{10u});
-    1202             :                                                 else
-    1203             :                                                         std::tie(quotient, remainder) = std::make_pair(value<(Bits > 4 ? Bits : 4)>{0u}, xval);
-    1204             :                                                 buf += '0' + remainder.template trunc<4>().template get<uint8_t>();
-    1205             :                                                 xval = quotient;
-    1206             :                                                 index++;
-    1207             :                                         }
-    1208             :                                 } else assert(false && "Unsupported base for fmt_part");
-    1209             :                                 if (justify == NUMERIC && group && padding == '0') {
-    1210             :                                         int group_size = base == 10 ? 3 : 4;
-    1211             :                                         while (prefix.size() + buf.size() < width) {
-    1212             :                                                 if (buf.size() % (group_size + 1) == group_size)
-    1213             :                                                         buf += '_';
-    1214             :                                                 buf += '0';
-    1215             :                                         }
-    1216             :                                 }
-    1217             :                                 std::reverse(buf.begin(), buf.end());
-    1218             :                                 break;
-    1219             :                         }
-    1220             : 
-    1221             :                         case VLOG_TIME: {
-    1222             :                                 if (performer) {
-    1223             :                                         buf = realtime ? std::to_string(performer->vlog_realtime()) : std::to_string(performer->vlog_time());
-    1224             :                                 } else {
-    1225             :                                         buf = realtime ? std::to_string(0.0) : std::to_string(0);
-    1226             :                                 }
-    1227             :                                 break;
-    1228             :                         }
-    1229             :                 }
-    1230             : 
-    1231             :                 std::string str;
-    1232             :                 assert(width == 0 || padding != '\0');
-    1233             :                 if (prefix.size() + buf.size() < width) {
-    1234             :                         size_t pad_width = width - prefix.size() - buf.size();
-    1235             :                         switch (justify) {
-    1236             :                                 case LEFT:
-    1237             :                                         str += prefix;
-    1238             :                                         str += buf;
-    1239             :                                         str += std::string(pad_width, padding);
-    1240             :                                         break;
-    1241             :                                 case RIGHT:
-    1242             :                                         str += std::string(pad_width, padding);
-    1243             :                                         str += prefix;
-    1244             :                                         str += buf;
-    1245             :                                         break;
-    1246             :                                 case NUMERIC:
-    1247             :                                         str += prefix;
-    1248             :                                         str += std::string(pad_width, padding);
-    1249             :                                         str += buf;
-    1250             :                                         break;
-    1251             :                                 }
-    1252             :                 } else {
-    1253             :                         str += prefix;
-    1254             :                         str += buf;
-    1255             :                 }
-    1256             :                 return str;
-    1257             :         }
-    1258             : };
-    1259             : 
-    1260             : // Tag class to disambiguate values/wires and their aliases.
-    1261             : struct debug_alias {};
-    1262             : 
-    1263             : // Tag declaration to disambiguate values and debug outlines.
-    1264             : using debug_outline = ::_cxxrtl_outline;
-    1265             : 
-    1266             : // This structure is intended for consumption via foreign function interfaces, like Python's ctypes.
-    1267             : // Because of this it uses a C-style layout that is easy to parse rather than more idiomatic C++.
-    1268             : //
-    1269             : // To avoid violating strict aliasing rules, this structure has to be a subclass of the one used
-    1270             : // in the C API, or it would not be possible to cast between the pointers to these.
-    1271             : //
-    1272             : // The `attrs` member cannot be owned by this structure because a `cxxrtl_object` can be created
-    1273             : // from external C code.
-    1274             : struct debug_item : ::cxxrtl_object {
-    1275             :         // Object types.
-    1276             :         enum : uint32_t {
-    1277             :                 VALUE   = CXXRTL_VALUE,
-    1278             :                 WIRE    = CXXRTL_WIRE,
-    1279             :                 MEMORY  = CXXRTL_MEMORY,
-    1280             :                 ALIAS   = CXXRTL_ALIAS,
-    1281             :                 OUTLINE = CXXRTL_OUTLINE,
-    1282             :         };
-    1283             : 
-    1284             :         // Object flags.
-    1285             :         enum : uint32_t {
-    1286             :                 INPUT  = CXXRTL_INPUT,
-    1287             :                 OUTPUT = CXXRTL_OUTPUT,
-    1288             :                 INOUT  = CXXRTL_INOUT,
-    1289             :                 DRIVEN_SYNC = CXXRTL_DRIVEN_SYNC,
-    1290             :                 DRIVEN_COMB = CXXRTL_DRIVEN_COMB,
-    1291             :                 UNDRIVEN    = CXXRTL_UNDRIVEN,
-    1292             :         };
-    1293             : 
-    1294             :         debug_item(const ::cxxrtl_object &object) : cxxrtl_object(object) {}
-    1295             : 
-    1296             :         template<size_t Bits>
-    1297           9 :         debug_item(value<Bits> &item, size_t lsb_offset = 0, uint32_t flags_ = 0) {
-    1298             :                 static_assert(Bits == 0 || sizeof(item) == value<Bits>::chunks * sizeof(chunk_t),
-    1299             :                               "value<Bits> is not compatible with C layout");
-    1300           9 :                 type    = VALUE;
-    1301           9 :                 flags   = flags_;
-    1302           9 :                 width   = Bits;
-    1303           9 :                 lsb_at  = lsb_offset;
-    1304           9 :                 depth   = 1;
-    1305           9 :                 zero_at = 0;
-    1306           9 :                 curr    = item.data;
-    1307           9 :                 next    = item.data;
-    1308           9 :                 outline = nullptr;
-    1309           9 :                 attrs   = nullptr;
-    1310             :         }
-    1311             : 
-    1312             :         template<size_t Bits>
-    1313             :         debug_item(const value<Bits> &item, size_t lsb_offset = 0) {
-    1314             :                 static_assert(Bits == 0 || sizeof(item) == value<Bits>::chunks * sizeof(chunk_t),
-    1315             :                               "value<Bits> is not compatible with C layout");
-    1316             :                 type    = VALUE;
-    1317             :                 flags   = DRIVEN_COMB;
-    1318             :                 width   = Bits;
-    1319             :                 lsb_at  = lsb_offset;
-    1320             :                 depth   = 1;
-    1321             :                 zero_at = 0;
-    1322             :                 curr    = const_cast<chunk_t*>(item.data);
-    1323             :                 next    = nullptr;
-    1324             :                 outline = nullptr;
-    1325             :                 attrs   = nullptr;
-    1326             :         }
-    1327             : 
-    1328             :         template<size_t Bits>
-    1329             :         debug_item(wire<Bits> &item, size_t lsb_offset = 0, uint32_t flags_ = 0) {
-    1330             :                 static_assert(Bits == 0 ||
-    1331             :                               (sizeof(item.curr) == value<Bits>::chunks * sizeof(chunk_t) &&
-    1332             :                                sizeof(item.next) == value<Bits>::chunks * sizeof(chunk_t)),
-    1333             :                               "wire<Bits> is not compatible with C layout");
-    1334             :                 type    = WIRE;
-    1335             :                 flags   = flags_;
-    1336             :                 width   = Bits;
-    1337             :                 lsb_at  = lsb_offset;
-    1338             :                 depth   = 1;
-    1339             :                 zero_at = 0;
-    1340             :                 curr    = item.curr.data;
-    1341             :                 next    = item.next.data;
-    1342             :                 outline = nullptr;
-    1343             :                 attrs   = nullptr;
-    1344             :         }
-    1345             : 
-    1346             :         template<size_t Width>
-    1347             :         debug_item(memory<Width> &item, size_t zero_offset = 0) {
-    1348             :                 static_assert(Width == 0 || sizeof(item.data[0]) == value<Width>::chunks * sizeof(chunk_t),
-    1349             :                               "memory<Width> is not compatible with C layout");
-    1350             :                 type    = MEMORY;
-    1351             :                 flags   = 0;
-    1352             :                 width   = Width;
-    1353             :                 lsb_at  = 0;
-    1354             :                 depth   = item.depth;
-    1355             :                 zero_at = zero_offset;
-    1356             :                 curr    = item.data ? item.data[0].data : nullptr;
-    1357             :                 next    = nullptr;
-    1358             :                 outline = nullptr;
-    1359             :                 attrs   = nullptr;
-    1360             :         }
-    1361             : 
-    1362             :         template<size_t Bits>
-    1363             :         debug_item(debug_alias, const value<Bits> &item, size_t lsb_offset = 0) {
-    1364             :                 static_assert(Bits == 0 || sizeof(item) == value<Bits>::chunks * sizeof(chunk_t),
-    1365             :                               "value<Bits> is not compatible with C layout");
-    1366             :                 type    = ALIAS;
-    1367             :                 flags   = DRIVEN_COMB;
-    1368             :                 width   = Bits;
-    1369             :                 lsb_at  = lsb_offset;
-    1370             :                 depth   = 1;
-    1371             :                 zero_at = 0;
-    1372             :                 curr    = const_cast<chunk_t*>(item.data);
-    1373             :                 next    = nullptr;
-    1374             :                 outline = nullptr;
-    1375             :                 attrs   = nullptr;
-    1376             :         }
-    1377             : 
-    1378             :         template<size_t Bits>
-    1379             :         debug_item(debug_alias, const wire<Bits> &item, size_t lsb_offset = 0) {
-    1380             :                 static_assert(Bits == 0 ||
-    1381             :                               (sizeof(item.curr) == value<Bits>::chunks * sizeof(chunk_t) &&
-    1382             :                                sizeof(item.next) == value<Bits>::chunks * sizeof(chunk_t)),
-    1383             :                               "wire<Bits> is not compatible with C layout");
-    1384             :                 type    = ALIAS;
-    1385             :                 flags   = DRIVEN_COMB;
-    1386             :                 width   = Bits;
-    1387             :                 lsb_at  = lsb_offset;
-    1388             :                 depth   = 1;
-    1389             :                 zero_at = 0;
-    1390             :                 curr    = const_cast<chunk_t*>(item.curr.data);
-    1391             :                 next    = nullptr;
-    1392             :                 outline = nullptr;
-    1393             :                 attrs   = nullptr;
-    1394             :         }
-    1395             : 
-    1396             :         template<size_t Bits>
-    1397             :         debug_item(debug_outline &group, const value<Bits> &item, size_t lsb_offset = 0) {
-    1398             :                 static_assert(Bits == 0 || sizeof(item) == value<Bits>::chunks * sizeof(chunk_t),
-    1399             :                               "value<Bits> is not compatible with C layout");
-    1400             :                 type    = OUTLINE;
-    1401             :                 flags   = DRIVEN_COMB;
-    1402             :                 width   = Bits;
-    1403             :                 lsb_at  = lsb_offset;
-    1404             :                 depth   = 1;
-    1405             :                 zero_at = 0;
-    1406             :                 curr    = const_cast<chunk_t*>(item.data);
-    1407             :                 next    = nullptr;
-    1408             :                 outline = &group;
-    1409             :                 attrs   = nullptr;
-    1410             :         }
-    1411             : 
-    1412             :         template<size_t Bits, class IntegerT>
-    1413             :         IntegerT get() const {
-    1414             :                 assert(width == Bits && depth == 1);
-    1415             :                 value<Bits> item;
-    1416             :                 std::copy(curr, curr + value<Bits>::chunks, item.data);
-    1417             :                 return item.template get<IntegerT>();
-    1418             :         }
-    1419             : 
-    1420             :         template<size_t Bits, class IntegerT>
-    1421             :         void set(IntegerT other) const {
-    1422             :                 assert(width == Bits && depth == 1);
-    1423             :                 value<Bits> item;
-    1424             :                 item.template set<IntegerT>(other);
-    1425             :                 std::copy(item.data, item.data + value<Bits>::chunks, next);
-    1426             :         }
-    1427             : };
-    1428             : static_assert(std::is_standard_layout<debug_item>::value, "debug_item is not compatible with C layout");
-    1429             : 
-    1430             : } // namespace cxxrtl
-    1431             : 
-    1432           9 : typedef struct _cxxrtl_attr_set {
-    1433             :         cxxrtl::metadata_map map;
-    1434             : } *cxxrtl_attr_set;
-    1435             : 
-    1436             : namespace cxxrtl {
-    1437             : 
-    1438             : // Representation of an attribute set in the C++ interface.
-    1439             : using debug_attrs = ::_cxxrtl_attr_set;
-    1440             : 
-    1441           3 : struct debug_items {
-    1442             :         // Debug items may be composed of multiple parts, but the attributes are shared between all of them.
-    1443             :         // There are additional invariants, not all of which are not checked by this code:
-    1444             :         // - Memories and non-memories cannot be mixed together.
-    1445             :         // - Bit indices (considering `lsb_at` and `width`) must not overlap.
-    1446             :         // - Row indices (considering `depth` and `zero_at`) must be the same.
-    1447             :         // - The `INPUT` and `OUTPUT` flags must be the same for all parts.
-    1448             :         // Other than that, the parts can be quite different, e.g. it is OK to mix a value, a wire, an alias,
-    1449             :         // and an outline, in the debug information for a single name in four parts.
-    1450             :         std::map<std::string, std::vector<debug_item>> table;
-    1451             :         std::map<std::string, std::unique_ptr<debug_attrs>> attrs_table;
-    1452             : 
-    1453           9 :         void add(const std::string &path, debug_item &&item, metadata_map &&item_attrs = {}) {
-    1454           9 :                 assert((path.empty() || path[path.size() - 1] != ' ') && path.find("  ") == std::string::npos);
-    1455           9 :                 std::unique_ptr<debug_attrs> &attrs = attrs_table[path];
-    1456           9 :                 if (attrs.get() == nullptr)
-    1457           9 :                         attrs = std::unique_ptr<debug_attrs>(new debug_attrs);
-    1458          18 :                 for (auto attr : item_attrs)
-    1459          18 :                         attrs->map.insert(attr);
-    1460           9 :                 item.attrs = attrs.get();
-    1461           9 :                 std::vector<debug_item> &parts = table[path];
-    1462           9 :                 parts.emplace_back(item);
-    1463           9 :                 std::sort(parts.begin(), parts.end(),
-    1464           0 :                         [](const debug_item &a, const debug_item &b) {
-    1465           0 :                                 return a.lsb_at < b.lsb_at;
-    1466             :                         });
-    1467           9 :         }
-    1468             : 
-    1469             :         // This overload exists to reduce excessive stack slot allocation in `CXXRTL_EXTREMELY_COLD void debug_info()`.
-    1470             :         template<class... T>
-    1471           9 :         void add(const std::string &base_path, const char *path, const char *serialized_item_attrs, T&&... args) {
-    1472          18 :                 add(base_path + path, debug_item(std::forward<T>(args)...), metadata::deserialize(serialized_item_attrs));
-    1473           9 :         }
-    1474             : 
-    1475             :         size_t count(const std::string &path) const {
-    1476             :                 if (table.count(path) == 0)
-    1477             :                         return 0;
-    1478             :                 return table.at(path).size();
-    1479             :         }
-    1480             : 
-    1481             :         const std::vector<debug_item> &at(const std::string &path) const {
-    1482             :                 return table.at(path);
-    1483             :         }
-    1484             : 
-    1485             :         // Like `at()`, but operates only on single-part debug items.
-    1486             :         const debug_item &operator [](const std::string &path) const {
-    1487             :                 const std::vector<debug_item> &parts = table.at(path);
-    1488             :                 assert(parts.size() == 1);
-    1489             :                 return parts.at(0);
-    1490             :         }
-    1491             : 
-    1492             :         bool is_memory(const std::string &path) const {
-    1493             :                 return at(path).at(0).type == debug_item::MEMORY;
-    1494             :         }
-    1495             : 
-    1496             :         const metadata_map &attrs(const std::string &path) const {
-    1497             :                 return attrs_table.at(path)->map;
-    1498             :         }
-    1499             : };
-    1500             : 
-    1501             : // Only `module` scopes are defined. The type is implicit, since Yosys does not currently support
-    1502             : // any other scope types.
-    1503           3 : struct debug_scope {
-    1504             :         std::string module_name;
-    1505             :         std::unique_ptr<debug_attrs> module_attrs;
-    1506             :         std::unique_ptr<debug_attrs> cell_attrs;
-    1507             : };
-    1508             : 
-    1509             : struct debug_scopes {
-    1510             :         std::map<std::string, debug_scope> table;
-    1511             : 
-    1512           0 :         void add(const std::string &path, const std::string &module_name, metadata_map &&module_attrs, metadata_map &&cell_attrs) {
-    1513           0 :                 assert((path.empty() || path[path.size() - 1] != ' ') && path.find("  ") == std::string::npos);
-    1514           0 :                 assert(table.count(path) == 0);
-    1515           0 :                 debug_scope &scope = table[path];
-    1516           0 :                 scope.module_name = module_name;
-    1517           0 :                 scope.module_attrs = std::unique_ptr<debug_attrs>(new debug_attrs { module_attrs });
-    1518           0 :                 scope.cell_attrs = std::unique_ptr<debug_attrs>(new debug_attrs { cell_attrs });
-    1519           0 :         }
-    1520             : 
-    1521             :         // This overload exists to reduce excessive stack slot allocation in `CXXRTL_EXTREMELY_COLD void debug_info()`.
-    1522             :         void add(const std::string &base_path, const char *path, const char *module_name, const char *serialized_module_attrs, const char *serialized_cell_attrs) {
-    1523             :                 add(base_path + path, module_name, metadata::deserialize(serialized_module_attrs), metadata::deserialize(serialized_cell_attrs));
-    1524             :         }
-    1525             : 
-    1526             :         size_t contains(const std::string &path) const {
-    1527             :                 return table.count(path);
-    1528             :         }
-    1529             : 
-    1530             :         const debug_scope &operator [](const std::string &path) const {
-    1531             :                 return table.at(path);
-    1532             :         }
-    1533             : };
-    1534             : 
-    1535             : // Tag class to disambiguate the default constructor used by the toplevel module that calls `reset()`,
-    1536             : // and the constructor of interior modules that should not call it.
-    1537             : struct interior {};
-    1538             : 
-    1539             : // The core API of the `module` class consists of only four virtual methods: `reset()`, `eval()`,
-    1540             : // `commit`, and `debug_info()`. (The virtual destructor is made necessary by C++.) Every other method
-    1541             : // is a convenience method, and exists solely to simplify some common pattern for C++ API consumers.
-    1542             : // No behavior may be added to such convenience methods that other parts of CXXRTL can rely on, since
-    1543             : // there is no guarantee they will be called (and, for example, other CXXRTL libraries will often call
-    1544             : // the `eval()` and `commit()` directly instead, as well as being exposed in the C API).
-    1545             : struct module {
-    1546           3 :         module() {}
-    1547           3 :         virtual ~module() {}
-    1548             : 
-    1549             :         // Modules with black boxes cannot be copied. Although not all designs include black boxes,
-    1550             :         // delete the copy constructor and copy assignment operator to make sure that any downstream
-    1551             :         // code that manipulates modules doesn't accidentally depend on their availability.
-    1552             :         module(const module &) = delete;
-    1553             :         module &operator=(const module &) = delete;
-    1554             : 
-    1555             :         module(module &&) = default;
-    1556             :         module &operator=(module &&) = default;
-    1557             : 
-    1558             :         virtual void reset() = 0;
-    1559             : 
-    1560             :         // The `eval()` callback object, `performer`, is included in the virtual call signature since
-    1561             :         // the generated code has broadly identical performance properties.
-    1562             :         virtual bool eval(performer *performer = nullptr) = 0;
-    1563             : 
-    1564             :         // The `commit()` callback object, `observer`, is not included in the virtual call signature since
-    1565             :         // the generated code is severely pessimized by it. To observe commit events, the non-virtual
-    1566             :         // `commit(observer *)` overload must be called directly on a `module` subclass.
-    1567             :         virtual bool commit() = 0;
-    1568             : 
-    1569          33 :         size_t step(performer *performer = nullptr) {
-    1570          33 :                 size_t deltas = 0;
-    1571          33 :                 bool converged = false;
-    1572          33 :                 do {
-    1573          33 :                         converged = eval(performer);
-    1574          33 :                         deltas++;
-    1575          66 :                 } while (commit() && !converged);
-    1576          33 :                 return deltas;
-    1577             :         }
-    1578             : 
-    1579             :         virtual void debug_info(debug_items *items, debug_scopes *scopes, std::string path, metadata_map &&cell_attrs = {}) {
-    1580             :                 (void)items, (void)scopes, (void)path, (void)cell_attrs;
-    1581             :         }
-    1582             : 
-    1583             :         // Compatibility method.
-    1584             : #if __has_attribute(deprecated)
-    1585             :         __attribute__((deprecated("Use `debug_info(path, &items, /*scopes=*/nullptr);` instead. (`path` could be \"top \".)")))
-    1586             : #endif
-    1587             :         void debug_info(debug_items &items, std::string path) {
-    1588             :                 debug_info(&items, /*scopes=*/nullptr, path);
-    1589             :         }
-    1590             : };
-    1591             : 
-    1592             : } // namespace cxxrtl
-    1593             : 
-    1594             : // Internal structures used to communicate with the implementation of the C interface.
-    1595             : 
-    1596             : typedef struct _cxxrtl_toplevel {
-    1597             :         std::unique_ptr<cxxrtl::module> module;
-    1598             : } *cxxrtl_toplevel;
-    1599             : 
-    1600             : typedef struct _cxxrtl_outline {
-    1601             :         std::function<void()> eval;
-    1602             : } *cxxrtl_outline;
-    1603             : 
-    1604             : // Definitions of internal Yosys cells. Other than the functions in this namespace, CXXRTL is fully generic
-    1605             : // and indepenent of Yosys implementation details.
-    1606             : //
-    1607             : // The `write_cxxrtl` pass translates internal cells (cells with names that start with `$`) to calls of these
-    1608             : // functions. All of Yosys arithmetic and logical cells perform sign or zero extension on their operands,
-    1609             : // whereas basic operations on arbitrary width values require operands to be of the same width. These functions
-    1610             : // bridge the gap by performing the necessary casts. They are named similar to `cell_A[B]`, where A and B are `u`
-    1611             : // if the corresponding operand is unsigned, and `s` if it is signed.
-    1612             : namespace cxxrtl_yosys {
-    1613             : 
-    1614             : using namespace cxxrtl;
-    1615             : 
-    1616             : // std::max isn't constexpr until C++14 for no particular reason (it's an oversight), so we define our own.
-    1617             : template<class T>
-    1618             : CXXRTL_ALWAYS_INLINE
-    1619             : constexpr T max(const T &a, const T &b) {
-    1620             :         return a > b ? a : b;
-    1621             : }
-    1622             : 
-    1623             : // Logic operations
-    1624             : template<size_t BitsY, size_t BitsA>
-    1625             : CXXRTL_ALWAYS_INLINE
-    1626             : value<BitsY> logic_not(const value<BitsA> &a) {
-    1627             :         return value<BitsY> { a ? 0u : 1u };
-    1628             : }
-    1629             : 
-    1630             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1631             : CXXRTL_ALWAYS_INLINE
-    1632             : value<BitsY> logic_and(const value<BitsA> &a, const value<BitsB> &b) {
-    1633             :         return value<BitsY> { (bool(a) && bool(b)) ? 1u : 0u };
-    1634             : }
-    1635             : 
-    1636             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1637             : CXXRTL_ALWAYS_INLINE
-    1638             : value<BitsY> logic_or(const value<BitsA> &a, const value<BitsB> &b) {
-    1639             :         return value<BitsY> { (bool(a) || bool(b)) ? 1u : 0u };
-    1640             : }
-    1641             : 
-    1642             : // Reduction operations
-    1643             : template<size_t BitsY, size_t BitsA>
-    1644             : CXXRTL_ALWAYS_INLINE
-    1645             : value<BitsY> reduce_and(const value<BitsA> &a) {
-    1646             :         return value<BitsY> { a.bit_not().is_zero() ? 1u : 0u };
-    1647             : }
-    1648             : 
-    1649             : template<size_t BitsY, size_t BitsA>
-    1650             : CXXRTL_ALWAYS_INLINE
-    1651             : value<BitsY> reduce_or(const value<BitsA> &a) {
-    1652             :         return value<BitsY> { a ? 1u : 0u };
-    1653             : }
-    1654             : 
-    1655             : template<size_t BitsY, size_t BitsA>
-    1656             : CXXRTL_ALWAYS_INLINE
-    1657             : value<BitsY> reduce_xor(const value<BitsA> &a) {
-    1658             :         return value<BitsY> { (a.ctpop() % 2) ? 1u : 0u };
-    1659             : }
-    1660             : 
-    1661             : template<size_t BitsY, size_t BitsA>
-    1662             : CXXRTL_ALWAYS_INLINE
-    1663             : value<BitsY> reduce_xnor(const value<BitsA> &a) {
-    1664             :         return value<BitsY> { (a.ctpop() % 2) ? 0u : 1u };
-    1665             : }
-    1666             : 
-    1667             : template<size_t BitsY, size_t BitsA>
-    1668             : CXXRTL_ALWAYS_INLINE
-    1669             : value<BitsY> reduce_bool(const value<BitsA> &a) {
-    1670             :         return value<BitsY> { a ? 1u : 0u };
-    1671             : }
-    1672             : 
-    1673             : // Bitwise operations
-    1674             : template<size_t BitsY, size_t BitsA>
-    1675             : CXXRTL_ALWAYS_INLINE
-    1676             : value<BitsY> not_u(const value<BitsA> &a) {
-    1677             :         return a.template zcast<BitsY>().bit_not();
-    1678             : }
-    1679             : 
-    1680             : template<size_t BitsY, size_t BitsA>
-    1681             : CXXRTL_ALWAYS_INLINE
-    1682             : value<BitsY> not_s(const value<BitsA> &a) {
-    1683             :         return a.template scast<BitsY>().bit_not();
-    1684             : }
-    1685             : 
-    1686             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1687             : CXXRTL_ALWAYS_INLINE
-    1688             : value<BitsY> and_uu(const value<BitsA> &a, const value<BitsB> &b) {
-    1689             :         return a.template zcast<BitsY>().bit_and(b.template zcast<BitsY>());
-    1690             : }
-    1691             : 
-    1692             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1693             : CXXRTL_ALWAYS_INLINE
-    1694             : value<BitsY> and_ss(const value<BitsA> &a, const value<BitsB> &b) {
-    1695             :         return a.template scast<BitsY>().bit_and(b.template scast<BitsY>());
-    1696             : }
-    1697             : 
-    1698             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1699             : CXXRTL_ALWAYS_INLINE
-    1700             : value<BitsY> or_uu(const value<BitsA> &a, const value<BitsB> &b) {
-    1701             :         return a.template zcast<BitsY>().bit_or(b.template zcast<BitsY>());
-    1702             : }
-    1703             : 
-    1704             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1705             : CXXRTL_ALWAYS_INLINE
-    1706             : value<BitsY> or_ss(const value<BitsA> &a, const value<BitsB> &b) {
-    1707             :         return a.template scast<BitsY>().bit_or(b.template scast<BitsY>());
-    1708             : }
-    1709             : 
-    1710             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1711             : CXXRTL_ALWAYS_INLINE
-    1712             : value<BitsY> xor_uu(const value<BitsA> &a, const value<BitsB> &b) {
-    1713             :         return a.template zcast<BitsY>().bit_xor(b.template zcast<BitsY>());
-    1714             : }
-    1715             : 
-    1716             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1717             : CXXRTL_ALWAYS_INLINE
-    1718             : value<BitsY> xor_ss(const value<BitsA> &a, const value<BitsB> &b) {
-    1719             :         return a.template scast<BitsY>().bit_xor(b.template scast<BitsY>());
-    1720             : }
-    1721             : 
-    1722             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1723             : CXXRTL_ALWAYS_INLINE
-    1724             : value<BitsY> xnor_uu(const value<BitsA> &a, const value<BitsB> &b) {
-    1725             :         return a.template zcast<BitsY>().bit_xor(b.template zcast<BitsY>()).bit_not();
-    1726             : }
-    1727             : 
-    1728             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1729             : CXXRTL_ALWAYS_INLINE
-    1730             : value<BitsY> xnor_ss(const value<BitsA> &a, const value<BitsB> &b) {
-    1731             :         return a.template scast<BitsY>().bit_xor(b.template scast<BitsY>()).bit_not();
-    1732             : }
-    1733             : 
-    1734             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1735             : CXXRTL_ALWAYS_INLINE
-    1736             : value<BitsY> shl_uu(const value<BitsA> &a, const value<BitsB> &b) {
-    1737             :         return a.template zcast<BitsY>().shl(b);
-    1738             : }
-    1739             : 
-    1740             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1741             : CXXRTL_ALWAYS_INLINE
-    1742             : value<BitsY> shl_su(const value<BitsA> &a, const value<BitsB> &b) {
-    1743             :         return a.template scast<BitsY>().shl(b);
-    1744             : }
-    1745             : 
-    1746             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1747             : CXXRTL_ALWAYS_INLINE
-    1748             : value<BitsY> sshl_uu(const value<BitsA> &a, const value<BitsB> &b) {
-    1749             :         return a.template zcast<BitsY>().shl(b);
-    1750             : }
-    1751             : 
-    1752             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1753             : CXXRTL_ALWAYS_INLINE
-    1754             : value<BitsY> sshl_su(const value<BitsA> &a, const value<BitsB> &b) {
-    1755             :         return a.template scast<BitsY>().shl(b);
-    1756             : }
-    1757             : 
-    1758             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1759             : CXXRTL_ALWAYS_INLINE
-    1760             : value<BitsY> shr_uu(const value<BitsA> &a, const value<BitsB> &b) {
-    1761             :         return a.shr(b).template zcast<BitsY>();
-    1762             : }
-    1763             : 
-    1764             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1765             : CXXRTL_ALWAYS_INLINE
-    1766             : value<BitsY> shr_su(const value<BitsA> &a, const value<BitsB> &b) {
-    1767             :         return a.shr(b).template scast<BitsY>();
-    1768             : }
-    1769             : 
-    1770             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1771             : CXXRTL_ALWAYS_INLINE
-    1772             : value<BitsY> sshr_uu(const value<BitsA> &a, const value<BitsB> &b) {
-    1773             :         return a.shr(b).template zcast<BitsY>();
-    1774             : }
-    1775             : 
-    1776             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1777             : CXXRTL_ALWAYS_INLINE
-    1778             : value<BitsY> sshr_su(const value<BitsA> &a, const value<BitsB> &b) {
-    1779             :         return a.sshr(b).template scast<BitsY>();
-    1780             : }
-    1781             : 
-    1782             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1783             : CXXRTL_ALWAYS_INLINE
-    1784             : value<BitsY> shift_uu(const value<BitsA> &a, const value<BitsB> &b) {
-    1785             :         return shr_uu<BitsY>(a, b);
-    1786             : }
-    1787             : 
-    1788             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1789             : CXXRTL_ALWAYS_INLINE
-    1790             : value<BitsY> shift_su(const value<BitsA> &a, const value<BitsB> &b) {
-    1791             :         return shr_su<BitsY>(a, b);
-    1792             : }
-    1793             : 
-    1794             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1795             : CXXRTL_ALWAYS_INLINE
-    1796             : value<BitsY> shift_us(const value<BitsA> &a, const value<BitsB> &b) {
-    1797             :         return b.is_neg() ? shl_uu<BitsY>(a, b.template sext<BitsB + 1>().neg()) : shr_uu<BitsY>(a, b);
-    1798             : }
-    1799             : 
-    1800             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1801             : CXXRTL_ALWAYS_INLINE
-    1802             : value<BitsY> shift_ss(const value<BitsA> &a, const value<BitsB> &b) {
-    1803             :         return b.is_neg() ? shl_su<BitsY>(a, b.template sext<BitsB + 1>().neg()) : shr_su<BitsY>(a, b);
-    1804             : }
-    1805             : 
-    1806             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1807             : CXXRTL_ALWAYS_INLINE
-    1808             : value<BitsY> shiftx_uu(const value<BitsA> &a, const value<BitsB> &b) {
-    1809             :         return shift_uu<BitsY>(a, b);
-    1810             : }
-    1811             : 
-    1812             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1813             : CXXRTL_ALWAYS_INLINE
-    1814             : value<BitsY> shiftx_su(const value<BitsA> &a, const value<BitsB> &b) {
-    1815             :         return shift_su<BitsY>(a, b);
-    1816             : }
-    1817             : 
-    1818             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1819             : CXXRTL_ALWAYS_INLINE
-    1820             : value<BitsY> shiftx_us(const value<BitsA> &a, const value<BitsB> &b) {
-    1821             :         return shift_us<BitsY>(a, b);
-    1822             : }
-    1823             : 
-    1824             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1825             : CXXRTL_ALWAYS_INLINE
-    1826             : value<BitsY> shiftx_ss(const value<BitsA> &a, const value<BitsB> &b) {
-    1827             :         return shift_ss<BitsY>(a, b);
-    1828             : }
-    1829             : 
-    1830             : // Comparison operations
-    1831             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1832             : CXXRTL_ALWAYS_INLINE
-    1833             : value<BitsY> eq_uu(const value<BitsA> &a, const value<BitsB> &b) {
-    1834             :         constexpr size_t BitsExt = max(BitsA, BitsB);
-    1835             :         return value<BitsY>{ a.template zext<BitsExt>() == b.template zext<BitsExt>() ? 1u : 0u };
-    1836             : }
-    1837             : 
-    1838             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1839             : CXXRTL_ALWAYS_INLINE
-    1840             : value<BitsY> eq_ss(const value<BitsA> &a, const value<BitsB> &b) {
-    1841             :         constexpr size_t BitsExt = max(BitsA, BitsB);
-    1842             :         return value<BitsY>{ a.template sext<BitsExt>() == b.template sext<BitsExt>() ? 1u : 0u };
-    1843             : }
-    1844             : 
-    1845             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1846             : CXXRTL_ALWAYS_INLINE
-    1847             : value<BitsY> ne_uu(const value<BitsA> &a, const value<BitsB> &b) {
-    1848             :         constexpr size_t BitsExt = max(BitsA, BitsB);
-    1849             :         return value<BitsY>{ a.template zext<BitsExt>() != b.template zext<BitsExt>() ? 1u : 0u };
-    1850             : }
-    1851             : 
-    1852             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1853             : CXXRTL_ALWAYS_INLINE
-    1854             : value<BitsY> ne_ss(const value<BitsA> &a, const value<BitsB> &b) {
-    1855             :         constexpr size_t BitsExt = max(BitsA, BitsB);
-    1856             :         return value<BitsY>{ a.template sext<BitsExt>() != b.template sext<BitsExt>() ? 1u : 0u };
-    1857             : }
-    1858             : 
-    1859             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1860             : CXXRTL_ALWAYS_INLINE
-    1861             : value<BitsY> eqx_uu(const value<BitsA> &a, const value<BitsB> &b) {
-    1862             :         return eq_uu<BitsY>(a, b);
-    1863             : }
-    1864             : 
-    1865             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1866             : CXXRTL_ALWAYS_INLINE
-    1867             : value<BitsY> eqx_ss(const value<BitsA> &a, const value<BitsB> &b) {
-    1868             :         return eq_ss<BitsY>(a, b);
-    1869             : }
-    1870             : 
-    1871             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1872             : CXXRTL_ALWAYS_INLINE
-    1873             : value<BitsY> nex_uu(const value<BitsA> &a, const value<BitsB> &b) {
-    1874             :         return ne_uu<BitsY>(a, b);
-    1875             : }
-    1876             : 
-    1877             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1878             : CXXRTL_ALWAYS_INLINE
-    1879             : value<BitsY> nex_ss(const value<BitsA> &a, const value<BitsB> &b) {
-    1880             :         return ne_ss<BitsY>(a, b);
-    1881             : }
-    1882             : 
-    1883             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1884             : CXXRTL_ALWAYS_INLINE
-    1885             : value<BitsY> gt_uu(const value<BitsA> &a, const value<BitsB> &b) {
-    1886             :         constexpr size_t BitsExt = max(BitsA, BitsB);
-    1887             :         return value<BitsY> { b.template zext<BitsExt>().ucmp(a.template zext<BitsExt>()) ? 1u : 0u };
-    1888             : }
-    1889             : 
-    1890             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1891             : CXXRTL_ALWAYS_INLINE
-    1892             : value<BitsY> gt_ss(const value<BitsA> &a, const value<BitsB> &b) {
-    1893             :         constexpr size_t BitsExt = max(BitsA, BitsB);
-    1894             :         return value<BitsY> { b.template sext<BitsExt>().scmp(a.template sext<BitsExt>()) ? 1u : 0u };
-    1895             : }
-    1896             : 
-    1897             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1898             : CXXRTL_ALWAYS_INLINE
-    1899             : value<BitsY> ge_uu(const value<BitsA> &a, const value<BitsB> &b) {
-    1900             :         constexpr size_t BitsExt = max(BitsA, BitsB);
-    1901             :         return value<BitsY> { !a.template zext<BitsExt>().ucmp(b.template zext<BitsExt>()) ? 1u : 0u };
-    1902             : }
-    1903             : 
-    1904             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1905             : CXXRTL_ALWAYS_INLINE
-    1906             : value<BitsY> ge_ss(const value<BitsA> &a, const value<BitsB> &b) {
-    1907             :         constexpr size_t BitsExt = max(BitsA, BitsB);
-    1908             :         return value<BitsY> { !a.template sext<BitsExt>().scmp(b.template sext<BitsExt>()) ? 1u : 0u };
-    1909             : }
-    1910             : 
-    1911             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1912             : CXXRTL_ALWAYS_INLINE
-    1913             : value<BitsY> lt_uu(const value<BitsA> &a, const value<BitsB> &b) {
-    1914             :         constexpr size_t BitsExt = max(BitsA, BitsB);
-    1915             :         return value<BitsY> { a.template zext<BitsExt>().ucmp(b.template zext<BitsExt>()) ? 1u : 0u };
-    1916             : }
-    1917             : 
-    1918             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1919             : CXXRTL_ALWAYS_INLINE
-    1920             : value<BitsY> lt_ss(const value<BitsA> &a, const value<BitsB> &b) {
-    1921             :         constexpr size_t BitsExt = max(BitsA, BitsB);
-    1922             :         return value<BitsY> { a.template sext<BitsExt>().scmp(b.template sext<BitsExt>()) ? 1u : 0u };
-    1923             : }
-    1924             : 
-    1925             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1926             : CXXRTL_ALWAYS_INLINE
-    1927             : value<BitsY> le_uu(const value<BitsA> &a, const value<BitsB> &b) {
-    1928             :         constexpr size_t BitsExt = max(BitsA, BitsB);
-    1929             :         return value<BitsY> { !b.template zext<BitsExt>().ucmp(a.template zext<BitsExt>()) ? 1u : 0u };
-    1930             : }
-    1931             : 
-    1932             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1933             : CXXRTL_ALWAYS_INLINE
-    1934             : value<BitsY> le_ss(const value<BitsA> &a, const value<BitsB> &b) {
-    1935             :         constexpr size_t BitsExt = max(BitsA, BitsB);
-    1936             :         return value<BitsY> { !b.template sext<BitsExt>().scmp(a.template sext<BitsExt>()) ? 1u : 0u };
-    1937             : }
-    1938             : 
-    1939             : // Arithmetic operations
-    1940             : template<size_t BitsY, size_t BitsA>
-    1941             : CXXRTL_ALWAYS_INLINE
-    1942             : value<BitsY> pos_u(const value<BitsA> &a) {
-    1943             :         return a.template zcast<BitsY>();
-    1944             : }
-    1945             : 
-    1946             : template<size_t BitsY, size_t BitsA>
-    1947             : CXXRTL_ALWAYS_INLINE
-    1948             : value<BitsY> pos_s(const value<BitsA> &a) {
-    1949             :         return a.template scast<BitsY>();
-    1950             : }
-    1951             : 
-    1952             : template<size_t BitsY, size_t BitsA>
-    1953             : CXXRTL_ALWAYS_INLINE
-    1954             : value<BitsY> neg_u(const value<BitsA> &a) {
-    1955             :         return a.template zcast<BitsY>().neg();
-    1956             : }
-    1957             : 
-    1958             : template<size_t BitsY, size_t BitsA>
-    1959             : CXXRTL_ALWAYS_INLINE
-    1960             : value<BitsY> neg_s(const value<BitsA> &a) {
-    1961             :         return a.template scast<BitsY>().neg();
-    1962             : }
-    1963             : 
-    1964             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1965             : CXXRTL_ALWAYS_INLINE
-    1966          33 : value<BitsY> add_uu(const value<BitsA> &a, const value<BitsB> &b) {
-    1967          33 :         return a.template zcast<BitsY>().add(b.template zcast<BitsY>());
-    1968             : }
-    1969             : 
-    1970             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1971             : CXXRTL_ALWAYS_INLINE
-    1972             : value<BitsY> add_ss(const value<BitsA> &a, const value<BitsB> &b) {
-    1973             :         return a.template scast<BitsY>().add(b.template scast<BitsY>());
-    1974             : }
-    1975             : 
-    1976             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1977             : CXXRTL_ALWAYS_INLINE
-    1978             : value<BitsY> sub_uu(const value<BitsA> &a, const value<BitsB> &b) {
-    1979             :         return a.template zcast<BitsY>().sub(b.template zcast<BitsY>());
-    1980             : }
-    1981             : 
-    1982             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1983             : CXXRTL_ALWAYS_INLINE
-    1984             : value<BitsY> sub_ss(const value<BitsA> &a, const value<BitsB> &b) {
-    1985             :         return a.template scast<BitsY>().sub(b.template scast<BitsY>());
-    1986             : }
-    1987             : 
-    1988             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1989             : CXXRTL_ALWAYS_INLINE
-    1990             : value<BitsY> mul_uu(const value<BitsA> &a, const value<BitsB> &b) {
-    1991             :         constexpr size_t BitsM = BitsA >= BitsB ? BitsA : BitsB;
-    1992             :         return a.template zcast<BitsM>().template mul<BitsY>(b.template zcast<BitsM>());
-    1993             : }
-    1994             : 
-    1995             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    1996             : CXXRTL_ALWAYS_INLINE
-    1997             : value<BitsY> mul_ss(const value<BitsA> &a, const value<BitsB> &b) {
-    1998             :         return a.template scast<BitsY>().template mul<BitsY>(b.template scast<BitsY>());
-    1999             : }
-    2000             : 
-    2001             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    2002             : CXXRTL_ALWAYS_INLINE
-    2003             : std::pair<value<BitsY>, value<BitsY>> divmod_uu(const value<BitsA> &a, const value<BitsB> &b) {
-    2004             :         constexpr size_t Bits = max(BitsY, max(BitsA, BitsB));
-    2005             :         value<Bits> quotient;
-    2006             :         value<Bits> remainder;
-    2007             :         value<Bits> dividend = a.template zext<Bits>();
-    2008             :         value<Bits> divisor = b.template zext<Bits>();
-    2009             :         std::tie(quotient, remainder) = dividend.udivmod(divisor);
-    2010             :         return {quotient.template trunc<BitsY>(), remainder.template trunc<BitsY>()};
-    2011             : }
-    2012             : 
-    2013             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    2014             : CXXRTL_ALWAYS_INLINE
-    2015             : std::pair<value<BitsY>, value<BitsY>> divmod_ss(const value<BitsA> &a, const value<BitsB> &b) {
-    2016             :         constexpr size_t Bits = max(BitsY, max(BitsA, BitsB));
-    2017             :         value<Bits> quotient;
-    2018             :         value<Bits> remainder;
-    2019             :         value<Bits> dividend = a.template sext<Bits>();
-    2020             :         value<Bits> divisor = b.template sext<Bits>();
-    2021             :         std::tie(quotient, remainder) = dividend.sdivmod(divisor);
-    2022             :         return {quotient.template trunc<BitsY>(), remainder.template trunc<BitsY>()};
-    2023             : }
-    2024             : 
-    2025             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    2026             : CXXRTL_ALWAYS_INLINE
-    2027             : value<BitsY> div_uu(const value<BitsA> &a, const value<BitsB> &b) {
-    2028             :         return divmod_uu<BitsY>(a, b).first;
-    2029             : }
-    2030             : 
-    2031             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    2032             : CXXRTL_ALWAYS_INLINE
-    2033             : value<BitsY> div_ss(const value<BitsA> &a, const value<BitsB> &b) {
-    2034             :         return divmod_ss<BitsY>(a, b).first;
-    2035             : }
-    2036             : 
-    2037             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    2038             : CXXRTL_ALWAYS_INLINE
-    2039             : value<BitsY> mod_uu(const value<BitsA> &a, const value<BitsB> &b) {
-    2040             :         return divmod_uu<BitsY>(a, b).second;
-    2041             : }
-    2042             : 
-    2043             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    2044             : CXXRTL_ALWAYS_INLINE
-    2045             : value<BitsY> mod_ss(const value<BitsA> &a, const value<BitsB> &b) {
-    2046             :         return divmod_ss<BitsY>(a, b).second;
-    2047             : }
-    2048             : 
-    2049             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    2050             : CXXRTL_ALWAYS_INLINE
-    2051             : value<BitsY> modfloor_uu(const value<BitsA> &a, const value<BitsB> &b) {
-    2052             :         return divmod_uu<BitsY>(a, b).second;
-    2053             : }
-    2054             : 
-    2055             : // GHDL Modfloor operator. Returns r=a mod b, such that r has the same sign as b and
-    2056             : // a=b*N+r where N is some integer
-    2057             : // In practical terms, when a and b have different signs and the remainder returned by divmod_ss is not 0
-    2058             : // then return the remainder + b
-    2059             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    2060             : CXXRTL_ALWAYS_INLINE
-    2061             : value<BitsY> modfloor_ss(const value<BitsA> &a, const value<BitsB> &b) {
-    2062             :         value<BitsY> r;
-    2063             :         r = divmod_ss<BitsY>(a, b).second;
-    2064             :         if((b.is_neg() != a.is_neg()) && !r.is_zero())
-    2065             :                 return add_ss<BitsY>(b, r);
-    2066             :         return r;
-    2067             : }
-    2068             : 
-    2069             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    2070             : CXXRTL_ALWAYS_INLINE
-    2071             : value<BitsY> divfloor_uu(const value<BitsA> &a, const value<BitsB> &b) {
-    2072             :         return divmod_uu<BitsY>(a, b).first;
-    2073             : }
-    2074             : 
-    2075             : // Divfloor. Similar to above: returns q=a//b, where q has the sign of a*b and a=b*q+N.
-    2076             : // In other words, returns (truncating) a/b, except if a and b have different signs
-    2077             : // and there's non-zero remainder, subtract one more towards floor.
-    2078             : template<size_t BitsY, size_t BitsA, size_t BitsB>
-    2079             : CXXRTL_ALWAYS_INLINE
-    2080             : value<BitsY> divfloor_ss(const value<BitsA> &a, const value<BitsB> &b) {
-    2081             :         value<BitsY> q, r;
-    2082             :         std::tie(q, r) = divmod_ss<BitsY>(a, b);
-    2083             :         if ((b.is_neg() != a.is_neg()) && !r.is_zero())
-    2084             :                 return sub_uu<BitsY>(q, value<1> { 1u });
-    2085             :         return q;
-    2086             : 
-    2087             : }
-    2088             : 
-    2089             : // Memory helper
-    2090             : struct memory_index {
-    2091             :         bool valid;
-    2092             :         size_t index;
-    2093             : 
-    2094             :         template<size_t BitsAddr>
-    2095             :         memory_index(const value<BitsAddr> &addr, size_t offset, size_t depth) {
-    2096             :                 static_assert(value<BitsAddr>::chunks <= 1, "memory address is too wide");
-    2097             :                 size_t offset_index = addr.data[0];
-    2098             : 
-    2099             :                 valid = (offset_index >= offset && offset_index < offset + depth);
-    2100             :                 index = offset_index - offset;
-    2101             :         }
-    2102             : };
-    2103             : 
-    2104             : } // namespace cxxrtl_yosys
-    2105             : 
-    2106             : #endif
-
-
-
- - - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl_vcd.h.func-sort-c.html b/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl_vcd.h.func-sort-c.html deleted file mode 100644 index cf6db54ca95..00000000000 --- a/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl_vcd.h.func-sort-c.html +++ /dev/null @@ -1,136 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - /home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl_vcd.h - functions - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl - cxxrtl_vcd.h (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:11216070.0 %
Date:1980-01-01 00:00:00Functions:151693.8 %
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Function Name Sort by function nameHit count Sort by hit count
_ZN6cxxrtl10vcd_writer11emit_vectorERKNS0_8variableE0
_ZN6cxxrtl10vcd_writer14emit_timescaleEjRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE3
_ZN6cxxrtl10vcd_writer19emit_enddefinitionsEv3
_ZN6cxxrtl10vcd_writer3addIZNS0_20add_without_memoriesERKNS_11debug_itemsEEUlRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_10debug_itemEE_EEvS4_RKT_3
_ZN6cxxrtl10vcd_writer15split_hierarchyERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE9
_ZN6cxxrtl10vcd_writer17register_variableEmPjbP15_cxxrtl_outline9
_ZN6cxxrtl10vcd_writer3addERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_10debug_itemEb9
_ZN6cxxrtl10vcd_writer8emit_varERKNS0_8variableERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESB_mb9
_ZN6cxxrtl10vcd_writer9emit_nameERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE9
_ZN6cxxrtl10vcd_writer10emit_scopeERKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS7_EE12
_ZN6cxxrtl10vcd_writer14reset_outlinesEv33
_ZN6cxxrtl10vcd_writer6sampleEm33
_ZN6cxxrtl10vcd_writer9emit_timeEm33
_ZN6cxxrtl10vcd_writer11emit_scalarERKNS0_8variableE51
_ZN6cxxrtl10vcd_writer10emit_identEm60
_ZN6cxxrtl10vcd_writer13test_variableERKNS0_8variableE99
-
-
- - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl_vcd.h.func.html b/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl_vcd.h.func.html deleted file mode 100644 index 5ceeb75a190..00000000000 --- a/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl_vcd.h.func.html +++ /dev/null @@ -1,136 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - /home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl_vcd.h - functions - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl - cxxrtl_vcd.h (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:11216070.0 %
Date:1980-01-01 00:00:00Functions:151693.8 %
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Function Name Sort by function nameHit count Sort by hit count
_ZN6cxxrtl10vcd_writer10emit_identEm60
_ZN6cxxrtl10vcd_writer10emit_scopeERKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS7_EE12
_ZN6cxxrtl10vcd_writer11emit_scalarERKNS0_8variableE51
_ZN6cxxrtl10vcd_writer11emit_vectorERKNS0_8variableE0
_ZN6cxxrtl10vcd_writer13test_variableERKNS0_8variableE99
_ZN6cxxrtl10vcd_writer14emit_timescaleEjRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE3
_ZN6cxxrtl10vcd_writer14reset_outlinesEv33
_ZN6cxxrtl10vcd_writer15split_hierarchyERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE9
_ZN6cxxrtl10vcd_writer17register_variableEmPjbP15_cxxrtl_outline9
_ZN6cxxrtl10vcd_writer19emit_enddefinitionsEv3
_ZN6cxxrtl10vcd_writer3addERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_10debug_itemEb9
_ZN6cxxrtl10vcd_writer3addIZNS0_20add_without_memoriesERKNS_11debug_itemsEEUlRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_10debug_itemEE_EEvS4_RKT_3
_ZN6cxxrtl10vcd_writer6sampleEm33
_ZN6cxxrtl10vcd_writer8emit_varERKNS0_8variableERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESB_mb9
_ZN6cxxrtl10vcd_writer9emit_nameERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE9
_ZN6cxxrtl10vcd_writer9emit_timeEm33
-
-
- - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl_vcd.h.gcov.html b/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl_vcd.h.gcov.html deleted file mode 100644 index 79fb13319cd..00000000000 --- a/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl_vcd.h.gcov.html +++ /dev/null @@ -1,351 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - /home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/cxxrtl_vcd.h - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl - cxxrtl_vcd.h (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:11216070.0 %
Date:1980-01-01 00:00:00Functions:151693.8 %
-
- - - - - - - - -

-
          Line data    Source code
-
-       1             : /*
-       2             :  *  yosys -- Yosys Open SYnthesis Suite
-       3             :  *
-       4             :  *  Copyright (C) 2020  whitequark <whitequark@whitequark.org>
-       5             :  *
-       6             :  *  Permission to use, copy, modify, and/or distribute this software for any
-       7             :  *  purpose with or without fee is hereby granted.
-       8             :  *
-       9             :  *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-      10             :  *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-      11             :  *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-      12             :  *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-      13             :  *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-      14             :  *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-      15             :  *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-      16             :  *
-      17             :  */
-      18             : 
-      19             : #ifndef CXXRTL_VCD_H
-      20             : #define CXXRTL_VCD_H
-      21             : 
-      22             : #include <cxxrtl/cxxrtl.h>
-      23             : 
-      24             : namespace cxxrtl {
-      25             : 
-      26             : class vcd_writer {
-      27             :         struct variable {
-      28             :                 size_t ident;
-      29             :                 size_t width;
-      30             :                 chunk_t *curr;
-      31             :                 size_t cache_offset;
-      32             :                 debug_outline *outline;
-      33             :                 bool *outline_warm;
-      34             :         };
-      35             : 
-      36             :         std::vector<std::string> current_scope;
-      37             :         std::map<debug_outline*, bool> outlines;
-      38             :         std::vector<variable> variables;
-      39             :         std::vector<chunk_t> cache;
-      40             :         std::map<chunk_t*, size_t> aliases;
-      41             :         bool streaming = false;
-      42             : 
-      43           3 :         void emit_timescale(unsigned number, const std::string &unit) {
-      44           3 :                 assert(!streaming);
-      45           3 :                 assert(number == 1 || number == 10 || number == 100);
-      46           3 :                 assert(unit == "s" || unit == "ms" || unit == "us" ||
-      47             :                        unit == "ns" || unit == "ps" || unit == "fs");
-      48          12 :                 buffer += "$timescale " + std::to_string(number) + " " + unit + " $end\n";
-      49           3 :         }
-      50             : 
-      51          12 :         void emit_scope(const std::vector<std::string> &scope) {
-      52          12 :                 assert(!streaming);
-      53          12 :                 while (current_scope.size() > scope.size() ||
-      54          12 :                        (current_scope.size() > 0 &&
-      55           0 :                         current_scope[current_scope.size() - 1] != scope[current_scope.size() - 1])) {
-      56           0 :                         buffer += "$upscope $end\n";
-      57           0 :                         current_scope.pop_back();
-      58             :                 }
-      59          12 :                 while (current_scope.size() < scope.size()) {
-      60           0 :                         buffer += "$scope module " + scope[current_scope.size()] + " $end\n";
-      61           0 :                         current_scope.push_back(scope[current_scope.size()]);
-      62             :                 }
-      63          12 :         }
-      64             : 
-      65          60 :         void emit_ident(size_t ident) {
-      66          60 :                 do {
-      67          60 :                         buffer += '!' + ident % 94; // "base94"
-      68          60 :                         ident /= 94;
-      69          60 :                 } while (ident != 0);
-      70          60 :         }
-      71             : 
-      72           9 :         void emit_name(const std::string &name) {
-      73          24 :                 for (char c : name) {
-      74          15 :                         if (c == ':') {
-      75             :                                 // Due to a bug, GTKWave cannot parse a colon in the variable name, causing the VCD file
-      76             :                                 // to be unreadable. It cannot be escaped either, so replace it with the sideways colon.
-      77           0 :                                 buffer += "..";
-      78             :                         } else {
-      79          30 :                                 buffer += c;
-      80             :                         }
-      81             :                 }
-      82           9 :         }
-      83             : 
-      84           9 :         void emit_var(const variable &var, const std::string &type, const std::string &name,
-      85             :                       size_t lsb_at, bool multipart) {
-      86           9 :                 assert(!streaming);
-      87          36 :                 buffer += "$var " + type + " " + std::to_string(var.width) + " ";
-      88           9 :                 emit_ident(var.ident);
-      89           9 :                 buffer += " ";
-      90           9 :                 emit_name(name);
-      91           9 :                 if (multipart || name.back() == ']' || lsb_at != 0) {
-      92           0 :                         if (var.width == 1)
-      93           0 :                                 buffer += " [" + std::to_string(lsb_at) + "]";
-      94             :                         else
-      95           0 :                                 buffer += " [" + std::to_string(lsb_at + var.width - 1) + ":" + std::to_string(lsb_at) + "]";
-      96             :                 }
-      97           9 :                 buffer += " $end\n";
-      98           9 :         }
-      99             : 
-     100           3 :         void emit_enddefinitions() {
-     101           3 :                 assert(!streaming);
-     102           3 :                 buffer += "$enddefinitions $end\n";
-     103           3 :                 streaming = true;
-     104           3 :         }
-     105             : 
-     106          33 :         void emit_time(uint64_t timestamp) {
-     107          33 :                 assert(streaming);
-     108          99 :                 buffer += "#" + std::to_string(timestamp) + "\n";
-     109          33 :         }
-     110             : 
-     111          51 :         void emit_scalar(const variable &var) {
-     112          51 :                 assert(streaming);
-     113          51 :                 assert(var.width == 1);
-     114          78 :                 buffer += (*var.curr ? '1' : '0');
-     115          51 :                 emit_ident(var.ident);
-     116          51 :                 buffer += '\n';
-     117          51 :         }
-     118             : 
-     119           0 :         void emit_vector(const variable &var) {
-     120           0 :                 assert(streaming);
-     121           0 :                 buffer += 'b';
-     122           0 :                 for (size_t bit = var.width - 1; bit != (size_t)-1; bit--) {
-     123           0 :                         bool bit_curr = var.curr[bit / (8 * sizeof(chunk_t))] & (1 << (bit % (8 * sizeof(chunk_t))));
-     124           0 :                         buffer += (bit_curr ? '1' : '0');
-     125             :                 }
-     126           0 :                 buffer += ' ';
-     127           0 :                 emit_ident(var.ident);
-     128           0 :                 buffer += '\n';
-     129           0 :         }
-     130             : 
-     131          33 :         void reset_outlines() {
-     132          66 :                 for (auto &outline_it : outlines)
-     133          33 :                         outline_it.second = /*warm=*/(outline_it.first == nullptr);
-     134          33 :         }
-     135             : 
-     136           9 :         variable &register_variable(size_t width, chunk_t *curr, bool constant = false, debug_outline *outline = nullptr) {
-     137           9 :                 if (aliases.count(curr)) {
-     138           0 :                         return variables[aliases[curr]];
-     139             :                 } else {
-     140           9 :                         auto outline_it = outlines.emplace(outline, /*warm=*/(outline == nullptr)).first;
-     141           9 :                         const size_t chunks = (width + (sizeof(chunk_t) * 8 - 1)) / (sizeof(chunk_t) * 8);
-     142           9 :                         aliases[curr] = variables.size();
-     143           9 :                         if (constant) {
-     144           0 :                                 variables.emplace_back(variable { variables.size(), width, curr, (size_t)-1, outline_it->first, &outline_it->second });
-     145             :                         } else {
-     146           9 :                                 variables.emplace_back(variable { variables.size(), width, curr, cache.size(), outline_it->first, &outline_it->second });
-     147           9 :                                 cache.insert(cache.end(), &curr[0], &curr[chunks]);
-     148             :                         }
-     149           9 :                         return variables.back();
-     150             :                 }
-     151             :         }
-     152             : 
-     153          99 :         bool test_variable(const variable &var) {
-     154          99 :                 if (var.cache_offset == (size_t)-1)
-     155             :                         return false; // constant
-     156          99 :                 if (!*var.outline_warm) {
-     157           0 :                         var.outline->eval();
-     158           0 :                         *var.outline_warm = true;
-     159             :                 }
-     160          99 :                 const size_t chunks = (var.width + (sizeof(chunk_t) * 8 - 1)) / (sizeof(chunk_t) * 8);
-     161          99 :                 if (std::equal(&var.curr[0], &var.curr[chunks], &cache[var.cache_offset])) {
-     162             :                         return false;
-     163             :                 } else {
-     164          42 :                         std::copy(&var.curr[0], &var.curr[chunks], &cache[var.cache_offset]);
-     165          42 :                         return true;
-     166             :                 }
-     167             :         }
-     168             : 
-     169           9 :         static std::vector<std::string> split_hierarchy(const std::string &hier_name) {
-     170           9 :                 std::vector<std::string> hierarchy;
-     171           9 :                 size_t prev = 0;
-     172           9 :                 while (true) {
-     173           9 :                         size_t curr = hier_name.find_first_of(' ', prev);
-     174           9 :                         if (curr == std::string::npos) {
-     175          18 :                                 hierarchy.push_back(hier_name.substr(prev));
-     176           9 :                                 break;
-     177             :                         } else {
-     178           0 :                                 hierarchy.push_back(hier_name.substr(prev, curr - prev));
-     179           0 :                                 prev = curr + 1;
-     180             :                         }
-     181           0 :                 }
-     182           9 :                 return hierarchy;
-     183           0 :         }
-     184             : 
-     185             : public:
-     186             :         std::string buffer;
-     187             : 
-     188           3 :         void timescale(unsigned number, const std::string &unit) {
-     189           3 :                 emit_timescale(number, unit);
-     190           3 :         }
-     191             : 
-     192           9 :         void add(const std::string &hier_name, const debug_item &item, bool multipart = false) {
-     193           9 :                 std::vector<std::string> scope = split_hierarchy(hier_name);
-     194           9 :                 std::string name = scope.back();
-     195           9 :                 scope.pop_back();
-     196             : 
-     197           9 :                 emit_scope(scope);
-     198           9 :                 switch (item.type) {
-     199             :                         // Not the best naming but oh well...
-     200           9 :                         case debug_item::VALUE:
-     201          18 :                                 emit_var(register_variable(item.width, item.curr, /*constant=*/item.next == nullptr),
-     202           9 :                                          "wire", name, item.lsb_at, multipart);
-     203           9 :                                 break;
-     204           0 :                         case debug_item::WIRE:
-     205           0 :                                 emit_var(register_variable(item.width, item.curr),
-     206           0 :                                          "reg", name, item.lsb_at, multipart);
-     207           0 :                                 break;
-     208           0 :                         case debug_item::MEMORY: {
-     209           0 :                                 const size_t stride = (item.width + (sizeof(chunk_t) * 8 - 1)) / (sizeof(chunk_t) * 8);
-     210           0 :                                 for (size_t index = 0; index < item.depth; index++) {
-     211           0 :                                         chunk_t *nth_curr = &item.curr[stride * index];
-     212           0 :                                         std::string nth_name = name + '[' + std::to_string(index) + ']';
-     213           0 :                                         emit_var(register_variable(item.width, nth_curr),
-     214           0 :                                                  "reg", nth_name, item.lsb_at, multipart);
-     215           0 :                                 }
-     216             :                                 break;
-     217             :                         }
-     218           0 :                         case debug_item::ALIAS:
-     219             :                                 // Like VALUE, but, even though `item.next == nullptr` always holds, the underlying value
-     220             :                                 // can actually change, and must be tracked. In most cases the VCD identifier will be
-     221             :                                 // unified with the aliased reg, but we should handle the case where only the alias is
-     222             :                                 // added to the VCD writer, too.
-     223           0 :                                 emit_var(register_variable(item.width, item.curr),
-     224           0 :                                          "wire", name, item.lsb_at, multipart);
-     225           0 :                                 break;
-     226           0 :                         case debug_item::OUTLINE:
-     227           0 :                                 emit_var(register_variable(item.width, item.curr, /*constant=*/false, item.outline),
-     228           0 :                                          "wire", name, item.lsb_at, multipart);
-     229           0 :                                 break;
-     230             :                 }
-     231           9 :         }
-     232             : 
-     233             :         template<class Filter>
-     234           3 :         void add(const debug_items &items, const Filter &filter) {
-     235             :                 // `debug_items` is a map, so the items are already sorted in an order optimal for emitting
-     236             :                 // VCD scope sections.
-     237          12 :                 for (auto &it : items.table)
-     238          18 :                         for (auto &part : it.second)
-     239           9 :                                 if (filter(it.first, part))
-     240           9 :                                         add(it.first, part, it.second.size() > 1);
-     241           3 :         }
-     242             : 
-     243             :         void add(const debug_items &items) {
-     244             :                 this->add(items, [](const std::string &, const debug_item &) {
-     245             :                         return true;
-     246             :                 });
-     247             :         }
-     248             : 
-     249           3 :         void add_without_memories(const debug_items &items) {
-     250           3 :                 this->add(items, [](const std::string &, const debug_item &item) {
-     251           9 :                         return item.type != debug_item::MEMORY;
-     252             :                 });
-     253             :         }
-     254             : 
-     255          33 :         void sample(uint64_t timestamp) {
-     256          33 :                 bool first_sample = !streaming;
-     257          33 :                 if (first_sample) {
-     258           3 :                         emit_scope({});
-     259           3 :                         emit_enddefinitions();
-     260             :                 }
-     261          33 :                 reset_outlines();
-     262          33 :                 emit_time(timestamp);
-     263         132 :                 for (auto var : variables)
-     264          99 :                         if (test_variable(var) || first_sample) {
-     265          51 :                                 if (var.width == 1)
-     266          51 :                                         emit_scalar(var);
-     267             :                                 else
-     268           0 :                                         emit_vector(var);
-     269             :                         }
-     270          33 :         }
-     271             : };
-     272             : 
-     273             : }
-     274             : 
-     275             : #endif
-
-
-
- - - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/index-sort-f.html b/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/index-sort-f.html deleted file mode 100644 index c99c203f1d4..00000000000 --- a/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/index-sort-f.html +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - /home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - /home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtlHitTotalCoverage
Test:vcd_harness.infoLines:20227872.7 %
Date:1980-01-01 00:00:00Functions:222588.0 %
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
cxxrtl.h -
76.3%76.3%
-
76.3 %90 / 11877.8 %7 / 9
cxxrtl_vcd.h -
70.0%70.0%
-
70.0 %112 / 16093.8 %15 / 16
-
-
- - - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/index-sort-l.html b/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/index-sort-l.html deleted file mode 100644 index 540500d9b36..00000000000 --- a/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/index-sort-l.html +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - /home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - /home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtlHitTotalCoverage
Test:vcd_harness.infoLines:20227872.7 %
Date:1980-01-01 00:00:00Functions:222588.0 %
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
cxxrtl_vcd.h -
70.0%70.0%
-
70.0 %112 / 16093.8 %15 / 16
cxxrtl.h -
76.3%76.3%
-
76.3 %90 / 11877.8 %7 / 9
-
-
- - - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/index.html b/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/index.html deleted file mode 100644 index cb7c4a6f2f4..00000000000 --- a/tests/functional/coverage_report/home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl/index.html +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - /home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtl - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - /home/roland/my_yosys/backends/cxxrtl/runtime/cxxrtlHitTotalCoverage
Test:vcd_harness.infoLines:20227872.7 %
Date:1980-01-01 00:00:00Functions:222588.0 %
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
cxxrtl.h -
76.3%76.3%
-
76.3 %90 / 11877.8 %7 / 9
cxxrtl_vcd.h -
70.0%70.0%
-
70.0 %112 / 16093.8 %15 / 16
-
-
- - - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/index-sort-f.html b/tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/index-sort-f.html deleted file mode 100644 index d2049083e2e..00000000000 --- a/tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/index-sort-f.html +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - /home/roland/my_yosys/backends/functional/cxx_runtime - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - /home/roland/my_yosys/backends/functional/cxx_runtimeHitTotalCoverage
Test:vcd_harness.infoLines:88100.0 %
Date:1980-01-01 00:00:00Functions:00-
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - -

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
sim.h -
100.0%
-
100.0 %8 / 8-0 / 0
-
-
- - - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/index-sort-l.html b/tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/index-sort-l.html deleted file mode 100644 index 9b62553938b..00000000000 --- a/tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/index-sort-l.html +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - /home/roland/my_yosys/backends/functional/cxx_runtime - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - /home/roland/my_yosys/backends/functional/cxx_runtimeHitTotalCoverage
Test:vcd_harness.infoLines:88100.0 %
Date:1980-01-01 00:00:00Functions:00-
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - -

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
sim.h -
100.0%
-
100.0 %8 / 8-0 / 0
-
-
- - - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/index.html b/tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/index.html deleted file mode 100644 index fdffcc1bd9d..00000000000 --- a/tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/index.html +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - /home/roland/my_yosys/backends/functional/cxx_runtime - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - /home/roland/my_yosys/backends/functional/cxx_runtimeHitTotalCoverage
Test:vcd_harness.infoLines:88100.0 %
Date:1980-01-01 00:00:00Functions:00-
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - -

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
sim.h -
100.0%
-
100.0 %8 / 8-0 / 0
-
-
- - - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/sim.h.func-sort-c.html b/tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/sim.h.func-sort-c.html deleted file mode 100644 index f4433ccc8b5..00000000000 --- a/tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/sim.h.func-sort-c.html +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - /home/roland/my_yosys/backends/functional/cxx_runtime/sim.h - functions - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - home/roland/my_yosys/backends/functional/cxx_runtime - sim.h (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:88100.0 %
Date:1980-01-01 00:00:00Functions:00-
-
- -
- - - - - - -

Function Name Sort by function nameHit count Sort by hit count
-
-
- - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/sim.h.func.html b/tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/sim.h.func.html deleted file mode 100644 index 27443d08173..00000000000 --- a/tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/sim.h.func.html +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - /home/roland/my_yosys/backends/functional/cxx_runtime/sim.h - functions - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - home/roland/my_yosys/backends/functional/cxx_runtime - sim.h (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:88100.0 %
Date:1980-01-01 00:00:00Functions:00-
-
- -
- - - - - - -

Function Name Sort by function nameHit count Sort by hit count
-
-
- - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/sim.h.gcov.html b/tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/sim.h.gcov.html deleted file mode 100644 index 7f21dcee36c..00000000000 --- a/tests/functional/coverage_report/home/roland/my_yosys/backends/functional/cxx_runtime/sim.h.gcov.html +++ /dev/null @@ -1,444 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - /home/roland/my_yosys/backends/functional/cxx_runtime/sim.h - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - home/roland/my_yosys/backends/functional/cxx_runtime - sim.h (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:88100.0 %
Date:1980-01-01 00:00:00Functions:00-
-
- - - - - - - - -

-
          Line data    Source code
-
-       1             : /*
-       2             :  *  yosys -- Yosys Open SYnthesis Suite
-       3             :  *
-       4             :  *  Copyright (C) 2024  Emily Schmidt <emily@yosyshq.com>
-       5             :  *
-       6             :  *  Permission to use, copy, modify, and/or distribute this software for any
-       7             :  *  purpose with or without fee is hereby granted, provided that the above
-       8             :  *  copyright notice and this permission notice appear in all copies.
-       9             :  *
-      10             :  *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-      11             :  *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-      12             :  *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-      13             :  *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-      14             :  *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-      15             :  *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-      16             :  *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-      17             :  *
-      18             :  */
-      19             : 
-      20             : #ifndef SIM_H
-      21             : #define SIM_H
-      22             : 
-      23             : #include <array>
-      24             : #include <cstdint>
-      25             : #include <cassert>
-      26             : 
-      27             : template<size_t n>
-      28             : using Signal = std::array<bool, n>;
-      29             : 
-      30             : template<size_t n, size_t m>
-      31             : Signal<n> slice(Signal<m> const& a, size_t offset)
-      32             : {
-      33             :     Signal<n> ret;
-      34             : 
-      35             :     std::copy(a.begin() + offset, a.begin() + offset + n, ret.begin());
-      36             :     return ret;
-      37             : }
-      38             : 
-      39             : template<size_t n>
-      40          30 : Signal<n> $const(uint32_t val)
-      41             : {
-      42             :     size_t i;
-      43             :     Signal<n> ret;
-      44             : 
-      45          30 :     for(i = 0; i < n; i++)
-      46             :         if(i < 32)
-      47          33 :             ret[i] = val & (1<<i);
-      48             :         else
-      49             :             ret[i] = false;
-      50             :     return ret;
-      51             : }
-      52             : 
-      53             : template<size_t n>
-      54             : Signal<n> $const(std::initializer_list<uint32_t> vals)
-      55             : {
-      56             :     size_t k, i;
-      57             :     Signal<n> ret;
-      58             : 
-      59             :     k = 0;
-      60             :     for (auto val : vals) {
-      61             :         for(i = 0; i < 32; i++)
-      62             :             if(i + k < n)
-      63             :                 ret[i + k] = val & (1<<i);
-      64             :         k += 32;
-      65             :     }
-      66             :     for(; k < n; k++)
-      67             :         ret[k] = false;
-      68             :     return ret;
-      69             : }
-      70             : 
-      71             : template<size_t n>
-      72             : bool as_bool(Signal<n> sig)
-      73             : {
-      74             :     for(int i = 0; i < n; i++)
-      75             :         if(sig[i])
-      76             :             return true;
-      77             :     return false;
-      78             : }
-      79             : 
-      80             : template<size_t n>
-      81             : uint32_t as_int(Signal<n> sig)
-      82             : {
-      83             :     uint32_t ret = 0;
-      84             :     for(int i = 0; i < n; i++)
-      85             :         if(sig[i] && i < 32)
-      86             :             ret |= 1<<i;
-      87             :     return ret;
-      88             : }
-      89             : 
-      90             : template<size_t n>
-      91             : Signal<n> $mux(Signal<n> const& a, Signal<n> const &b, Signal<1> const &s)
-      92             : {
-      93             :     return s[0] ? b : a;
-      94             : }
-      95             : 
-      96             : template<size_t n>
-      97             : Signal<n> $not(Signal<n> const& a)
-      98             : {
-      99             :     Signal<n> ret;
-     100             :     for(size_t i = 0; i < n; i++)
-     101             :         ret[i] = !a[i];
-     102             :     return ret;
-     103             : }
-     104             : 
-     105             : template<size_t n>
-     106             : Signal<n> $neg(Signal<n> const& a)
-     107             : {
-     108             :     Signal<n> ret;
-     109             :     bool carry = true;
-     110             :     for(size_t i = 0; i < n; i++) {
-     111             :         int r = !a[i] + carry;
-     112             :         ret[i] = (r & 1) != 0;
-     113             :         carry = (r >> 1) != 0;
-     114             :     }
-     115             :     return ret;
-     116             : }
-     117             : 
-     118             : template<size_t n>
-     119             : Signal<1> $reduce_or(Signal<n> const& a)
-     120             : {
-     121             :     return { as_bool(a) };
-     122             : }
-     123             : 
-     124             : template<size_t n>
-     125             : Signal<1> $reduce_and(Signal<n> const& a)
-     126             : {
-     127             :     for(size_t i = 0; i < n; i++)
-     128             :         if(!a[i])
-     129             :             return { false };
-     130             :     return { true };
-     131             : }
-     132             : 
-     133             : template<size_t n>
-     134             : Signal<1> $reduce_bool(Signal<n> const& a)
-     135             : {
-     136             :     return { as_bool(a) };
-     137             : }
-     138             : 
-     139             : template<size_t n>
-     140             : Signal<1> $logic_and(Signal<n> const& a, Signal<n> const& b)
-     141             : {
-     142             :     return { as_bool(a) && as_bool(b) };
-     143             : }
-     144             : 
-     145             : template<size_t n>
-     146             : Signal<1> $logic_or(Signal<n> const& a, Signal<n> const& b)
-     147             : {
-     148             :     return { as_bool(a) || as_bool(b) };
-     149             : }
-     150             : 
-     151             : template<size_t n>
-     152             : Signal<1> $logic_not(Signal<n> const& a)
-     153             : {
-     154             :     return { !as_bool(a) };
-     155             : }
-     156             : 
-     157             : template<size_t n>
-     158          30 : Signal<n> $add(Signal<n> const& a, Signal<n> const &b)
-     159             : {
-     160             :     Signal<n> ret;
-     161             :     size_t i;
-     162             :     int x = 0;
-     163          30 :     for(i = 0; i < n; i++){
-     164          30 :         x += (int)a[i] + (int)b[i];
-     165          30 :         ret[i] = x & 1;
-     166          30 :         x >>= 1;
-     167             :     }
-     168             :     return ret;
-     169             : }
-     170             : template<size_t n>
-     171             : Signal<n> $sub(Signal<n> const& a, Signal<n> const &b)
-     172             : {
-     173             :     Signal<n> ret;
-     174             :     int x = 1;
-     175             :     for(size_t i = 0; i < n; i++){
-     176             :         x += (int)a[i] + (int)!b[i];
-     177             :         ret[i] = x & 1;
-     178             :         x >>= 1;
-     179             :     }
-     180             :     return ret;
-     181             : }
-     182             : 
-     183             : template<size_t n>
-     184             : Signal<1> $uge(Signal<n> const& a, Signal<n> const &b)
-     185             : {
-     186             :     for(size_t i = n; i-- != 0; )
-     187             :         if(a[i] != b[i])
-     188             :             return { a[i] };
-     189             :     return { true };
-     190             : }
-     191             : 
-     192             : template<size_t n>
-     193             : Signal<1> $ugt(Signal<n> const& a, Signal<n> const &b)
-     194             : {
-     195             :     for(size_t i = n; i-- != 0; )
-     196             :         if(a[i] != b[i])
-     197             :             return { a[i] };
-     198             :     return { false };
-     199             : }
-     200             : 
-     201             : template<size_t n>
-     202             : Signal<1> $ge(Signal<n> const& a, Signal<n> const &b)
-     203             : {
-     204             :     if(a[n-1] != b[n-1])
-     205             :         return { b[n-1] };
-     206             :     return $uge(a, b);
-     207             : }
-     208             : 
-     209             : template<size_t n>
-     210             : Signal<1> $gt(Signal<n> const& a, Signal<n> const &b)
-     211             : {
-     212             :     if(a[n-1] != b[n-1])
-     213             :         return { b[n-1] };
-     214             :     return $ugt(a, b);
-     215             : }
-     216             : 
-     217             : template<size_t n> Signal<1> $ule(Signal<n> const& a, Signal<n> const &b) { return $uge(b, a); }
-     218             : template<size_t n> Signal<1> $ult(Signal<n> const& a, Signal<n> const &b) { return $ugt(b, a); }
-     219             : template<size_t n> Signal<1> $le(Signal<n> const& a, Signal<n> const &b) { return $ge(b, a); }
-     220             : template<size_t n> Signal<1> $lt(Signal<n> const& a, Signal<n> const &b) { return $gt(b, a); }
-     221             : 
-     222             : template<size_t n>
-     223             : Signal<n> $and(Signal<n> const& a, Signal<n> const &b)
-     224             : {
-     225             :     Signal<n> ret;
-     226             :     for(size_t i = 0; i < n; i++)
-     227             :         ret[i] = a[i] && b[i];
-     228             :     return ret;
-     229             : }
-     230             : 
-     231             : template<size_t n>
-     232             : Signal<n> $or(Signal<n> const& a, Signal<n> const &b)
-     233             : {
-     234             :     Signal<n> ret;
-     235             :     for(size_t i = 0; i < n; i++)
-     236             :         ret[i] = a[i] || b[i];
-     237             :     return ret;
-     238             : }
-     239             : 
-     240             : template<size_t n>
-     241             : Signal<n> $xor(Signal<n> const& a, Signal<n> const &b)
-     242             : {
-     243             :     Signal<n> ret;
-     244             :     for(size_t i = 0; i < n; i++)
-     245             :         ret[i] = a[i] != b[i];
-     246             :     return ret;
-     247             : }
-     248             : 
-     249             : template<size_t n, size_t na, size_t nb>
-     250             : Signal<n> $shl(Signal<na> const& a, Signal<nb> const &b)
-     251             : {
-     252             :     if(nb >= sizeof(int) * 8 - 1)
-     253             :         for(size_t i = sizeof(int) * 8 - 1; i < nb; i++)
-     254             :             assert(!b[i]);
-     255             :     size_t amount = as_int(b);
-     256             :     Signal<n> ret = $const<n>(0);
-     257             :     if(amount < n){
-     258             :         if(amount + na > n)
-     259             :             std::copy(a.begin(), a.begin() + (n - amount), ret.begin() + amount);
-     260             :         else
-     261             :             std::copy(a.begin(), a.end(), ret.begin() + amount);
-     262             :     }
-     263             :     return ret;
-     264             : }
-     265             : 
-     266             : template<size_t n, size_t nb>
-     267             : Signal<n> $shr(Signal<n> const& a, Signal<nb> const &b)
-     268             : {
-     269             :     if(nb >= sizeof(int) * 8 - 1)
-     270             :         for(size_t i = sizeof(int) * 8 - 1; i < nb; i++)
-     271             :             assert(!b[i]);
-     272             :     size_t amount = as_int(b);
-     273             :     Signal<n> ret;
-     274             :     for (size_t i = 0; i < n; i++) {
-     275             :         if(i + amount < n)
-     276             :             ret[i] = a[i + amount];
-     277             :         else
-     278             :             ret[i] = false;
-     279             :     }
-     280             :     return ret;
-     281             : }
-     282             : 
-     283             : template<size_t n, size_t nb>
-     284             : Signal<n> $asr(Signal<n> const& a, Signal<nb> const &b)
-     285             : {
-     286             :     if(nb >= sizeof(int) * 8 - 1)
-     287             :         for(size_t i = sizeof(int) * 8 - 1; i < nb; i++)
-     288             :             assert(!b[i]);
-     289             :     size_t amount = as_int(b);
-     290             :     Signal<n> ret;
-     291             :     for (size_t i = 0; i < n; i++) {
-     292             :         if(i + amount < n)
-     293             :             ret[i] = a[i + amount];
-     294             :         else
-     295             :             ret[i] = a[n - 1];
-     296             :     }
-     297             :     return ret;
-     298             : }
-     299             : 
-     300             : template<size_t n>
-     301             : Signal<1> $eq(Signal<n> const& a, Signal<n> const &b)
-     302             : {
-     303             :     for(size_t i = 0; i < n; i++)
-     304             :         if(a[i] != b[i])
-     305             :             return { false };
-     306             :     return { true };
-     307             : }
-     308             : 
-     309             : template<size_t n>
-     310             : Signal<1> $ne(Signal<n> const& a, Signal<n> const &b)
-     311             : {
-     312             :     for(size_t i = 0; i < n; i++)
-     313             :         if(a[i] != b[i])
-     314             :             return { true };
-     315             :     return { false };
-     316             : }
-     317             : 
-     318             : template<size_t n, size_t ns>
-     319             : Signal<n> $pmux(Signal<n> const& a, Signal<n*ns> const &b, Signal<ns> const &s)
-     320             : {
-     321             :     bool found;
-     322             :     Signal<n> ret;
-     323             : 
-     324             :     found = false;
-     325             :     ret = a;
-     326             :     for(size_t i = 0; i < ns; i++){
-     327             :         if(s[i]){
-     328             :             if(found)
-     329             :                 return $const<n>(0);
-     330             :             found = true;
-     331             :             ret = slice<n>(b, n * i);
-     332             :         }
-     333             :     }
-     334             :     return ret;
-     335             : }
-     336             : 
-     337             : template<size_t n, size_t m>
-     338             : Signal<n+m> concat(Signal<n> const& a, Signal<m> const& b)
-     339             : {
-     340             :     Signal<n + m> ret;
-     341             :     std::copy(a.begin(), a.end(), ret.begin());
-     342             :     std::copy(b.begin(), b.end(), ret.begin() + n);
-     343             :     return ret;
-     344             : }
-     345             : 
-     346             : template<size_t n, size_t m>
-     347             : Signal<n> $zero_extend(Signal<m> const& a)
-     348             : {
-     349             :     assert(n >= m);
-     350             :     Signal<n> ret;
-     351             :     std::copy(a.begin(), a.end(), ret.begin());
-     352             :     for(size_t i = m; i < n; i++)
-     353             :         ret[i] = false;
-     354             :     return ret;
-     355             : }
-     356             : 
-     357             : template<size_t n, size_t m>
-     358             : Signal<n> $sign_extend(Signal<m> const& a)
-     359             : {
-     360             :     assert(n >= m);
-     361             :     Signal<n> ret;
-     362             :     std::copy(a.begin(), a.end(), ret.begin());
-     363             :     for(size_t i = m; i < n; i++)
-     364             :         ret[i] = a[m-1];
-     365             :     return ret;
-     366             : }
-     367             : 
-     368             : #endif
-
-
-
- - - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_cxxrtl.cc.func-sort-c.html b/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_cxxrtl.cc.func-sort-c.html deleted file mode 100644 index e325523d6be..00000000000 --- a/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_cxxrtl.cc.func-sort-c.html +++ /dev/null @@ -1,100 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - /home/roland/my_yosys/tests/functional/and_cxxrtl.cc - functions - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - home/roland/my_yosys/tests/functional - and_cxxrtl.cc (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:222975.9 %
Date:1980-01-01 00:00:00Functions:5771.4 %
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Function Name Sort by function nameHit count Sort by hit count
_ZN13cxxrtl_design7p_Adder10debug_evalEv0
cxxrtl_design_create0
_ZN13cxxrtl_design7p_Adder10debug_infoEPN6cxxrtl11debug_itemsEPNS1_12debug_scopesENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEOSt3mapISB_NS1_8metadataESt4lessISB_ESaISt4pairIKSB_SD_EEE3
_ZN13cxxrtl_design7p_Adder5resetEv3
_ZN13cxxrtl_design7p_AdderC2Ev3
_ZN13cxxrtl_design7p_Adder4evalEPN6cxxrtl9performerE33
_ZN13cxxrtl_design7p_Adder6commitEv33
-
-
- - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_cxxrtl.cc.func.html b/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_cxxrtl.cc.func.html deleted file mode 100644 index 61a536bc000..00000000000 --- a/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_cxxrtl.cc.func.html +++ /dev/null @@ -1,100 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - /home/roland/my_yosys/tests/functional/and_cxxrtl.cc - functions - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - home/roland/my_yosys/tests/functional - and_cxxrtl.cc (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:222975.9 %
Date:1980-01-01 00:00:00Functions:5771.4 %
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Function Name Sort by function nameHit count Sort by hit count
_ZN13cxxrtl_design7p_Adder10debug_evalEv0
_ZN13cxxrtl_design7p_Adder10debug_infoEPN6cxxrtl11debug_itemsEPNS1_12debug_scopesENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEOSt3mapISB_NS1_8metadataESt4lessISB_ESaISt4pairIKSB_SD_EEE3
_ZN13cxxrtl_design7p_Adder4evalEPN6cxxrtl9performerE33
_ZN13cxxrtl_design7p_Adder5resetEv3
_ZN13cxxrtl_design7p_Adder6commitEv33
_ZN13cxxrtl_design7p_AdderC2Ev3
cxxrtl_design_create0
-
-
- - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_cxxrtl.cc.gcov.html b/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_cxxrtl.cc.gcov.html deleted file mode 100644 index 83033d50085..00000000000 --- a/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_cxxrtl.cc.gcov.html +++ /dev/null @@ -1,161 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - /home/roland/my_yosys/tests/functional/and_cxxrtl.cc - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - home/roland/my_yosys/tests/functional - and_cxxrtl.cc (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:222975.9 %
Date:1980-01-01 00:00:00Functions:5771.4 %
-
- - - - - - - - -

-
          Line data    Source code
-
-       1             : #include <cxxrtl/cxxrtl.h>
-       2             : 
-       3             : #if defined(CXXRTL_INCLUDE_CAPI_IMPL) || \
-       4             :     defined(CXXRTL_INCLUDE_VCD_CAPI_IMPL)
-       5             : #include <cxxrtl/capi/cxxrtl_capi.cc>
-       6             : #endif
-       7             : 
-       8             : #if defined(CXXRTL_INCLUDE_VCD_CAPI_IMPL)
-       9             : #include <cxxrtl/capi/cxxrtl_capi_vcd.cc>
-      10             : #endif
-      11             : 
-      12             : using namespace cxxrtl_yosys;
-      13             : 
-      14             : namespace cxxrtl_design {
-      15             : 
-      16             : // \top: 1
-      17             : // \src: verilog/and.v:1.1-9.10
-      18           3 : struct p_Adder : public module {
-      19             :         // \src: verilog/and.v:4.14-4.17
-      20             :         /*output*/ value<1> p_sum;
-      21             :         // \src: verilog/and.v:3.14-3.15
-      22             :         /*input*/ value<1> p_b;
-      23             :         // \src: verilog/and.v:2.14-2.15
-      24             :         /*input*/ value<1> p_a;
-      25             :         p_Adder(interior) {}
-      26           3 :         p_Adder() {
-      27           3 :                 reset();
-      28           3 :         };
-      29             : 
-      30             :         void reset() override;
-      31             : 
-      32             :         bool eval(performer *performer = nullptr) override;
-      33             : 
-      34             :         template<class ObserverT>
-      35             :         bool commit(ObserverT &observer) {
-      36          33 :                 bool changed = false;
-      37             :                 return changed;
-      38             :         }
-      39             : 
-      40          33 :         bool commit() override {
-      41          33 :                 observer observer;
-      42          33 :                 return commit<>(observer);
-      43             :         }
-      44             : 
-      45             :         void debug_eval();
-      46             : 
-      47             :         void debug_info(debug_items *items, debug_scopes *scopes, std::string path, metadata_map &&cell_attrs = {}) override;
-      48             : }; // struct p_Adder
-      49             : 
-      50           3 : void p_Adder::reset() {
-      51           3 : }
-      52             : 
-      53          33 : bool p_Adder::eval(performer *performer) {
-      54          33 :         bool converged = true;
-      55             :         // \src: verilog/and.v:7.17-7.22
-      56             :         // cell $add$verilog/and.v:7$1
-      57          33 :         p_sum = add_uu<1>(p_a, p_b);
-      58          33 :         return converged;
-      59             : }
-      60             : 
-      61           0 : void p_Adder::debug_eval() {
-      62           0 : }
-      63             : 
-      64             : CXXRTL_EXTREMELY_COLD
-      65           3 : void p_Adder::debug_info(debug_items *items, debug_scopes *scopes, std::string path, metadata_map &&cell_attrs) {
-      66           3 :         assert(path.empty() || path[path.size() - 1] == ' ');
-      67           3 :         if (scopes) {
-      68           0 :                 scopes->add(path.empty() ? path : path.substr(0, path.size() - 1), "Adder", metadata_map({
-      69           0 :                         { "top", UINT64_C(1) },
-      70             :                         { "src", "verilog/and.v:1.1-9.10" },
-      71           0 :                 }), std::move(cell_attrs));
-      72             :         }
-      73           3 :         if (items) {
-      74           3 :                 items->add(path, "sum", "src\000sverilog/and.v:4.14-4.17\000", p_sum, 0, debug_item::OUTPUT|debug_item::DRIVEN_COMB);
-      75           3 :                 items->add(path, "b", "src\000sverilog/and.v:3.14-3.15\000", p_b, 0, debug_item::INPUT|debug_item::UNDRIVEN);
-      76           3 :                 items->add(path, "a", "src\000sverilog/and.v:2.14-2.15\000", p_a, 0, debug_item::INPUT|debug_item::UNDRIVEN);
-      77             :         }
-      78           3 : }
-      79             : 
-      80             : } // namespace cxxrtl_design
-      81             : 
-      82             : extern "C"
-      83           0 : cxxrtl_toplevel cxxrtl_design_create() {
-      84           0 :         return new _cxxrtl_toplevel { std::unique_ptr<cxxrtl_design::p_Adder>(new cxxrtl_design::p_Adder) };
-      85             : }
-
-
-
- - - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_functional_cxx.cc.func-sort-c.html b/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_functional_cxx.cc.func-sort-c.html deleted file mode 100644 index 1ff7fb0d449..00000000000 --- a/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_functional_cxx.cc.func-sort-c.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - /home/roland/my_yosys/tests/functional/and_functional_cxx.cc - functions - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - home/roland/my_yosys/tests/functional - and_functional_cxx.cc (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:1313100.0 %
Date:1980-01-01 00:00:00Functions:33100.0 %
-
- -
- - - - - - - - - - - - - - - - - - -

Function Name Sort by function nameHit count Sort by hit count
_ZN12Adder_Inputs4dumpI10DumpHeaderEEvRT_3
_Z5AdderRK12Adder_InputsR13Adder_OutputsRK11Adder_StateRS4_30
_ZN12Adder_Inputs4dumpI4DumpEEvRT_33
-
-
- - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_functional_cxx.cc.func.html b/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_functional_cxx.cc.func.html deleted file mode 100644 index 8a02bda164c..00000000000 --- a/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_functional_cxx.cc.func.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - /home/roland/my_yosys/tests/functional/and_functional_cxx.cc - functions - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - home/roland/my_yosys/tests/functional - and_functional_cxx.cc (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:1313100.0 %
Date:1980-01-01 00:00:00Functions:33100.0 %
-
- -
- - - - - - - - - - - - - - - - - - -

Function Name Sort by function nameHit count Sort by hit count
_Z5AdderRK12Adder_InputsR13Adder_OutputsRK11Adder_StateRS4_30
_ZN12Adder_Inputs4dumpI10DumpHeaderEEvRT_3
_ZN12Adder_Inputs4dumpI4DumpEEvRT_33
-
-
- - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_functional_cxx.cc.gcov.html b/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_functional_cxx.cc.gcov.html deleted file mode 100644 index 57e77268202..00000000000 --- a/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/and_functional_cxx.cc.gcov.html +++ /dev/null @@ -1,108 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - /home/roland/my_yosys/tests/functional/and_functional_cxx.cc - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - home/roland/my_yosys/tests/functional - and_functional_cxx.cc (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:1313100.0 %
Date:1980-01-01 00:00:00Functions:33100.0 %
-
- - - - - - - - -

-
          Line data    Source code
-
-       1             : #include "sim.h"
-       2             : struct Adder_Inputs {
-       3             :         Signal<1> b;
-       4             :         Signal<1> a;
-       5             : 
-       6          36 :         template <typename T> void dump(T &out) {
-       7          36 :                 out("b", b);
-       8          36 :                 out("a", a);
-       9          36 :         }
-      10             : };
-      11             : 
-      12             : struct Adder_Outputs {
-      13             :         Signal<1> sum;
-      14             : 
-      15          36 :         template <typename T> void dump(T &out) {
-      16          36 :                 out("sum", sum);
-      17          36 :         }
-      18             : };
-      19             : 
-      20             : struct Adder_State {
-      21             : 
-      22             :         template <typename T> void dump(T &out) {
-      23             :         }
-      24             : };
-      25             : 
-      26          30 : void Adder(Adder_Inputs const &input, Adder_Outputs &output, Adder_State const &current_state, Adder_State &next_state)
-      27             : {
-      28          30 :         Signal<1> b = input.b;
-      29          30 :         Signal<1> a = input.a;
-      30          30 :         Signal<1> $add$verilog_and_v_7$1$_Y = $add(a, b); //
-      31          30 :         output.sum = $add$verilog_and_v_7$1$_Y;
-      32          30 : }
-
-
-
- - - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/index-sort-f.html b/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/index-sort-f.html deleted file mode 100644 index 476b5417b52..00000000000 --- a/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/index-sort-f.html +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - /home/roland/my_yosys/tests/functional - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - /home/roland/my_yosys/tests/functionalHitTotalCoverage
Test:vcd_harness.infoLines:10511293.8 %
Date:1980-01-01 00:00:00Functions:111384.6 %
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
and_cxxrtl.cc -
75.9%75.9%
-
75.9 %22 / 2971.4 %5 / 7
vcd_harness.cpp -
100.0%
-
100.0 %70 / 70100.0 %3 / 3
and_functional_cxx.cc -
100.0%
-
100.0 %13 / 13100.0 %3 / 3
-
-
- - - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/index-sort-l.html b/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/index-sort-l.html deleted file mode 100644 index aad1a23666d..00000000000 --- a/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/index-sort-l.html +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - /home/roland/my_yosys/tests/functional - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - /home/roland/my_yosys/tests/functionalHitTotalCoverage
Test:vcd_harness.infoLines:10511293.8 %
Date:1980-01-01 00:00:00Functions:111384.6 %
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
and_cxxrtl.cc -
75.9%75.9%
-
75.9 %22 / 2971.4 %5 / 7
and_functional_cxx.cc -
100.0%
-
100.0 %13 / 13100.0 %3 / 3
vcd_harness.cpp -
100.0%
-
100.0 %70 / 70100.0 %3 / 3
-
-
- - - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/index.html b/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/index.html deleted file mode 100644 index 548ec95fffd..00000000000 --- a/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/index.html +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - /home/roland/my_yosys/tests/functional - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - /home/roland/my_yosys/tests/functionalHitTotalCoverage
Test:vcd_harness.infoLines:10511293.8 %
Date:1980-01-01 00:00:00Functions:111384.6 %
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
and_cxxrtl.cc -
75.9%75.9%
-
75.9 %22 / 2971.4 %5 / 7
and_functional_cxx.cc -
100.0%
-
100.0 %13 / 13100.0 %3 / 3
vcd_harness.cpp -
100.0%
-
100.0 %70 / 70100.0 %3 / 3
-
-
- - - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/vcd_harness.cpp.func-sort-c.html b/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/vcd_harness.cpp.func-sort-c.html deleted file mode 100644 index 07fdc01e640..00000000000 --- a/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/vcd_harness.cpp.func-sort-c.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - /home/roland/my_yosys/tests/functional/vcd_harness.cpp - functions - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - home/roland/my_yosys/tests/functional - vcd_harness.cpp (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:7070100.0 %
Date:1980-01-01 00:00:00Functions:33100.0 %
-
- -
- - - - - - - - - - - - - - - - - - -

Function Name Sort by function nameHit count Sort by hit count
main3
_ZN10DumpHeaderclILm1EEEvPKcSt5arrayIbXT_EE9
_ZN4DumpclILm1EEEvPKcSt5arrayIbXT_EE99
-
-
- - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/vcd_harness.cpp.func.html b/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/vcd_harness.cpp.func.html deleted file mode 100644 index 6a9159b0109..00000000000 --- a/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/vcd_harness.cpp.func.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - /home/roland/my_yosys/tests/functional/vcd_harness.cpp - functions - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - home/roland/my_yosys/tests/functional - vcd_harness.cpp (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:7070100.0 %
Date:1980-01-01 00:00:00Functions:33100.0 %
-
- -
- - - - - - - - - - - - - - - - - - -

Function Name Sort by function nameHit count Sort by hit count
_ZN10DumpHeaderclILm1EEEvPKcSt5arrayIbXT_EE9
_ZN4DumpclILm1EEEvPKcSt5arrayIbXT_EE99
main3
-
-
- - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/vcd_harness.cpp.gcov.html b/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/vcd_harness.cpp.gcov.html deleted file mode 100644 index 805ab98d73e..00000000000 --- a/tests/functional/coverage_report/home/roland/my_yosys/tests/functional/vcd_harness.cpp.gcov.html +++ /dev/null @@ -1,216 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - /home/roland/my_yosys/tests/functional/vcd_harness.cpp - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - home/roland/my_yosys/tests/functional - vcd_harness.cpp (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:7070100.0 %
Date:1980-01-01 00:00:00Functions:33100.0 %
-
- - - - - - - - -

-
          Line data    Source code
-
-       1             : #include <cstdio>
-       2             : #include <iostream>
-       3             : #include <fstream>
-       4             : #include <random>
-       5             : 
-       6             : #include <cxxrtl/cxxrtl_vcd.h>
-       7             : 
-       8             : #include "and_cxxrtl.cc"
-       9             : #include "and_functional_cxx.cc"
-      10             : 
-      11             : struct DumpHeader {
-      12             :     std::ofstream &ofs;
-      13           3 :     DumpHeader(std::ofstream &ofs) : ofs(ofs) {}
-      14             :     template <size_t n>
-      15           9 :     void operator()(const char *name, Signal<n> value) {
-      16           9 :         ofs << "$var wire " << n << " " << name[0] << " " << name << " $end\n";
-      17           9 :     }
-      18             : };
-      19             : 
-      20             : struct Dump {
-      21             :     std::ofstream &ofs;
-      22          33 :     Dump(std::ofstream &ofs) : ofs(ofs) {}
-      23             :     template <size_t n>
-      24          99 :     void operator()(const char *name, Signal<n> value) {
-      25             :         // Bit
-      26             :         if (n == 1) {
-      27         156 :             ofs << (value[0] ? '1' : '0');
-      28          99 :             ofs << name[0] << "\n";
-      29             :             return;
-      30             :         }
-      31             :         // vector (multi-bit) signals
-      32             :         ofs << "b";
-      33             :         for (size_t i = n; i-- > 0;)
-      34             :             ofs << (value[i] ? '1' : '0');
-      35             :         ofs << " " << name[0] << "\n";
-      36             :     }
-      37             : };
-      38             : 
-      39           3 : int main(int argc, char **argv)
-      40             : {
-      41           3 :     constexpr int steps = 10;
-      42           3 :     constexpr int number_timescale = 1;
-      43           3 :     const std::string units_timescale = "us";
-      44           3 :     Adder_Inputs inputs;
-      45           3 :     Adder_Outputs outputs;
-      46           3 :     Adder_State state;
-      47           3 :     Adder_State next_state;
-      48             : 
-      49           3 :     std::ofstream vcd_file("functional_cxx.vcd");
-      50             : 
-      51           3 :     vcd_file << "$timescale " << number_timescale << " " << units_timescale << " $end\n"; //$scope module logic $end\n";
-      52           3 :     {
-      53           3 :         DumpHeader d(vcd_file);
-      54           3 :         inputs.dump(d);
-      55           3 :         outputs.dump(d);
-      56             :         // vcd_file << "$scope module state $end\n";
-      57           3 :         state.dump(d);
-      58             :     }
-      59           3 :     vcd_file << "$enddefinitions $end\n$dumpvars\n";
-      60             : 
-      61           3 :     cxxrtl_design::p_Adder top;
-      62             : 
-      63             :     // debug_items maps the hierarchical names of signals and memories in the design
-      64             :     // to a cxxrtl_object (a value, a wire, or a memory)
-      65           3 :     cxxrtl::debug_items all_debug_items;
-      66           3 :     cxxrtl::debug_scope debug_scope;
-      67             :     // Load the debug items of the top down the whole design hierarchy
-      68           6 :     top.debug_info(&all_debug_items, nullptr, "");
-      69             : 
-      70             :     // vcd_writer is the CXXRTL object that's responsible for creating a string with
-      71             :     // the VCD file contents.
-      72           3 :     cxxrtl::vcd_writer vcd;
-      73           3 :     vcd.timescale(number_timescale, units_timescale);
-      74             : 
-      75             :     // Here we tell the vcd writer to dump all the signals of the design, except for the
-      76             :     // memories, to the VCD file.
-      77             :     //
-      78             :     // It's not necessary to load all debug objects to the VCD. There is, for example,
-      79             :     // a  vcd.add(<debug items>, <filter>)) method which allows creating your custom filter to decide
-      80             :     // what to add and what not.
-      81           3 :     vcd.add_without_memories(all_debug_items);
-      82             : 
-      83           3 :     std::ofstream waves("cxxrtl.vcd");
-      84             : 
-      85           3 :     top.p_a.set<bool>(false);
-      86           3 :     top.p_b.set<bool>(false);
-      87           3 :     top.step();
-      88             : 
-      89             :     // We need to manually tell the VCD writer when to sample and write out the traced items.
-      90             :     // This is only a slight inconvenience and allows for complete flexibility.
-      91             :     // E.g. you could only start waveform tracing when an internal signal has reached some specific
-      92             :     // value etc.
-      93           3 :     vcd.sample(0);
-      94           3 :     vcd_file << "#0\n";
-      95           3 :     inputs.a = $const<1>(false);
-      96           3 :     inputs.b = $const<1>(false);
-      97           3 :     {
-      98           3 :         Dump d(vcd_file);
-      99           3 :         inputs.dump(d);
-     100           3 :         outputs.dump(d);
-     101           3 :         state.dump(d);
-     102             :     }
-     103             : 
-     104             :     // Initialize random number generator
-     105           3 :     std::random_device rd;
-     106           3 :     std::mt19937 gen(rd());
-     107           3 :     std::bernoulli_distribution dist(0.5); // 50% chance for true or false
-     108             :     
-     109          33 :     for (int step = 0; step < steps; ++step) {
-     110          30 :       const bool a_value = dist(gen);
-     111          30 :       const bool b_value = dist(gen);
-     112             : 
-     113             :         // cxxrtl
-     114          30 :         top.p_a.set<bool>(a_value);
-     115          30 :         top.p_b.set<bool>(b_value);
-     116          30 :         top.step();
-     117          30 :         vcd.sample(step + 1);
-     118             : 
-     119          30 :         waves << vcd.buffer;
-     120          30 :         vcd.buffer.clear();
-     121             : 
-     122             :         // Functional backend cxx
-     123          30 :         vcd_file << "#" << (step + 1) << "\n";
-     124          30 :         inputs.a = $const<1>(a_value);
-     125          30 :         inputs.b = $const<1>(b_value);
-     126          30 :         Adder(inputs, outputs, state, next_state);
-     127          30 :         {
-     128          30 :             Dump d(vcd_file);
-     129          30 :             inputs.dump(d);
-     130          30 :             outputs.dump(d);
-     131          30 :             state.dump(d);
-     132             :         }
-     133          30 :         state = next_state;
-     134             :     }
-     135             : 
-     136           3 :     vcd_file.close();
-     137           3 :     waves.close();
-     138             : 
-     139           3 :     return 0;
-     140           3 : }
-
-
-
- - - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/index-sort-f.html b/tests/functional/coverage_report/index-sort-f.html deleted file mode 100644 index e83963227e1..00000000000 --- a/tests/functional/coverage_report/index-sort-f.html +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top levelHitTotalCoverage
Test:vcd_harness.infoLines:10511293.8 %
Date:1980-01-01 00:00:00Functions:111384.6 %
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - -

Directory Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
functional -
93.8%93.8%
-
93.8 %105 / 11284.6 %11 / 13
-
-
- - - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/index-sort-l.html b/tests/functional/coverage_report/index-sort-l.html deleted file mode 100644 index ddc964eb34a..00000000000 --- a/tests/functional/coverage_report/index-sort-l.html +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top levelHitTotalCoverage
Test:vcd_harness.infoLines:10511293.8 %
Date:1980-01-01 00:00:00Functions:111384.6 %
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - -

Directory Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
functional -
93.8%93.8%
-
93.8 %105 / 11284.6 %11 / 13
-
-
- - - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/index.html b/tests/functional/coverage_report/index.html deleted file mode 100644 index 65d715c439e..00000000000 --- a/tests/functional/coverage_report/index.html +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top levelHitTotalCoverage
Test:vcd_harness.infoLines:10511293.8 %
Date:1980-01-01 00:00:00Functions:111384.6 %
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - -

Directory Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
functional -
93.8%93.8%
-
93.8 %105 / 11284.6 %11 / 13
-
-
- - - - -
Generated by: LCOV version 1.0
-
- - - diff --git a/tests/functional/coverage_report/nix/store/B0S2LKF593R3585038WS4JD3LYLF2WDX-glibc-2.38-44-dev/include/bits/string_fortified.h.gcov.html b/tests/functional/coverage_report/nix/store/B0S2LKF593R3585038WS4JD3LYLF2WDX-glibc-2.38-44-dev/include/bits/string_fortified.h.gcov.html deleted file mode 100644 index 7c9e3ccdcd7..00000000000 --- a/tests/functional/coverage_report/nix/store/B0S2LKF593R3585038WS4JD3LYLF2WDX-glibc-2.38-44-dev/include/bits/string_fortified.h.gcov.html +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - LCOV - vcd_harness.info - /nix/store/B0S2LKF593R3585038WS4JD3LYLF2WDX-glibc-2.38-44-dev/include/bits/string_fortified.h - - - - - - - - - - - - - - -
LCOV - code coverage report
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Current view:top level - nix/store/B0S2LKF593R3585038WS4JD3LYLF2WDX-glibc-2.38-44-dev/include/bits - string_fortified.h (source / functions)HitTotalCoverage
Test:vcd_harness.infoLines:020.0 %
Date:1980-01-01 00:00:00Functions:00-
-
- diff --git a/tests/functional/coverage_report/ruby.png b/tests/functional/coverage_report/ruby.png deleted file mode 100644 index 991b6d4ec9e78be165e3ef757eed1aada287364d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 141 zcmeAS@N?(olHy`uVBq!ia0vp^j3CU&3?x-=hn)ga>?NMQuI!iC1^FceV#7`HfI^%F z9+AZi4BSE>%y{W;-5;PJOS+@4BLl<6e(pbstUx|nfKQ0)e^Y%R^MdiLxj>4`)5S5Q b;#P73kj=!v_*DHKNFRfztDnm{r-UW|iOwIS diff --git a/tests/functional/coverage_report/snow.png b/tests/functional/coverage_report/snow.png deleted file mode 100644 index 2cdae107fceec6e7f02ac7acb4a34a82a540caa5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 141 zcmeAS@N?(olHy`uVBq!ia0vp^j3CU&3?x-=hn)ga>?NMQuI!iC1^MM!lvI6;R0X`wF|Ns97GD8ntt^-nBo-U3d c6}OTTfNUlP#;5A{K>8RwUHx3vIVCg!071?oo&W#< diff --git a/tests/functional/coverage_report/updown.png b/tests/functional/coverage_report/updown.png deleted file mode 100644 index aa56a238b3e6c435265250f9266cd1b8caba0f20..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 117 zcmeAS@N?(olHy`uVBq!ia0vp^AT}Qd8;}%R+`Ae`*?77*hG?8mPH5^{)z4*}Q$iB}huR`+ diff --git a/tests/functional/smt/and.smt2 b/tests/functional/smt/and.smt2 new file mode 100644 index 00000000000..c6002daa163 --- /dev/null +++ b/tests/functional/smt/and.smt2 @@ -0,0 +1,23 @@ +(declare-datatype my_module_inputs ((my_module_inputs + (my_module_inputs_b (_ BitVec 1)) + (my_module_inputs_a (_ BitVec 1)) +))) +(declare-datatype my_module_outputs ((my_module_outputs + (my_module_outputs_y (_ BitVec 1)) +))) +(declare-datatype my_module_state ((my_module_state +))) +(declare-datatypes ((Pair 2)) ((par (X Y) ((pair (first X) (second Y)))))) +(define-fun my_module_step ((inputs my_module_inputs) (current_state my_module_state)) (Pair my_module_outputs my_module_state) + (let (((b (my_module_inputs_b inputs)))) + (let (((a (my_module_inputs_a inputs)))) + (let ((($and$tests/functional/single_bit/verilog/my_module_and.v_7$1$_Y (bvand a b)))) + (pair + (my_module_outputs + $and$tests/functional/single_bit/verilog/my_module_and.v_7$1$_Y ; y + ) + (my_module_state + ) + ) + ))) +) diff --git a/tests/functional/smt/test_smt.rkt b/tests/functional/smt/test_smt.rkt new file mode 100644 index 00000000000..cb27d28bf40 --- /dev/null +++ b/tests/functional/smt/test_smt.rkt @@ -0,0 +1,22 @@ +#lang rosette/safe + +(require rosette/lib/smt) + +;; Define a function to load SMT-LIB from a file +(define (load-smt-file filepath) + (define smt-content (file->string filepath)) + (smt->rosette smt-content)) + +;; Path to your SMT-LIB file +(define smt-file-path "and.smt2") + +;; Load the SMT-LIB content +(define smt-formula (load-smt-file smt-file-path)) + +;; Example: Asserting a simple query +(define (test-smt-formula) + (define result (verify smt-formula)) + (printf "Result: ~a\n" result)) + +;; Run the test +(test-smt-formula) \ No newline at end of file diff --git a/vvp.vcd b/vvp.vcd new file mode 100644 index 00000000000..eb8b21e32e2 --- /dev/null +++ b/vvp.vcd @@ -0,0 +1,10489 @@ +$date + Tue May 28 17:57:15 2024 +$end +$version + Icarus Verilog +$end +$timescale + 1s +$end +$scope module testbench $end +$var wire 1 ! sig_my_module_y $end +$var reg 1024 " filename [1023:0] $end +$var reg 1 # sig_my_module_a $end +$var reg 1 $ sig_my_module_b $end +$var reg 32 % xorshift128_t [31:0] $end +$var reg 32 & xorshift128_w [31:0] $end +$var reg 32 ' xorshift128_x [31:0] $end +$var reg 32 ( xorshift128_y [31:0] $end +$var reg 32 ) xorshift128_z [31:0] $end +$var integer 32 * file [31:0] $end +$var integer 32 + i [31:0] $end +$scope module uut_my_module $end +$var wire 1 # a $end +$var wire 1 $ b $end +$var wire 1 ! y $end +$upscope $end +$scope task my_module_print_header $end +$upscope $end +$scope task my_module_print_status $end +$upscope $end +$scope task my_module_reset $end +$upscope $end +$scope task my_module_test $end +$upscope $end +$scope task my_module_update_clock $end +$upscope $end +$scope task my_module_update_data $end +$upscope $end +$scope task xorshift128 $end +$upscope $end +$upscope $end +$enddefinitions $end +$comment Show the parameter values. $end +$dumpall +$end +#0 +$dumpvars +bx + +b10 * +b11111000100100011101110110101 ) +b10101100110100101010111100101 ( +b111010110111100110100010101 ' +b1100110010101011111110101100011 & +bx % +x$ +x# +b1110110011101100111000000101110011101100110001101100100 " +x! +$end +#2 +0! +0# +#4 +0$ +#102 +1# +#104 +1! +1$ +#200 +b0 + +#300 +b1111000010011011111100010110110 & +b10111111101111111010011111011001 ) +b1100110010101011111110101100011 ( +b11111000100100011101110110101 ' +b11000111001101010111110111100101 % +#304 +0! +0$ +#600 +b1 + +#700 +b111111011110111110111011011110 & +b11110110000011001010101110011001 ) +b1111000010011011111100010110110 ( +b10111111101111111010011111011001 ' +b11001001101111101110010101100011 % +#1000 +b10 + +#1100 +b1101010001001111100100011001110 & +b1111101101110000000011110000111 ) +b111111011110111110111011011110 ( +b11110110000011001010101110011001 ' +b10111100010000100100010110110 % +#1400 +b11 + +#1500 +b11001000010011111101010001100 & +b11111001111001001111011001110000 ) +b1101010001001111100100011001110 ( +b1111101101110000000011110000111 ' +b11100000000011010001111011011110 % +#1502 +0# +#1800 +b100 + +#1900 +b11110000000001011000111111100101 & +b10100100001100000100001000010101 ) +b11001000010011111101010001100 ( +b11111001111001001111011001110000 ' +b1010100011000011011100011001110 % +#1902 +1# +#1904 +1! +1$ +#2200 +b101 + +#2300 +b1111000000001111111001000100100 & +b101110100011001011000011100011 ) +b11110000000001011000111111100101 ( +b10100100001100000100001000010101 ' +b1010110110111011001101010001100 % +#2304 +0! +0$ +#2600 +b110 + +#2700 +b10000010101001111110000101011001 & +b1011110000000010011011111011011 ) +b1111000000001111111001000100100 ( +b101110100011001011000011100011 ' +b11011100011110101010011111100101 % +#2704 +1! +1$ +#3000 +b111 + +#3100 +b10001110001101100000111110001100 & +b11001001111001110101001001000110 ) +b10000010101001111110000101011001 ( +b1011110000000010011011111011011 ' +b1000111100101101101001000100100 % +#3102 +0! +0# +#3104 +0$ +#3400 +b1000 + +#3500 +b1100100110011101101000100110101 & +b11011001110111100100111001111110 ) +b10001110001101100000111110001100 ( +b11001001111001110101001001000110 ' +b10111101101011010010100101011001 % +#3504 +1$ +#3800 +b1001 + +#3900 +b10101001001111001111110110000010 & +b10010111010010001100101010001000 ) +b1100100110011101101000100110101 ( +b11011001110111100100111001111110 ' +b111110010010100110111110001100 % +#3904 +0$ +#4200 +b1010 + +#4300 +b10010000111011111101010101111110 & +b10000010101110101111101101100101 ) +b10101001001111001111110110000010 ( +b10010111010010001100101010001000 ' +b10010010001110111100100110101 % +#4302 +1# +#4600 +b1011 + +#4700 +b1111101111000110010000101010 & +b1000001001000100101000101100001 ) +b10010000111011111101010101111110 ( +b10000010101110101111101101100101 ' +b1001110110100001110110110000010 % +#5000 +b1100 + +#5100 +b10110100001000101011110101100001 & +b1011010100010001101011101101011 ) +b1111101111000110010000101010 ( +b1000001001000100101000101100001 ' +b11101110010001000010010101111110 % +#5104 +1! +1$ +#5400 +b1101 + +#5500 +b1011101010011110111000111000 & +b11100111110110000101101111011101 ) +b10110100001000101011110101100001 ( +b1011010100010001101011101101011 ' +b11101100100111010011010000101010 % +#5504 +0! +0$ +#5800 +b1110 + +#5900 +b10110110111011100010110110001101 & +b10111100001100101001110101001 ) +b1011101010011110111000111000 ( +b11100111110110000101101111011101 ' +b10100001110010011011010101100001 % +#5904 +1! +1$ +#6200 +b1111 + +#6300 +b11010111010100010110101001010001 & +b10010011110011011000111000111110 ) +b10110110111011100010110110001101 ( +b10111100001100101001110101001 ' +b1000100110110000010111000111000 % +#6302 +0! +0# +#6600 +b10000 + +#6700 +b110101001010101010100110001100 & +b11110010011011110111000000001001 ) +b11010111010100010110101001010001 ( +b10010011110011011000111000111110 ' +b11000111100000100100010110001101 % +#6702 +1! +1# +#6704 +0! +0$ +#7000 +b10001 + +#7100 +b10010110001101101001010110010111 & +b11001010011010010110110101101001 ) +b110101001010101010100110001100 ( +b11110010011011110111000000001001 ' +b1011100000000111110001001010001 % +#7104 +1! +1$ +#7400 +b10010 + +#7500 +b1111111010101101111110011001111 & +b11111010100000101000001100000 ) +b10010110001101101001010110010111 ( +b11001010011010010110110101101001 ' +b1100000011001101100100110001100 % +#7502 +0! +0# +#7800 +b10011 + +#7900 +b11011100011011010111110000001001 & +b11111110110101011101010001101001 ) +b1111111010101101111110011001111 ( +b11111010100000101000001100000 ' +b100010100110100010110110010111 % +#7902 +1! +1# +#8200 +b10100 + +#8300 +b10001001010110111101100011011011 & +b1000001001000111110010010110100 ) +b11011100011011010111110000001001 ( +b11111110110101011101010001101001 ' +b11001000101100001000010011001111 % +#8302 +0! +0# +#8600 +b10101 + +#8700 +b1101110010001111000000100010111 & +b11011001011111010010001100000101 ) +b10001001010110111101100011011011 ( +b1000001001000111110010010110100 ' +b10110111100011010011010000001001 % +#8702 +1! +1# +#9000 +b10110 + +#9100 +b1100111110101010101010111110111 & +b110000000111111100111000101111 ) +b1101110010001111000000100010111 ( +b11011001011111010010001100000101 ' +b1010111100111010000000011011011 % +#9400 +b10111 + +#9500 +b101100111010100101111011101 & +b1010111100000000011011100000011 ) +b1100111110101010101010111110111 ( +b110000000111111100111000101111 ' +b1010010010011110011100100010111 % +#9800 +b11000 + +#9900 +b110100010100001110110001010 & +b11001011001111011001001111110111 ) +b101100111010100101111011101 ( +b1010111100000000011011100000011 ' +b11001101011110101110110111110111 % +#9904 +0! +0$ +#10200 +b11001 + +#10300 +b10111111110010000110000000010101 & +b1010000111001000000101001110111 ) +b110100010100001110110001010 ( +b11001011001111011001001111110111 ' +b11101111110000111010001111011101 % +#10304 +1! +1$ +#10600 +b11010 + +#10700 +b11001110011111011100011011111110 & +b10011000010011011111111000110000 ) +b10111111110010000110000000010101 ( +b1010000111001000000101001110111 ' +b1010110011001100100110110001010 % +#10702 +0! +0# +#10704 +0$ +#11000 +b11011 + +#11100 +b1000010100011101100110111111110 & +b10111110101110101101101011110100 ) +b11001110011111011100011011111110 ( +b10011000010011011111111000110000 ' +b11111100110010001100100000010101 % +#11400 +b11100 + +#11500 +b10010101101011110110110110010001 & +b10110101110001010000011111100001 ) +b1000010100011101100110111111110 ( +b10111110101110101101101011110100 ' +b100000010010100011011011111110 % +#11502 +1# +#11504 +1! +1$ +#11800 +b11101 + +#11900 +b11001001011111111010101111011100 & +b11111101101010100110100010101010 ) +b10010101101011110110110110010001 ( +b10110101110001010000011111100001 ' +b110100111000010011110111111110 % +#11902 +0! +0# +#11904 +0$ +#12200 +b11110 + +#12300 +b10111010001101010110101111101010 & +b1010100000110000100011100011101 ) +b11001001011111111010101111011100 ( +b11111101101010100110100010101010 ' +b11101110110000111110010110010001 % +#12302 +1# +#12600 +b11111 + +#12700 +b100000011000011100001100100111 & +b10100011101001010101100111110 ) +b10111010001101010110101111101010 ( +b1010100000110000100011100011101 ' +b110100001000010100101111011100 % +#12702 +0# +#12704 +1$ +#13000 +b100000 + +#13100 +b10100111101011000000111110010010 & +b10110110110101110100100010011001 ) +b100000011000011100001100100111 ( +b10100011101001010101100111110 ' +b10001011010100011101111101010 % +#13102 +1! +1# +#13104 +0! +0$ +#13400 +b100001 + +#13500 +b111000011001101110110000011000 & +b10110001100000110110100000010 ) +b10100111101011000000111110010010 ( +b10110110110101110100100010011001 ' +b101110011110001111101100100111 % +#13502 +0# +#13800 +b100010 + +#13900 +b11110011111011101011000110011111 & +b110100111110011111100000001101 ) +b111000011001101110110000011000 ( +b10110001100000110110100000010 ' +b11000111110100001001111110010010 % +#13902 +1# +#13904 +1! +1$ +#14200 +b100011 + +#14300 +b1101001001010101010110001101101 & +b1100110001000111000101010011101 ) +b11110011111011101011000110011111 ( +b110100111110011111100000001101 ' +b1111000001100010110000011000 % +#14600 +b100100 + +#14700 +b10100000011000011000101011110 & +b10010010111010000000100011010101 ) +b1101001001010101010110001101101 ( +b1100110001000111000101010011101 ' +b10000110011000100100100110011111 % +#14704 +0! +0$ +#15000 +b100101 + +#15100 +b1010010011101001010011001001001 & +b1101110000000010010011000100000 ) +b10100000011000011000101011110 ( +b10010010111010000000100011010101 ' +b111100010010011100010001101101 % +#15102 +0# +#15104 +1$ +#15400 +b100110 + +#15500 +b11110101111110111111010111101100 & +b10000000000010001010001001110010 ) +b1010010011101001010011001001001 ( +b1101110000000010010011000100000 ' +b1110101100001101100000101011110 % +#15504 +0$ +#15800 +b100111 + +#15900 +b1100101000111010100011110100111 & +b10010010101011001111110101010101 ) +b11110101111110111111010111101100 ( +b10000000000010001010001001110010 ' +b11110111010001101110111001001001 % +#15902 +1# +#15904 +1! +1$ +#16200 +b101000 + +#16300 +b10001010101111011011011100100101 & +b10100000110000110110001001000100 ) +b1100101000111010100011110100111 ( +b10010010101011001111110101010101 ' +b101010010101001001010111101100 % +#16302 +0! +0# +#16600 +b101001 + +#16700 +b11110000101000011110010101001011 & +b1111111000011101011010101110010 ) +b10001010101111011011011100100101 ( +b10100000110000110110001001000100 ' +b10001111001000000111111110100111 % +#17000 +b101010 + +#17100 +b101100101010001111101010011010 & +b1001011110010110110100001011001 ) +b11110000101000011110010101001011 ( +b1111111000011101011010101110010 ' +b1100111000001001001111100100101 % +#17102 +1! +1# +#17104 +0! +0$ +#17400 +b101011 + +#17500 +b11011001011100110100110101101110 & +b100110000001110111111101011000 ) +b101100101010001111101010011010 ( +b1001011110010110110100001011001 ' +b11111111100010111011110101001011 % +#17502 +0# +#17800 +b101100 + +#17900 +b10100010111111010011000000110100 & +b11001001111010100111111110111001 ) +b11011001011100110100110101101110 ( +b100110000001110111111101011000 ' +b1101011011111000010101010011010 % +#17902 +1# +#18200 +b101101 + +#18300 +b11111100010001100101010000111100 & +b10111111000111010110011010001100 ) +b10100010111111010011000000110100 ( +b11001001111010100111111110111001 ' +b1000011000110000011110101101110 % +#18302 +0# +#18600 +b101110 + +#18700 +b101101111111000000101111000111 & +b1100110110010111110101110111010 ) +b11111100010001100101010000111100 ( +b10111111000111010110011010001100 ' +b1001011011111001001000000110100 % +#18704 +1$ +#19000 +b101111 + +#19100 +b10110111101010000111110101001010 & +b1111001100000010010000111110010 ) +b101101111111000000101111000111 ( +b1100110110010111110101110111010 ' +b11001110111001111011010000111100 % +#19104 +0$ +#19400 +b110000 + +#19500 +b1000011011010000100011000001010 & +b10001110000001111100011000111110 ) +b10110111101010000111110101001010 ( +b1111001100000010010000111110010 ' +b11001101101000100011001111000111 % +#19800 +b110001 + +#19900 +b11000111001000000001100000110001 & +b110011100101100111000100100100 ) +b1000011011010000100011000001010 ( +b10001110000001111100011000111110 ' +b11110100010000100010110101001010 % +#19904 +1$ +#20200 +b110010 + +#20300 +b1110110111111110100000000110101 & +b1110111101001100000000011011101 ) +b11000111001000000001100000110001 ( +b110011100101100111000100100100 ' +b1010110000001011000001010 % +#20302 +1! +1# +#20600 +b110011 + +#20700 +b110001010001100110111111110010 & +b11110110011000000000000010011111 ) +b1110110111111110100000000110101 ( +b1110111101001100000000011011101 ' +b11000111111000011001000000110001 % +#20704 +0! +0$ +#21000 +b110100 + +#21100 +b11111010110100110011100111100110 & +b1110110101000010010000111101111 ) +b110001010001100110111111110010 ( +b11110110011000000000000010011111 ' +b10001100111111101110100000110101 % +#21400 +b110101 + +#21500 +b1110011110100111110101011110 & +b1100010000011011101011011011 ) +b11111010110100110011100111100110 ( +b1110110101000010010000111101111 ' +b10001110011111111111110010 % +#21800 +b110110 + +#21900 +b10010110101001001000011111101 & +b1110001101010111000101100100111 ) +b1110011110100111110101011110 ( +b1100010000011011101011011011 ' +b1100011000111000000100111100110 % +#21904 +1! +1$ +#22200 +b110111 + +#22300 +b11001110000011110111100010100101 & +b10011010000100110011100011110 ) +b10010110101001001000011111101 ( +b1110001101010111000101100100111 ' +b11011101100100001000110101011110 % +#22302 +0! +0# +#22600 +b111000 + +#22700 +b1010101001101010001011100001111 & +b11100011110100000010000011110000 ) +b11001110000011110111100010100101 ( +b10011010000100110011100011110 ' +b10110110010100110111100011111101 % +#23000 +b111001 + +#23100 +b11100000001100000110000001111100 & +b1010101010011111111000000100000 ) +b1010101001101010001011100001111 ( +b11100011110100000010000011110000 ' +b10110101110010100101000010100101 % +#23104 +0$ +#23400 +b111010 + +#23500 +b1111111111101011111100100011010 & +b10000010100001010000101100101010 ) +b11100000001100000110000001111100 ( +b1010101010011111111000000100000 ' +b11111101100011010110111100001111 % +#23800 +b111011 + +#23900 +b110110010000010111000101101010 & +b1010101000100011100100000110100 ) +b1111111111101011111100100011010 ( +b10000010100001010000101100101010 ' +b1100011001100111000000001111100 % +#24200 +b111100 + +#24300 +b1001100110110101111011101100110 & +b10011100001101111111000011010011 ) +b110110010000010111000101101010 ( +b1010101000100011100100000110100 ' +b11010000001111010010100100011010 % +#24302 +1# +#24600 +b111101 + +#24700 +b10101010101001100011111100000000 & +b10010111010100011100011010100001 ) +b1001100110110101111011101100110 ( +b10011100001101111111000011010011 ' +b111101110010100010000101101010 % +#25000 +b111110 + +#25100 +b10010110011100100010001101000 & +b10001001001101001111001111101111 ) +b10101010101001100011111100000000 ( +b10010111010100011100011010100001 ' +b10011011011000011100011101100110 % +#25400 +b111111 + +#25500 +b10010000011101101000110000010111 & +b1011101100111110110001011110 ) +b10010110011100100010001101000 ( +b10001001001101001111001111101111 ' +b10011011010111100011111100000000 % +#25502 +0# +#25504 +1$ +#25800 +b1000000 + +#25900 +b11011110011111100100000011001111 & +b10111110111100111011111001111101 ) +b10010000011101101000110000010111 ( +b1011101100111110110001011110 ' +b1100000111011010000010001101000 % +#25902 +1! +1# +#26200 +b1000001 + +#26300 +b1101110000010011011110100100110 & +b1001010001110111001011001000010 ) +b11011110011111100100000011001111 ( +b10111110111100111011111001111101 ' +b100100000101100011010000010111 % +#26302 +0! +0# +#26304 +0$ +#26600 +b1000010 + +#26700 +b1100001011111101010111110011110 & +b1001101001010101110011011001100 ) +b1101110000010011011110100100110 ( +b1001010001110111001011001000010 ' +b101100011110000011100011001111 % +#27000 +b1000011 + +#27100 +b11010100101000101101111100110010 & +b11110111011000011010110001110101 ) +b1100001011111101010111110011110 ( +b1001101001010101110011011001100 ' +b100011111000001000110100100110 % +#27102 +1# +#27400 +b1000100 + +#27500 +b1011010001100100001101111111001 & +b11001110101001000101111111101100 ) +b11010100101000101101111100110010 ( +b11110111011000011010110001110101 ' +b10010100000000100101111110011110 % +#27502 +0# +#27504 +1$ +#27800 +b1000101 + +#27900 +b1100010010100110001011010101010 & +b10100000110010100001011011001110 ) +b1011010001100100001101111111001 ( +b11001110101001000101111111101100 ' +b11000010010110110100111100110010 % +#27904 +0$ +#28200 +b1000110 + +#28300 +b1000100110000110101000111000101 & +b10001110111001000111111000110011 ) +b1100010010100110001011010101010 ( +b10100000110010100001011011001110 ' +b11001010111011011101001111111001 % +#28302 +1# +#28304 +1! +1$ +#28600 +b1000111 + +#28700 +b1001110010100111111010110010000 & +b10110100010011110100001111110101 ) +b1000100110000110101000111000101 ( +b10001110111001000111111000110011 ' +b11111010111001100100011010101010 % +#28704 +0! +0$ +#29000 +b1001000 + +#29100 +b10111101111110000010011101001110 & +b11100011111010110000111110001111 ) +b1001110010100111111010110010000 ( +b10110100010011110100001111110101 ' +b1011110010011010111100111000101 % +#29400 +b1001001 + +#29500 +b10100010010010000000111101100110 & +b1110011011001101000101111101111 ) +b10111101111110000010011101001110 ( +b11100011111010110000111110001111 ' +b11010001111111110111010110010000 % +#29800 +b1001010 + +#29900 +b1100101110110100110110111100010 & +b11001011001001111101111010111 ) +b10100010010010000000111101100110 ( +b1110011011001101000101111101111 ' +b1111100110000100101011101001110 % +#30200 +b1001011 + +#30300 +b11000000011101011010001101001000 & +b100010101001001010101101000101 ) +b1100101110110100110110111100010 ( +b11001011001001111101111010111 ' +b11100010001100110011111101100110 % +#30600 +b1001100 + +#30700 +b1001000111100101001010110010011 & +b11111110111100010100001011010010 ) +b11000000011101011010001101001000 ( +b100010101001001010101101000101 ' +b10110110101101010111110111100010 % +#30702 +0# +#30704 +1$ +#31000 +b1001101 + +#31100 +b100010000010010110010000000001 & +b1001111000010111110000101001011 ) +b1001000111100101001010110010011 ( +b11111110111100010100001011010010 ' +b1101101011011111110001101001000 % +#31102 +1! +1# +#31400 +b1001110 + +#31500 +b10001010000110000000110000001101 & +b1010110100110100101010101000000 ) +b100010000010010110010000000001 ( +b1001111000010111110000101001011 ' +b11011100010111100000110110010011 % +#31502 +0! +0# +#31800 +b1001111 + +#31900 +b11110011010010011111001110010000 & +b10011010000010011010010110111100 ) +b10001010000110000000110000001101 ( +b1010110100110100101010101000000 ' +b1101001001010010110110000000001 % +#31904 +0$ +#32200 +b1010000 + +#32300 +b111101110011111001101001111010 & +b1110111111111011000100011101100 ) +b11110011010010011111001110010000 ( +b10011010000010011010010110111100 ' +b1001010011110000110010000001101 % +#32600 +b1010001 + +#32700 +b1010110010101010100011110011110 & +b11101010001111001111110000111010 ) +b111101110011111001101001111010 ( +b1110111111111011000100011101100 ' +b10111100110101010111001110010000 % +#33000 +b1010010 + +#33100 +b10001100001010010101000011001110 & +b11001101011101000001111101010000 ) +b1010110010101010100011110011110 ( +b11101010001111001111110000111010 ' +b1000001000111000100101001111010 % +#33400 +b1010011 + +#33500 +b1111101011011000111111001001011 & +b10000001111110011011000001011101 ) +b10001100001010010101000011001110 ( +b11001101011101000001111101010000 ' +b11111100011010011011011110011110 % +#33502 +1# +#33504 +1! +1$ +#33800 +b1010100 + +#33900 +b11010110111001101110110111010110 & +b10000100011110110000000101001 ) +b1111101011011000111111001001011 ( +b10000001111110011011000001011101 ' +b11000110101011110010000011001110 % +#33904 +0! +0$ +#34200 +b1010101 + +#34300 +b10000100010100010111111100111000 & +b10011010110100011101010000001111 ) +b11010110111001101110110111010110 ( +b10000100011110110000000101001 ' +b11110100111100010011001001011 % +#34600 +b1010110 + +#34700 +b1110110111010000000111001110 & +b11101111101101001100100110110011 ) +b10000100010100010111111100111000 ( +b10011010110100011101010000001111 ' +b11100001100010000101110111010110 % +#35000 +b1010111 + +#35100 +b10101000111111100100101100110 & +b11010101110001101110110110110 ) +b1110110111010000000111001110 ( +b11101111101101001100100110110011 ' +b1111101010001011111100111000 % +#35102 +0# +#35400 +b1011000 + +#35500 +b10111010100110101100101000001101 & +b1011100101011110110001100100111 ) +b10101000111111100100101100110 ( +b11010101110001101110110110110 ' +b11100110110100110111000111001110 % +#35502 +1# +#35504 +1! +1$ +#35800 +b1011001 + +#35900 +b10001101101011000100010011011000 & +b1100110000100111110010110000101 ) +b10111010100110101100101000001101 ( +b1011100101011110110001100100111 ' +b11101011010101001111100101100110 % +#35904 +0! +0$ +#36200 +b1011010 + +#36300 +b11000110100110111100010111111001 & +b10101010001111011011100000010001 ) +b10001101101011000100010011011000 ( +b1100110000100111110010110000101 ' +b1101100110010101010001000001101 % +#36304 +1! +1$ +#36600 +b1011011 + +#36700 +b11010000001110000010011011010101 & +b111111010111010010111101100010 ) +b11000110100110111100010111111001 ( +b10101010001111011011100000010001 ' +b11101111100010101000010011011000 % +#36702 +0! +0# +#37000 +b1011100 + +#37100 +b10001111001011100101101011110111 & +b10010111100000101111000111110011 ) +b11010000001110000010011011010101 ( +b111111010111010010111101100010 ' +b11000101101000000110111111001 % +#37102 +1! +1# +#37400 +b1011101 + +#37500 +b1001000110000011101100100101111 & +b1011001110111100101001001001111 ) +b10001111001011100101101011110111 ( +b10010111100000101111000111110011 ' +b10001000011101000111011010101 % +#37800 +b1011110 + +#37900 +b110101010010001011011010110001 & +b11001000010011001011010010101101 ) +b1001000110000011101100100101111 ( +b1011001110111100101001001001111 ' +b11111101111110011110001011110111 % +#38200 +b1011111 + +#38300 +b11011000111000010110110000100110 & +b10011110101011111101011001111101 ) +b110101010010001011011010110001 ( +b11001000010011001011010010101101 ' +b1000110000010001010000100101111 % +#38304 +0! +0$ +#38600 +b1100000 + +#38700 +b101001010001000111101110000 & +b1110101101001010100001001001011 ) +b11011000111000010110110000100110 ( +b10011110101011111101011001111101 ' +b1110000111111010011111010110001 % +#39000 +b1100001 + +#39100 +b110110100001110110110101010110 & +b11100101110101001010110110010110 ) +b101001010001000111101110000 ( +b1110101101001010100001001001011 ' +b11010011100000000101110000100110 % +#39102 +0# +#39400 +b1100010 + +#39500 +b101000011111011001011110000101 & +b1101001011011111100011011010111 ) +b110110100001110110110101010110 ( +b11100101110101001010110110010110 ' +b1000001010100110000111101110000 % +#39502 +1# +#39504 +1! +1$ +#39800 +b1100011 + +#39900 +b1100101011001010000101010011010 & +b1101000100001010011011100000001 ) +b101000011111011001011110000101 ( +b1101001011011111100011011010111 ' +b1101111011011101110101010110 % +#39904 +0! +0$ +#40200 +b1100100 + +#40300 +b10110110001011100101000111100000 & +b1110010001010110010000110011111 ) +b1100101011001010000101010011010 ( +b1101000100001010011011100000001 ' +b11000100110000011011111110000101 % +#40600 +b1100101 + +#40700 +b10111010001011101011000010110001 & +b11110111010100100100010100011011 ) +b10110110001011100101000111100000 ( +b1110010001010110010000110011111 ' +b1001101001100011101101010011010 % +#40704 +1! +1$ +#41000 +b1100110 + +#41100 +b1010101010001111011101100100111 & +b10010001001000100101100110110010 ) +b10111010001011101011000010110001 ( +b11110111010100100100010100011011 ' +b11000100101000010101000111100000 % +#41102 +0! +0# +#41400 +b1100111 + +#41500 +b11111111001111001100001110001011 & +b110000010110000101011000001001 ) +b1010101010001111011101100100111 ( +b10010001001000100101100110110010 ' +b11001111101010110011100010110001 % +#41502 +1! +1# +#41800 +b1101000 + +#41900 +b10100101001101110100000111001 & +b1111100010100001111101000010111 ) +b11111111001111001100001110001011 ( +b110000010110000101011000001001 ' +b1101000100111101000001100100111 % +#42200 +b1101001 + +#42300 +b11111111100001011011101101111101 & +b11100110101111000001110010111010 ) +b10100101001101110100000111001 ( +b1111100010100001111101000010111 ' +b11001001000001001101110001011 % +#42302 +0! +0# +#42600 +b1101010 + +#42700 +b100111001110101010000101011110 & +b100111111100110011011011000 ) +b11111111100001011011101101111101 ( +b11100110101111000001110010111010 ' +b100011111001110010000000111001 % +#42704 +0$ +#43000 +b1101011 + +#43100 +b11110011111010010011100111001101 & +b100001011001010011000011001111 ) +b100111001110101010000101011110 ( +b100111111100110011011011000 ' +b11010010010111100101001101111101 % +#43102 +1# +#43104 +1! +1$ +#43400 +b1101100 + +#43500 +b11110110000101000010100001011011 & +b100110101100100100111001110 ) +b11110011111010010011100111001101 ( +b100001011001010011000011001111 ' +b11110010001100000101000101011110 % +#43502 +0! +0# +#43800 +b1101101 + +#43900 +b1000100011000101111010001011101 & +b11111110111111111001110100011110 ) +b11110110000101000010100001011011 ( +b100110101100100100111001110 ' +b10111010001001110101000111001101 % +#44200 +b1101110 + +#44300 +b10100101010011011110010111000100 & +b11110010010011000101110100100110 ) +b1000100011000101111010001011101 ( +b11111110111111111001110100011110 ' +b1010111010101101111000001011011 % +#44304 +0$ +#44600 +b1101111 + +#44700 +b11110100110010110100001110110100 & +b10100111010110001000101100011110 ) +b10100101010011011110010111000100 ( +b11110010010011000101110100100110 ' +b1010011110000000001110001011101 % +#45000 +b1110000 + +#45100 +b10101110010101110011111111111000 & +b1100100111111101001010101100110 ) +b11110100110010110100001110110100 ( +b10100111010110001000101100011110 ' +b11001010011000111100010111000100 % +#45400 +b1110001 + +#45500 +b1100011010011000111110110100110 & +b11001101001101000101000101010111 ) +b10101110010101110011111111111000 ( +b1100100111111101001010101100110 ' +b10101110110101101110001110110100 % +#45502 +1# +#45800 +b1110010 + +#45900 +b11100100001101101100100001111010 & +b11110011100010011000000100001100 ) +b1100011010011000111110110100110 ( +b11001101001101000101000101010111 ' +b10111101010001111111111111000 % +#45902 +0# +#46200 +b1110011 + +#46300 +b10001011010001100111111011010101 & +b10001011111001111000001101000010 ) +b11100100001101101100100001111010 ( +b11110011100010011000000100001100 ' +b101000010100110110100110 % +#46304 +1$ +#46600 +b1110100 + +#46700 +b1100110010111110110010010111101 & +b110100011110000000111101010000 ) +b10001011010001100111111011010101 ( +b10001011111001111000001101000010 ' +b1010010011101010001100001111010 % +#47000 +b1110101 + +#47100 +b1101001000111010111101010000110 & +b11010001000101010000011010100111 ) +b1100110010111110110010010111101 ( +b110100011110000000111101010000 ' +b10111000101100001101011011010101 % +#47102 +1! +1# +#47104 +0! +0$ +#47400 +b1110110 + +#47500 +b11000001111111110110 & +b10011101111010111111101001111010 ) +b1101001000111010111101010000110 ( +b11010001000101010000011010100111 ' +b10011101011110101000110010111101 % +#47502 +0# +#47800 +b1110111 + +#47900 +b11111011000111101000110110001000 & +b1111001010101010000000101101110 ) +b11000001111111110110 ( +b10011101111010111111101001111010 ' +b10000010110010010100101010000110 % +#48200 +b1111000 + +#48300 +b1011001011101111101101111011110 & +b111001111001001000000010111011 ) +b11111011000111101000110110001000 ( +b1111001010101010000000101101110 ' +b1100000111100111010111111110110 % +#48302 +1# +#48600 +b1111001 + +#48700 +b10000111100001010101000110110101 & +b10001000111110001111111111101111 ) +b1011001011101111101101111011110 ( +b111001111001001000000010111011 ' +b1111011100101100110110001000 % +#48704 +1! +1$ +#49000 +b1111010 + +#49100 +b1111101001101110110100100011100 & +b10011010011110011111100010100110 ) +b10000111100001010101000110110101 ( +b10001000111110001111111111101111 ' +b11100111101010010010101111011110 % +#49102 +0! +0# +#49104 +0$ +#49400 +b1111011 + +#49500 +b10011111110110100001000111010001 & +b110010011111111110011011010010 ) +b1111101001101110110100100011100 ( +b10011010011110011111100010100110 ' +b10101101000010001111100110110101 % +#49504 +1$ +#49800 +b1111100 + +#49900 +b1100100010101001100110010111 & +b11001010001100110111011001000100 ) +b10011111110110100001000111010001 ( +b110010011111111110011011010010 ' +b11000110011111111000100100011100 % +#50200 +b1111101 + +#50300 +b10001110000101010111001011001011 & +b11000001000011101010011110100010 ) +b1100100010101001100110010111 ( +b11001010001100110111011001000100 ' +b1001111010101001001100111010001 % +#50600 +b1111110 + +#50700 +b10000111110110111100100001010101 & +b11011111110001011011010000011011 ) +b10001110000101010111001011001011 ( +b11000001000011101010011110100010 ' +b1011000010001100010000110010111 % +#50702 +1! +1# +#51000 +b1111111 + +#51100 +b10110111110101111001100110001 & +b110011010111000101110010111011 ) +b10000111110110111100100001010101 ( +b11011111110001011011010000011011 ' +b100101100000110010101011001011 % +#51400 +b10000000 + +#51500 +b10111101101011010001110100100001 & +b11100100011011011111100010011001 ) +b10110111110101111001100110001 ( +b110011010111000101110010111011 ' +b1011001100110010110000001010101 % +#51800 +b10000001 + +#51900 +b10101101011001110010001001111001 & +b1101100110001010011011110101011 ) +b10111101101011010001110100100001 ( +b11100100011011011111100010011001 ' +b11000001011000110111101100110001 % +#52200 +b10000010 + +#52300 +b11110011110101001111101110000000 & +b100110010001011010111001111100 ) +b10101101011001110010001001111001 ( +b1101100110001010011011110101011 ' +b11010101010001000001010100100001 % +#52302 +0! +0# +#52304 +0$ +#52600 +b10000011 + +#52700 +b100010000010010111101001110000 & +b10110110111010011111001000111110 ) +b11110011110101001111101110000000 ( +b100110010001011010111001111100 ' +b10010100011101001110101001111001 % +#53000 +b10000100 + +#53100 +b1111101011010001111000001011110 & +b101001001101000000011000000011 ) +b100010000010010111101001110000 ( +b10110110111010011111001000111110 ' +b1010100000010001111101110000000 % +#53102 +1# +#53400 +b10000101 + +#53500 +b11101101010110101011010111011000 & +b10000100111010011000010111001111 ) +b1111101011010001111000001011110 ( +b101001001101000000011000000011 ' +b1101001110110101111101001110000 % +#53800 +b10000110 + +#53900 +b1011110000001110101010010101010 & +b1100100110101111011001001101110 ) +b11101101010110101011010111011000 ( +b10000100111010011000010111001111 ' +b111010111010100000000001011110 % +#53902 +0# +#54200 +b10000111 + +#54300 +b10101110110001001111011000110100 & +b10010110000010000110010101011000 ) +b1011110000001110101010010101010 ( +b1100100110101111011001001101110 ' +b111000111101000111010111011000 % +#54600 +b10001000 + +#54700 +b10011100111111100110100000101 & +b1110111010110010110010101000000 ) +b10101110110001001111011000110100 ( +b10010110000010000110010101011000 ' +b1100100101000100000010010101010 % +#54704 +1$ +#55000 +b10001001 + +#55100 +b1001111100101000111001100100100 & +b11000110011010000100100010001011 ) +b10011100111111100110100000101 ( +b1110111010110010110010101000000 ' +b10001001011101010101011000110100 % +#55102 +1! +1# +#55104 +0! +0$ +#55400 +b10001010 + +#55500 +b11110010000010110000001111000 & +b11110011010110110110110011110011 ) +b1001111100101000111001100100100 ( +b11000110011010000100100010001011 ' +b11101101111101111110010100000101 % +#55800 +b10001011 + +#55900 +b1110110000010000001001000000001 & +b10011010111010010101111100101011 ) +b11110010000010110000001111000 ( +b11110011010110110110110011110011 ' +b11101100000011010101001100100100 % +#55904 +1! +1$ +#56200 +b10001100 + +#56300 +b1001011010010110011110111011100 & +b1011110000111001101010011000111 ) +b1110110000010000001001000000001 ( +b10011010111010010101111100101011 ' +b10101010000101010000001111000 % +#56304 +0! +0$ +#56600 +b10001101 + +#56700 +b10101101001001011011001011110011 & +b10011011100010110010001110011001 ) +b1001011010010110011110111011100 ( +b1011110000111001101010011000111 ' +b110110100110000001101000000001 % +#56704 +1! +1$ +#57000 +b10001110 + +#57100 +b111100100001000101111011001 & +b10101001001111111000101111100 ) +b10101101001001011011001011110011 ( +b10011011100010110010001110011001 ' +b10010101001011101110111011100 % +#57102 +0! +0# +#57400 +b10001111 + +#57500 +b1000101111101110111011100111000 & +b11000101110001011111011101011001 ) +b111100100001000101111011001 ( +b10101001001111111000101111100 ' +b10000000101100100010101011110011 % +#57502 +1! +1# +#57504 +0! +0$ +#57800 +b10010000 + +#57900 +b11101100001111000100001010011111 & +b1101111011100011100001011101011 ) +b1000101111101110111011100111000 ( +b11000101110001011111011101011001 ' +b10000011110011100100001111011001 % +#57904 +1! +1$ +#58200 +b10010001 + +#58300 +b11111000000110011110011000100100 & +b110101010010001111101111110 ) +b11101100001111000100001010011111 ( +b1101111011100011100001011101011 ' +b11111110010011101011011100111000 % +#58302 +0! +0# +#58304 +0$ +#58600 +b10010010 + +#58700 +b10111101110001001010001000000 & +b11001100111100000010101010110 ) +b11111000000110011110011000100100 ( +b110101010010001111101111110 ' +b1110001010001011101010011111 % +#59000 +b10010011 + +#59100 +b1101110101110111100111011110000 & +b1011001101001000010101100100110 ) +b10111101110001001010001000000 ( +b11001100111100000010101010110 ' +b110111001010001100011000100100 % +#59400 +b10010100 + +#59500 +b1010100001011110101110011101100 & +b10000111111001101100001011000100 ) +b1101110101110111100111011110000 ( +b1011001101001000010101100100110 ' +b11010011000110101001010001000000 % +#59800 +b10010101 + +#59900 +b10011100110101100011011101111111 & +b101100101010101011000001010100 ) +b1010100001011110101110011101100 ( +b10000111111001101100001011000100 ' +b10110000110011000100111011110000 % +#59904 +1$ +#60200 +b10010110 + +#60300 +b11011100011100011110100001 & +b101101100101110011011011000011 ) +b10011100110101100011011101111111 ( +b101100101010101011000001010100 ' +b101110110010000011110011101100 % +#60302 +1! +1# +#60600 +b10010111 + +#60700 +b1010111011000000101001001111111 & +b1111010001000001111111110001011 ) +b11011100011100011110100001 ( +b101101100101110011011011000011 ' +b101101011011011100111101111111 % +#61000 +b10011000 + +#61100 +b1001110000101001100110001101010 & +b11000011110101010101011101111110 ) +b1010111011000000101001001111111 ( +b1111010001000001111111110001011 ' +b10001101010011001100111110100001 % +#61102 +0! +0# +#61104 +0$ +#61400 +b10011001 + +#61500 +b1100110000100111110000100100111 & +b110011101101011011111010000100 ) +b1001110000101001100110001101010 ( +b11000011110101010101011101111110 ' +b1010101111100111010101001111111 % +#61504 +1$ +#61800 +b10011010 + +#61900 +b11100111100010111100111000101000 & +b1111000101000010010000111100 ) +b1100110000100111110000100100111 ( +b110011101101011011111010000100 ' +b11101000011101111001110001101010 % +#61904 +0$ +#62200 +b10011011 + +#62300 +b10000000101101111100000100010111 & +b1111001010101000000110111000011 ) +b11100111100010111100111000101000 ( +b1111000101000010010000111100 ' +b11111001000110101101100100100111 % +#62302 +1# +#62304 +1! +1$ +#62600 +b10011100 + +#62700 +b10010111011011110101000110011010 & +b101110001011000010000011111001 ) +b10000000101101111100000100010111 ( +b1111001010101000000110111000011 ' +b10111001111110101000111000101000 % +#62704 +0! +0$ +#63000 +b10011101 + +#63100 +b1110000000011011010001100011110 & +b1001110100011000110110010100001 ) +b10010111011011110101000110011010 ( +b101110001011000010000011111001 ' +b111110101111110111100100010111 % +#63400 +b10011110 + +#63500 +b11010010011001110000101111111000 & +b111111011010010110111000001110 ) +b1110000000011011010001100011110 ( +b1001110100011000110110010100001 ' +b11101101111000111000000110011010 % +#63502 +0# +#63800 +b10011111 + +#63900 +b11100010101010111100010111001000 & +b11111111101000111001110001110001 ) +b11010010011001110000101111111000 ( +b111111011010010110111000001110 ' +b11101000101010101001100011110 % +#63902 +1# +#64200 +b10100000 + +#64300 +b1111100000101000011111101100110 & +b10010110110001101101111010001101 ) +b11100010101010111100010111001000 ( +b11111111101000111001110001110001 ' +b11101010001110001100101111111000 % +#64600 +b10100001 + +#64700 +b100011100011100111011100111010 & +b10011111101101110110010010000001 ) +b1111100000101000011111101100110 ( +b10010110110001101101111010001101 ' +b10111100100001011000010111001000 % +#65000 +b10100010 + +#65100 +b1011110001011100000011101111010 & +b10000011000111001111011101110000 ) +b100011100011100111011100111010 ( +b10011111101101110110010010000001 ' +b11011101111011110000111101100110 % +#65102 +0# +#65400 +b10100011 + +#65500 +b101010111111100110110010011100 & +b1111010100110011111001101010010 ) +b1011110001011100000011101111010 ( +b10000011000111001111011101110000 ' +b1010000001101111010011100111010 % +#65800 +b10100100 + +#65900 +b1100000000001100111001010101110 & +b1001110001111011011100111000100 ) +b101010111111100110110010011100 ( +b1111010100110011111001101010010 ' +b101110000101011101011101111010 % +#66200 +b10100101 + +#66300 +b1100111100110001001000111001 & +b11010101101100000001111010011111 ) +b1100000000001100111001010101110 ( +b1001110001111011011100111000100 ' +b11011001100110101000110010011100 % +#66302 +1# +#66304 +1! +1$ +#66600 +b10100110 + +#66700 +b11111100011000111111110110100010 & +b10101111101000110111100111111010 ) +b1100111100110001001000111001 ( +b11010101101100000001111010011111 ' +b1010011100100110000001010101110 % +#66702 +0! +0# +#66704 +0$ +#67000 +b10100111 + +#67100 +b111101100001001110110110011010 & +b10101001011100100100000001010111 ) +b11111100011000111111110110100010 ( +b10101111101000110111100111111010 ' +b10010100011000101101101000111001 % +#67102 +1# +#67400 +b10101000 + +#67500 +b1101010001100010101110100011101 & +b10001001010111000010111101111001 ) +b111101100001001110110110011010 ( +b10101001011100100100000001010111 ' +b11100011100011101110110110100010 % +#67504 +1! +1$ +#67800 +b10101001 + +#67900 +b1001011100010000000011101111100 & +b1010001011110101101100011110100 ) +b1101010001100010101110100011101 ( +b10001001010111000010111101111001 ' +b11010111010000011110110011010 % +#67902 +0! +0# +#67904 +0$ +#68200 +b10101010 + +#68300 +b11000011111111101010011001000011 & +b100011110001111100111010010011 ) +b1001011100010000000011101111100 ( +b1010001011110101101100011110100 ' +b11100000110110011011010100011101 % +#68302 +1# +#68304 +1! +1$ +#68600 +b10101011 + +#68700 +b1001111011111000010011110110011 & +b1000100110001000111101110110000 ) +b11000011111111101010011001000011 ( +b100011110001111100111010010011 ' +b1011101100111110011101111100 % +#68702 +0! +0# +#69000 +b10101100 + +#69100 +b1100100001010001011001100111110 & +b1010010110100101100101110011001 ) +b1001111011111000010011110110011 ( +b1000100110001000111101110110000 ' +b110110110011001011111001000011 % +#69102 +1! +1# +#69104 +0! +0$ +#69400 +b10101101 + +#69500 +b10101101101110011010001110010110 & +b11010101100101110111110000 ) +b1100100001010001011001100111110 ( +b1010010110100101100101110011001 ' +b10101110010000011011111110110011 % +#69502 +0# +#69800 +b10101110 + +#69900 +b1001000011000111100010011111000 & +b1101001111100110011101110111011 ) +b10101101101110011010001110010110 ( +b11010101100101110111110000 ' +b100001101100010100001100111110 % +#69902 +1# +#70200 +b10101111 + +#70300 +b10011001101011100000000001110001 & +b11111001011010111010100111011001 ) +b1001000011000111100010011111000 ( +b1101001111100110011101110111011 ' +b1100000101001010001001110010110 % +#70304 +1! +1$ +#70600 +b10110000 + +#70700 +b111111011000101001001111001110 & +b1101001011100001101111000011100 ) +b10011001101011100000000001110001 ( +b11111001011010111010100111011001 ' +b1010110010001000000010011111000 % +#70702 +0! +0# +#70704 +0$ +#71000 +b10110001 + +#71100 +b1110010101001111110011000011111 & +b10011011111000111101000010011010 ) +b111111011000101001001111001110 ( +b1101001011100001101111000011100 ' +b11101001101011011000100001110001 % +#71104 +1$ +#71400 +b10110010 + +#71500 +b10110110000111110101101011111101 & +b10011101110010000101011001101001 ) +b1110010101001111110011000011111 ( +b10011011111000111101000010011010 ' +b101011111111001110001111001110 % +#71502 +1! +1# +#71800 +b10110011 + +#71900 +b1111110001001111010010011011010 & +b110011111111010010101110100100 ) +b10110110000111110101101011111101 ( +b10011101110010000101011001101001 ' +b1001101100101110001111000011111 % +#71902 +0! +0# +#71904 +0$ +#72200 +b10110100 + +#72300 +b11101101000001111010000000010110 & +b10100001100000111100111001101001 ) +b1111110001001111010010011011010 ( +b110011111111010010101110100100 ' +b1001100110010001011001011111101 % +#72302 +1# +#72600 +b10110101 + +#72700 +b1110100001111110110010101011000 & +b110111011111010001011000011001 ) +b11101101000001111010000000010110 ( +b10100001100000111100111001101001 ' +b1000011000000010111010011011010 % +#73000 +b10110110 + +#73100 +b11011101001110001001101011000 & +b11001011011100000001110100110000 ) +b1110100001111110110010101011000 ( +b110111011111010001011000011001 ' +b11010000000001110001000000010110 % +#73102 +0# +#73400 +b10110111 + +#73500 +b1001011001011111010101110000000 & +b11000100101101010000001111101011 ) +b11011101001110001001101011000 ( +b11001011011100000001110100110000 ' +b10001111000101011010010101011000 % +#73502 +1# +#73800 +b10111000 + +#73900 +b100011111000110100100011011100 & +b111111011010011001001000 ) +b1001011001011111010101110000000 ( +b11000100101101010000001111101011 ' +b100011001111011101001101011000 % +#73902 +0# +#74200 +b10111001 + +#74300 +b1111001011000000110110011011111 & +b1001111001001011011110100010000 ) +b100011111000110100100011011100 ( +b111111011010011001001000 ' +b110110011100111010101110000000 % +#74304 +1$ +#74600 +b10111010 + +#74700 +b10101101110111100101010110100001 & +b10010100010000100100101001011101 ) +b1111001011000000110110011011111 ( +b1001111001001011011110100010000 ' +b111001101001011010100011011100 % +#74702 +1! +1# +#75000 +b10111011 + +#75100 +b10110101000011010011101110010010 & +b11001111011100011011000000110111 ) +b10101101110111100101010110100001 ( +b10010100010000100100101001011101 ' +b1111010000001101001010011011111 % +#75104 +0! +0$ +#75400 +b10111100 + +#75500 +b1101100101101111011011101000011 & +b110011100110111001111111001100 ) +b10110101000011010011101110010010 ( +b11001111011100011011000000110111 ' +b1011111011100110101110110100001 % +#75502 +0# +#75504 +1$ +#75800 +b10111101 + +#75900 +b11110010000010000011110100010011 & +b101110000001010100001011101010 ) +b1101100101101111011011101000011 ( +b110011100110111001111111001100 ' +b11011100110100011010101110010010 % +#76200 +b10111110 + +#76300 +b11001100010111100001100000111101 & +b11101100000101011100101100001 ) +b11110010000010000011110100010011 ( +b101110000001010100001011101010 ' +b11010001000011011010111101000011 % +#76302 +1! +1# +#76600 +b10111111 + +#76700 +b1111011000110110101110111110001 & +b11001000010010000000000101001110 ) +b11001100010111100001100000111101 ( +b11101100000101011100101100001 ' +b10110011111000001010010100010011 % +#76702 +0! +0# +#77000 +b11000000 + +#77100 +b1001111111110011100101111100100 & +b1110011010110101010101001000010 ) +b1111011000110110101110111110001 ( +b11001000010010000000000101001110 ' +b111100100111111111000000111101 % +#77104 +0$ +#77400 +b11000001 + +#77500 +b1100110011001101100100011100110 & +b11000111001100111111000100100100 ) +b1001111111110011100101111100100 ( +b1110011010110101010101001000010 ' +b10100001111101001101010111110001 % +#77800 +b11000010 + +#77900 +b1000001111011110010001111000100 & +b11000000110010000111011011010010 ) +b1100110011001101100100011100110 ( +b11000111001100111111000100100100 ' +b10000001101001101110101111100100 % +#78200 +b11000011 + +#78300 +b1001001011111001001101000110011 & +b11001000011010100000000001100 ) +b1000001111011110010001111000100 ( +b11000000110010000111011011010010 ' +b1010000001000011111100011100110 % +#78304 +1$ +#78600 +b11000100 + +#78700 +b11110010010010001110000010111111 & +b11001010100000010000101100101000 ) +b1001001011111001001101000110011 ( +b11001000011010100000000001100 ' +b111000111100010000001111000100 % +#79000 +b11000101 + +#79100 +b101100001101100110110011001101 & +b10000001001101101101001111011010 ) +b11110010010010001110000010111111 ( +b11001010100000010000101100101000 ' +b10101101101011010000001000110011 % +#79400 +b11000110 + +#79500 +b1011011110101001011001001001010 & +b11101110001011001111101000101000 ) +b101100001101100110110011001101 ( +b10000001001101101101001111011010 ' +b10110101010011010001100010111111 % +#79504 +0$ +#79800 +b11000111 + +#79900 +b11110011100001000100101110101001 & +b1101100010010110001001011101001 ) +b1011011110101001011001001001010 ( +b11101110001011001111101000101000 ' +b10011111010100000000010011001101 % +#79902 +1# +#79904 +1! +1$ +#80200 +b11001000 + +#80300 +b10000100010010001011100110111101 & +b1111010111100000001001001001011 ) +b11110011100001000100101110101001 ( +b1101100010010110001001011101001 ' +b11111110010001101110001001001010 % +#80600 +b11001001 + +#80700 +b1100001101010001110001100111001 & +b10110000101000000010111110000111 ) +b10000100010010001011100110111101 ( +b1111010111100000001001001001011 ' +b11010001110110010000001110101001 % +#81000 +b11001010 + +#81100 +b1011010011101000000000010000111 & +b10011011001100001100011100001101 ) +b1100001101010001110001100111001 ( +b10110000101000000010111110000111 ' +b11000001100001010101000110111101 % +#81400 +b11001011 + +#81500 +b11001101100011100100011100101000 & +b11101011000110011100000001011001 ) +b1011010011101000000000010000111 ( +b10011011001100001100011100001101 ' +b100110101100010010101100111001 % +#81504 +0! +0$ +#81800 +b11001100 + +#81900 +b101010000100011010101110010111 & +b11010000100110111111100100111011 ) +b11001101100011100100011100101000 ( +b11101011000110011100000001011001 ' +b11111010011100000011100010000111 % +#81904 +1! +1$ +#82200 +b11001101 + +#82300 +b10110000001001110000110001001110 & +b1111001011111011110110000100 ) +b101010000100011010101110010111 ( +b11010000100110111111100100111011 ' +b10111111101101110000011100101000 % +#82302 +0! +0# +#82304 +0$ +#82600 +b11001110 + +#82700 +b11000100100000010000000111011 & +b10111111011110100110100101010000 ) +b10110000001001110000110001001110 ( +b1111001011111011110110000100 ' +b10100111010011010001001110010111 % +#82704 +1$ +#83000 +b11001111 + +#83100 +b11100010111011000100100101000110 & +b1101010001000010111110100110000 ) +b11000100100000010000000111011 ( +b10111111011110100110100101010000 ' +b10001000010001010111110001001110 % +#83104 +0$ +#83400 +b11010000 + +#83500 +b10111101110001111010010110111 & +b10001110101100001000110010100010 ) +b11100010111011000100100101000110 ( +b1101010001000010111110100110000 ' +b10011001100100011111100000111011 % +#83504 +1$ +#83800 +b11010001 + +#83900 +b11110110001101110001001001110000 & +b1110110000100011100001110001101 ) +b10111101110001111010010110111 ( +b10001110101100001000110010100010 ' +b10000000101001100111100101000110 % +#83902 +1! +1# +#83904 +0! +0$ +#84200 +b11010010 + +#84300 +b101100001001010000101111101110 & +b11111100111010000100010110001000 ) +b11110110001101110001001001110000 ( +b1110110000100011100001110001101 ' +b11010000000111010100110010110111 % +#84302 +0# +#84600 +b11010011 + +#84700 +b10011010001110101000010000110100 & +b11010100110100001010100001001100 ) +b101100001001010000101111101110 ( +b11111100111010000100010110001000 ' +b1001110101001001001001001110000 % +#85000 +b11010100 + +#85100 +b100000001111100101001111100011 & +b100100010000000101011011111110 ) +b10011010001110101000010000110100 ( +b11010100110100001010100001001100 ' +b100011110100111101111101110 % +#85104 +1$ +#85400 +b11010101 + +#85500 +b111111101010000011110001001111 & +b1110001111111010000110101100000 ) +b100000001111100101001111100011 ( +b100100010000000101011011111110 ' +b1001110000110110010010000110100 % +#85800 +b11010110 + +#85900 +b11001011000010101000001101100101 & +b11001011110010110101011100010 ) +b111111101010000011110001001111 ( +b1110001111111010000110101100000 ' +b11010010101000010100101111100011 % +#86200 +b11010111 + +#86300 +b101100001100010000010100100010 & +b1010010000001010000000101101001 ) +b11001011000010101000001101100101 ( +b11001011110010110101011100010 ' +b1111110010010100100010001001111 % +#86302 +1! +1# +#86304 +0! +0$ +#86600 +b11011000 + +#86700 +b1100001010000111111000100101011 & +b11111110110011010101010000111100 ) +b101100001100010000010100100010 ( +b1010010000001010000000101101001 ' +b10011111000100011010101101100101 % +#86702 +0# +#86704 +1$ +#87000 +b11011001 + +#87100 +b10111111100010111011010001110010 & +b11011001101111011101000100011 ) +b1100001010000111111000100101011 ( +b11111110110011010101010000111100 ' +b10100100000110000001010100100010 % +#87102 +1! +1# +#87104 +0! +0$ +#87400 +b11011010 + +#87500 +b1010101110001110001110111100111 & +b101011011100110111101100001011 ) +b10111111100010111011010001110010 ( +b11011001101111011101000100011 ' +b1111110110010101010100100101011 % +#87504 +1! +1$ +#87800 +b11011011 + +#87900 +b10001010011010100000111111000 & +b11110011100001110101001111011110 ) +b1010101110001110001110111100111 ( +b101011011100110111101100001011 ' +b11100010001010000010010001110010 % +#87902 +0! +0# +#87904 +0$ +#88200 +b11011100 + +#88300 +b11001100000100111101001000010001 & +b10100001010101101100101111111001 ) +b10001010011010100000111111000 ( +b11110011100001110101001111011110 ' +b1101101001010000010010111100111 % +#88302 +1# +#88304 +1! +1$ +#88600 +b11011101 + +#88700 +b1111110111110101011001000101111 & +b101110000110111000111101110 ) +b11001100000100111101001000010001 ( +b10100001010101101100101111111001 ' +b1111011010000101000000111111000 % +#88702 +0! +0# +#89000 +b11011110 + +#89100 +b111011001101010110001101111101 & +b1101001111001001011011100001010 ) +b1111110111110101011001000101111 ( +b101110000110111000111101110 ' +b1010010100000110101101000010001 % +#89400 +b11011111 + +#89500 +b10001110101001111000110010111101 & +b100101011001110010100111110100 ) +b111011001101010110001101111101 ( +b1101001111001001011011100001010 ' +b10101011011010111100101000101111 % +#89800 +b11100000 + +#89900 +b1010010000010011001101100100100 & +b11000010101101110010011010000100 ) +b10001110101001111000110010111101 ( +b100101011001110010100111110100 ' +b10010000001011101000101101111101 % +#89904 +0$ +#90200 +b11100001 + +#90300 +b11111100010011011001111100000110 & +b1001110001111010011000000011000 ) +b1010010000010011001101100100100 ( +b11000010101101110010011010000100 ' +b10110010110000100110010010111101 % +#90600 +b11100010 + +#90700 +b10011001011110110111111001100100 & +b10000111101101010000010100001101 ) +b11111100010011011001111100000110 ( +b1001110001111010011000000011000 ' +b11110110100001011101100100100 % +#90702 +1# +#91000 +b11100011 + +#91100 +b10101110010001000011110111000110 & +b111110011000010010000010100011 ) +b10011001011110110111111001100100 ( +b10000111101101010000010100001101 ' +b10010000101101011010111100000110 % +#91400 +b11100100 + +#91500 +b11000011001111000001111001101010 & +b10000001111101101101100001101110 ) +b10101110010001000011110111000110 ( +b111110011000010010000010100011 ' +b1000010100010000101111001100100 % +#91502 +0# +#91800 +b11100101 + +#91900 +b1111011010010101110001111010000 & +b11110100011011110101101010010110 ) +b11000011001111000001111001101010 ( +b10000001111101101101100001101110 ' +b10001111101010100000110111000110 % +#92200 +b11100110 + +#92300 +b1101111101001001111100111010010 & +b1001100010010000111000101111111 ) +b1111011010010101110001111010000 ( +b11110100011011110101101010010110 ' +b100011110011110100111001101010 % +#92302 +1# +#92600 +b11100111 + +#92700 +b11001101111010011000111011011011 & +b11100001100100011010010101011010 ) +b1101111101001001111100111010010 ( +b1001100010010000111000101111111 ' +b101100010101000110001111010000 % +#92702 +0# +#92704 +1$ +#93000 +b11101000 + +#93100 +b10001010000001111100011001101111 & +b11000010001001011101110110010000 ) +b11001101111010011000111011011011 ( +b11100001100100011010010101011010 ' +b1001000011010100110100111010010 % +#93400 +b11101001 + +#93500 +b1100111110011101100110001010111 & +b11100110110100000001100100000000 ) +b10001010000001111100011001101111 ( +b11000010001001011101110110010000 ' +b10000001100111110101011011011011 % +#93800 +b11101010 + +#93900 +b111111011010111100111111001111 & +b10001011111010110101010001100011 ) +b1100111110011101100110001010111 ( +b11100110110100000001100100000000 ' +b10110100001101001011111001101111 % +#93902 +1! +1# +#94200 +b11101011 + +#94300 +b1001000101010000001101000111010 & +b1011001000101011100100100111011 ) +b111111011010111100111111001111 ( +b10001011111010110101010001100011 ' +b10001101011000111010001010111 % +#94304 +0! +0$ +#94600 +b11101100 + +#94700 +b11111000010001011010011001011110 & +b10011001001100010001011100000000 ) +b1001000101010000001101000111010 ( +b1011001000101011100100100111011 ' +b1100001000101011011011111001111 % +#94702 +0# +#95000 +b11101101 + +#95100 +b111100111110100011001110001 & +b1111111011101111010001111100 ) +b11111000010001011010011001011110 ( +b10011001001100010001011100000000 ' +b1000011110011100101000111010 % +#95104 +1$ +#95400 +b11101110 + +#95500 +b11000011101001011111101101011101 & +b10110000001111101100010010101 ) +b111100111110100011001110001 ( +b1111111011101111010001111100 ' +b11010101011101110101011001011110 % +#95502 +1! +1# +#95800 +b11101111 + +#95900 +b1000110110000011100111110001100 & +b10111011100100001011101001000001 ) +b11000011101001011111101101011101 ( +b10110000001111101100010010101 ' +b11111101101011001100111001110001 % +#95904 +0! +0$ +#96200 +b11110000 + +#96300 +b10000010101110010001010100111010 & +b1101110001010100111010010110001 ) +b1000110110000011100111110001100 ( +b10111011100100001011101001000001 ' +b11101100011111110001001101011101 % +#96600 +b11110001 + +#96700 +b11110100001100001111000000100101 & +b10111100110001011111010110011110 ) +b10000010101110010001010100111010 ( +b1101110001010100111010010110001 ' +b1001000101111011010111110001100 % +#96702 +0# +#96704 +1$ +#97000 +b11110010 + +#97100 +b10000011110110000101000100100001 & +b11001001100000101001110111101110 ) +b11110100001100001111000000100101 ( +b10111100110001011111010110011110 ' +b1001010000100001100010100111010 % +#97400 +b11110011 + +#97500 +b1100011111000000100011000111000 & +b10000001000100010110111000001 ) +b10000011110110000101000100100001 ( +b11001001100000101001110111101110 ' +b1110011101100011101100000100101 % +#97502 +1! +1# +#97504 +0! +0$ +#97800 +b11110100 + +#97900 +b11111111010000001101010111110101 & +b10111110010100001100101001000111 ) +b1100011111000000100011000111000 ( +b10000001000100010110111000001 ' +b1000001010100010101100100100001 % +#97904 +1! +1$ +#98200 +b11110101 + +#98300 +b10011111101111011110101110000110 & +b11111110000011011010001111111001 ) +b11111111010000001101010111110101 ( +b10111110010100001100101001000111 ' +b1100001110100011000011000111000 % +#98304 +0! +0$ +#98600 +b11110110 + +#98700 +b1011110100100011000111010111100 & +b10100111100001110000100011000100 ) +b10011111101111011110101110000110 ( +b11111110000011011010001111111001 ' +b11111001111011110111110111110101 % +#98702 +0# +#99000 +b11110111 + +#99100 +b10111101100000011101111100000011 & +b11001101000100001111110011111100 ) +b1011110100100011000111010111100 ( +b10100111100001110000100011000100 ' +b1110000111000011101101110000110 % +#99104 +1$ +#99400 +b11111000 + +#99500 +b11110000111010011010111111010110 & +b100010110111110010000101011111 ) +b10111101100000011101111100000011 ( +b11001101000100001111110011111100 ' +b11010010111001000110111010111100 % +#99502 +1! +1# +#99504 +0! +0$ +#99800 +b11111001 + +#99900 +b1001100111101111001110100101 & +b10111010010101000101101000101011 ) +b11110000111010011010111111010110 ( +b100010110111110010000101011111 ' +b10110011011110011100011100000011 % +#99904 +1! +1$ +#100200 +b11111010 + +#100300 +b1101111101110100110110010001011 & +b11010010100100001111111000010000 ) +b1001100111101111001110100101 ( +b10111010010101000101101000101011 ' +b10111101100101110001111111010110 % +#100302 +0! +0# +#100600 +b11111011 + +#100700 +b10001001110110100011000011001111 & +b1110111001001111110011001010101 ) +b1101111101110100110110010001011 ( +b11010010100100001111111000010000 ' +b11111110000000111101101110100101 % +#100702 +1! +1# +#101000 +b11111100 + +#101100 +b1100000100011011100111010111000 & +b11011100111011110011111110011010 ) +b10001001110110100011000011001111 ( +b1110111001001111110011001010101 ' +b10111100110111100011010010001011 % +#101102 +0! +0# +#101104 +0$ +#101400 +b11111101 + +#101500 +b1110000110101001000100000101111 & +b101000110100001001100110110010 ) +b1100000100011011100111010111000 ( +b11011100111011110011111110011010 ' +b1011000010111000100100011001111 % +#101504 +1$ +#101800 +b11111110 + +#101900 +b11011011100101001001011001011010 & +b11010101011000100111101001000000 ) +b1110000110101001000100000101111 ( +b101000110100001001100110110010 ' +b1110111110000000111010111000 % +#101904 +0$ +#102200 +b11111111 + +#102300 +b10100011011001001111001010101000 & +b1110111001001011001100110010011 ) +b11011011100101001001011001011010 ( +b11010101011000100111101001000000 ' +b11010100100101011111000000101111 % +#102302 +1# +#102600 +b100000000 + +#102700 +b11010010010110100000001000000 & +b1100101000100100010110011111110 ) +b10100011011001001111001010101000 ( +b1110111001001011001100110010011 ' +b1111111001001100100011001011010 % +#102702 +0# +#103000 +b100000001 + +#103100 +b11000101100011001110000010111110 & +b1000001111110011010101110011011 ) +b11010010010110100000001000000 ( +b1100101000100100010110011111110 ' +b10000100111100011011001010101000 % +#103102 +1# +#103400 +b100000010 + +#103500 +b1110001000001000101111000001100 & +b110001000011010101000100101101 ) +b11000101100011001110000010111110 ( +b1000001111110011010101110011011 ' +b1000000010010010100000001000000 % +#103800 +b100000011 + +#103900 +b1011111000001100000000011001111 & +b11111101001011011000011011000100 ) +b1110001000001000101111000001100 ( +b110001000011010101000100101101 ' +b10100010100010010001000010111110 % +#103902 +0# +#103904 +1$ +#104200 +b100000100 + +#104300 +b1010111011111100111110010010010 & +b100110110011011011000111011 ) +b1011111000001100000000011001111 ( +b11111101001011011000011011000100 ' +b1010011111101000011111000001100 % +#104302 +1! +1# +#104304 +0! +0$ +#104600 +b100000101 + +#104700 +b10101001100110111010101101110110 & +b11000110111101001100101100011111 ) +b1010111011111100111110010010010 ( +b100110110011011011000111011 ' +b1101111000000000111100011001111 % +#105000 +b100000110 + +#105100 +b11000100000001001100001001101001 & +b1100000001110101011100000010000 ) +b10101001100110111010101101110110 ( +b11000110111101001100101100011111 ' +b10100100100110101110110010010010 % +#105102 +0# +#105104 +1$ +#105400 +b100000111 + +#105500 +b11010000011111001000101000110001 & +b10100100110010000100010111000101 ) +b11000100000001001100001001101001 ( +b1100000001110101011100000010000 ' +b1110100110000000001101101110110 % +#105502 +1! +1# +#105800 +b100001000 + +#105900 +b10000111110001101100001101010011 & +b1100101001100110101001000010110 ) +b11010000011111001000101000110001 ( +b10100100110010000100010111000101 ' +b11100010000101111000101001101001 % +#105902 +0! +0# +#106200 +b100001001 + +#106300 +b1010101110111110111101100001000 & +b1100001110001100101100000000011 ) +b10000111110001101100001101010011 ( +b1100101001100110101001000010110 ' +b110100001011010000001000110001 % +#106302 +1! +1# +#106304 +0! +0$ +#106600 +b100001010 + +#106700 +b11011111011101010001000011111 & +b10101010100000110011000001000111 ) +b1010101110111110111101100001000 ( +b1100001110001100101100000000011 ' +b10110001110111000101101101010011 % +#106704 +1! +1$ +#107000 +b100001011 + +#107100 +b11100110000100101101001000000101 & +b1001000101110111110011100100001 ) +b11011111011101010001000011111 ( +b10101010100000110011000001000111 ' +b10101110000001110011101100001000 % +#107400 +b100001100 + +#107500 +b111011001100000110100101111001 & +b1010101101000001100011110001000 ) +b11100110000100101101001000000101 ( +b1001000101110111110011100100001 ' +b1101110111111100101101000011111 % +#107502 +0! +0# +#107800 +b100001101 + +#107900 +b11011100110101110110111010101010 & +b10101100001001010000001111010001 ) +b111011001100000110100101111001 ( +b1010101101000001100011110001000 ' +b1110000100000101111101000000101 % +#107902 +1! +1# +#107904 +0! +0$ +#108200 +b100001110 + +#108300 +b110111110110111010010100000100 & +b10001111000110000110111000111111 ) +b11011100110101110110111010101010 ( +b10101100001001010000001111010001 ' +b10111000011110111010000101111001 % +#108600 +b100001111 + +#108700 +b11010100101000011001100101011101 & +b10110011011001000001001110100101 ) +b110111110110111010010100000100 ( +b10001111000110000110111000111111 ' +b1100111101000100011111010101010 % +#108704 +1! +1$ +#109000 +b100010000 + +#109100 +b1110010100111010001100111110001 & +b10011000100001000111110001100000 ) +b11010100101000011001100101011101 ( +b10110011011001000001001110100101 ' +b11101010111100111000010100000100 % +#109102 +0! +0# +#109400 +b100010001 + +#109500 +b111001010001001101001100101110 & +b11100001111101111101010100111100 ) +b1110010100111010001100111110001 ( +b10011000100001000111110001100000 ' +b11011000011010110111000101011101 % +#109504 +0$ +#109800 +b100010010 + +#109900 +b11000010100000001110000101001 & +b10000010100110001100111100011010 ) +b111001010001001101001100101110 ( +b11100001111101111101010100111100 ' +b10011010010100101001000111110001 % +#109904 +1$ +#110200 +b100010011 + +#110300 +b1011000100100110000001001001101 & +b1000111010100010111010000101010 ) +b11000010100000001110000101001 ( +b10000010100110001100111100011010 ' +b11111110111011010001100101110 % +#110600 +b100010100 + +#110700 +b10000100000111100001000010100001 & +b11100001101111111011001011010 ) +b1011000100100110000001001001101 ( +b1000111010100010111010000101010 ' +b10011000101100010101010000101001 % +#111000 +b100010101 + +#111100 +b10001000011000110011011000001111 & +b1001000001000101101010000101100 ) +b10000100000111100001000010100001 ( +b11100001101111111011001011010 ' +b11000000100000010110101001001101 % +#111400 +b100010110 + +#111500 +b1011111101010100000001010101110 & +b101011010001011000010001111111 ) +b10001000011000110011011000001111 ( +b1001000001000101101010000101100 ' +b1110100100110110001100010100001 % +#111502 +1! +1# +#111504 +0! +0$ +#111800 +b100010111 + +#111900 +b10010000001101011010001110101100 & +b1011101110011111011000011 ) +b1011111101010100000001010101110 ( +b101011010001011000010001111111 ' +b10010001110100110100111000001111 % +#112200 +b100011000 + +#112300 +b10011000111001000111010010011111 & +b10010111010101001010101110101001 ) +b10010000001101011010001110101100 ( +b1011101110011111011000011 ' +b1111101111110111001010101110 % +#112304 +1! +1$ +#112600 +b100011001 + +#112700 +b11101110010000010111100010010 & +b100000110111011100000001100110 ) +b10011000111001000111010010011111 ( +b10010111010101001010101110101001 ' +b111101001010001100001110101100 % +#112702 +0! +0# +#112704 +0$ +#113000 +b100011010 + +#113100 +b10010100000010000000111100001100 & +b101111111100111100011011100001 ) +b11101110010000010111100010010 ( +b100000110111011100000001100110 ' +b10111011010000001000110010011111 % +#113102 +1# +#113400 +b100011011 + +#113500 +b110111101000011011111110101 & +b1011010000110000011001100011011 ) +b10010100000010000000111100001100 ( +b101111111100111100011011100001 ' +b1011100101100001011111100010010 % +#113504 +1! +1$ +#113800 +b100011100 + +#113900 +b1100011001001010011010010010111 & +b10110111100000010011110100000100 ) +b110111101000011011111110101 ( +b1011010000110000011001100011011 ' +b11010100011100000110111100001100 % +#113902 +0! +0# +#114200 +b100011101 + +#114300 +b1011111110100101001100001101110 & +b11111000001111100101001100000011 ) +b1100011001001010011010010010111 ( +b10110111100000010011110100000100 ' +b10100111010010111001111111110101 % +#114302 +1! +1# +#114304 +0! +0$ +#114600 +b100011110 + +#114700 +b10101011110011101111011010110110 & +b11100001000001011110011110001101 ) +b1011111110100101001100001101110 ( +b11111000001111100101001100000011 ' +b1001010100000011000110010010111 % +#115000 +b100011111 + +#115100 +b1101010101110001110001100101101 & +b10100001011000100000111010000111 ) +b10101011110011101111011010110110 ( +b11100001000001011110011110001101 ' +b11001011000100011110100001101110 % +#115104 +1! +1$ +#115400 +b100100000 + +#115500 +b1111000111010000111000100000001 & +b10100100010011110101100001111000 ) +b1101010101110001110001100101101 ( +b10100001011000100000111010000111 ' +b11011100011110110100011010110110 % +#115502 +0! +0# +#115800 +b100100001 + +#115900 +b1100100010000110110110100100010 & +b11001001010011110101111010101101 ) +b1111000111010000111000100000001 ( +b10100100010011110101100001111000 ' +b10101101101000011000101100101101 % +#115902 +1! +1# +#115904 +0! +0$ +#116200 +b100100010 + +#116300 +b10000001010010100111101101110000 & +b10111010000100010111010101001010 ) +b1100100010000110110110100100010 ( +b11001001010011110101111010101101 ' +b111011011000000111100100000001 % +#116302 +0# +#116600 +b100100011 + +#116700 +b1001101000101101011011011010101 & +b110010010000111110011111000010 ) +b10000001010010100111101101110000 ( +b10111010000100010111010101001010 ' +b1111111001010100111110100100010 % +#116704 +1$ +#117000 +b100100100 + +#117100 +b10101110110111110100010000000000 & +b1111100100111000010000100011000 ) +b1001101000101101011011011010101 ( +b110010010000111110011111000010 ' +b11010010100100011111101101110000 % +#117104 +0$ +#117400 +b100100101 + +#117500 +b1111011110101110111010101010100 & +b10000011100011111101101111101110 ) +b10101110110111110100010000000000 ( +b1111100100111000010000100011000 ' +b11111000101000000001111011010101 % +#117800 +b100100110 + +#117900 +b10110010011101011010100001001000 & +b11100110110111100000111111010111 ) +b1111011110101110111010101010100 ( +b10000011100011111101101111101110 ' +b1010100111111110100010000000000 % +#117902 +1# +#118200 +b100100111 + +#118300 +b10001111011001011110010000111001 & +b1001111110110000100010101000011 ) +b10110010011101011010100001001000 ( +b11100110110111100000111111010111 ' +b11000000011111011101010101010100 % +#118304 +1! +1$ +#118600 +b100101000 + +#118700 +b10000110111110110010111000101111 & +b10011001110100111110001010110101 ) +b10001111011001011110010000111001 ( +b1001111110110000100010101000011 ' +b11111001101111110100001001000 % +#119000 +b100101001 + +#119100 +b10101011011000001111100010001011 & +b1011100001001001000111101110 ) +b10000110111110110010111000101111 ( +b10011001110100111110001010110101 ' +b10100000010001000010110000111001 % +#119102 +0! +0# +#119400 +b100101010 + +#119500 +b11110010011101011010100011010101 & +b10101101101000000110000100011000 ) +b10101011011000001111100010001011 ( +b1011100001001001000111101110 ' +b1011111100010100101011000101111 % +#119800 +b100101011 + +#119900 +b1110001010110010100001100010101 & +b11011101010100010101110010010100 ) +b11110010011101011010100011010101 ( +b10101101101000000110000100011000 ' +b10101100101001001010000010001011 % +#120200 +b100101100 + +#120300 +b10000000001100110110110010111001 & +b11011111010111110100010010000111 ) +b1110001010110010100001100010101 ( +b11011101010100010101110010010100 ' +b1011111001100110000000011010101 % +#120302 +1! +1# +#120600 +b100101101 + +#120700 +b1101100001010111000010111010011 & +b11010111110100010011010111010111 ) +b10000000001100110110110010111001 ( +b11011111010111110100010010000111 ' +b10111011010000011110101100010101 % +#121000 +b100101110 + +#121100 +b1010010001110000111010010011110 & +b1001001011101011000111110101101 ) +b1101100001010111000010111010011 ( +b11010111110100010011010111010111 ' +b11011010101101010010010111001 % +#121104 +0! +0$ +#121400 +b100101111 + +#121500 +b111100001011001001010111001110 & +b1100000110011000110010000011 ) +b1010010001110000111010010011110 ( +b1001001011101011000111110101101 ' +b110000000001010001110111010011 % +#121800 +b100110000 + +#121900 +b1001000110011000111111000100011 & +b11011001110000010111110100000001 ) +b111100001011001001010111001110 ( +b1100000110011000110010000011 ' +b10010001100111001000010010011110 % +#121904 +1! +1$ +#122200 +b100110001 + +#122300 +b11010000101010111110100000001000 & +b10001000011100011001111000101101 ) +b1001000110011000111111000100011 ( +b11011001110000010111110100000001 ' +b1011000100000101110010111001110 % +#122304 +0! +0$ +#122600 +b100110010 + +#122700 +b101001010001101111010101100110 & +b10010100001010111001101001 ) +b11010000101010111110100000001000 ( +b10001000011100011001111000101101 ' +b101011001111010110011000100011 % +#123000 +b100110011 + +#123100 +b10100010101001101100000010001101 & +b101101110000101000011010010101 ) +b101001010001101111010101100110 ( +b10010100001010111001101001 ' +b10001111111010111010100000001000 % +#123104 +1! +1$ +#123400 +b100110100 + +#123500 +b111011111100010011110101010101 & +b100101000000100001000101010110 ) +b10100010101001101100000010001101 ( +b101101110000101000011010010101 ' +b11110111011011100010101100110 % +#123502 +0! +0# +#123800 +b100110101 + +#123900 +b10010110000010001110100011110010 & +b10001111101110001010010000 ) +b111011111100010011110101010101 ( +b100101000000100001000101010110 ' +b10010100101000101010100010001101 % +#123904 +0$ +#124200 +b100110110 + +#124300 +b10001000111000100100101110010 & +b10100011101101011101001111000100 ) +b10010110000010001110100011110010 ( +b10001111101110001010010000 ' +b10110010000110111001010101010101 % +#124600 +b100110111 + +#124700 +b110101010111010010100010110001 & +b11100100110000110000001110100011 ) +b10001000111000100100101110010 ( +b10100011101101011101001111000100 ' +b11010001010011110111100011110010 % +#124702 +1# +#124704 +1! +1$ +#125000 +b100111000 + +#125100 +b11001011110111110111111110001001 & +b111000011110111111011000101101 ) +b110101010111010010100010110001 ( +b11100100110000110000001110100011 ' +b11110011010101111101100101110010 % +#125400 +b100111001 + +#125500 +b11101011001110010001110110100100 & +b110111111111011010001101001010 ) +b11001011110111110111111110001001 ( +b111000011110111111011000101101 ' +b11011100000110001010000010110001 % +#125502 +0! +0# +#125504 +0$ +#125800 +b100111010 + +#125900 +b111100000001110100000101001100 & +b1100000101000101010001110000 ) +b11101011001110010001110110100100 ( +b110111111111011010001101001010 ' +b110000001000110011011110001001 % +#126200 +b100111011 + +#126300 +b11000101110011011010011100101011 & +b11100110001110100101001001110101 ) +b111100000001110100000101001100 ( +b1100000101000101010001110000 ' +b100011110101000011110110100100 % +#126302 +1# +#126304 +1! +1$ +#126600 +b100111100 + +#126700 +b1101101110111111111110100100001 & +b1101011110101001101110000110110 ) +b11000101110011011010011100101011 ( +b11100110001110100101001001110101 ' +b110000011010010000101001100 % +#126702 +0! +0# +#127000 +b100111101 + +#127100 +b11110001000111101010001111101001 & +b1011001010000101010001100010101 ) +b1101101110111111111110100100001 ( +b1101011110101001101110000110110 ' +b10101000111101001111111100101011 % +#127102 +1! +1# +#127400 +b100111110 + +#127500 +b10101110010000100010000011011000 & +b111100111001101110010010010000 ) +b11110001000111101010001111101001 ( +b1011001010000101010001100010101 ' +b10010010001101101111010100100001 % +#127502 +0! +0# +#127504 +0$ +#127800 +b100111111 + +#127900 +b11100110010100011001001001000110 & +b11100010010101000110010000001110 ) +b10101110010000100010000011011000 ( +b111100111001101110010010010000 ' +b100000000011110101111101001 % +#128200 +b101000000 + +#128300 +b1010010011000111001000111110011 & +b11101101100110000010100001111000 ) +b11100110010100011001001001000110 ( +b11100010010101000110010000001110 ' +b10111111010001001110000011011000 % +#128304 +1$ +#128600 +b101000001 + +#128700 +b1111001111111111001100000101011 & +b10011010101101111101110100101 ) +b1010010011000111001000111110011 ( +b11101101100110000010100001111000 ' +b1101010110000111010001001000110 % +#128702 +1! +1# +#129000 +b101000010 + +#129100 +b11011101010100100101111011111 & +b1010101000010001010010010000100 ) +b1111001111111111001100000101011 ( +b10011010101101111101110100101 ' +b1001110111011000000100111110011 % +#129102 +0! +0# +#129400 +b101000011 + +#129500 +b111010001111101111100111000111 & +b10111111100001010001000011011100 ) +b11011101010100100101111011111 ( +b1010101000010001010010010000100 ' +b10000101001111101100000000101011 % +#129800 +b101000100 + +#129900 +b1100011101111110001010010101100 & +b101010000000100101011010000000 ) +b111010001111101111100111000111 ( +b10111111100001010001000011011100 ' +b1001001111101001011001111011111 % +#129904 +0$ +#130200 +b101000101 + +#130300 +b111001000101101100010001110100 & +b11110100001010111110101111110111 ) +b1100011101111110001010010101100 ( +b101010000000100101011010000000 ' +b11001101111100001100000111000111 % +#130302 +1# +#130600 +b101000110 + +#130700 +b10011010000110010100110101101011 & +b1100110000010001110000000 ) +b111001000101101100010001110100 ( +b11110100001010111110101111110111 ' +b10011011000110100111010010101100 % +#130702 +0# +#130704 +1$ +#131000 +b101000111 + +#131100 +b10111110011111000010111010100100 & +b110001110001100111100110001100 ) +b10011010000110010100110101101011 ( +b1100110000010001110000000 ' +b10001111001101010110010001110100 % +#131104 +0$ +#131400 +b101001000 + +#131500 +b101110000110101111011001110001 & +b1111110001110001001111011001000 ) +b10111110011111000010111010100100 ( +b110001110001100111100110001100 ' +b1010000011100100001010101101011 % +#131504 +1$ +#131800 +b101001001 + +#131900 +b1110011010001001110001000001111 & +b101100000100101110000000100111 ) +b101110000110101111011001110001 ( +b1111110001110001001111011001000 ' +b1011111000010010000111010100100 % +#131902 +1! +1# +#132200 +b101001010 + +#132300 +b110000011000000011001001011000 & +b11001001001100001111110001110001 ) +b1110011010001001110001000001111 ( +b101100000100101110000000100111 ' +b11111001101010010111111001110001 % +#132304 +0! +0$ +#132600 +b101001011 + +#132700 +b11011111110010000010000001000111 & +b10001011110010001111111110101011 ) +b110000011000000011001001011000 ( +b11001001001100001111110001110001 ' +b1010100010101001001101000001111 % +#132704 +1! +1$ +#133000 +b101001100 + +#133100 +b10100000100101101000111000111011 & +b10010001010101011001110010111011 ) +b11011111110010000010000001000111 ( +b10001011110010001111111110101011 ' +b110001111100101111001001011000 % +#133400 +b101001101 + +#133500 +b11110010001110111101011111110111 & +b1101100011011110000100000100101 ) +b10100000100101101000111000111011 ( +b10010001010101011001110010111011 ' +b10011110110010100001100001000111 % +#133800 +b101001110 + +#133900 +b11011011010001011001010111010100 & +b11001111101101100011110101001111 ) +b11110010001110111101011111110111 ( +b1101100011011110000100000100101 ' +b10100111001110101011000111011 % +#133904 +0! +0$ +#134200 +b101001111 + +#134300 +b11100011110101110111001011001110 & +b11001111011111111000000010111001 ) +b11011011010001011001010111010100 ( +b11001111101101100011110101001111 ' +b101100100001000110111111110111 % +#134600 +b101010000 + +#134700 +b1101010111010011011101011100001 & +b10011101111101010111011110111110 ) +b11100011110101110111001011001110 ( +b11001111011111111000000010111001 ' +b11110111111010110011010111010100 % +#134702 +0# +#134704 +1$ +#135000 +b101010001 + +#135100 +b1101110011100110110110101 & +b1011001101000001000010101001101 ) +b1101010111010011011101011100001 ( +b10011101111101010111011110111110 ' +b1011000010000010000001011001110 % +#135102 +1! +1# +#135400 +b101010010 + +#135500 +b10000110111101000100000010000 & +b110111110001110000001010111011 ) +b1101110011100110110110101 ( +b1011001101000001000010101001101 ' +b100111001111101011001011100001 % +#135504 +0! +0$ +#135800 +b101010011 + +#135900 +b10000010000100100101010111011010 & +b1001101000010011110110110101011 ) +b10000110111101000100000010000 ( +b110111110001110000001010111011 ' +b11001111110101000110010110110101 % +#136200 +b101010100 + +#136300 +b1101001101101011100101001011000 & +b10001101110011110100110111111001 ) +b10000010000100100101010111011010 ( +b1001101000010011110110110101011 ' +b11100100100111100000100000010000 % +#136600 +b101010101 + +#136700 +b1111011011111110010001001010101 & +b1101011110100110001011001110000 ) +b1101001101101011100101001011000 ( +b10001101110011110100110111111001 ' +b10000101111001000010111011010 % +#136702 +0# +#136704 +1$ +#137000 +b101010110 + +#137100 +b1001011000010001111010010010001 & +b10001100001010000000100001000110 ) +b1111011011111110010001001010101 ( +b1101011110100110001011001110000 ' +b11000111111001110000101001011000 % +#137400 +b101010111 + +#137500 +b111010011101001111101111011010 & +b10111000100110110000101100010110 ) +b1001011000010001111010010010001 ( +b10001100001010000000100001000110 ' +b10000010011011011000101001010101 % +#137504 +0$ +#137800 +b101011000 + +#137900 +b11111010011100100110000011011101 & +b11110110110100101010111011101010 ) +b111010011101001111101111011010 ( +b10111000100110110000101100010110 ' +b1100101011000111110010010001 % +#137904 +1$ +#138200 +b101011001 + +#138300 +b111111001101001010110010101 & +b10011010110100010000011100111110 ) +b11111010011100100110000011011101 ( +b11110110110100101010111011101010 ' +b10011101101010100010101111011010 % +#138600 +b101011010 + +#138700 +b1101001111010011111010101100 & +b1100100001000001100111001111101 ) +b111111001101001010110010101 ( +b10011010110100010000011100111110 ' +b1101001011101001000100011011101 % +#138702 +1! +1# +#138704 +0! +0$ +#139000 +b101011011 + +#139100 +b101100101111100101010010010010 & +b11111110001110010000011000010 ) +b1101001111010011111010101100 ( +b1100100001000001100111001111101 ' +b110011010010100011110110010101 % +#139102 +0# +#139400 +b101011100 + +#139500 +b10101010101000111011101101111101 & +b1001110100011110010010001011110 ) +b101100101111100101010010010010 ( +b11111110001110010000011000010 ' +b11100100110010000101111010101100 % +#139504 +1$ +#139800 +b101011101 + +#139900 +b1010010100000001001000000000101 & +b10001100010001000101111111011011 ) +b10101010101000111011101101111101 ( +b1001110100011110010010001011110 ' +b11011110000110101100010010010010 % +#139902 +1! +1# +#140200 +b101011110 + +#140300 +b11010010110101011100010001010010 & +b1100101000110101110001111011111 ) +b1010010100000001001000000000101 ( +b10001100010001000101111111011011 ' +b10110111011110000101001101111101 % +#140304 +0! +0$ +#140600 +b101011111 + +#140700 +b101010100101110101010001110001 & +b1111100110000011110001101010100 ) +b11010010110101011100010001010010 ( +b1100101000110101110001111011111 ' +b1010110000000001011100000000101 % +#140702 +0# +#140704 +1$ +#141000 +b101100000 + +#141100 +b11100100101010101111111011100101 & +b10011000001000010100111011100111 ) +b101010100101110101010001110001 ( +b1111100110000011110001101010100 ' +b1111100111101110101010001010010 % +#141102 +1! +1# +#141400 +b101100001 + +#141500 +b111101001101000000000101010 & +b10010111000000100111101001100111 ) +b11100100101010101111111011100101 ( +b10011000001000010100111011100111 ' +b10010000001101001101110001110001 % +#141504 +0! +0$ +#141800 +b101100010 + +#141900 +b100110100011000011100111010000 & +b10010101011000101010000001001111 ) +b111101001101000000000101010 ( +b10010111000000100111101001100111 ' +b10110011010111011101011011100101 % +#142200 +b101100011 + +#142300 +b10010001010011011100110110000101 & +b10100010110110011010111000100100 ) +b100110100011000011100111010000 ( +b10010101011000101010000001001111 ' +b110011101001111101000000101010 % +#142302 +0# +#142304 +1$ +#142600 +b101100100 + +#142700 +b1010110101010001001111001100111 & +b10001101011010110011100111011 ) +b10010001010011011100110110000101 ( +b10100010110110011010111000100100 ' +b1000111010000101011100111010000 % +#142702 +1! +1# +#143000 +b101100101 + +#143100 +b11000110101100010111000101010101 & +b111001011011111011001000011000 ) +b1010110101010001001111001100111 ( +b10001101011010110011100111011 ' +b11111111001000011110010110000101 % +#143102 +0! +0# +#143400 +b101100110 + +#143500 +b10101110000101101010100001001101 & +b10111100010111110100001000000111 ) +b11000110101100010111000101010101 ( +b111001011011111011001000011000 ' +b10010010110111010011001100111 % +#143502 +1! +1# +#143800 +b101100111 + +#143900 +b10100111110110111100111100111100 & +b11101010101011010011000011100101 ) +b10101110000101101010100001001101 ( +b10111100010111110100001000000111 ' +b1001101001110111101100101010101 % +#143904 +0! +0$ +#144200 +b101101000 + +#144300 +b11111010100111010110011000001101 & +b11100001110100101110111010111010 ) +b10100111110110111100111100111100 ( +b11101010101011010011000011100101 ' +b11011010101001100000001001101 % +#144302 +0# +#144304 +1$ +#144600 +b101101001 + +#144700 +b111011111100100110010110 & +b1111001001101000100101110100011 ) +b11111010100111010110011000001101 ( +b11100001110100101110111010111010 ' +b1111001101000100010111100111100 % +#144702 +1! +1# +#144704 +0! +0$ +#145000 +b101101010 + +#145100 +b1100111100000101111110111001011 & +b1110110001111100101000000001111 ) +b111011111100100110010110 ( +b1111001001101000100101110100011 ' +b10001101011010000111000001101 % +#145104 +1! +1$ +#145400 +b101101011 + +#145500 +b11000010111011010000011010100010 & +b10111100001100001100101111001011 ) +b1100111100000101111110111001011 ( +b1110110001111100101000000001111 ' +b1111110101000110111100110010110 % +#145504 +0! +0$ +#145800 +b101101100 + +#145900 +b110110110010110100100101101100 & +b1000110110101111000100011011000 ) +b11000010111011010000011010100010 ( +b10111100001100001100101111001011 ' +b1110000011011001010010111001011 % +#145902 +0# +#146200 +b101101101 + +#146300 +b10100110111011010111110111001010 & +b1100100111111011001011101101 ) +b110110110010110100100101101100 ( +b1000110110101111000100011011000 ' +b10101010110110000001011010100010 % +#146302 +1# +#146600 +b101101110 + +#146700 +b110000011010100001001001010010 & +b1011100100001101011000010000111 ) +b10100110111011010111110111001010 ( +b1100100111111011001011101101 ' +b1101100100000000010100101101100 % +#147000 +b101101111 + +#147100 +b1100010111011111000010111101 & +b11000001100100111100011001101000 ) +b110000011010100001001001010010 ( +b1011100100001101011000010000111 ' +b11001101000000110010110111001010 % +#147102 +0# +#147104 +1$ +#147400 +b101110000 + +#147500 +b101101011100000110101001111 & +b1100101001101100111101100111001 ) +b1100010111011111000010111101 ( +b11000001100100111100011001101000 ' +b1100000111110001000001001010010 % +#147502 +1! +1# +#147800 +b101110001 + +#147900 +b10111001011010101110000011111011 & +b1011010010100010010101100010100 ) +b101101011100000110101001111 ( +b1100101001101100111101100111001 ' +b11100011110110000001100010111101 % +#147902 +0! +0# +#148200 +b101110010 + +#148300 +b11010111000100001011110001100 & +b1101111010100111010101101011100 ) +b10111001011010101110000011111011 ( +b1011010010100010010101100010100 ' +b1110101110001000111010101001111 % +#148304 +0$ +#148600 +b101110011 + +#148700 +b100111101110111101101010101011 & +b11001001001110001001011001001111 ) +b11010111000100001011110001100 ( +b1101111010100111010101101011100 ' +b11101110011011010011100011111011 % +#148702 +1# +#148704 +1! +1$ +#149000 +b101110100 + +#149100 +b11011111000101001010111100011000 & +b11010101010000001001110001001011 ) +b100111101110111101101010101011 ( +b11001001001110001001011001001111 ' +b1010010111100111011110001100 % +#149104 +0! +0$ +#149400 +b101110101 + +#149500 +b101011000001000010011000100000 & +b11010010100100111101000001011011 ) +b11011111000101001010111100011000 ( +b11010101010000001001110001001011 ' +b11111001011011101000001010101011 % +#149800 +b101110110 + +#149900 +b10000000011000010101100111110110 & +b11111010011101110100010111001111 ) +b101011000001000010011000100000 ( +b11010010100100111101000001011011 ' +b1111010011011000110111100011000 % +#150200 +b101110111 + +#150300 +b11000110000000110101101000101000 & +b11001100001111000101000010101001 ) +b10000000011000010101100111110110 ( +b11111010011101110100010111001111 ' +b1010001101010010011000100000 % +#150600 +b101111000 + +#150700 +b1100001111100111000111000110 & +b10000110000110100010011000011010 ) +b11000110000000110101101000101000 ( +b11001100001111000101000010101001 ' +b10001010101011101110100111110110 % +#150702 +0# +#151000 +b101111001 + +#151100 +b11111110101001110001110110010111 & +b100010101010011101000111110000 ) +b1100001111100111000111000110 ( +b10000110000110100010011000011010 ' +b11011100110100100001101000101000 % +#151104 +1$ +#151400 +b101111010 + +#151500 +b1010110100101010011101000010011 & +b10101001110110101101111010101111 ) +b11111110101001110001110110010111 ( +b100010101010011101000111110000 ' +b11111111101100000100000111000110 % +#151502 +1! +1# +#151800 +b101111011 + +#151900 +b11111100010100101010111000001001 & +b111010110111110100011101100000 ) +b1010110100101010011101000010011 ( +b10101001110110101101111010101111 ' +b11000110010010111010010110010111 % +#151902 +0! +0# +#152200 +b101111100 + +#152300 +b1111100101110001100111101011011 & +b10000011000000100011100010001010 ) +b11111100010100101010111000001001 ( +b111010110111110100011101100000 ' +b11111111010001011010001000010011 % +#152600 +b101111101 + +#152700 +b11010101110101111011000010010111 & +b10111100100111000110001111101011 ) +b1111100101110001100111101011011 ( +b10000011000000100011100010001010 ' +b1101001001000101110011000001001 % +#152702 +1! +1# +#153000 +b101111110 + +#153100 +b11111101111110111101100101110011 & +b1000111100000110000010011001111 ) +b11010101110101111011000010010111 ( +b10111100100111000110001111101011 ' +b10111010110000100001011101011011 % +#153400 +b101111111 + +#153500 +b11001010000111000011000111000111 & +b10100010001001110111111000011100 ) +b11111101111110111101100101110011 ( +b1000111100000110000010011001111 ' +b1101000010100110000100010010111 % +#153502 +0! +0# +#153800 +b110000000 + +#153900 +b10110110111101011001001010111001 & +b10010101111001101111000100110111 ) +b11001010000111000011000111000111 ( +b10100010001001110111111000011100 ' +b100011001100000100000101110011 % +#153902 +1! +1# +#154200 +b110000001 + +#154300 +b100000000100101001111011100 & +b101111101110111100110111100101 ) +b10110110111101011001001010111001 ( +b10010101111001101111000100110111 ' +b101011100100100000100111000111 % +#154304 +0! +0$ +#154600 +b110000010 + +#154700 +b10111100101101010101101100011000 & +b10100110110011110111010100100010 ) +b100000000100101001111011100 ( +b101111101110111100110111100101 ' +b11010011000000101101010111001 % +#154702 +0# +#155000 +b110000011 + +#155100 +b1011011000110100101101101010011 & +b1001101100100000111110110001110 ) +b10111100101101010101101100011000 ( +b10100110110011110111010100100010 ' +b10110100111001011001111011100 % +#155104 +1$ +#155400 +b110000100 + +#155500 +b10010000110110101011010100100000 & +b10000110101000010101001101110111 ) +b1011011000110100101101101010011 ( +b1001101100100000111110110001110 ' +b10110011011011001101100011000 % +#155502 +1! +1# +#155504 +0! +0$ +#155800 +b110000101 + +#155900 +b11010111001000011101111011100101 & +b1011110011010001101011010111000 ) +b10010000110110101011010100100000 ( +b10000110101000010101001101110111 ' +b10001001110000001100001101010011 % +#155902 +0# +#155904 +1$ +#156200 +b110000110 + +#156300 +b11110101000011101100001111010 & +b1011011100101110001010110011101 ) +b11010111001000011101111011100101 ( +b1011110011010001101011010111000 ' +b1000101011100111011010100100000 % +#156302 +1! +1# +#156304 +0! +0$ +#156600 +b110000111 + +#156700 +b11011111011010110011000011011111 & +b110011001000001000000000000 ) +b11110101000011101100001111010 ( +b1011011100101110001010110011101 ' +b11011001110101101111011011100101 % +#156702 +0# +#156704 +1$ +#157000 +b110001000 + +#157100 +b101100110000011000000010110110 & +b111100101100111110110101010010 ) +b11011111011010110011000011011111 ( +b110011001000001000000000000 ' +b10000011000100000100001111010 % +#157104 +0$ +#157400 +b110001001 + +#157500 +b10001100011010000101010101101001 & +b1010000000110111000100111110 ) +b101100110000011000000010110110 ( +b111100101100111110110101010010 ' +b10000110111011011100100011011111 % +#157504 +1$ +#157800 +b110001010 + +#157900 +b1111111101100001000110101111 & +b101111000100101110000011001011 ) +b10001100011010000101010101101001 ( +b1010000000110111000100111110 ' +b100000110001000011000010110110 % +#157902 +1! +1# +#158200 +b110001011 + +#158300 +b11010000011000001100011001010111 & +b11110011011010001101111101110 ) +b1111111101100001000110101111 ( +b101111000100101110000011001011 ' +b11001110110000110001110101101001 % +#158302 +0! +0# +#158600 +b110001100 + +#158700 +b11010111000010000110111111110111 & +b1101000110011000111000000101000 ) +b11010000011000001100011001010111 ( +b11110011011010001101111101110 ' +b10111111011110110110100110101111 % +#159000 +b110001101 + +#159100 +b1110111010010001001010010000011 & +b10100001110011001010110010010011 ) +b11010111000010000110111111110111 ( +b1101000110011000111000000101000 ' +b11010110010100100111111001010111 % +#159102 +1! +1# +#159400 +b110001110 + +#159500 +b11101000111011010100100011010011 & +b1111100000011101110011101110010 ) +b1110111010010001001010010000011 ( +b10100001110011001010110010010011 ' +b10010100011101111101011111110111 % +#159502 +0! +0# +#159800 +b110001111 + +#159900 +b11111010111101010110011110110 & +b101100100000011100100101101001 ) +b11101000111011010100100011010011 ( +b1111100000011101110011101110010 ' +b110011111011001000110010000011 % +#159902 +1! +1# +#159904 +0! +0$ +#160200 +b110010000 + +#160300 +b10010110010010011001010010010111 & +b10100011000001110110100011000 ) +b11111010111101010110011110110 ( +b101100100000011100100101101001 ' +b10000010101010111101000011010011 % +#160302 +0# +#160304 +1$ +#160600 +b110010001 + +#160700 +b1011110011100101111111011001000 & +b10110100101000011100110110110110 ) +b10010110010010011001010010010111 ( +b10100011000001110110100011000 ' +b11101010001110010001110011110110 % +#160704 +0$ +#161000 +b110010010 + +#161100 +b10010111010111100001100000100101 & +b1001101011010011101000000110011 ) +b1011110011100101111111011001000 ( +b10110100101000011100110110110110 ' +b11011010111011010010110010010111 % +#161102 +1# +#161104 +1! +1$ +#161400 +b110010011 + +#161500 +b11100100011001011000010011010110 & +b101101001010001011101100000101 ) +b10010111010111100001100000100101 ( +b1001101011010011101000000110011 ' +b11001001100001001011111011001000 % +#161504 +0! +0$ +#161800 +b110010100 + +#161900 +b10000000011101101000101111000101 & +b11100111100011100011100000100001 ) +b11100100011001011000010011010110 ( +b101101001010001011101100000101 ' +b1100111100111110011000000100101 % +#161904 +1! +1$ +#162200 +b110010101 + +#162300 +b100000011001011001001010100010 & +b11101000111011101111100001011101 ) +b10000000011101101000101111000101 ( +b11100111100011100011100000100001 ' +b11001000010000110011010011010110 % +#162304 +0! +0$ +#162600 +b110010110 + +#162700 +b10000010101000000111010000001110 & +b10110110101111001110100110111111 ) +b100000011001011001001010100010 ( +b11101000111011101111100001011101 ' +b110100001010001010001111000101 % +#163000 +b110010111 + +#163100 +b10001111011110010100110010101 & +b11101000100110101100000010111 ) +b10000010101000000111010000001110 ( +b10110110101111001110100110111111 ' +b1100111100001000001010100010 % +#163104 +1! +1$ +#163400 +b110011000 + +#163500 +b11000001110011101100011100000101 & +b1000000010011111100101100000110 ) +b10001111011110010100110010101 ( +b11101000100110101100000010111 ' +b10000001000000000000010000001110 % +#163502 +0! +0# +#163800 +b110011001 + +#163900 +b101110010100011100011000001100 & +b1000110100110101110110011001011 ) +b11000001110011101100011100000101 ( +b1000000010011111100101100000110 ' +b1101000101000111000000110010101 % +#163902 +1! +1# +#163904 +0! +0$ +#164200 +b110011010 + +#164300 +b10100111001110010011010011011110 & +b10000011110000010111100111011 ) +b101110010100011100011000001100 ( +b1000110100110101110110011001011 ' +b10110111111101101110111100000101 % +#164600 +b110011011 + +#164700 +b10010110100101011010100100100110 & +b110110010101000110100001000110 ) +b10100111001110010011010011011110 ( +b10000011110000010111100111011 ' +b10100000011000011010011000001100 % +#164702 +0# +#165000 +b110011100 + +#165100 +b101001101101000001111011001010 & +b1000111010001010100110100111000 ) +b10010110100101011010100100100110 ( +b110110010101000110100001000110 ' +b1101110100111111100010011011110 % +#165400 +b110011101 + +#165500 +b10000111110100000000011111011011 & +b10111100001101110101010111100010 ) +b101001101101000001111011001010 ( +b1000111010001010100110100111000 ' +b111011110111001001100100100110 % +#165504 +1$ +#165800 +b110011110 + +#165900 +b1100011010110101010011101000010 & +b11101010100100011011011010010100 ) +b10000111110100000000011111011011 ( +b10111100001101110101010111100010 ' +b10001001010000100100111011001010 % +#165904 +0$ +#166200 +b110011111 + +#166300 +b1100010001011010100101100110010 & +b1100101110001000111011010001110 ) +b1100011010110101010011101000010 ( +b11101010100100011011011010010100 ' +b111111011101101111111011011 % +#166600 +b110100000 + +#166700 +b10110011101110011010001110101101 & +b101011011110111010011110101 ) +b1100010001011010100101100110010 ( +b1100101110001000111011010001110 ' +b10110110011000001011011101000010 % +#166702 +1# +#166704 +1! +1$ +#167000 +b110100001 + +#167100 +b11111101111100110111001000001010 & +b11110101100011111100001101010010 ) +b10110011101110011010001110101101 ( +b101011011110111010011110101 ' +b1000011101001101101100110010 % +#167102 +0! +0# +#167104 +0$ +#167400 +b110100010 + +#167500 +b11111101100111110000011010010011 & +b10000011010001010111100110011101 ) +b11111101111100110111001000001010 ( +b11110101100011111100001101010010 ' +b1111110101001001100101110101101 % +#167502 +1# +#167504 +1! +1$ +#167800 +b110100011 + +#167900 +b10000100001001001000011011001 & +b1110110100000011101111100100001 ) +b11111101100111110000011010010011 ( +b10000011010001010111100110011101 ' +b1100110011000110010001000001010 % +#168200 +b110100100 + +#168300 +b10111101000010111010100011011100 & +b10111000101001011000101011000101 ) +b10000100001001001000011011001 ( +b1110110100000011101111100100001 ' +b101101010111001111010010011 % +#168304 +0! +0$ +#168600 +b110100101 + +#168700 +b11110001001111010101001010101011 & +b11000101000010110001000010001011 ) +b10111101000010111010100011011100 ( +b10111000101001011000101011000101 ' +b110100000000100101100011011001 % +#168704 +1! +1$ +#169000 +b110100110 + +#169100 +b10000101111101110001010011010100 & +b1100101010110100001110111101011 ) +b11110001001111010101001010101011 ( +b11000101000010110001000010001011 ' +b11100000010011010100100011011100 % +#169104 +0! +0$ +#169400 +b110100111 + +#169500 +b11010101100110001000010100 & +b11000111001011100001110101001 ) +b10000101111101110001010011010100 ( +b1100101010110100001110111101011 ' +b11011101010000000101010101011 % +#169800 +b110101000 + +#169900 +b10001011001110100110000101111010 & +b10110110010101101001001011010000 ) +b11010101100110001000010100 ( +b11000111001011100001110101001 ' +b111101010100011011010011010100 % +#169902 +0# +#170200 +b110101001 + +#170300 +b1101000000101001000001010111 & +b10111101111101000000001100111111 ) +b10001011001110100110000101111010 ( +b10110110010101101001001011010000 ' +b10110000010001101100001000010100 % +#170302 +1# +#170304 +1! +1$ +#170600 +b110101010 + +#170700 +b1010111101010011100001000000110 & +b1111110000000100001100110101 ) +b1101000000101001000001010111 ( +b10111101111101000000001100111111 ' +b1011000001100011011000101111010 % +#170704 +0! +0$ +#171000 +b110101011 + +#171100 +b1010011110000000111111100000011 & +b1001010010110011101111000110111 ) +b1010111101010011100001000000110 ( +b1111110000000100001100110101 ' +b11001100000000010100001010111 % +#171104 +1! +1$ +#171400 +b110101100 + +#171500 +b1000111101101000000011110010011 & +b1011110000101000100011110100101 ) +b1010011110000000111111100000011 ( +b1001010010110011101111000110111 ' +b11001101110011111001000000110 % +#171800 +b110101101 + +#171900 +b10010011111100001000011000100011 & +b11000011100110001100000100110100 ) +b1000111101101000000011110010011 ( +b1011110000101000100011110100101 ' +b1010000001110000110011100000011 % +#171902 +0! +0# +#172200 +b110101110 + +#172300 +b10001000010010101100100001111111 & +b1101111001001011101001010010111 ) +b10010011111100001000011000100011 ( +b11000011100110001100000100110100 ' +b11100111100010001001111110010011 % +#172302 +1! +1# +#172600 +b110101111 + +#172700 +b10011010000010000110011100100101 & +b10001101110111100010100100100011 ) +b10001000010010101100100001111111 ( +b1101111001001011101001010010111 ' +b10111110000011001111000100011 % +#173000 +b110110000 + +#173100 +b101001011111000110110101001 & +b11011011111110001010111110011001 ) +b10011010000010000110011100100101 ( +b10001101110111100010100100100011 ' +b11011110000010010011000001111111 % +#173400 +b110110001 + +#173500 +b10100000001011000101101001001100 & +b1111001110001000010101100011110 ) +b101001011111000110110101001 ( +b11011011111110001010111110011001 ' +b11011001001100010100111100100101 % +#173502 +0! +0# +#173504 +0$ +#173800 +b110110010 + +#173900 +b11000111100011010011110100001101 & +b10111110101101101010110110110111 ) +b10100000001011000101101001001100 ( +b1111001110001000010101100011110 ' +b1111001010000101100010110101001 % +#173902 +1# +#173904 +1! +1$ +#174200 +b110110011 + +#174300 +b1011101011101011011010110100110 & +b10011111010010010110001000111001 ) +b11000111100011010011110100001101 ( +b10111110101101101010110110110111 ' +b11000010111111100011101001001100 % +#174304 +0! +0$ +#174600 +b110110100 + +#174700 +b11111000011011100100101000100110 & +b1010110101001010111000010101010 ) +b1011101011101011011010110100110 ( +b10011111010010010110001000111001 ' +b10101110011001010101010100001101 % +#174702 +0# +#175000 +b110110101 + +#175100 +b11011100110010101111111100000111 & +b101100111000101010011110111000 ) +b11111000011011100100101000100110 ( +b1010110101001010111000010101010 ' +b11110000110110001000010110100110 % +#175104 +1$ +#175400 +b110110110 + +#175500 +b101011001000101011010101111010 & +b10100001100101111110010000010100 ) +b11011100110010101111111100000111 ( +b101100111000101010011110111000 ' +b10001010001111110111101000100110 % +#175504 +0$ +#175800 +b110110111 + +#175900 +b10011001011111011111111101011001 & +b10010110001000000100011000001 ) +b101011001000101011010101111010 ( +b10100001100101111110010000010100 ' +b10001011001100101100011100000111 % +#175902 +1# +#175904 +1! +1$ +#176200 +b110111000 + +#176300 +b10111001011000111110001111000011 & +b10000111110101000001111100100110 ) +b10011001011111011111111101011001 ( +b10010110001000000100011000001 ' +b111110100010010110010101111010 % +#176302 +0! +0# +#176600 +b110111001 + +#176700 +b11111101001000101101011100111010 & +b10001011110100110111011000101110 ) +b10111001011000111110001111000011 ( +b10000111110101000001111100100110 ' +b1110110100001110011011101011001 % +#176704 +0$ +#177000 +b110111010 + +#177100 +b1111100111100110101011111101010 & +b11011010001010001100101010010111 ) +b11111101001000101101011100111010 ( +b10001011110100110111011000101110 ' +b10100110011111011111101111000011 % +#177102 +1# +#177400 +b110111011 + +#177500 +b10000111111100011010110111110001 & +b1101100100000010011110001011100 ) +b1111100111100110101011111101010 ( +b11011010001010001100101010010111 ' +b11101011100110110000011100111010 % +#177502 +0# +#177504 +1$ +#177800 +b110111100 + +#177900 +b11111101101110111111101101100101 & +b11011000100011011001111101010 ) +b10000111111100011010110111110001 ( +b1101100100000010011110001011100 ' +b11100110010011000000011111101010 % +#178200 +b110111101 + +#178300 +b10010010001010011111001110010001 & +b10011000101111010101101101010010 ) +b11111101101110111111101101100101 ( +b11011000100011011001111101010 ' +b1010100111100010010111110001 % +#178600 +b110111110 + +#178700 +b100110011100110011111111101101 & +b100001100011000110011011101 ) +b10010010001010011111001110010001 ( +b10011000101111010101101101010010 ' +b100010011000001101001101100101 % +#178702 +1! +1# +#179000 +b110111111 + +#179100 +b10001001000011100101001111011100 & +b1010100011001101001011110111010 ) +b100110011100110011111111101101 ( +b100001100011000110011011101 ' +b11011101101101010111101110010001 % +#179102 +0! +0# +#179104 +0$ +#179400 +b111000000 + +#179500 +b10111110111000101010101011000100 & +b1110100010111000101000100 ) +b10001001000011100101001111011100 ( +b1010100011001101001011110111010 ' +b10111111100011000101011111101101 % +#179800 +b111000001 + +#179900 +b100101001100100001100101000001 & +b11011110010110010010000111100101 ) +b10111110111000101010101011000100 ( +b1110100010111000101000100 ' +b11111011100100001011001111011100 % +#179902 +1# +#179904 +1! +1$ +#180200 +b111000010 + +#180300 +b100111111000011110001000000 & +b10101111111000110001011111110010 ) +b100101001100100001100101000001 ( +b11011110010110010010000111100101 ' +b10101011101101001000101011000100 % +#180302 +0! +0# +#180304 +0$ +#180600 +b111000011 + +#180700 +b10100110111100001000100000010100 & +b10011101111010110001100110011 ) +b100111111000011110001000000 ( +b10101111111000110001011111110010 ' +b10110101111110000001000101000001 % +#180702 +1# +#181000 +b111000100 + +#181100 +b11110100111000000110011111100000 & +b10001000110110100011110111111 ) +b10100110111100001000100000010100 ( +b10011101111010110001100110011 ' +b11100101000111100011110001000000 % +#181400 +b111000101 + +#181500 +b101110001011101011111100011111 & +b1100101111000010011010110100 ) +b11110100111000000110011111100000 ( +b10001000110110100011110111111 ' +b100010101100000010100000010100 % +#181502 +0# +#181504 +1$ +#181800 +b111000110 + +#181900 +b10010111010111000011111100101 & +b11100101110000110010001111011010 ) +b101110001011101011111100011111 ( +b1100101111000010011010110100 ' +b11110111110111110110011111100000 % +#182200 +b111000111 + +#182300 +b10100100000000100000010000100011 & +b11111111100011111000101010001010 ) +b10010111010111000011111100101 ( +b11100101110000110010001111011010 ' +b1011011110101100100011100011111 % +#182600 +b111001000 + +#182700 +b10110101110010100111011000100 & +b1011000001000110011111010001010 ) +b10100100000000100000010000100011 ( +b11111111100011111000101010001010 ' +b1001110110101001010111111100101 % +#182704 +0$ +#183000 +b111001001 + +#183100 +b100001011101100110000011000000 & +b10010101111000010100110101000011 ) +b10110101110010100111011000100 ( +b1011000001000110011111010001010 ' +b10110100001000110001110000100011 % +#183102 +1# +#183400 +b111001010 + +#183500 +b10111100111100110111000010111100 & +b1100000111000001101110100001010 ) +b100001011101100110000011000000 ( +b10010101111000010100110101000011 ' +b11011100110011110110111011000100 % +#183502 +0# +#183800 +b111001011 + +#183900 +b10110001000001011010110111101000 & +b100011111001111011100100110100 ) +b10111100111100110111000010111100 ( +b1100000111000001101110100001010 ' +b10010010011100000110000011000000 % +#184200 +b111001100 + +#184300 +b11110000001110101100001010001110 & +b11010111011010110011111001001111 ) +b10110001000001011010110111101000 ( +b100011111001111011100100110100 ' +b100111011101101001000010111100 % +#184302 +1# +#184600 +b111001101 + +#184700 +b1110010111111000111000101100000 & +b11101110000010101110101110100100 ) +b11110000001110101100001010001110 ( +b11010111011010110011111001001111 ' +b10011100011010101110110111101000 % +#184702 +0# +#185000 +b111001110 + +#185100 +b11011010111000110010001110010111 & +b11111100111010111010000000110110 ) +b1110010111111000111000101100000 ( +b11101110000010101110101110100100 ' +b100110001011101011001010001110 % +#185104 +1$ +#185400 +b111001111 + +#185500 +b11110010111010111010111011010100 & +b1100011000011011010010010100100 ) +b11011010111000110010001110010111 ( +b11111100111010111010000000110110 ' +b10010001011101110111000101100000 % +#185504 +0$ +#185800 +b111010000 + +#185900 +b10010000100111000010010011010111 & +b1010011101000000100101010101111 ) +b11110010111010111010111011010100 ( +b1100011000011011010010010100100 ' +b11000011111111111001101110010111 % +#185902 +1# +#185904 +1! +1$ +#186200 +b111010001 + +#186300 +b110001100010000001101011101001 & +b10011110101110101001101011100100 ) +b10010000100111000010010011010111 ( +b1010011101000000100101010101111 ' +b10101111100111010000111011010100 % +#186302 +0! +0# +#186600 +b111010010 + +#186700 +b10001111001111111000100001011 & +b1100000001011001101101101000101 ) +b110001100010000001101011101001 ( +b10011110101110101001101011100100 ' +b1110001101110101001110011010111 % +#186702 +1! +1# +#187000 +b111010011 + +#187100 +b101010111011100010001010101010 & +b1011011110000000010010001101001 ) +b10001111001111111000100001011 ( +b1100000001011001101101101000101 ' +b1110001010111110101001011101001 % +#187104 +0! +0$ +#187400 +b111010100 + +#187500 +b10010111111110000101100000 & +b101100000111100010001001000001 ) +b101010111011100010001010101010 ( +b1011011110000000010010001101001 ' +b101110011011111010100100001011 % +#187800 +b111010101 + +#187900 +b11010001101110110011101010 & +b1011000111001100110111000101110 ) +b10010111111110000101100000 ( +b101100000111100010001001000001 ' +b1011011111110110111001010101010 % +#187902 +0# +#188200 +b111010110 + +#188300 +b100011001111100110010010111010 & +b11011110100101111100101011101001 ) +b11010001101110110011101010 ( +b1011000111001100110111000101110 ' +b11111101010101001110000101100000 % +#188302 +1# +#188600 +b111010111 + +#188700 +b1111100110101110111110110100011 & +b1001000110000101110100111101101 ) +b100011001111100110010010111010 ( +b11011110100101111100101011101001 ' +b110100001000011011110011101010 % +#188704 +1! +1$ +#189000 +b111011000 + +#189100 +b11001100101111001001110011010010 & +b11100011101110011000001010010 ) +b1111100110101110111110110100011 ( +b1001000110000101110100111101101 ' +b11010000000110111011010010111010 % +#189102 +0! +0# +#189104 +0$ +#189400 +b111011001 + +#189500 +b1010100100100111100010010000010 & +b10010011011011101000100100101001 ) +b11001100101111001001110011010010 ( +b11100011101110011000001010010 ' +b11000111001110100110010110100011 % +#189502 +1# +#189800 +b111011010 + +#189900 +b11011001101100011101001100000100 & +b11110001110000111001101111100010 ) +b1010100100100111100010010000010 ( +b10010011011011101000100100101001 ' +b101000010110100000110011010010 % +#189902 +0# +#190200 +b111011011 + +#190300 +b11110100000011000100101001000010 & +b111110011100010010111011011010 ) +b11011001101100011101001100000100 ( +b11110001110000111001101111100010 ' +b11001010101101111101010010000010 % +#190600 +b111011100 + +#190700 +b1001110100000110001101001100010 & +b11001111111011100001110101010 ) +b11110100000011000100101001000010 ( +b111110011100010010111011011010 ' +b1010111001010011111001100000100 % +#191000 +b111011101 + +#191100 +b1101111111110111111000110101000 & +b11111001001100111110101010010110 ) +b1001110100000110001101001100010 ( +b11001111111011100001110101010 ' +b10010110010111100101101001000010 % +#191400 +b111011110 + +#191500 +b11001110111010101100011000011011 & +b10011000111011001000111101101110 ) +b1101111111110111111000110101000 ( +b11111001001100111110101010010110 ' +b1010110010100000000101001100010 % +#191504 +1$ +#191800 +b111011111 + +#191900 +b11000001011010011000000001110 & +b10101000111010111110001000001010 ) +b11001110111010101100011000011011 ( +b10011000111011001000111101101110 ' +b10110000011101101011000110101000 % +#191904 +0$ +#192200 +b111100000 + +#192300 +b1111100000001001000001100010111 & +b11100100010001100101101110011010 ) +b11000001011010011000000001110 ( +b10101000111010111110001000001010 ' +b10011000110110100001111000011011 % +#192304 +1$ +#192600 +b111100001 + +#192700 +b11111010110101000011100100000000 & +b10001011000010001100010100101111 ) +b1111100000001001000001100010111 ( +b11100100010001100101101110011010 ' +b1110001101011010100000000001110 % +#192702 +1! +1# +#192704 +0! +0$ +#193000 +b111100010 + +#193100 +b1110100110111000001010111110100 & +b101100100110000011011101001011 ) +b11111010110101000011100100000000 ( +b10001011000010001100010100101111 ' +b1011000000111000011101100010111 % +#193400 +b111100011 + +#193500 +b11100010011101111011010111100010 & +b10111001001100001000011111111101 ) +b1110100110111000001010111110100 ( +b101100100110000011011101001011 ' +b1011011000111000011100100000000 % +#193800 +b111100100 + +#193900 +b10011011010111110010001100111110 & +b1111101110001110010010001000 ) +b11100010011101111011010111100010 ( +b10111001001100001000011111111101 ' +b10010100011100111011010111110100 % +#193902 +0# +#194200 +b111100101 + +#194300 +b11111001111010100011100101001101 & +b10100110011011010101000011000111 ) +b10011011010111110010001100111110 ( +b1111101110001110010010001000 ' +b1011111110110001010010111100010 % +#194302 +1# +#194304 +1! +1$ +#194600 +b111100110 + +#194700 +b1010011100110101000110110000110 & +b110001101111100001111001011100 ) +b11111001111010100011100101001101 ( +b10100110011011010101000011000111 ' +b1100010010001101101001100111110 % +#194702 +0! +0# +#194704 +0$ +#195000 +b111100111 + +#195100 +b110111001101010110011010110001 & +b10011111101111010000010001011010 ) +b1010011100110101000110110000110 ( +b110001101111100001111001011100 ' +b10101000001000000101000101001101 % +#195104 +1$ +#195400 +b111101000 + +#195500 +b1110001110010011000011100011001 & +b11110110101110001101001011110101 ) +b110111001101010110011010110001 ( +b10011111101111010000010001011010 ' +b10000111111101101011110110000110 % +#195502 +1! +1# +#195800 +b111101001 + +#195900 +b10011010101111010010110000110101 & +b110001000011100001010101110 ) +b1110001110010011000011100011001 ( +b11110110101110001101001011110101 ' +b10011100000000001110111010110001 % +#195902 +0! +0# +#196200 +b111101010 + +#196300 +b10010111011011101100000111101111 & +b10101010101000100110101011101101 ) +b10011010101111010010110000110101 ( +b110001000011100001010101110 ' +b111101111100010100111100011001 % +#196302 +1! +1# +#196600 +b111101011 + +#196700 +b11101100111111010001111001000101 & +b10011111010100100101010100011110 ) +b10010111011011101100000111101111 ( +b10101010101000100110101011101101 ' +b1110011110111001000010000110101 % +#196702 +0! +0# +#197000 +b111101100 + +#197100 +b10110100001100010010011011010101 & +b1010101101100011111010000110101 ) +b11101100111111010001111001000101 ( +b10011111010100100101010100011110 ' +b11100001011000011011100111101111 % +#197102 +1! +1# +#197400 +b111101101 + +#197500 +b10111101110011010100000110100011 & +b10111001110001100110111111101000 ) +b10110100001100010010011011010101 ( +b1010101101100011111010000110101 ' +b100000011110011011001000101 % +#197502 +0! +0# +#197800 +b111101110 + +#197900 +b1011010001111011001111111001000 & +b1100111000001110001101001110011 ) +b10111101110011010100000110100011 ( +b10111001110001100110111111101000 ' +b111101000001111000111011010101 % +#197902 +1! +1# +#197904 +0! +0$ +#198200 +b111101111 + +#198300 +b111000110011000000110110011 & +b11010000000011100000001001001000 ) +b1011010001111011001111111001000 ( +b1100111000001110001101001110011 ' +b11010111110000000101100110100011 % +#198302 +0# +#198304 +1$ +#198600 +b111110000 + +#198700 +b11101110111001111100000010100100 & +b1011000100100101101011110100001 ) +b111000110011000000110110011 ( +b11010000000011100000001001001000 ' +b10110110110000111101111111001000 % +#198702 +1! +1# +#198704 +0! +0$ +#199000 +b111110001 + +#199100 +b10000101100001001000011100010011 & +b1001110010110111000001101110010 ) +b11101110111001111100000010100100 ( +b1011000100100101101011110100001 ' +b11001011000101000001100110110011 % +#199102 +0# +#199104 +1$ +#199400 +b111110010 + +#199500 +b10011011010101110110110011110101 & +b1001011011001010110011111011101 ) +b10000101100001001000011100010011 ( +b1001110010110111000001101110010 ' +b11010000111000101110000010100100 % +#199502 +1! +1# +#199800 +b111110011 + +#199900 +b10101000100110001000111011000010 & +b1001100001010010110011111110 ) +b10011011010101110110110011110101 ( +b1001011011001010110011111011101 ' +b10100001101111000001111100010011 % +#199902 +0! +0# +#199904 +0$ +#200200 +b111110100 + +#200300 +b11101000101100111010001010100110 & +b11001000101000110100111110000011 ) +b10101000100110001000111011000010 ( +b1001100001010010110011111110 ' +b100000001100001100010011110101 % +#200302 +1# +#200600 +b111110101 + +#200700 +b10100100111100111110100011000000 & +b11001000011100011000000110010010 ) +b11101000101100111010001010100110 ( +b11001000101000110100111110000011 ' +b1101100111011101001111011000010 % +#200702 +0# +#201000 +b111110110 + +#201100 +b11001011010100111001100001 & +b1110110111111100111010010001010 ) +b10100100111100111110100011000000 ( +b11001000011100011000000110010010 ' +b1110101101001101001001010100110 % +#201104 +1$ +#201400 +b111110111 + +#201500 +b1111100100110100111011101001101 & +b1000111000101000010001010000111 ) +b11001011010100111001100001 ( +b1110110111111100111010010001010 ' +b111011101101011110100011000000 % +#201502 +1! +1# +#201800 +b111111000 + +#201900 +b10010000011100100000000101111111 & +b11111001010001010000011001110000 ) +b1111100100110100111011101001101 ( +b1000111000101000010001010000111 ' +b1101001010111100100011001100001 % +#201902 +0! +0# +#202200 +b111111001 + +#202300 +b11011001000110110011100001101100 & +b1110110100101000000100111101100 ) +b10010000011100100000000101111111 ( +b11111001010001010000011001110000 ' +b10101111001000000001111101001101 % +#202304 +0$ +#202600 +b111111010 + +#202700 +b1000110001010101001000101000 & +b1000101111001101001110111001 ) +b11011001000110110011100001101100 ( +b1110110100101000000100111101100 ' +b11110011111100101111111 % +#202702 +1# +#203000 +b111111011 + +#203100 +b11011110000100000111101001011000 & +b11011110110010001110000110110101 ) +b1000110001010101001000101000 ( +b1000101111001101001110111001 ' +b110110000101100001101100 % +#203400 +b111111100 + +#203500 +b10010101010010001101100011001 & +b110000110111110101101100111000 ) +b11011110000100000111101001011000 ( +b11011110110010001110000110110101 ' +b100010010101000001001000101000 % +#203502 +0# +#203504 +1$ +#203800 +b111111101 + +#203900 +b11010110011010101111110000101100 & +b10001011111101011001010110110000 ) +b10010101010010001101100011001 ( +b110000110111110101101100111000 ' +b1011101110000101011101001011000 % +#203904 +0$ +#204200 +b111111110 + +#204300 +b1000110100011011101101000011100 & +b11100101001100111101101000010 ) +b11010110011010101111110000101100 ( +b10001011111101011001010110110000 ' +b1011010011100011101001100011001 % +#204600 +b111111111 + +#204700 +b11100000111110001000010011100110 & +b1100001111100101001111101101000 ) +b1000110100011011101101000011100 ( +b11100101001100111101101000010 ' +b10000001100010111001110000101100 % +#205000 +b1000000000 + +#205100 +b11100111110111101111000100000011 & +b11001111101010111000111111010000 ) +b11100000111110001000010011100110 ( +b1100001111100101001111101101000 ' +b101000010111010011101000011100 % +#205104 +1$ +#205400 +b1000000001 + +#205500 +b110110110110010101001001011001 & +b10010001000100011101101001111 ) +b11100111110111101111000100000011 ( +b11001111101010111000111111010000 ' +b100100110111111011010011100110 % +#205502 +1! +1# +#205800 +b1000000010 + +#205900 +b10110101110110010010010100000100 & +b10100101100111111000111001011101 ) +b110110110110010101001001011001 ( +b10010001000100011101101001111 ' +b10000010101101110100100000011 % +#205904 +0! +0$ +#206200 +b1000000011 + +#206300 +b1001010100101010100111110110100 & +b10110110001000101000100010110011 ) +b10110101110110010010010100000100 ( +b10100101100111111000111001011101 ' +b11111100010010111001101001011001 % +#206600 +b1000000100 + +#206700 +b1101111101011000011101110111000 & +b10011001000011100110111011101 ) +b1001010100101010100111110110100 ( +b10110110001000101000100010110011 ' +b1111100111100010000010100000100 % +#207000 +b1000000101 + +#207100 +b101101011000010101111100011000 & +b11001101011010010100000111101110 ) +b1101111101011000011101110111000 ( +b10011001000011100110111011101 ' +b11100000111010001110111110110100 % +#207102 +0# +#207400 +b1000000110 + +#207500 +b111110010011001011110000001001 & +b110000001100110011000001001100 ) +b101101011000010101111100011000 ( +b11001101011010010100000111101110 ' +b1110011100011111101110111000 % +#207504 +1$ +#207800 +b1000000111 + +#207900 +b10011110000100111111110110101101 & +b10111001101011011110110000011111 ) +b111110010011001011110000001001 ( +b110000001100110011000001001100 ' +b100111100110011001111100011000 % +#207902 +1! +1# +#208200 +b1000001000 + +#208300 +b1101100111111000101000101101111 & +b110111000010110000111101110011 ) +b10011110000100111111110110101101 ( +b10111001101011011110110000011111 ' +b1011011101011001111010000001001 % +#208600 +b1000001001 + +#208700 +b10111011000110001111100110011111 & +b10111010111001111000010111111011 ) +b1101100111111000101000101101111 ( +b110111000010110000111101110011 ' +b1111111101001010110101101 % +#209000 +b1000001010 + +#209100 +b1011010111111100100110111011110 & +b11010100000001110000100100011000 ) +b10111011000110001111100110011111 ( +b10111010111001111000010111111011 ' +b10001110011101110010100101101111 % +#209102 +0! +0# +#209104 +0$ +#209400 +b1000001011 + +#209500 +b10100000000110000001110100101111 & +b11011100101100001101001100100111 ) +b1011010111111100100110111011110 ( +b11010100000001110000100100011000 ' +b1111100110101000000000110011111 % +#209502 +1# +#209504 +1! +1$ +#209800 +b1000001100 + +#209900 +b11100100100000111010101100001001 & +b1001100101110111000111111111101 ) +b10100000000110000001110100101111 ( +b11011100101100001101001100100111 ' +b10101000100100001011110111011110 % +#210200 +b1000001101 + +#210300 +b11011110011000011111011011000001 & +b10111110111100000111010101010101 ) +b11100100100000111010101100001001 ( +b1001100101110111000111111111101 ' +b1100000111100010110010100101111 % +#210600 +b1000001110 + +#210700 +b10110111000101110111111110111011 & +b1001110001101010100111010010111 ) +b11011110011000011111011011000001 ( +b10111110111100000111010101010101 ' +b11111001110110111110001100001001 % +#211000 +b1000001111 + +#211100 +b1011011011101101101011010100000 & +b10001010011100001110111011010001 ) +b10110111000101110111111110111011 ( +b1001110001101010100111010010111 ' +b11010001110101111111111011000001 % +#211104 +0! +0$ +#211400 +b1000010000 + +#211500 +b10110011001101010011000001001001 & +b10111111110100110110101010101111 ) +b1011011011101101101011010100000 ( +b10001010011100001110111011010001 ' +b1100111010101010011110111011 % +#211504 +1! +1$ +#211800 +b1000010001 + +#211900 +b1010011000100000100010000101001 & +b10111110001111100100011010011000 ) +b10110011001101010011000001001001 ( +b10111111110100110110101010101111 ' +b11101101110000111101011010100000 % +#211902 +0! +0# +#212200 +b1000010010 + +#212300 +b1101101000111110001101100110001 & +b1110111101100101101101011110110 ) +b1010011000100000100010000101001 ( +b10111110001111100100011010011000 ' +b11010101101110111100001001001 % +#212600 +b1000010011 + +#212700 +b11110000101110011010001110000010 & +b100001010110011001101010001100 ) +b1101101000111110001101100110001 ( +b1110111101100101101101011110110 ' +b11010001001100010000110000101001 % +#212704 +0$ +#213000 +b1000010100 + +#213100 +b10000100011011101110010110001100 & +b10001001111011011001000001001 ) +b11110000101110011010001110000010 ( +b100001010110011001101010001100 ' +b10010101110001101001001100110001 % +#213102 +1# +#213400 +b1000010101 + +#213500 +b1010100100101101001100101100111 & +b1101001000011101000001001110111 ) +b10000100011011101110010110001100 ( +b10001001111011011001000001001 ' +b111101101001011011001110000010 % +#213504 +1! +1$ +#213800 +b1000010110 + +#213900 +b1011011011101100001011000010111 & +b10101000110001111100010000000110 ) +b1010100100101101001100101100111 ( +b1101001000011101000001001110111 ' +b11110011010000101000010110001100 % +#213902 +0! +0# +#214200 +b1000010111 + +#214300 +b10100110110010111100111000111100 & +b1000110011101100011101000110100 ) +b1011011011101100001011000010111 ( +b10101000110001111100010000000110 ' +b11100000010111011010000101100111 % +#214304 +0$ +#214600 +b1000011000 + +#214700 +b11011011100101111010011110111001 & +b110000101110101100100100010111 ) +b10100110110010111100111000111100 ( +b1000110011101100011101000110100 ' +b11101011110001101010111000010111 % +#214702 +1# +#214704 +1! +1$ +#215000 +b1000011001 + +#215100 +b11010100100001010001000011101111 & +b101100110001111000000101100101 ) +b11011011100101111010011110111001 ( +b110000101110101100100100010111 ' +b11111000101110100010111000111100 % +#215400 +b1000011010 + +#215500 +b1010100010111010100101010011101 & +b110010100100011000100100011001 ) +b11010100100001010001000011101111 ( +b101100110001111000000101100101 ' +b1100110101010100110111110111001 % +#215800 +b1000011011 + +#215900 +b10111000011111110100011111001101 & +b1000100100000010010010111011010 ) +b1010100010111010100101010011101 ( +b110010100100011000100100011001 ' +b11111100000000100110100011101111 % +#215902 +0! +0# +#216200 +b1000011100 + +#216300 +b10111000101011110110001101100110 & +b110000110001100100010011010 ) +b10111000011111110100011111001101 ( +b1000100100000010010010111011010 ' +b10111110000010011010001010011101 % +#216304 +0$ +#216600 +b1000011101 + +#216700 +b10110111010011100101111000010111 & +b11110101010011010010111001011100 ) +b10111000101011110110001101100110 ( +b110000110001100100010011010 ' +b1000010010000010010111111001101 % +#216704 +1$ +#217000 +b1000011110 + +#217100 +b10110100101001011110010110110011 & +b1110111110100100000110001111100 ) +b10110111010011100101111000010111 ( +b11110101010011010010111001011100 ' +b11000011101101000101001101100110 % +#217400 +b1000011111 + +#217500 +b11101101011111010101111101000100 & +b101000000001100000001010110101 ) +b10110100101001011110010110110011 ( +b1110111110100100000110001111100 ' +b11000101101111101110011000010111 % +#217502 +1! +1# +#217504 +0! +0$ +#217800 +b1000100000 + +#217900 +b10010001001110001110101111110000 & +b1010001010110001111101111011 ) +b11101101011111010101111101000100 ( +b101000000001100000001010110101 ' +b10011011100010000111110110110011 % +#218200 +b1000100001 + +#218300 +b10001110101100111010100111010101 & +b10001001001100110100000011001000 ) +b10010001001110001110101111110000 ( +b1010001010110001111101111011 ' +b111100001110111111101000100 % +#218302 +0# +#218304 +1$ +#218600 +b1000100010 + +#218700 +b10001010000000001011100010100010 & +b11011100001100011010111110111111 ) +b10001110101100111010100111010101 ( +b10001001001100110100000011001000 ' +b1010110011001110110101111110000 % +#218702 +1! +1# +#218704 +0! +0$ +#219000 +b1000100011 + +#219100 +b10001010110010000111001111011010 & +b10011001001001101001110000101010 ) +b10001010000000001011100010100010 ( +b11011100001100011010111110111111 ' +b10011111111010000000111010101 % +#219102 +0# +#219400 +b1000100100 + +#219500 +b1010100100111110000111100011011 & +b11011011110101010111100101101011 ) +b10001010110010000111001111011010 ( +b10011001001001101001110000101010 ' +b10001111110001011010100010100010 % +#219502 +1# +#219504 +1! +1$ +#219800 +b1000100101 + +#219900 +b110000011010101110010000101001 & +b11111001111101010000111001101110 ) +b1010100100111110000111100011011 ( +b11011011110101010111100101101011 ' +b11001001010101101010001111011010 % +#219902 +0! +0# +#220200 +b1000100110 + +#220300 +b11101100010011111110010110100010 & +b1000000000001001101110101101110 ) +b110000011010101110010000101001 ( +b11111001111101010000111001101110 ' +b10101100111001111101011100011011 % +#220304 +0$ +#220600 +b1000100111 + +#220700 +b11011010101101001111000000001101 & +b10111101100110000000000000111011 ) +b11101100010011111110010110100010 ( +b1000000000001001101110101101110 ' +b1100111010010111010110000101001 % +#220702 +1# +#220704 +1! +1$ +#221000 +b1000101000 + +#221100 +b101111110011000010100101001000 & +b10111100001111011010100110011000 ) +b11011010101101001111000000001101 ( +b10111101100110000000000000111011 ' +b10010011011000101111010110100010 % +#221102 +0! +0# +#221104 +0$ +#221400 +b1000101001 + +#221500 +b101111011000011100101110000010 & +b1010010001010000110110101010010 ) +b101111110011000010100101001000 ( +b10111100001111011010100110011000 ' +b1111101001101001001100000001101 % +#221800 +b1000101010 + +#221900 +b110000100010010011011001110110 & +b1111110010000011101011010011111 ) +b101111011000011100101110000010 ( +b1010010001010000110110101010010 ' +b1001110100001100110100101001000 % +#221902 +1# +#222200 +b1000101011 + +#222300 +b110001100110110110101010 & +b100001110110101000111111001000 ) +b110000100010010011011001110110 ( +b1111110010000011101011010011111 ' +b100001001111011101101110000010 % +#222302 +0# +#222600 +b1000101100 + +#222700 +b1001000000000000010011111011 & +b1110000010000111011011000000011 ) +b110001100110110110101010 ( +b100001110110101000111111001000 ' +b1111001001110101000011001110110 % +#222702 +1# +#222704 +1! +1$ +#223000 +b1000101101 + +#223100 +b11001111110010011110011111000001 & +b11111100010100010110111011011100 ) +b1001000000000000010011111011 ( +b1110000010000111011011000000011 ' +b110011101010110011110110101010 % +#223102 +0! +0# +#223400 +b1000101110 + +#223500 +b10101011011110010100110011111000 & +b10100010010101111010001110010101 ) +b11001111110010011110011111000001 ( +b11111100010100010110111011011100 ' +b1001001001111101110011111011 % +#223502 +1! +1# +#223504 +0! +0$ +#223800 +b1000101111 + +#223900 +b1011100010111101111001101101110 & +b11011100001010011111000011000101 ) +b10101011011110010100110011111000 ( +b10100010010101111010001110010101 ' +b10000000111101111110111111000001 % +#224200 +b1000110000 + +#224300 +b100010011101010010001001101110 & +b1000011000010101011100001111011 ) +b1011100010111101111001101101110 ( +b11011100001010011111000011000101 ' +b1100001000111101000110011111000 % +#224600 +b1000110001 + +#224700 +b11010001001110000000111111001 & +b10110001010010010101000100111101 ) +b100010011101010010001001101110 ( +b1000011000010101011100001111011 ' +b10101011110001011000001101101110 % +#224704 +1! +1$ +#225000 +b1000110010 + +#225100 +b10000111000101011001111000000101 & +b1100111110001010101110100110 ) +b11010001001110000000111111001 ( +b10110001010010010101000100111101 ' +b10001011011001100101001001101110 % +#225102 +0! +0# +#225400 +b1000110011 + +#225500 +b1011110001001000001100111010110 & +b1111100001011101111011101100011 ) +b10000111000101011001111000000101 ( +b1100111110001010101110100110 ' +b100010001010001100100111111001 % +#225502 +1! +1# +#225504 +0! +0$ +#225800 +b1000110100 + +#225900 +b10111100100001100110110101110101 & +b10010111010010000010110000101111 ) +b1011110001001000001100111010110 ( +b1111100001011101111011101100011 ' +b101011111001011011011000000101 % +#225904 +1! +1$ +#226200 +b1000110101 + +#226300 +b11001001100011000101010111110101 & +b10110111000110000000000001101001 ) +b10111100100001100110110101110101 ( +b10010111010010000010110000101111 ' +b1111110111010101010100111010110 % +#226600 +b1000110110 + +#226700 +b10010000000100010001101011100001 & +b11111011100110011000110111111 ) +b11001001100011000101010111110101 ( +b10110111000110000000000001101001 ' +b10001111111011011100010101110101 % +#227000 +b1000110111 + +#227100 +b1001100111101011001100100100101 & +b11100111011111010101101111000010 ) +b10010000000100010001101011100001 ( +b11111011100110011000110111111 ' +b10101011001000111111110111110101 % +#227102 +0! +0# +#227400 +b1000111000 + +#227500 +b11010010010100110110101001101111 & +b11001010100011011010011111001101 ) +b1001100111101011001100100100101 ( +b11100111011111010101101111000010 ' +b11000110001100001001011100001 % +#227502 +1! +1# +#227800 +b1000111001 + +#227900 +b111111001000010000111011000111 & +b11011111111111011001100010101100 ) +b11010010010100110110101001101111 ( +b11001010100011011010011111001101 ' +b11100000001111001011000100100101 % +#227902 +0! +0# +#228200 +b1000111010 + +#228300 +b11010001011111000111010001011010 & +b10011000001101010111010100100001 ) +b111111001000010000111011000111 ( +b11011111111111011001100010101100 ' +b1001001000000000001001001101111 % +#228302 +1! +1# +#228304 +0! +0$ +#228600 +b1000111011 + +#228700 +b11010101000101111101001110011110 & +b11100010011101111010111000100001 ) +b11010001011111000111010001011010 ( +b10011000001101010111010100100001 ' +b110111010101110011011011000111 % +#229000 +b1000111100 + +#229100 +b11010100010101000100111001001001 & +b11100110101110000010100001100000 ) +b11010101000101111101001110011110 ( +b11100010011101111010111000100001 ' +b110010110111101010010001011010 % +#229102 +0# +#229104 +1$ +#229400 +b1000111101 + +#229500 +b11100000111011010100110110011000 & +b10001011000011011111010001000100 ) +b11010100010101000100111001001001 ( +b11100110101110000010100001100000 ' +b1101011100010110010001110011110 % +#229504 +0$ +#229800 +b1000111110 + +#229900 +b10110001011000011011101001100100 & +b11000111001100011000001011001101 ) +b11100000111011010100110110011000 ( +b10001011000011011111010001000100 ' +b1110110001001100000011001001001 % +#229902 +1# +#230200 +b1000111111 + +#230300 +b11011111001000011101000101101000 & +b1010101001010101101011111011000 ) +b10110001011000011011101001100100 ( +b11000111001100011000001011001101 ' +b10001010100000011000110110011000 % +#230302 +0# +#230600 +b1001000000 + +#230700 +b101000010000110011110111011100 & +b10010100010011010000011110101011 ) +b11011111001000011101000101101000 ( +b1010101001010101101011111011000 ' +b10111100101100101001101001100100 % +#230702 +1# +#231000 +b1001000001 + +#231100 +b11111010101011111000010110011000 & +b101011110101001011101100011011 ) +b101000010000110011110111011100 ( +b10010100010011010000011110101011 ' +b11010001101010101001000101101000 % +#231400 +b1001000010 + +#231500 +b110111101111111100010111111100 & +b110001000111011010100111001 ) +b11111010101011111000010110011000 ( +b101011110101001011101100011011 ' +b110001101011011101110111011100 % +#231800 +b1001000011 + +#231900 +b111111001110000111110110001001 & +b10111001001111011010110001110011 ) +b110111101111111100010111111100 ( +b110001000111011010100111001 ' +b10000110100000110100010110011000 % +#231904 +1! +1$ +#232200 +b1001000100 + +#232300 +b11101101111100000011110001100110 & +b100100101010011000110100101010 ) +b111111001110000111110110001001 ( +b10111001001111011010110001110011 ' +b11001001100100000010010111111100 % +#232302 +0! +0# +#232304 +0$ +#232600 +b1001000101 + +#232700 +b1000101110100101011110100011100 & +b10111001111110100100101110011111 ) +b11101101111100000011110001100110 ( +b100100101010011000110100101010 ' +b11111100110101000011010110001001 % +#232702 +1# +#233000 +b1001000110 + +#233100 +b1000001000001011011001010010100 & +b101101011110101010100001010001 ) +b1000101110100101011110100011100 ( +b10111001111110100100101110011111 ' +b1101100000100110000110001100110 % +#233400 +b1001000111 + +#233500 +b11111010001000101100110110000000 & +b101010110010001010111110011000 ) +b1000001000001011011001010010100 ( +b101101011110101010100001010001 ' +b11010000001110100101110100011100 % +#233502 +0# +#233800 +b1001001000 + +#233900 +b1101110000111110100100101101111 & +b10111000101100101010110101 ) +b11111010001000101100110110000000 ( +b101010110010001010111110011000 ' +b1101100100100010001001010010100 % +#233902 +1# +#233904 +1! +1$ +#234200 +b1001001001 + +#234300 +b11101101011001100001110000101110 & +b1110001001001111101011011 ) +b1101110000111110100100101101111 ( +b10111000101100101010110101 ' +b11101100010011101100110110000000 % +#234304 +0! +0$ +#234600 +b1001001010 + +#234700 +b1101101000001011010111000110011 & +b11111001110001011101010001010101 ) +b11101101011001100001110000101110 ( +b1110001001001111101011011 ' +b10010100010101000011000101101111 % +#234704 +1! +1$ +#235000 +b1001001011 + +#235100 +b10010101010001000011100011001110 & +b1001000000111101101101010001111 ) +b1101101000001011010111000110011 ( +b11111001110001011101010001010101 ' +b11011101100001110110110000101110 % +#235104 +0! +0$ +#235400 +b1001001100 + +#235500 +b10110000000111101100010100 & +b1000010111101000011000101001111 ) +b10010101010001000011100011001110 ( +b1001000000111101101101010001111 ' +b1000000011101000011011000110011 % +#235800 +b1001001101 + +#235900 +b1000100000101100111001110001 & +b10111100101101000001001101100001 ) +b10110000000111101100010100 ( +b1000010111101000011000101001111 ' +b10110100100000100100100011001110 % +#235904 +1! +1$ +#236200 +b1001001110 + +#236300 +b11101010000001100010011011001011 & +b11101011000111111111100001100111 ) +b1000100000101100111001110001 ( +b10111100101101000001001101100001 ' +b1000110001101101100010100 % +#236600 +b1001001111 + +#236700 +b11101000110110101010011000000000 & +b11110110001101010000111111110001 ) +b11101010000001100010011011001011 ( +b11101011000111111111100001100111 ' +b11110111100010100011001110001 % +#236704 +0! +0$ +#237000 +b1001010000 + +#237100 +b100111111110011111011010001011 & +b11111100000100101010011110111100 ) +b11101000110110101010011000000000 ( +b11110110001101010000111111110001 ' +b11011011001100000111111011001011 % +#237102 +0# +#237104 +1$ +#237400 +b1001010001 + +#237500 +b1000100001110100111110010011001 & +b1111001111011010011111100000010 ) +b100111111110011111011010001011 ( +b11111100000100101010011110111100 ' +b111101111010101010011000000000 % +#237800 +b1001010010 + +#237900 +b11000101110110011111101001101111 & +b101101011111000001110011100101 ) +b1000100001110100111110010011001 ( +b1111001111011010011111100000010 ' +b11101000010011011010111010001011 % +#237902 +1! +1# +#238200 +b1001010011 + +#238300 +b1000010100101011010100001101111 & +b11010101110111001101100011111001 ) +b11000101110110011111101001101111 ( +b101101011111000001110011100101 ' +b10010111110111101011010010011001 % +#238600 +b1001010100 + +#238700 +b10000101110000111001011011111001 & +b10001111110000110000111111101100 ) +b1000010100101011010100001101111 ( +b11010101110111001101100011111001 ' +b1010000010101000001001101111 % +#238702 +0! +0# +#239000 +b1001010101 + +#239100 +b1011001110100101001110111001010 & +b10110110111010111000110110101000 ) +b10000101110000111001011011111001 ( +b10001111110000110000111111101100 ' +b11101111110101101101000001101111 % +#239104 +0$ +#239400 +b1001010110 + +#239500 +b1010111000101000111011000001011 & +b11001110111110010100010101110011 ) +b1011001110100101001110111001010 ( +b10110110111010111000110110101000 ' +b10011001011101000101111011111001 % +#239502 +1# +#239504 +1! +1$ +#239800 +b1001010111 + +#239900 +b1110000100010011101000100100100 & +b10111101011110000011011110001100 ) +b1010111000101000111011000001011 ( +b11001110111110010100010101110011 ' +b11001101001111001100110111001010 % +#239902 +0! +0# +#239904 +0$ +#240200 +b1001011000 + +#240300 +b10000000000011110101010000110101 & +b1110100010111111101000010011011 ) +b1110000100010011101000100100100 ( +b10111101011110000011011110001100 ' +b11110100101001000010111000001011 % +#240302 +1# +#240304 +1! +1$ +#240600 +b1001011001 + +#240700 +b11000010100010010011100110101100 & +b11111100101101111101011111101111 ) +b10000000000011110101010000110101 ( +b1110100010111111101000010011011 ' +b111110000000001111000100100100 % +#240704 +0! +0$ +#241000 +b1001011010 + +#241100 +b10110010100011001010100110111100 & +b1001000110110001111001001101110 ) +b11000010100010010011100110101100 ( +b11111100101101111101011111101111 ' +b11111010101011101111110000110101 % +#241102 +0# +#241400 +b1001011011 + +#241500 +b1111011000010010001101101000000 & +b11110000110001100001100010101101 ) +b10110010100011001010100110111100 ( +b1001000110110001111001001101110 ' +b10001011010001000101100110101100 % +#241502 +1# +#241800 +b1001011100 + +#241900 +b100011110110110100101110100001 & +b11110100110011011101110111001101 ) +b1111011000010010001101101000000 ( +b11110000110001100001100010101101 ' +b11010111110000010100100110111100 % +#241904 +1! +1$ +#242200 +b1001011101 + +#242300 +b11010000111110001110100000111111 & +b11100011000110000011110000000111 ) +b100011110110110100101110100001 ( +b11110100110011011101110111001101 ' +b110011110100110001101101000000 % +#242600 +b1001011110 + +#242700 +b10110011001111101010100011110010 & +b1001010010000010110010001011000 ) +b11010000111110001110100000111111 ( +b11100011000110000011110000000111 ' +b11111001100001100100001110100001 % +#242702 +0! +0# +#242704 +0$ +#243000 +b1001011111 + +#243100 +b10000110010010101111100110000101 & +b10010001111001000100001010010110 ) +b10110011001111101010100011110010 ( +b1001010010000010110010001011000 ' +b10111101110010001000000111111 % +#243104 +1$ +#243400 +b1001100000 + +#243500 +b10000001010101110111011110010111 & +b11000111011010000010111010110000 ) +b10000110010010101111100110000101 ( +b10010001111001000100001010010110 ' +b1000110011110010011100011110010 % +#243800 +b1001100001 + +#243900 +b11100011010000110011010011001111 & +b110010000101000110010111011001 ) +b10000001010101110111011110010111 ( +b11000111011010000010111010110000 ' +b11010001100001101101000110000101 % +#243902 +1! +1# +#244200 +b1001100010 + +#244300 +b1011111000010011011001101011010 & +b1100101110110001001101110111001 ) +b11100011010000110011010011001111 ( +b110010000101000110010111011001 ' +b111010111010111100111110010111 % +#244304 +0! +0$ +#244600 +b1001100011 + +#244700 +b110100101111011001111110011000 & +b11001110101000100010111111001111 ) +b1011111000010011011001101011010 ( +b1100101110110001001101110111001 ' +b11111010111001010100110011001111 % +#245000 +b1001100100 + +#245100 +b10000111100110000010110101111111 & +b10010101000110011100111111100101 ) +b110100101111011001111110011000 ( +b11001110101000100010111111001111 ' +b10010100100110110001101011010 % +#245104 +1! +1$ +#245400 +b1001100101 + +#245500 +b10000000000000101010001111000000 & +b1011000100110111011011000010100 ) +b10000111100110000010110101111111 ( +b10010101000110011100111111100101 ' +b11011000010000010101111110011000 % +#245502 +0! +0# +#245504 +0$ +#245800 +b1001100110 + +#245900 +b10011101100010100000111100001111 & +b11011011001111110011001011000010 ) +b10000000000000101010001111000000 ( +b1011000100110111011011000010100 ' +b1000110111100111101010101111111 % +#245904 +1$ +#246200 +b1001100111 + +#246300 +b10001101101011011001110111011011 & +b11000001001000010000110111100 ) +b10011101100010100000111100001111 ( +b11011011001111110011001011000010 ' +b10010101000111001010001111000000 % +#246600 +b1001101000 + +#246700 +b1100010000110011001011100010010 & +b10101111001001100000011110001110 ) +b10001101101011011001110111011011 ( +b11000001001000010000110111100 ' +b11001101111100100111011100001111 % +#246704 +0$ +#247000 +b1001101001 + +#247100 +b10111010101010110111111011010011 & +b1011011000010010111001100101100 ) +b1100010000110011001011100010010 ( +b10101111001001100000011110001110 ' +b11100001010000110100010111011011 % +#247104 +1$ +#247400 +b1001101010 + +#247500 +b10001011001000011010011011001111 & +b100101001011100000010001111111 ) +b10111010101010110111111011010011 ( +b1011011000010010111001100101100 ' +b10101110101000010000011100010010 % +#247502 +1! +1# +#247800 +b1001101011 + +#247900 +b1111010000111011001110011010101 & +b10011011101000010011010010010100 ) +b10001011001000011010011011001111 ( +b100101001011100000010001111111 ' +b11100001010111011110011011010011 % +#247902 +0! +0# +#248200 +b1001101100 + +#248300 +b10101001110101001010111011101100 & +b101111010001010110001000010101 ) +b1111010000111011001110011010101 ( +b10011011101000010011010010010100 ' +b10000110000101111101111011001111 % +#248302 +1! +1# +#248304 +0! +0$ +#248600 +b1001101101 + +#248700 +b10101101001011101110001001011111 & +b111011010000110010101011010110 ) +b10101001110101001010111011101100 ( +b101111010001010110001000010101 ' +b10010110111110110011010011010101 % +#248702 +0# +#248704 +1$ +#249000 +b1001101110 + +#249100 +b10100101110100000001000000101000 & +b10101001011111110110100000100101 ) +b10101101001011101110001001011111 ( +b111011010000110010101011010110 ' +b1100101000111100111011101100 % +#249102 +1! +1# +#249104 +0! +0$ +#249400 +b1001101111 + +#249500 +b1011101000000011011110101100111 & +b10000111111001111000101111011110 ) +b10100101110100000001000000101000 ( +b10101001011111110110100000100101 ' +b11011010001111000001101001011111 % +#249502 +0# +#249504 +1$ +#249800 +b1001110000 + +#249900 +b101010000110011100100000110111 & +b1111011011011100100010100010 ) +b1011101000000011011110101100111 ( +b10000111111001111000101111011110 ' +b100101010100010101000000101000 % +#250200 +b1001110001 + +#250300 +b11000001101000010111001000010000 & +b10010001000110110000111111010001 ) +b101010000110011100100000110111 ( +b1111011011011100100010100010 ' +b1010000111010101000010101100111 % +#250302 +1! +1# +#250304 +0! +0$ +#250600 +b1001110010 + +#250700 +b1000100010101001010011000000100 & +b10100000111010001001101001011110 ) +b11000001101000010111001000010000 ( +b10010001000110110000111111010001 ' +b11100100010110000111000000110111 % +#250702 +0# +#251000 +b1001110011 + +#251100 +b11000111100000111000111010010101 & +b1101011110000100110011011000 ) +b1000100010101001010011000000100 ( +b10100000111010001001101001011110 ' +b11001010001100011111001000010000 % +#251104 +1$ +#251400 +b1001110100 + +#251500 +b11000010110110000010000010111000 & +b100011010111011100011001010001 ) +b11000111100000111000111010010101 ( +b1101011110000100110011011000 ' +b11100001011001001000011000000100 % +#251502 +1! +1# +#251504 +0! +0$ +#251800 +b1001110101 + +#251900 +b11010110001001010111101010100101 & +b1101000010011010101010110111 ) +b11000010110110000010000010111000 ( +b100011010111011100011001010001 ' +b11011011111101110010011010010101 % +#251904 +1! +1$ +#252200 +b1001110110 + +#252300 +b11000010110010111111101010110 & +b11011100001110100000101111110 ) +b11010110001001010111101010100101 ( +b1101000010011010101010110111 ' +b11110111011110000010111000 % +#252302 +0! +0# +#252304 +0$ +#252600 +b1001110111 + +#252700 +b10100101010010001001101100000111 & +b1011000010001010011001011111000 ) +b11000010110010111111101010110 ( +b11011100001110100000101111110 ' +b11111101111100000101001010100101 % +#252704 +1$ +#253000 +b1001111000 + +#253100 +b1010111100101011100111001100100 & +b10000100111001011011001001100001 ) +b10100101010010001001101100000111 ( +b1011000010001010011001011111000 ' +b11010011101000111100111101010110 % +#253102 +1! +1# +#253104 +0! +0$ +#253400 +b1001111001 + +#253500 +b11000111010001111101001111111110 & +b100110001101101110010010011100 ) +b1010111100101011100111001100100 ( +b10000100111001011011001001100001 ' +b11100001100100001010001100000111 % +#253502 +0# +#253800 +b1001111010 + +#253900 +b10010111100001110000001010010100 & +b1101110100110000000011111001101 ) +b11000111010001111101001111111110 ( +b100110001101101110010010011100 ' +b11111001111001101110111001100100 % +#253902 +1# +#254200 +b1001111011 + +#254300 +b11111111001001011111110111100001 & +b110000001000000011011111100 ) +b10010111100001110000001010010100 ( +b1101110100110000000011111001101 ' +b11111001110110000010001111111110 % +#254302 +0# +#254304 +1$ +#254600 +b1001111100 + +#254700 +b11111110000100010001000010110100 & +b1010001001011010010101110100111 ) +b11111111001001011111110111100001 ( +b110000001000000011011111100 ' +b10101111100100111010001010010100 % +#254702 +1! +1# +#254704 +0! +0$ +#255000 +b1001111101 + +#255100 +b1000000111101111111001111000 & +b11011000000001001101101001101100 ) +b11111110000100010001000010110100 ( +b1010001001011010010101110100111 ' +b11010000110010101111010111100001 % +#255102 +0# +#255400 +b1001111110 + +#255500 +b1000110101101001011111011000001 & +b110000010101101001110011001111 ) +b1000000111101111111001111000 ( +b11011000000001001101101001101100 ' +b1110110100101001011000010110100 % +#255502 +1# +#255504 +1! +1$ +#255800 +b1001111111 + +#255900 +b1000111100011110001111110010100 & +b10111000100111011101101111000001 ) +b1000110101101001011111011000001 ( +b110000010101101001110011001111 ' +b11111111111011010011111001111000 % +#255904 +0! +0$ +#256200 +b1010000000 + +#256300 +b100000000110101010111101001110 & +b11000011101110110100001101001110 ) +b1000111100011110001111110010100 ( +b10111000100111011101101111000001 ' +b11100011010000101011011011000001 % +#256302 +0# +#256600 +b1010000001 + +#256700 +b1001001010000111111100110110101 & +b1110110000011110011101101011111 ) +b100000000110101010111101001110 ( +b11000011101110110100001101001110 ' +b111111011100111011111110010100 % +#256702 +1# +#256704 +1! +1$ +#257000 +b1010000010 + +#257100 +b10100101011011101101011101101110 & +b1010000111110110110001011100000 ) +b1001001010000111111100110110101 ( +b1110110000011110011101101011111 ' +b11110101011000001101111101001110 % +#257102 +0! +0# +#257104 +0$ +#257400 +b1010000011 + +#257500 +b11111100011011000001111111101101 & +b10101010101101001101010101011111 ) +b10100101011011101101011101101110 ( +b1010000111110110110001011100000 ' +b1010110100011100101000110110101 % +#257502 +1# +#257504 +1! +1$ +#257800 +b1010000100 + +#257900 +b10100100000011011111001011001010 & +b1110111000010111000111011100010 ) +b11111100011011000001111111101101 ( +b10101010101101001101010101011111 ' +b11010011110101011010011101101110 % +#257902 +0! +0# +#257904 +0$ +#258200 +b1010000101 + +#258300 +b110100000100000010010010100000 & +b10101000000111111101010100111001 ) +b10100100000011011111001011001010 ( +b1110111000010111000111011100010 ' +b10011100100100110111011111101101 % +#258302 +1# +#258600 +b1010000110 + +#258700 +b11010100000101111111101011011110 & +b11111010001111100000001011110 ) +b110100000100000010010010100000 ( +b10101000000111111101010100111001 ' +b11001011100110111010001011001010 % +#258702 +0# +#259000 +b1010000111 + +#259100 +b110111011101110100101010100010 & +b10000010111101110100101101111000 ) +b11010100000101111111101011011110 ( +b11111010001111100000001011110 ' +b10110101001101010010010010100000 % +#259400 +b1010001000 + +#259500 +b1111101101110011111000000110100 & +b10110000100110011100100100010 ) +b110111011101110100101010100010 ( +b10000010111101110100101101111000 ' +b1101011110000010000101011011110 % +#259800 +b1010001001 + +#259900 +b11001000100000101010100000101101 & +b1000101001011011101100001110000 ) +b1111101101110011111000000110100 ( +b10110000100110011100100100010 ' +b10001101001000100101101010100010 % +#259904 +1$ +#260200 +b1010001010 + +#260300 +b11110101010111010010001010101000 & +b1000111110101110100001000110110 ) +b11001000100000101010100000101101 ( +b1000101001011011101100001110000 ' +b10110010001110000101000000110100 % +#260304 +0$ +#260600 +b1010001011 + +#260700 +b11100001101001001000010101 & +b11011110100110001000101000101011 ) +b11110101010111010010001010101000 ( +b1000111110101110100001000110110 ' +b11011101110000111100000000101101 % +#260702 +1# +#260704 +1! +1$ +#261000 +b1010001100 + +#261100 +b11100010111010011001001110111100 & +b11111110101111011010011010100001 ) +b11100001101001001000010101 ( +b11011110100110001000101000101011 ' +b11100010010000110001010101000 % +#261104 +0! +0$ +#261400 +b1010001101 + +#261500 +b11001111000110111010011100110000 & +b11111000001110101001010000011000 ) +b11100010111010011001001110111100 ( +b11111110101111011010011010100001 ' +b110111000101100011101000010101 % +#261502 +0# +#261800 +b1010001110 + +#261900 +b1110010010110101000010010000011 & +b11011100100000001001100011011100 ) +b11001111000110111010011100110000 ( +b11111000001110101001010000011000 ' +b10101110011101000111001110111100 % +#261904 +1$ +#262200 +b1010001111 + +#262300 +b1001100110111000100101001001110 & +b1011110111011000100010010000100 ) +b1110010010110101000010010000011 ( +b11011100100000001001100011011100 ' +b10010001000100010011100110000 % +#262304 +0$ +#262600 +b1010010000 + +#262700 +b110010100110101000110111100110 & +b10010100010000100111110101110001 ) +b1001100110111000100101001001110 ( +b1011110111011000100010010000100 ' +b10100110011111101001110010000011 % +#262702 +1# +#263000 +b1010010001 + +#263100 +b10100000010011101001001011101100 & +b1110011011100010011101010101 ) +b110010100110101000110111100110 ( +b10010100010000100111110101110001 ' +b10101110100011100011101001001110 % +#263400 +b1010010010 + +#263500 +b11000001011100111001011011010110 & +b100111011000001101101001100001 ) +b10100000010011101001001011101100 ( +b1110011011100010011101010101 ' +b11100110111101011011110111100110 % +#263800 +b1010010011 + +#263900 +b1101010010101010110100111110111 & +b10111110010110000101010100100010 ) +b11000001011100111001011011010110 ( +b100111011000001101101001100001 ' +b11010100110110011111001011101100 % +#263902 +0# +#263904 +1$ +#264200 +b1010010100 + +#264300 +b10110010111111110111110000110 & +b1001011110001110000010100001110 ) +b1101010010101010110100111110111 ( +b10111110010110000101010100100010 ' +b1011101110001010010011011010110 % +#264304 +0$ +#264600 +b1010010101 + +#264700 +b10101011000010011001111101010110 & +b1101010110100100101100100101010 ) +b10110010111111110111110000110 ( +b1001011110001110000010100001110 ' +b11000001000110101101000111110111 % +#265000 +b1010010110 + +#265100 +b110001010111111111011100000111 & +b11011000100101010001000001001100 ) +b10101011000010011001111101010110 ( +b1101010110100100101100100101010 ' +b11101001001000111101111110000110 % +#265104 +1$ +#265400 +b1010010111 + +#265500 +b101110101010000010011001000001 & +b11001001101111001110001100001111 ) +b110001010111111111011100000111 ( +b11011000100101010001000001001100 ' +b11100111111100110010111101010110 % +#265502 +1! +1# +#265800 +b1010011000 + +#265900 +b10010000111001100110011110111001 & +b1011110110011110100010010101000 ) +b101110101010000010011001000001 ( +b11001001101111001110001100001111 ' +b11001110111001111100111100000111 % +#265902 +0! +0# +#266200 +b1010011001 + +#266300 +b11010001100110011110100110010011 & +b10111110011011000100101000110001 ) +b10010000111001100110011110111001 ( +b1011110110011110100010010101000 ' +b1101111100110100010111001000001 % +#266302 +1! +1# +#266600 +b1010011010 + +#266700 +b1010110001011110111011110110000 & +b11110101010101110001110100001100 ) +b11010001100110011110100110010011 ( +b10111110011011000100101000110001 ' +b10100011110110111010111110111001 % +#266702 +0! +0# +#266704 +0$ +#267000 +b1010011011 + +#267100 +b10010100000001010011011100111101 & +b10001010110011101000001010000110 ) +b1010110001011110111011110110000 ( +b11110101010101110001110100001100 ' +b11110110101010111000110010011 % +#267104 +1$ +#267400 +b1010011100 + +#267500 +b11110100010010001001100110110101 & +b11011001111101111110011111001100 ) +b10010100000001010011011100111101 ( +b10001010110011101000001010000110 ' +b101101100100101111011110110000 % +#267800 +b1010011101 + +#267900 +b10110111011011011000110110100111 & +b1010011011001110111100001000 ) +b11110100010010001001100110110101 ( +b11011001111101111110011111001100 ' +b10111101101111001101111100111101 % +#268200 +b1010011110 + +#268300 +b1100001111101110111101110111101 & +b11010001110000101101010100000001 ) +b10110111011011011000110110100111 ( +b1010011011001110111100001000 ' +b10110000100001010011000110110101 % +#268302 +1! +1# +#268600 +b1010011111 + +#268700 +b11010111010101010111100010100111 & +b1100100011101100110000100100 ) +b1100001111101110111101110111101 ( +b11010001110000101101010100000001 ' +b11011011000000001011010110100111 % +#268702 +0! +0# +#269000 +b1010100000 + +#269100 +b11001010000010000110111010100000 & +b10000111110001101010110010001 ) +b11010111010101010111100010100111 ( +b1100100011101100110000100100 ' +b11011010001010101001001110111101 % +#269102 +1! +1# +#269104 +0! +0$ +#269400 +b1010100001 + +#269500 +b11001100011100011011001011011101 & +b10110000100111010111010000101001 ) +b11001010000010000110111010100000 ( +b10000111110001101010110010001 ' +b1111100100100000100000010100111 % +#269504 +1! +1$ +#269800 +b1010100010 + +#269900 +b10010011000001111011001000001111 & +b11010111100111010001010011111 ) +b11001100011100011011001011011101 ( +b10110000100111010111010000101001 ' +b10001001011111010110111010100000 % +#270200 +b1010100011 + +#270300 +b10001001110001100000010011110001 & +b11001000011000001010000001111010 ) +b10010011000001111011001000001111 ( +b11010111100111010001010011111 ' +b1000001111001110101101011011101 % +#270302 +0! +0# +#270600 +b1010100100 + +#270700 +b10100000100111111111010000011101 & +b1110101001101010100000001100 ) +b10001001110001100000010011110001 ( +b11001000011000001010000001111010 ' +b10101110100101111100101000001111 % +#271000 +b1010100101 + +#271100 +b11010100011010011001001111011111 & +b1101101001100011111001100000100 ) +b10100000100111111111010000011101 ( +b1110101001101010100000001100 ' +b10111001111000011000110011110001 % +#271400 +b1010100110 + +#271500 +b10110000110101001001100101100001 & +b11101111101101001010011110010110 ) +b11010100011010011001001111011111 ( +b1101101001100011111001100000100 ' +b1011111001111110001110000011101 % +#271800 +b1010100111 + +#271900 +b11001010111100000110001101001011 & +b1010010100111111111010110101100 ) +b10110000110101001001100101100001 ( +b11101111101101001010011110010110 ' +b10011000111101110110101111011111 % +#272200 +b1010101000 + +#272300 +b10010100001110010111101101100010 & +b10000000001100101110010110010100 ) +b11001010111100000110001101001011 ( +b1010010100111111111010110101100 ' +b10100000111111001000101100001 % +#272304 +0$ +#272600 +b1010101001 + +#272700 +b1110000000001010001100010011000 & +b111001101001101100111011011100 ) +b10010100001110010111101101100010 ( +b10000000001100101110010110010100 ' +b1001001111010100011101101001011 % +#273000 +b1010101010 + +#273100 +b111000101100011100100010100001 & +b1100111000011000100110101001001 ) +b1110000000001010001100010011000 ( +b111001101001101100111011011100 ' +b1011111111000100110101101100010 % +#273102 +1# +#273104 +1! +1$ +#273400 +b1010101011 + +#273500 +b1101111111101110010111011101000 & +b110111011011100011000101000101 ) +b111000101100011100100010100001 ( +b1100111000011000100110101001001 ' +b1011000110000011101100010011000 % +#273504 +0! +0$ +#273800 +b1010101100 + +#273900 +b11011100110101100111100101101001 & +b1101010100101000100000001011010 ) +b1101111111101110010111011101000 ( +b110111011011100011000101000101 ' +b10110110111101001100000010100001 % +#273902 +0# +#273904 +1$ +#274200 +b1010101101 + +#274300 +b1001100001000100110001001100111 & +b10011010011101001001111110101111 ) +b11011100110101100111100101101001 ( +b1101010100101000100000001011010 ' +b11010110100000000110111011101000 % +#274302 +1! +1# +#274600 +b1010101110 + +#274700 +b11101011000011100101000111111110 & +b10000100011111000110110100101001 ) +b1001100001000100110001001100111 ( +b10011010011101001001111110101111 ' +b1101111000111010011000101101001 % +#274704 +0! +0$ +#275000 +b1010101111 + +#275100 +b10001010110101110101001101011101 & +b11010101101110010010001011010111 ) +b11101011000011100101000111111110 ( +b10000100011111000110110100101001 ' +b1011111001100010101101001100111 % +#275104 +1! +1$ +#275400 +b1010110000 + +#275500 +b1110100101111010100111111100000 & +b11101101101001010111001000001011 ) +b10001010110101110101001101011101 ( +b11010101101110010010001011010111 ' +b10011001100000011010000111111110 % +#275504 +0! +0$ +#275800 +b1010110001 + +#275900 +b1011000011100111000111111011101 & +b1101000000011100111010000111010 ) +b1110100101111010100111111100000 ( +b11101101101001010111001000001011 ' +b110000010011011011101101011101 % +#275902 +0# +#275904 +1$ +#276200 +b1010110010 + +#276300 +b110111000000010110001101 & +b10011110100000001001101111110010 ) +b1011000011100111000111111011101 ( +b1101000000011100111010000111010 ' +b10011110110000100100111111100000 % +#276600 +b1010110011 + +#276700 +b11011111101000010110011111011111 & +b11011011010000000111000001000 ) +b110111000000010110001101 ( +b10011110100000001001101111110010 ' +b11000100000011010110011111011101 % +#277000 +b1010110100 + +#277100 +b10100101011101001011110110011110 & +b1000101011001000010100011010010 ) +b11011111101000010110011111011111 ( +b11011011010000000111000001000 ' +b11100000111100000110110110001101 % +#277104 +0$ +#277400 +b1010110101 + +#277500 +b101010011111001110000011110000 & +b11111110001101111111111101110110 ) +b10100101011101001011110110011110 ( +b1000101011001000010100011010010 ' +b11010100100111111001111111011111 % +#277800 +b1010110110 + +#277900 +b1001110101000101010001111000001 & +b1001110001110100111111111010101 ) +b101010011111001110000011110000 ( +b11111110001101111111111101110110 ' +b100110000100110110011110 % +#277902 +1# +#277904 +1! +1$ +#278200 +b1010110111 + +#278300 +b11000010100110010011001101011001 & +b1111001011110010100100101100 ) +b1001110101000101010001111000001 ( +b1001110001110100111111111010101 ' +b11001101011110110110000011110000 % +#278302 +0! +0# +#278600 +b1010111000 + +#278700 +b100001001110010010010011010 & +b1011111110000000011100000001000 ) +b11000010100110010011001101011001 ( +b1111001011110010100100101100 ' +b1011011101111001010101111000001 % +#278704 +0$ +#279000 +b1010111001 + +#279100 +b1111001001111111111110110011111 & +b1110010001101110000101101111011 ) +b100001001110010010010011010 ( +b1011111110000000011100000001000 ' +b1011000000111111101101011001 % +#279102 +1# +#279104 +1! +1$ +#279400 +b1010111010 + +#279500 +b11010010111110111100101001010 & +b100111011000011000101011001000 ) +b1111001001111111111110110011111 ( +b1110010001101110000101101111011 ' +b111101000000111111010010011010 % +#279502 +0! +0# +#279504 +0$ +#279800 +b1010111011 + +#279900 +b1010110101011000000100100101100 & +b11010000111110011100010110101001 ) +b11010010111110111100101001010 ( +b100111011000011000101011001000 ' +b10000110110100110000010110011111 % +#279902 +1# +#280200 +b1010111100 + +#280300 +b10011100110001000100110100101110 & +b1111101101100001111111011111011 ) +b1010110101011000000100100101100 ( +b11010000111110011100010110101001 ' +b11100001100101010010100101001010 % +#280600 +b1010111101 + +#280700 +b10110100110111011001101110010110 & +b10000010000011100000011110010010 ) +b10011100110001000100110100101110 ( +b1111101101100001111111011111011 ' +b110110111001010110100100101100 % +#280702 +0# +#281000 +b1010111110 + +#281100 +b11110000011100110111010100001111 & +b1001110011000001110110011010000 ) +b10110100110111011001101110010110 ( +b10000010000011100000011110010010 ' +b10111110101011010011110100101110 % +#281104 +1$ +#281400 +b1010111111 + +#281500 +b1011010111010101110010011101111 & +b10101100111100111000000100 ) +b11110000011100110111010100001111 ( +b1001110011000001110110011010000 ' +b1011000000000010010101110010110 % +#281800 +b1011000000 + +#281900 +b1111000000101010101000101111000 & +b10011101001011000010100001110 ) +b1011010111010101110010011101111 ( +b10101100111100111000000100 ' +b1101011110110110000110100001111 % +#281904 +0$ +#282200 +b1011000001 + +#282300 +b11101001100010100011111001101010 & +b11100100010010100111001110010000 ) +b1111000000101010101000101111000 ( +b10011101001011000010100001110 ' +b1101110011011001110011101111 % +#282600 +b1011000010 + +#282700 +b100011101000100111010001110 & +b11010110001110000101101110100000 ) +b11101001100010100011111001101010 ( +b11100100010010100111001110010000 ' +b11010010100111101001000101111000 % +#283000 +b1011000011 + +#283100 +b1011110101000110101000000101 & +b10110011000101010110101101100011 ) +b100011101000100111010001110 ( +b11010110001110000101101110100000 ' +b10111000011110010110111001101010 % +#283102 +1# +#283104 +1! +1$ +#283400 +b1011000100 + +#283500 +b10111001100000111110100011010000 & +b11111001001011101010110000100 ) +b1011110101000110101000000101 ( +b10110011000101010110101101100011 ' +b10100110000000000011111010001110 % +#283502 +0! +0# +#283504 +0$ +#283800 +b1011000101 + +#283900 +b1001111110010001000010001101 & +b10100001110101011100001011110000 ) +b10111001100000111110100011010000 ( +b11111001001011101010110000100 ' +b10101000100001000100001000000101 % +#283904 +1$ +#284200 +b1011000110 + +#284300 +b10011110001000101100011101110011 & +b111000010000010110110111000011 ) +b1001111110010001000010001101 ( +b10100001110101011100001011110000 ' +b10100110110001010110100011010000 % +#284302 +1! +1# +#284600 +b1011000111 + +#284700 +b1010000010100110100001111001101 & +b10010001111011110101010000000101 ) +b10011110001000101100011101110011 ( +b111000010000010110110111000011 ' +b11000001011111010111100010001101 % +#285000 +b1011001000 + +#285100 +b11101011110111100101100100110100 & +b1100011010011110001001101110001 ) +b1010000010100110100001111001101 ( +b10010001111011110101010000000101 ' +b10001000000110010101111101110011 % +#285104 +0! +0$ +#285400 +b1011001001 + +#285500 +b11001010111111010001000111011111 & +b11110100111011100110110 ) +b11101011110111100101100100110100 ( +b1100011010011110001001101110001 ' +b11001010010011010010101111001101 % +#285502 +0# +#285504 +1$ +#285800 +b1011001010 + +#285900 +b11001000001111001011001110000001 & +b11010001001100100100011101101010 ) +b11001010111111010001000111011111 ( +b11110100111011100110110 ' +b11001000101111111100100110100 % +#286200 +b1011001011 + +#286300 +b111001011111010011011100100100 & +b11011001011001010111001110111 ) +b11001000001111001011001110000001 ( +b11010001001100100100011101101010 ' +b100010011100111110100111011111 % +#286302 +1! +1# +#286304 +0! +0$ +#286600 +b1011001100 + +#286700 +b1010111101110100011101000001010 & +b1111010001101110010111001110110 ) +b111001011111010011011100100100 ( +b11011001011001010111001110111 ' +b101101101000001011101110000001 % +#286702 +0# +#287000 +b1011001101 + +#287100 +b11111001100011111010111110011100 & +b101001100110110111100110011100 ) +b1010111101110100011101000001010 ( +b1111010001101110010111001110110 ' +b11010000110001000001011100100100 % +#287400 +b1011001110 + +#287500 +b10111100111001000110110101100100 & +b111010000010000110101001000101 ) +b11111001100011111010111110011100 ( +b101001100110110111100110011100 ' +b10000110011010100110101000001010 % +#287502 +1# +#287800 +b1011001111 + +#287900 +b11001010001101100000000111100110 & +b1001110010000011011010011111101 ) +b10111100111001000110110101100100 ( +b111010000010000110101001000101 ' +b10000100111100110100111110011100 % +#288200 +b1011010000 + +#288300 +b101100000001011101010011101100 & +b10110011000101010000000010100111 ) +b11001010001101100000000111100110 ( +b1001110010000011011010011111101 ' +b10011111100011110100110101100100 % +#288600 +b1011010001 + +#288700 +b10101111000110110111011101110 & +b1101111101000000110101111001101 ) +b101100000001011101010011101100 ( +b10110011000101010000000010100111 ' +b1111010001110010011000111100110 % +#289000 +b1011010010 + +#289100 +b1100010010000101001101001000 & +b1110111010000100010011001101 ) +b10101111000110110111011101110 ( +b1101111101000000110101111001101 ' +b10101000101011010011101100 % +#289400 +b1011010011 + +#289500 +b1101110010000000010100111100100 & +b1100000110110101010111100001111 ) +b1100010010000101001101001000 ( +b1110111010000100010011001101 ' +b1110100101000001111011101110 % +#289800 +b1011010100 + +#289900 +b1101100010111100000001111001110 & +b100010110000101100011011001101 ) +b1101110010000000010100111100100 ( +b1100000110110101010111100001111 ' +b1001110110100100001001101001000 % +#290200 +b1011010101 + +#290300 +b10110110001010010110011001011001 & +b11011001010010010111101110011101 ) +b1101100010111100000001111001110 ( +b100010110000101100011011001101 ' +b1101111000011110000100111100100 % +#290304 +1! +1$ +#290600 +b1011010110 + +#290700 +b11110001101010000100100011111 & +b10000010111010010010101011111111 ) +b10110110001010010110011001011001 ( +b11011001010010010111101110011101 ' +b10011100010000000111001111001110 % +#291000 +b1011010111 + +#291100 +b1110001110101001010100010100110 & +b10001100001100100000110011010111 ) +b11110001101010000100100011111 ( +b10000010111010010010101011111111 ' +b11111101000110111010111001011001 % +#291104 +0! +0$ +#291400 +b1011011000 + +#291500 +b1100011010100101000100001011 & +b10111010101000011100101010110001 ) +b1110001110101001010100010100110 ( +b10001100001100100000110011010111 ' +b10110110011111011111000100011111 % +#291504 +1! +1$ +#291800 +b1011011001 + +#291900 +b11000100011001111011101111011111 & +b10000001000101011000011100101 ) +b1100011010100101000100001011 ( +b10111010101000011100101010110001 ' +b11010100100100011001100010100110 % +#292200 +b1011011010 + +#292300 +b101110100110111111000010100110 & +b1110000001001110001010110100000 ) +b11000100011001111011101111011111 ( +b10000001000101011000011100101 ' +b1011110111000100000100100001011 % +#292302 +0! +0# +#292304 +0$ +#292600 +b1011011011 + +#292700 +b11010010011110110011011111110011 & +b101011001110111100100000001000 ) +b101110100110111111000010100110 ( +b1110000001001110001010110100000 ' +b11111001101110010100001111011111 % +#292704 +1$ +#293000 +b1011011100 + +#293100 +b1101011010101100111111100111000 & +b10011010101110011011001000001001 ) +b11010010011110110011011111110011 ( +b101011001110111100100000001000 ' +b11110001000111101100000010100110 % +#293102 +1! +1# +#293104 +0! +0$ +#293400 +b1011011101 + +#293500 +b10010101000101111111100101010101 & +b10011110110110001000000111010010 ) +b1101011010101100111111100111000 ( +b10011010101110011011001000001001 ' +b1011110001001010111111110011 % +#293502 +0# +#293504 +1$ +#293800 +b1011011110 + +#293900 +b11010000111100011000011001110 & +b11000010011010010011100000000100 ) +b10010101000101111111100101010101 ( +b10011110110110001000000111010010 ' +b11011000101011111011111100111000 % +#293904 +0$ +#294200 +b1011011111 + +#294300 +b1101010011001010111000001011000 & +b1000000100100101111010001001110 ) +b11010000111100011000011001110 ( +b11000010011010010011100000000100 ' +b101010110111010101000101010101 % +#294600 +b1011100000 + +#294700 +b1010001101000000100010101110 & +b11100001010001111100110000001000 ) +b1101010011001010111000001011000 ( +b1000000100100101111010001001110 ' +b11101011100110000100000011001110 % +#295000 +b1011100001 + +#295100 +b10011100011101011111000101110000 & +b11011101110100111011110100100010 ) +b1010001101000000100010101110 ( +b11100001010001111100110000001000 ' +b1000001111001111011000001011000 % +#295400 +b1011100010 + +#295500 +b11101001010101100100100011011101 & +b1000011100011010100100101111010 ) +b10011100011101011111000101110000 ( +b11011101110100111011110100100010 ' +b10101010011100010111100010101110 % +#295504 +1$ +#295800 +b1011100011 + +#295900 +b10011010111000010101100001011100 & +b10101001001011001100001001111000 ) +b11101001010101100100100011011101 ( +b1000011100011010100100101111010 ' +b110011111111100111000101110000 % +#295904 +0$ +#296200 +b1011100100 + +#296300 +b11101000010001011011001011111111 & +b10110011000011100001010011100011 ) +b10011010111000010101100001011100 ( +b10101001001011001100001001111000 ' +b1011011000100001010000011011101 % +#296302 +1# +#296304 +1! +1$ +#296600 +b1011100101 + +#296700 +b10110111000001100000110110011111 & +b100111101101011001001010001101 ) +b11101000010001011011001011111111 ( +b10110011000011100001010011100011 ' +b10010000001000111011100001011100 % +#297000 +b1011100110 + +#297100 +b10110001011110110010100010101000 & +b1110100011011001011111010010000 ) +b10110111000001100000110110011111 ( +b100111101101011001001010001101 ' +b11000101110100100100101011111111 % +#297102 +0! +0# +#297104 +0$ +#297400 +b1011100111 + +#297500 +b10111101001111000111110111000000 & +b111010110100011110010111110000 ) +b10110001011110110010100010101000 ( +b1110100011011001011111010010000 ' +b10000111011010101111010110011111 % +#297800 +b1011101000 + +#297900 +b11000100111000111000111110011111 & +b10101100101101011100110011001001 ) +b10111101001111000111110111000000 ( +b111010110100011110010111110000 ' +b1101000001111100110100010101000 % +#297902 +1# +#297904 +1! +1$ +#298200 +b1011101001 + +#298300 +b101111001001001010110100011110 & +b1110001101010000000110010010110 ) +b11000100111000111000111110011111 ( +b10101100101101011100110011001001 ' +b1011110110100100111110111000000 % +#298302 +0! +0# +#298304 +0$ +#298600 +b1011101010 + +#298700 +b11110101101100100001001011100001 & +b101101111101011111111110110111 ) +b101111001001001010110100011110 ( +b1110001101010000000110010010110 ' +b11011000100111110111011110011111 % +#298702 +1# +#298704 +1! +1$ +#299000 +b1011101011 + +#299100 +b11001110000010010111010110110111 & +b11000100010011110111110001111101 ) +b11110101101100100001001011100001 ( +b101101111101011111111110110111 ' +b1010010011000101110100011110 % +#299400 +b1011101100 + +#299500 +b101001110000110001010111101101 & +b1001100100000110010001110000110 ) +b11001110000010010111010110110111 ( +b11000100010011110111110001111101 ' +b1100101001001010001101011100001 % +#299502 +0! +0# +#299800 +b1011101101 + +#299900 +b10011111100010101001110011100 & +b10010110110100000010100000111100 ) +b101001110000110001010111101101 ( +b1001100100000110010001110000110 ' +b10000101101001001100110110110111 % +#299904 +0$ +#300200 +b1011101110 + +#300300 +b1110111011001101100010000100000 & +b1000110001110111101110101110111 ) +b10011111100010101001110011100 ( +b10010110110100000010100000111100 ' +b110001011011000111110111101101 % +#300302 +1# +#300600 +b1011101111 + +#300700 +b11111001000101000100000100001011 & +b1100000111000001001001100111000 ) +b1110111011001101100010000100000 ( +b1000110001110111101110101110111 ' +b10011001011011011011001110011100 % +#300702 +0# +#300704 +1$ +#301000 +b1011110000 + +#301100 +b100000010110100110010011110100 & +b1100001010111001110101100111011 ) +b11111001000101000100000100001011 ( +b1100000111000001001001100111000 ' +b1000001010001111100010000100000 % +#301102 +1! +1# +#301104 +0! +0$ +#301400 +b1011110001 + +#301500 +b11111000000000100011100001110 & +b1000100010001110100101010010100 ) +b100000010110100110010011110100 ( +b1100001010111001110101100111011 ' +b1011011000111000001100100001011 % +#301502 +0# +#301800 +b1011110010 + +#301900 +b1101010000011011101100011100110 & +b10011001100000110111001011100110 ) +b11111000000000100011100001110 ( +b1000100010001110100101010010100 ' +b11110011011111011100010011110100 % +#302200 +b1011110011 + +#302300 +b1001010001010010000101101100 & +b10100011000000010110011011001 ) +b1101010000011011101100011100110 ( +b10011001100000110111001011100110 ' +b11101001110000011011100001110 % +#302302 +1# +#302600 +b1011110100 + +#302700 +b10001111000111010100010110010100 & +b10001011110100110111011011100000 ) +b1001010001010010000101101100 ( +b10100011000000010110011011001 ' +b100110010101110100011100110 % +#302702 +0# +#303000 +b1011110101 + +#303100 +b10111010011000001010101000100110 & +b10011010000011101011011001001010 ) +b10001111000111010100010110010100 ( +b10001011110100110111011011100000 ' +b100000010011100100000101101100 % +#303400 +b1011110110 + +#303500 +b11001111010000000110111011001111 & +b10101010000101001010111111111100 ) +b10111010011000001010101000100110 ( +b10011010000011101011011001001010 ' +b1100101001100011110010110010100 % +#303504 +1$ +#303800 +b1011110111 + +#303900 +b10011111100111011000001000110101 & +b100000000100110010110110001011 ) +b11001111010000000110111011001111 ( +b10101010000101001010111111111100 ' +b10111111001100011001101000100110 % +#303902 +1! +1# +#304200 +b1011111000 + +#304300 +b1011100000000111000011110110011 & +b10010000111110011011010101110101 ) +b10011111100111011000001000110101 ( +b100000000100110010110110001011 ' +b11001100001101100001011011001111 % +#304600 +b1011111001 + +#304700 +b10010110001110100011110001101010 & +b11100101110001011000011011001101 ) +b1011100000000111000011110110011 ( +b10010000111110011011010101110101 ' +b1110011100011000010101000110101 % +#304704 +0! +0$ +#305000 +b1011111010 + +#305100 +b10001011010010110101100100001111 & +b11001011001101010110000111000101 ) +b10010110001110100011110001101010 ( +b11100101110001011000011011001101 ' +b1000000001111100001111110110011 % +#305104 +1! +1$ +#305400 +b1011111011 + +#305500 +b101111011111110100000001101 & +b1000010011100010101010101000101 ) +b10001011010010110101100100001111 ( +b11001011001101010110000111000101 ' +b1000111110110010110110001101010 % +#305800 +b1011111100 + +#305900 +b10110100111001100011010010100100 & +b1100101101101001001101000111100 ) +b101111011111110100000001101 ( +b1000010011100010101010101000101 ' +b11010001100000110010000100001111 % +#305902 +0! +0# +#305904 +0$ +#306200 +b1011111101 + +#306300 +b110001000001010010000010011 & +b1111100111101011000010000000000 ) +b10110100111001100011010010100100 ( +b1100101101101001001101000111100 ' +b1111010101011111000000000001101 % +#306304 +1$ +#306600 +b1011111110 + +#306700 +b1000010010000101111010011010001 & +b11000111100001001011101110010001 ) +b110001000001010010000010011 ( +b1111100111101011000010000000000 ' +b10000101010000110001010010100100 % +#306702 +1! +1# +#307000 +b1011111111 + +#307100 +b10010001010001001000001101111010 & +b10010010010001111010110100011101 ) +b1000010010000101111010011010001 ( +b11000111100001001011101110010001 ' +b11000000000011110000010011 % +#307104 +0! +0$ +#307400 +b1100000000 + +#307500 +b100110010011110110110000100010 & +b1110011111111101111101011110000 ) +b10010001010001001000001101111010 ( +b10010010010001111010110100011101 ' +b1010101111001000111110011010001 % +#307502 +0# +#307800 +b1100000001 + +#307900 +b111100001001010001111110100011 & +b10001001110011110000001010110011 ) +b100110010011110110110000100010 ( +b1110011111111101111101011110000 ' +b10110101010111110101001101111010 % +#307902 +1# +#307904 +1! +1$ +#308200 +b1100000010 + +#308300 +b11100101111110110000111011100010 & +b10111000100010000100101110101101 ) +b111100001001010001111110100011 ( +b10001001110011110000001010110011 ' +b1011101001011100111110000100010 % +#308304 +0! +0$ +#308600 +b1100000011 + +#308700 +b111001000111101001010 & +b10100110100000101001001110100 ) +b11100101111110110000111011100010 ( +b10111000100010000100101110101101 ' +b10100110110000000011110100011 % +#308702 +0# +#309000 +b1100000100 + +#309100 +b11000111100000101111010001111101 & +b11111010001100110111100111000111 ) +b111001000111101001010 ( +b10100110100000101001001110100 ' +b111101100011000001111011100010 % +#309102 +1# +#309104 +1! +1$ +#309400 +b1100000101 + +#309500 +b10110101110101011110111010110100 & +b1010001010101110101110100001011 ) +b11000111100000101111010001111101 ( +b11111010001100110111100111000111 ' +b11100100011001101101111101001010 % +#309504 +0! +0$ +#309800 +b1100000110 + +#309900 +b100101110000110001101100000 & +b11010100010010010100010010001000 ) +b10110101110101011110111010110100 ( +b1010001010101110101110100001011 ' +b11010000001000010001110001111101 % +#309902 +0# +#310200 +b1100000111 + +#310300 +b11110101010101100010101011111110 & +b11101111111011001101100111111001 ) +b100101110000110001101100000 ( +b11010100010010010100010010001000 ' +b11010101000000100111010110100 % +#310302 +1# +#310600 +b1100001000 + +#310700 +b10101100110000011001000010101111 & +b1101011101001010101110111011000 ) +b11110101010101100010101011111110 ( +b11101111111011001101100111111001 ' +b11000111101000110110001101100000 % +#310702 +0# +#310704 +1$ +#311000 +b1100001001 + +#311100 +b1100001001011100110100001010110 & +b100101011010111011011111011111 ) +b10101100110000011001000010101111 ( +b1101011101001010101110111011000 ' +b1000100000000011101101011111110 % +#311102 +1! +1# +#311104 +0! +0$ +#311400 +b1100001010 + +#311500 +b10000000110000000001101001110101 & +b100000001001001011001000110110 ) +b1100001001011100110100001010110 ( +b100101011010111011011111011111 ' +b10100000010001001110100010101111 % +#311502 +0# +#311504 +1$ +#311800 +b1100001011 + +#311900 +b11101010000100110011101101111110 & +b11111000011011011001000011111101 ) +b10000000110000000001101001110101 ( +b100000001001001011001000110110 ' +b10010011011001101100001010110 % +#311902 +1! +1# +#311904 +0! +0$ +#312200 +b1100001100 + +#312300 +b1101111001100000010110100111011 & +b11101111101000111001000100001000 ) +b11101010000100110011101101111110 ( +b11111000011011011001000011111101 ' +b10000000000100111011001001110101 % +#312302 +0# +#312304 +1$ +#312600 +b1100001101 + +#312700 +b10001000111101011010111010000100 & +b11111011010011101011001001011000 ) +b1101111001100000010110100111011 ( +b11101111101000111001000100001000 ' +b1110011110010001100101101111110 % +#312704 +0$ +#313000 +b1100001110 + +#313100 +b10010101100110101110011011101000 & +b1111011001011010100010101000011 ) +b10001000111101011010111010000100 ( +b11111011010011101011001001011000 ' +b11101110010110011111010100111011 % +#313102 +1# +#313400 +b1100001111 + +#313500 +b111110011011000101011000000010 & +b11011110010000101101001110001 ) +b10010101100110101110011011101000 ( +b1111011001011010100010101000011 ' +b100101100000011000111010000100 % +#313800 +b1100010000 + +#313900 +b1101101100101010000010101110000 & +b101111011110100000101111010001 ) +b111110011011000101011000000010 ( +b11011110010000101101001110001 ' +b1000010101011011010011011101000 % +#314200 +b1100010001 + +#314300 +b1101000010101110101110110111111 & +b110100110101111100000101100001 ) +b1101101100101010000010101110000 ( +b101111011110100000101111010001 ' +b1011100110111000100011000000010 % +#314304 +1! +1$ +#314600 +b1100010010 + +#314700 +b1010010111101111101111011100011 & +b10010111100011001111011111100111 ) +b1101000010101110101110110111111 ( +b110100110101111100000101100001 ' +b11000101101111101000010101110000 % +#315000 +b1100010011 + +#315100 +b1010110010011100010100011011 & +b11011000101000011100000100010101 ) +b1010010111101111101111011100011 ( +b10010111100011001111011111100111 ' +b11010010101110101010010110111111 % +#315400 +b1100010100 + +#315500 +b10110111001101110000100001110 & +b11111010000010100011100001101010 ) +b1010110010011100010100011011 ( +b11011000101000011100000100010101 ' +b11101100000000001100011011100011 % +#315502 +0! +0# +#315504 +0$ +#315800 +b1100010101 + +#315900 +b10000100001111001100011110111011 & +b11000000100110010010001110101110 ) +b10110111001101110000100001110 ( +b11111010000010100011100001101010 ' +b1000100111000010001110100011011 % +#315904 +1$ +#316200 +b1100010110 + +#316300 +b1110100100010000110001001010 & +b101111010111100111011000111110 ) +b10000100001111001100011110111011 ( +b11000000100110010010001110101110 ' +b100001111011101001000100001110 % +#316304 +0$ +#316600 +b1100010111 + +#316700 +b1100101011111111100010000100010 & +b111000111001101101001100101 ) +b1110100100010000110001001010 ( +b101111010111100111011000111110 ' +b1100010000000010001111110111011 % +#316702 +1# +#317000 +b1100011000 + +#317100 +b111111001110010001100100001010 & +b10111001010011001010000100110101 ) +b1100101011111111100010000100010 ( +b111000111001101101001100101 ' +b10000110111100110101110001001010 % +#317400 +b1100011001 + +#317500 +b1000101110100101011001001001110 & +b11011110000101110010001101111010 ) +b111111001110010001100100001010 ( +b10111001010011001010000100110101 ' +b10011011010111101101010000100010 % +#317502 +0# +#317800 +b1100011010 + +#317900 +b1101110010011010101110110100010 & +b10011001010010111111011011001000 ) +b1000101110100101011001001001110 ( +b11011110000101110010001101111010 ' +b11110111111100010100100100001010 % +#318200 +b1100011011 + +#318300 +b11011001101101100010110001001010 & +b1001001001101010111111100010 ) +b1101110010011010101110110100010 ( +b10011001010010111111011011001000 ' +b11010000010000001100001001001110 % +#318600 +b1100011100 + +#318700 +b11011001010011001001000011100 & +b11111100011010111110000000010 ) +b11011001101101100010110001001010 ( +b1001001001101010111111100010 ' +b100101000000100110110100010 % +#319000 +b1100011101 + +#319100 +b1001111111100001101101111111011 & +b100111010011000111011100100100 ) +b11011001010011001001000011100 ( +b11111100011010111110000000010 ' +b1101000110101000111110001001010 % +#319104 +1$ +#319400 +b1100011110 + +#319500 +b1101100000001110001111101111000 & +b111011111010011101001101101011 ) +b1001111111100001101101111111011 ( +b100111010011000111011100100100 ' +b1010111101110010111001000011100 % +#319502 +1! +1# +#319504 +0! +0$ +#319800 +b1100011111 + +#319900 +b11100001010100001001100101100101 & +b101000101101101011000010001011 ) +b1101100000001110001111101111000 ( +b111011111010011101001101101011 ' +b11001001001011110000001111111011 % +#319904 +1! +1$ +#320200 +b1100100000 + +#320300 +b11000000111111110100110110000010 & +b10010100010101110111110010101111 ) +b11100001010100001001100101100101 ( +b101000101101101011000010001011 ' +b1010100111111001101111101111000 % +#320304 +0! +0$ +#320600 +b1100100001 + +#320700 +b111000101011101010111010000000 & +b1011101010100001000111111111110 ) +b11000000111111110100110110000010 ( +b10010100010101110111110010101111 ' +b1100101100110111011000101100101 % +#320702 +0# +#321000 +b1100100010 + +#321100 +b101101100110101101001100000111 & +b10111001100110001111100111110 ) +b111000101011101010111010000000 ( +b1011101010100001000111111111110 ' +b111010100100110101110110000010 % +#321104 +1$ +#321400 +b1100100011 + +#321500 +b10111001111110111110110010010110 & +b11110100011011001000011000110101 ) +b101101100110101101001100000111 ( +b10111001100110001111100111110 ' +b1001101110110101010111010000000 % +#321502 +1! +1# +#321504 +0! +0$ +#321800 +b1100100100 + +#321900 +b11001101010001110011000101000011 & +b110110101111101101111001111000 ) +b10111001111110111110110010010110 ( +b11110100011011001000011000110101 ' +b11111011000000101110101100000111 % +#321902 +0# +#321904 +1$ +#322200 +b1100100101 + +#322300 +b111011011100111001001110001011 & +b1011101100010100101101111110000 ) +b11001101010001110011000101000011 ( +b110110101111101101111001111000 ' +b1100110100111110101110010010110 % +#322600 +b1100100110 + +#322700 +b1111110001110011110010010110 & +b11111011111111101100011110000011 ) +b111011011100111001001110001011 ( +b1011101100010100101101111110000 ' +b11110100110011010010100101000011 % +#322702 +1! +1# +#322704 +0! +0$ +#323000 +b1100100111 + +#323100 +b10100111110101011001011100010110 & +b100111011011001101000101 ) +b1111110001110011110010010110 ( +b11111011111111101100011110000011 ' +b10100111111011111100101110001011 % +#323400 +b1100101000 + +#323500 +b10011100000011110010010011101001 & +b10101010000110101001111010110000 ) +b10100111110101011001011100010110 ( +b100111011011001101000101 ' +b110110001000111000110010010110 % +#323502 +0# +#323504 +1$ +#323800 +b1100101001 + +#323900 +b1111010100000111110111110111011 & +b1110001111001011010101110110110 ) +b10011100000011110010010011101001 ( +b10101010000110101001111010110000 ' +b1011011011010010011100010110 % +#324200 +b1100101010 + +#324300 +b11100001110111110101010101000010 & +b100000100100001000101000101 ) +b1111010100000111110111110111011 ( +b1110001111001011010101110110110 ' +b11100101001010000110110011101001 % +#324302 +1! +1# +#324304 +0! +0$ +#324600 +b1100101011 + +#324700 +b11011000101000000011010011111111 & +b10111101001110111110101011010100 ) +b11100001110111110101010101000010 ( +b100000100100001000101000101 ' +b1100101111111100011011110111011 % +#324702 +0# +#324704 +1$ +#325000 +b1100101100 + +#325100 +b1010111110000101011011100000101 & +b1001100101011001000111010010111 ) +b11011000101000000011010011111111 ( +b10111101001110111110101011010100 ' +b11011011101010100010101000010 % +#325102 +1! +1# +#325400 +b1100101101 + +#325500 +b11101100000100110101011111101001 & +b110101110011011001101001100011 ) +b1010111110000101011011100000101 ( +b1001100101011001000111010010111 ' +b11011001000001111100110011111111 % +#325800 +b1100101110 + +#325900 +b10000110110110110101100111001100 & +b11000100111000111010010011001010 ) +b11101100000100110101011111101001 ( +b110101110011011001101001100011 ' +b1000010011110101001111100000101 % +#325902 +0! +0# +#325904 +0$ +#326200 +b1100101111 + +#326300 +b10101001010001100111110111110011 & +b11011111100111001101010111110110 ) +b10000110110110110101100111001100 ( +b11000100111000111010010011001010 ' +b1110110101011000001111111101001 % +#326304 +1$ +#326600 +b1100110000 + +#326700 +b101100000100110111101100011011 & +b1110000010110100101100111100101 ) +b10101001010001100111110111110011 ( +b11011111100111001101010111110110 ' +b1011100000101010011100111001100 % +#326702 +1! +1# +#327000 +b1100110001 + +#327100 +b10001111001010100110011010111111 & +b10101000110010010100000001010 ) +b101100000100110111101100011011 ( +b1110000010110100101100111100101 ' +b10011010101010011110010111110011 % +#327102 +0! +0# +#327400 +b1100110010 + +#327500 +b10011010011000011111111011010101 & +b101101000111011001001111001110 ) +b10001111001010100110011010111111 ( +b10101000110010010100000001010 ' +b10110111110010111010001100011011 % +#327800 +b1100110011 + +#327900 +b10011010001001110100010100010110 & +b1000110111001001100110011101011 ) +b10011010011000011111111011010101 ( +b101101000111011001001111001110 ' +b11011100000111111001111010111111 % +#327902 +1! +1# +#327904 +0! +0$ +#328200 +b1100110100 + +#328300 +b11001110011001111111110010010000 & +b1011011011001010011011001111111 ) +b10011010001001110100010100010110 ( +b1000110111001001100110011101011 ' +b10010101100101110101011011010101 % +#328600 +b1100110101 + +#328700 +b1110001010110001110100010000 & +b10101110100001001111001000100011 ) +b11001110011001111111110010010000 ( +b1011011011001010011011001111111 ' +b10100000000011111111010100010110 % +#329000 +b1100110110 + +#329100 +b10001101111111011111010000011001 & +b1111100100011110000010001100100 ) +b1110001010110001110100010000 ( +b10101110100001001111001000100011 ' +b11110001100000110111110010010000 % +#329102 +0# +#329104 +1$ +#329400 +b1100110111 + +#329500 +b1010010111101000100010001101110 & +b100011000010001101001101111 ) +b10001101111111011111010000011001 ( +b1111100100011110000010001100100 ' +b1010110110000111001110100010000 % +#329502 +1! +1# +#329504 +0! +0$ +#329800 +b1100111000 + +#329900 +b110100011000111010110110011110 & +b1010110010111001100011001110000 ) +b1010010111101000100010001101110 ( +b100011000010001101001101111 ' +b1100010010111010011110000011001 % +#329902 +0# +#330200 +b1100111001 + +#330300 +b11001000111110101001111101011110 & +b111000110111010111101100011111 ) +b110100011000111010110110011110 ( +b1010110010111001100011001110000 ' +b11110000110101110011010001101110 % +#330302 +1# +#330600 +b1100111010 + +#330700 +b1010001000000111111001010110000 & +b1111000001001011010111101110111 ) +b11001000111110101001111101011110 ( +b111000110111010111101100011111 ' +b101001000011110101110110011110 % +#331000 +b1100111011 + +#331100 +b10011110110010010000000101100111 & +b10000010110101010111111000001100 ) +b1010001000000111111001010110000 ( +b1111000001001011010111101110111 ' +b11100000000000110111101011110 % +#331102 +0# +#331104 +1$ +#331400 +b1100111100 + +#331500 +b10000101000110101010011001100100 & +b11001011110000100101101111011110 ) +b10011110110010010000000101100111 ( +b10000010110101010111111000001100 ' +b1001110100101100111001010110000 % +#331504 +0$ +#331800 +b1100111101 + +#331900 +b1111010000000100110001100001001 & +b10101100000101101000110111010101 ) +b10000101000110101010011001100100 ( +b11001011110000100101101111011110 ' +b11010110110000100011100101100111 % +#331902 +1# +#331904 +1! +1$ +#332200 +b1100111110 + +#332300 +b11110011101111100110000010100110 & +b10100011110001111101101100111100 ) +b1111010000000100110001100001001 ( +b10101100000101101000110111010101 ' +b1010000001010011000011001100100 % +#332302 +0! +0# +#332304 +0$ +#332600 +b1100111111 + +#332700 +b10000010101011010000111101111000 & +b11101011110111100010001100100001 ) +b11110011101111100110000010100110 ( +b10100011110001111101101100111100 ' +b1101001000110100010101100001001 % +#332702 +1# +#333000 +b1101000000 + +#333100 +b11111100101011101001000111001 & +b11111001011100011101000101010 ) +b10000010101011010000111101111000 ( +b11101011110111100010001100100001 ' +b101110110101000010100110 % +#333102 +0# +#333104 +1$ +#333400 +b1101000001 + +#333500 +b11101111011101000010010011011111 & +b101010010000011110111000001 ) +b11111100101011101001000111001 ( +b11111001011100011101000101010 ' +b11101010110101101100111101111000 % +#333502 +1! +1# +#333800 +b1101000010 + +#333900 +b110000010100001010001001101110 & +b10000001111001011010110001110001 ) +b11101111011101000010010011011111 ( +b101010010000011110111000001 ' +b10110001000001000001101000111001 % +#333904 +0! +0$ +#334200 +b1101000011 + +#334300 +b111010101011101011011100000101 & +b1110100101100100011011110010000 ) +b110000010100001010001001101110 ( +b10000001111001011010110001110001 ' +b1001110010100101101110011011111 % +#334302 +0# +#334304 +1$ +#334600 +b1101000100 + +#334700 +b100011011100101001000101101001 & +b10010110100001000001001000000101 ) +b111010101011101011011100000101 ( +b1110100101100100011011110010000 ' +b10110101010000111101001001101110 % +#334702 +1! +1# +#335000 +b1101000101 + +#335100 +b10001001110000001011110101101001 & +b11000110100110010010110000100000 ) +b100011011100101001000101101001 ( +b10010110100001000001001000000101 ' +b1001111000101101001111100000101 % +#335102 +0! +0# +#335400 +b1101000110 + +#335500 +b10001000001011001010010100110010 & +b111111011000101000001001101110 ) +b10001001110000001011110101101001 ( +b11000110100110010010110000100000 ' +b10110111111110011101100101101001 % +#335504 +0$ +#335800 +b1101000111 + +#335900 +b1011011111001010111001011100 & +b10000111110110110110000000111011 ) +b10001000001011001010010100110010 ( +b111111011000101000001001101110 ' +b10001100001010111111010101101001 % +#335902 +1# +#336200 +b1101001000 + +#336300 +b11001101110011100001100010101100 & +b100000001001100010110010101111 ) +b1011011111001010111001011100 ( +b10000111110110110110000000111011 ' +b11101101000001010011010100110010 % +#336600 +b1101001001 + +#336700 +b1111111101010000011000110101101 & +b10010001010010000110001110010110 ) +b11001101110011100001100010101100 ( +b100000001001100010110010101111 ' +b11101110000011100100111001011100 % +#336702 +0# +#336704 +1$ +#337000 +b1101001010 + +#337100 +b11010011010011000101011110101000 & +b1101110111110100010100110100011 ) +b1111111101010000011000110101101 ( +b10010001010010000110001110010110 ' +b10111101000010110111100010101100 % +#337102 +1! +1# +#337104 +0! +0$ +#337400 +b1101001011 + +#337500 +b111111110100011011011001001001 & +b1110010101100101010000100 ) +b11010011010011000101011110101000 ( +b1101110111110100010100110100011 ' +b111110001001010101100110101101 % +#337502 +0# +#337504 +1$ +#337800 +b1101001100 + +#337900 +b110001100110011100000110000101 & +b10000000110110010011011100100001 ) +b111111110100011011011001001001 ( +b1110010101100101010000100 ' +b10110001111100010001011110101000 % +#337902 +1! +1# +#338200 +b1101001101 + +#338300 +b11010100100000010010001010100101 & +b1100110010100001011001111011000 ) +b110001100110011100000110000101 ( +b10000000110110010011011100100001 ' +b10110010011000111111111001001001 % +#338302 +0! +0# +#338600 +b1101001110 + +#338700 +b1100010110000100000100011110010 & +b10011101101010000110011100101011 ) +b11010100100000010010001010100101 ( +b1100110010100001011001111011000 ' +b11111111100101011110100110000101 % +#338702 +1! +1# +#338704 +0! +0$ +#339000 +b1101001111 + +#339100 +b1011100101001100011011110010011 & +b10000001111011111011100100000001 ) +b1100010110000100000100011110010 ( +b10011101101010000110011100101011 ' +b11011101100101000000101010100101 % +#339104 +1! +1$ +#339400 +b1101010000 + +#339500 +b11110000000111101001111100100100 & +b10000010111010011001001000010011 ) +b1011100101001100011011110010011 ( +b10000001111011111011100100000001 ' +b1110010100001011001100011110010 % +#339504 +0! +0$ +#339800 +b1101010001 + +#339900 +b1100001101100101010001100110011 & +b1100110001010001011110010111 ) +b11110000000111101001111100100100 ( +b10000010111010011001001000010011 ' +b1101101000110101010111110010011 % +#339904 +1! +1$ +#340200 +b1101010010 + +#340300 +b10101011111001101001000101100111 & +b10101111000001011101110000011100 ) +b1100001101100101010001100110011 ( +b1100110001010001011110010111 ' +b100111001111011111100100100 % +#340302 +0! +0# +#340600 +b1101010011 + +#340700 +b1111011111001001101001111011100 & +b10001111101110110101001000100011 ) +b10101011111001101001000101100111 ( +b10101111000001011101110000011100 ' +b11110100101010110011101100110011 % +#340702 +1! +1# +#340704 +0! +0$ +#341000 +b1101010100 + +#341100 +b1100101011100101101111000011110 & +b11111010100000000000010110000000 ) +b1111011111001001101001111011100 ( +b10001111101110110101001000100011 ' +b10011111011011011010100101100111 % +#341102 +0# +#341400 +b1101010101 + +#341500 +b1101101001010101111110100110111 & +b110000000011011011001011011001 ) +b1100101011100101101111000011110 ( +b11111010100000000000010110000000 ' +b1011101011110100011001111011100 % +#341502 +1# +#341504 +1! +1$ +#341800 +b1101010110 + +#341900 +b1100100000011011110011111001000 & +b10010111011111000101100100010111 ) +b1101101001010101111110100110111 ( +b110000000011011011001011011001 ' +b11110011100000100010111000011110 % +#341904 +0! +0$ +#342200 +b1101010111 + +#342300 +b11001100101000101110100001 & +b111001110010110000101011101010 ) +b1100100000011011110011111001000 ( +b10010111011111000101100100010111 ' +b111010110000110100010100110111 % +#342302 +0# +#342304 +1$ +#342600 +b1101011000 + +#342700 +b1111101110010110100010010000000 & +b1110110111100111101111000110001 ) +b11001100101000101110100001 ( +b111001110010110000101011101010 ' +b1011001100111010011111001000 % +#342702 +1! +1# +#342704 +0! +0$ +#343000 +b1101011001 + +#343100 +b10001011110011100110001000101101 & +b11100001101101000110110001001 ) +b1111101110010110100010010000000 ( +b1110110111100111101111000110001 ' +b10010111011011111000001110100001 % +#343104 +1! +1$ +#343400 +b1101011010 + +#343500 +b1000100111011001000000010010011 & +b1100011001001000010011100110011 ) +b10001011110011100110001000101101 ( +b11100001101101000110110001001 ' +b100111111011110100010010000000 % +#343800 +b1101011011 + +#343900 +b10100001110011101111111100110 & +b11101100000111100001011101000010 ) +b1000100111011001000000010010011 ( +b1100011001001000010011100110011 ' +b11111000110111110000101000101101 % +#343902 +0! +0# +#343904 +0$ +#344200 +b1101011100 + +#344300 +b1110110101011101000010110101010 & +b1010110011001100111111111101101 ) +b10100001110011101111111100110 ( +b11101100000111100001011101000010 ' +b100000111010000001100010010011 % +#344302 +1# +#344600 +b1101011101 + +#344700 +b10110000000010100000110001110001 & +b1101010000101100010100000111010 ) +b1110110101011101000010110101010 ( +b1010110011001100111111111101101 ' +b11011010110001101110111111100110 % +#344702 +0# +#344704 +1$ +#345000 +b1101011110 + +#345100 +b11010111011101111101100001001011 & +b11010101111101101001010010001010 ) +b10110000000010100000110001110001 ( +b1101010000101100010100000111010 ' +b10100000111101010110101010 % +#345400 +b1101011111 + +#345500 +b11101100011100101000000100001101 & +b1100111110110110110101100111 ) +b11010111011101111101100001001011 ( +b11010101111101101001010010001010 ' +b11100000011010011000010001110001 % +#345502 +1! +1# +#345800 +b1101100000 + +#345900 +b11100100100111010010111010101110 & +b10001101010000010000101011001101 ) +b11101100011100101000000100001101 ( +b1100111110110110110101100111 ' +b1101001101101011000000001001011 % +#345904 +0! +0$ +#346200 +b1101100001 + +#346300 +b1001011110110000110001010010000 & +b110011110110101111011100001111 ) +b11100100100111010010111010101110 ( +b10001101010000010000101011001101 ' +b1111000011110101110100100001101 % +#346600 +b1101100010 + +#346700 +b11000011101011111011000101111101 & +b11001110010010100001111001000100 ) +b1001011110110000110001010010000 ( +b110011110110101111011100001111 ' +b1101111010000101111010101110 % +#346702 +0# +#346704 +1$ +#347000 +b1101100011 + +#347100 +b10101111011011010110111000011111 & +b100111001010010100010010001000 ) +b11000011101011111011000101111101 ( +b11001110010010100001111001000100 ' +b10001000110011001110001010010000 % +#347400 +b1101100100 + +#347500 +b10001111110100011000011010000101 & +b110001010010111111110110001000 ) +b10101111011011010110111000011111 ( +b100111001010010100010010001000 ' +b10111110001001000101100101111101 % +#347800 +b1101100101 + +#347900 +b100110011010000000100100101100 & +b11100010101100011001111011110011 ) +b10001111110100011000011010000101 ( +b110001010010111111110110001000 ' +b11000100000111011001011000011111 % +#347902 +1! +1# +#347904 +0! +0$ +#348200 +b1101100110 + +#348300 +b1001011010001110101010111101011 & +b1001000101000010001011111010100 ) +b100110011010000000100100101100 ( +b11100010101100011001111011110011 ' +b11111001011010111010000101 % +#348302 +0# +#348304 +1$ +#348600 +b1101100111 + +#348700 +b1000011001010000101000010011110 & +b100101011011110001110001110110 ) +b1001011010001110101010111101011 ( +b1001000101000010001011111010100 ' +b1100110001000010110100100101100 % +#348704 +0$ +#349000 +b1101101000 + +#349100 +b1110010111011100001010100010000 & +b11011101111111000010011000 ) +b1000011001010000101000010011110 ( +b100101011011110001110001110110 ' +b1110001111010000000110111101011 % +#349400 +b1101101001 + +#349500 +b101110100100100011001001001110 & +b101111001111110011101110010111 ) +b1110010111011100001010100010000 ( +b11011101111111000010011000 ' +b1101011001010000010011110 % +#349502 +1# +#349800 +b1101101010 + +#349900 +b10010000100110010011010111101010 & +b10010010110111011111010000110100 ) +b101110100100100011001001001110 ( +b101111001111110011101110010111 ' +b10010001101001010100010000 % +#349902 +0# +#350200 +b1101101011 + +#350300 +b11111001000100110000110100110100 & +b1000110101011000100011111101101 ) +b10010000100110010011010111101010 ( +b10010010110111011111010000110100 ' +b10111111000000000100001001001110 % +#350302 +1# +#350600 +b1101101100 + +#350700 +b11011101011111010111100101111011 & +b10000100000100100011101001110110 ) +b11111001000100110000110100110100 ( +b1000110101011000100011111101101 ' +b1011001001101100110010111101010 % +#350702 +0# +#350704 +1$ +#351000 +b1101101101 + +#351100 +b10011000110100010001011010110110 & +b11111001110010101101111000010110 ) +b11011101011111010111100101111011 ( +b10000100000100100011101001110110 ' +b1100001011110101010110100110100 % +#351104 +0$ +#351400 +b1101101110 + +#351500 +b10111011100001010100100000101010 & +b10001101000001010100111001010000 ) +b10011000110100010001011010110110 ( +b11111001110010101101111000010110 ' +b110110101101101010000101111011 % +#351800 +b1101101111 + +#351900 +b100011001001100101110110000 & +b10100000100000000101100100010 ) +b10111011100001010100100000101010 ( +b10001101000001010100111001010000 ' +b10000011001001010011010110110 % +#352200 +b1101110000 + +#352300 +b110010111000011011101011100110 & +b10100011101101000111001010100010 ) +b100011001001100101110110000 ( +b10100000100000000101100100010 ' +b10010001110001000001100000101010 % +#352600 +b1101110001 + +#352700 +b10000100001001111000100010111111 & +b10100110001111001110111010000011 ) +b110010111000011011101011100110 ( +b10100011101101000111001010100010 ' +b100010001110010100101110110000 % +#352702 +1# +#352704 +1! +1$ +#353000 +b1101110010 + +#353100 +b10111011000011110111011100010111 & +b10000100000001101101101111111011 ) +b10000100001001111000100010111111 ( +b10100110001111001110111010000011 ' +b111111001101101000101011100110 % +#353400 +b1101110011 + +#353500 +b1000010110111001101001110001100 & +b11111010000001101101111000000011 ) +b10111011000011110111011100010111 ( +b10000100000001101101101111111011 ' +b10111000011000100111000010111111 % +#353504 +0! +0$ +#353800 +b1101110100 + +#353900 +b110000110000000110011111100001 & +b11110000101101110000000100101111 ) +b1000010110111001101001110001100 ( +b11111010000001101101111000000011 ' +b11000000101101111100111100010111 % +#353904 +1! +1$ +#354200 +b1101110101 + +#354300 +b1011000000111101011110110011100 & +b11111100111110100101000100111100 ) +b110000110000000110011111100001 ( +b11110000101101110000000100101111 ' +b10100100010000001011001110001100 % +#354302 +0! +0# +#354304 +0$ +#354600 +b1101110110 + +#354700 +b100011001001001110001101011010 & +b10000111010000111000111001001 ) +b1011000000111101011110110011100 ( +b11111100111110100101000100111100 ' +b110011111111110110111111100001 % +#354702 +1# +#355000 +b1101110111 + +#355100 +b10100000001001101000101111011101 & +b1101011110010010010110110011 ) +b100011001001001110001101011010 ( +b10000111010000111000111001001 ' +b10101101111100100101110110011100 % +#355104 +1! +1$ +#355400 +b1101111000 + +#355500 +b11110111001010011101001100100010 & +b11110011000100111100000000101001 ) +b10100000001001101000101111011101 ( +b1101011110010010010110110011 ' +b100001111100011001101011010 % +#355504 +0! +0$ +#355800 +b1101111001 + +#355900 +b10100111010101010011100100000000 & +b110011101110010010010011001001 ) +b11110111001010011101001100100010 ( +b11110011000100111100000000101001 ' +b10010100011110000110001111011101 % +#356200 +b1101111010 + +#356300 +b1110011001000111101110111101111 & +b11001010001010101011011101001011 ) +b10100111010101010011100100000000 ( +b110011101110010010010011001001 ' +b10111001101100001100001100100010 % +#356304 +1! +1$ +#356600 +b1101111011 + +#356700 +b10000111110101011001010100111111 & +b10001001010001100010000000101110 ) +b1110011001000111101110111101111 ( +b11001010001010101011011101001011 ' +b1110100111010011100100000000 % +#356702 +0! +0# +#357000 +b1101111100 + +#357100 +b1110101011110111001000000110000 & +b11000110110101111101001100001 ) +b10000111110101011001010100111111 ( +b10001001010001100010000000101110 ' +b1101101110011001010010111101111 % +#357102 +1! +1# +#357104 +0! +0$ +#357400 +b1101111101 + +#357500 +b11100110110100111000000100000011 & +b11001101100001001000100111100001 ) +b1110101011110111001000000110000 ( +b11000110110101111101001100001 ' +b101011011111000110110100111111 % +#357504 +1! +1$ +#357800 +b1101111110 + +#357900 +b10000000010001101000100101001000 & +b101001000101010110011001001010 ) +b11100110110100111000000100000011 ( +b11001101100001001000100111100001 ' +b10101001111110100001000000110000 % +#357902 +0! +0# +#357904 +0$ +#358200 +b1101111111 + +#358300 +b10011110001011001110010010110 & +b1101001011001001101001100100000 ) +b10000000010001101000100101001000 ( +b101001000101010110011001001010 ' +b1111010110110111001100100000011 % +#358600 +b1110000000 + +#358700 +b100101110110000101100000111111 & +b10010001011000001000111110010010 ) +b10011110001011001110010010110 ( +b1101001011001001101001100100000 ' +b10110100000011001100100101001000 % +#358704 +1$ +#359000 +b1110000001 + +#359100 +b1010101011101000111001010000000 & +b1101010011010100111001001110111 ) +b100101110110000101100000111111 ( +b10010001011000001000111110010010 ' +b111111001000010010110010010110 % +#359102 +1! +1# +#359104 +0! +0$ +#359400 +b1110000010 + +#359500 +b100111000000111101101000100011 & +b11000000111111010111101110100011 ) +b1010101011101000111001010000000 ( +b1101010011010100111001001110111 ' +b11100111000110011010000000111111 % +#359504 +1! +1$ +#359800 +b1110000011 + +#359900 +b11101000110101010111110001010100 & +b11110110000111110110101111110 ) +b100111000000111101101000100011 ( +b11000000111111010111101110100011 ' +b11110110111000000111001010000000 % +#359902 +0! +0# +#359904 +0$ +#360200 +b1110000100 + +#360300 +b11111010001101010010101000010100 & +b11000011110111100010001010001110 ) +b11101000110101010111110001010100 ( +b11110110000111110110101111110 ' +b111001110100101100001000100011 % +#360600 +b1110000101 + +#360700 +b10111000111010000111010011001010 & +b11111011100111001000000000110001 ) +b11111010001101010010101000010100 ( +b11000011110111100010001010001110 ' +b1000011001101111101110001010100 % +#360702 +1# +#361000 +b1110000110 + +#361100 +b11011001001001100000010111010111 & +b10001010000100001111101100001011 ) +b10111000111010000111010011001010 ( +b11111011100111001000000000110001 ' +b1010011011001011000101000010100 % +#361104 +1! +1$ +#361400 +b1110000111 + +#361500 +b111101000100011111100111110000 & +b11000110101001001000101111001010 ) +b11011001001001100000010111010111 ( +b10001010000100001111101100001011 ' +b11111011010011100010010011001010 % +#361502 +0! +0# +#361504 +0$ +#361800 +b1110001000 + +#361900 +b11011001001101010010011010001010 & +b110000110101001001010111111010 ) +b111101000100011111100111110000 ( +b11000110101001001000101111001010 ' +b11101001000010001011110111010111 % +#362200 +b1110001001 + +#362300 +b10001001010000011011110001010001 & +b111011001011010001110010111101 ) +b11011001001101010010011010001010 ( +b110000110101001001010111111010 ' +b10110010110111100111100111110000 % +#362302 +1# +#362304 +1! +1$ +#362600 +b1110001010 + +#362700 +b1101101110111111110011110001111 & +b11101101011101001001111000110 ) +b10001001010000011011110001010001 ( +b111011001011010001110010111101 ' +b1110000000000010111011010001010 % +#362702 +0! +0# +#363000 +b1110001011 + +#363100 +b10111010011000110100011011010000 & +b111110010001001101011001111101 ) +b1101101110111111110011110001111 ( +b11101101011101001001111000110 ' +b10000100101000110011010001010001 % +#363102 +1! +1# +#363104 +0! +0$ +#363400 +b1110001100 + +#363500 +b1000001010010111010010010001110 & +b11010011001110101100001011111001 ) +b10111010011000110100011011010000 ( +b111110010001001101011001111101 ' +b10010010111000111001111110001111 % +#363800 +b1110001101 + +#363900 +b11111001010100011111110111000110 & +b1011001101001000110010111100100 ) +b1000001010010111010010010001110 ( +b11010011001110101100001011111001 ' +b10100000010101011100011011010000 % +#363902 +0# +#364200 +b1110001110 + +#364300 +b11100000000010100110000111001010 & +b11111100011110011100010100011111 ) +b11111001010100011111110111000110 ( +b1011001101001000110010111100100 ' +b11100011011111101010010001110 % +#364302 +1# +#364600 +b1110001111 + +#364700 +b11101100001100101101001000111110 & +b10011010111110111011001101101010 ) +b11100000000010100110000111001010 ( +b11111100011110011100010100011111 ' +b1110110101111111100110111000110 % +#364702 +0# +#365000 +b1110010000 + +#365100 +b1101101111001101000110110101011 & +b11011110010100011010001110011010 ) +b11101100001100101101001000111110 ( +b10011010111110111011001101101010 ' +b10110011000001000011000111001010 % +#365104 +1$ +#365400 +b1110010001 + +#365500 +b1010000000110001000011111011010 & +b101010110000010000001110011110 ) +b1101101111001101000110110101011 ( +b11011110010100011010001110011010 ' +b1111010101000110010001000111110 % +#365504 +0$ +#365800 +b1110010010 + +#365900 +b1011010110101001110110100101110 & +b11000001101011001100110000 ) +b1010000000110001000011111011010 ( +b101010110000010000001110011110 ' +b1011001100010111101010110101011 % +#366200 +b1110010011 + +#366300 +b11101100100110011011011010010001 & +b1111000001010111100100000011001 ) +b1011010110101001110110100101110 ( +b11000001101011001100110000 ' +b10010100001001100101011111011010 % +#366302 +1# +#366304 +1! +1$ +#366600 +b1110010100 + +#366700 +b100111011100000011110011110100 & +b11011010001100000000011100000001 ) +b11101100100110011011011010010001 ( +b1111000001010111100100000011001 ' +b11111101101111011001110100101110 % +#366704 +0! +0$ +#367000 +b1110010101 + +#367100 +b100000001100010100000010001011 & +b1001111010101001100000011 ) +b100111011100000011110011110100 ( +b11011010001100000000011100000001 ' +b100001001011010011111010010001 % +#367104 +1! +1$ +#367400 +b1110010110 + +#367500 +b11011100010100100100011110100111 & +b1111010011000110100001110000011 ) +b100000001100010100000010001011 ( +b1001111010101001100000011 ' +b10100110100101111001110011110100 % +#367800 +b1110010111 + +#367900 +b10011101100000111001100100010101 & +b110111000111001011001001100101 ) +b11011100010100100100011110100111 ( +b1111010011000110100001110000011 ' +b10101010001101010001100010001011 % +#368200 +b1110011000 + +#368300 +b10110011101111011010000100010110 & +b11111101100111001010111001111101 ) +b10011101100000111001100100010101 ( +b110111000111001011001001100101 ' +b1001110011011110111111110100111 % +#368304 +0! +0$ +#368600 +b1110011001 + +#368700 +b11100000001010101101010010000110 & +b1100001111000001010001010011110 ) +b10110011101111011010000100010110 ( +b11111101100111001010111001111101 ' +b10000001010010110011000100010101 % +#368702 +0# +#369000 +b1110011010 + +#369100 +b10100110001101101101101010100100 & +b11111000110111010110000110111000 ) +b11100000001010101101010010000110 ( +b1100001111000001010001010011110 ' +b1011110101101010001000100010110 % +#369400 +b1110011011 + +#369500 +b1110100100111100001101010011000 & +b11000010101001100110100010101110 ) +b10100110001101101101101010100100 ( +b11111000110111010110000110111000 ' +b10110110100011101110010010000110 % +#369800 +b1110011100 + +#369900 +b1110111101011100111000010100111 & +b1100111010111010110010100010010 ) +b1110100100111100001101010011000 ( +b11000010101001100110100010101110 ' +b10000111000111111101010100100 % +#369904 +1$ +#370200 +b1110011101 + +#370300 +b10011100100000010101110001 & +b10000110101111001000010111100100 ) +b1110111101011100111000010100111 ( +b1100111010111010110010100010010 ' +b10000100010010101101101010011000 % +#370600 +b1110011110 + +#370700 +b10001010101001001111011111100110 & +b10001110100010111000010111011000 ) +b10011100100000010101110001 ( +b10000110101111001000010111100100 ' +b100001010110100100010100111 % +#370704 +0$ +#371000 +b1110011111 + +#371100 +b1111010100111100001100100000101 & +b11101000010101011101000011110011 ) +b10001010101001001111011111100110 ( +b10001110100010111000010111011000 ' +b10010010010110011000110101110001 % +#371102 +1# +#371104 +1! +1$ +#371400 +b1110100000 + +#371500 +b101010111110011111111110111 & +b10101000111010011111011011001011 ) +b1111010100111100001100100000101 ( +b11101000010101011101000011110011 ' +b10101101000110111100011111100110 % +#371800 +b1110100001 + +#371900 +b11001001000101111100101010101010 & +b1000011110010111010010111100111 ) +b101010111110011111111110111 ( +b10101000111010011111011011001011 ' +b10001010010101100011000100000101 % +#371904 +0! +0$ +#372200 +b1110100010 + +#372300 +b11010010111100110000000001001000 & +b101110101011110010001011101101 ) +b11001001000101111100101010101010 ( +b1000011110010111010010111100111 ' +b11111100101000001000011111110111 % +#372600 +b1110100011 + +#372700 +b10111011001111001010001011011101 & +b11001100000010010110001101101100 ) +b11010010111100110000000001001000 ( +b101110101011110010001011101101 ' +b1110111010000101001101010101010 % +#372702 +0# +#372704 +1$ +#373000 +b1110100100 + +#373100 +b10100110011010001110101110001111 & +b11101100110100110100011100011101 ) +b10111011001111001010001011011101 ( +b11001100000010010110001101101100 ' +b1001010111100010100000001001000 % +#373102 +1! +1# +#373400 +b1110100101 + +#373500 +b1111111100010011000101010000101 & +b100001111111011110111000101101 ) +b10100110011010001110101110001111 ( +b11101100110100110100011100011101 ' +b1011110001010100100101011011101 % +#373800 +b1110100110 + +#373900 +b11101000110000010110011111111000 & +b1001000101001100000111000110 ) +b1111111100010011000101010000101 ( +b100001111111011110111000101101 ' +b11100001001101001001001110001111 % +#373902 +0! +0# +#373904 +0$ +#374200 +b1110100111 + +#374300 +b10101011011010000101110111100 & +b100110100000110111000001001011 ) +b11101000110000010110011111111000 ( +b1001000101001100000111000110 ' +b110011110111011010001010000101 % +#374302 +1# +#374600 +b1110101000 + +#374700 +b1011001110001011010110000100010 & +b10111010110110001110001000100110 ) +b10101011011010000101110111100 ( +b100110100000110111000001001011 ' +b11100011111111101010011111111000 % +#374702 +0# +#375000 +b1110101001 + +#375100 +b11001101101000101100110110001 & +b1100100111110011000111001111001 ) +b1011001110001011010110000100010 ( +b10111010110110001110001000100110 ' +b1111101001100001110101110111100 % +#375102 +1# +#375104 +1! +1$ +#375400 +b1110101010 + +#375500 +b10000110100000101010101101101 & +b1100100000000000100000101110011 ) +b11001101101000101100110110001 ( +b1100100111110011000111001111001 ' +b1110100101001001011110000100010 % +#375800 +b1110101011 + +#375900 +b11001100000010010000110110 & +b10111000111100101001101101001000 ) +b10000110100000101010101101101 ( +b1100100000000000100000101110011 ' +b10111011011110011101000110110001 % +#375902 +0! +0# +#375904 +0$ +#376200 +b1110101100 + +#376300 +b11110111101101001011110000000001 & +b1100101010111011111011011111010 ) +b11001100000010010000110110 ( +b10111000111100101001101101001000 ' +b10010010011110110011110101101101 % +#376304 +1$ +#376600 +b1110101101 + +#376700 +b1011001001000111100111110110000 & +b11011011101100000101000101100100 ) +b11110111101101001011110000000001 ( +b1100101010111011111011011111010 ' +b10000010000100011001010000110110 % +#376704 +0$ +#377000 +b1110101110 + +#377100 +b10000001010001011111001010010101 & +b11010011010000110000100001001000 ) +b1011001001000111100111110110000 ( +b11011011101100000101000101100100 ' +b1010010010101001011010000000001 % +#377104 +1$ +#377400 +b1110101111 + +#377500 +b10011111001111101010001001010011 & +b11011000001001111010100010101000 ) +b10000001010001011111001010010101 ( +b11010011010000110000100001001000 ' +b1000111010111100100111110110000 % +#377800 +b1110110000 + +#377900 +b11111010100010110111100111100101 & +b1010100111101001111100010110100 ) +b10011111001111101010001001010011 ( +b11011000001001111010100010101000 ' +b10101110110100010101101010010101 % +#378200 +b1110110001 + +#378300 +b1110101010010101111100101111100 & +b11111000011001110110011110100 ) +b11111010100010110111100111100101 ( +b1010100111101001111100010110100 ' +b1101010001011000011101001010011 % +#378304 +0$ +#378600 +b1110110010 + +#378700 +b100111011011011001101101011100 & +b10000110100010001001111000111001 ) +b1110101010010101111100101111100 ( +b11111000011001110110011110100 ' +b10100001010001000101000111100101 % +#378702 +1# +#379000 +b1110110011 + +#379100 +b1111101110111010010101110000011 & +b1011111011111101011100000001001 ) +b100111011011011001101101011100 ( +b10000110100010001001111000111001 ' +b100010100000010001100101111100 % +#379104 +1! +1$ +#379400 +b1110110100 + +#379500 +b11110100100110101101000010011100 & +b10111111011001100000101101010111 ) +b1111101110111010010101110000011 ( +b1011111011111101011100000001001 ' +b1001011101101110111101101011100 % +#379504 +0! +0$ +#379800 +b1110110101 + +#379900 +b11001010100110110011100110010111 & +b1011110100011101000000011110110 ) +b11110100100110101101000010011100 ( +b10111111011001100000101101010111 ' +b10010100100000010011001110000011 % +#379902 +0# +#379904 +1$ +#380200 +b1110110110 + +#380300 +b1100111000101001000100100101001 & +b1000101001010001010111100100000 ) +b11001010100110110011100110010111 ( +b1011110100011101000000011110110 ' +b100010000111100011000010011100 % +#380600 +b1110110111 + +#380700 +b1011110111100111110001110101101 & +b1001101101101110011110000001101 ) +b1100111000101001000100100101001 ( +b1000101001010001010111100100000 ' +b10011010101111000000110010111 % +#380702 +1! +1# +#381000 +b1110111000 + +#381100 +b10011101001111001000000111000000 & +b1011110101000100001011011111100 ) +b1011110111100111110001110101101 ( +b1001101101101110011110000001101 ' +b11000011010111011100000100101001 % +#381102 +0! +0# +#381104 +0$ +#381400 +b1110111001 + +#381500 +b10101000101100001111100100101011 & +b1101001100111111001000100111110 ) +b10011101001111001000000111000000 ( +b1011110101000100001011011111100 ' +b11000001111011101000101110101101 % +#381504 +1$ +#381800 +b1110111010 + +#381900 +b10011111101000001010000010101011 & +b11100110111010110000111100110111 ) +b10101000101100001111100100101011 ( +b1101001100111111001000100111110 ' +b1111001001100101000000111000000 % +#381902 +1! +1# +#382200 +b1110111011 + +#382300 +b100101011101010001110111001110 & +b1010001000111100010000000000 ) +b10011111101000001010000010101011 ( +b11100110111010110000111100110111 ' +b101111011110011010000100101011 % +#382302 +0! +0# +#382304 +0$ +#382600 +b1110111100 + +#382700 +b1011001100111001011011000 & +b10011011010110010011110011100000 ) +b100101011101010001110111001110 ( +b1010001000111100010000000000 ' +b10011010101001011111100010101011 % +#383000 +b1110111101 + +#383100 +b10011000011001110100000100111101 & +b10101011100011011010100110000 ) +b1011001100111001011011000 ( +b10011011010110010011110011100000 ' +b10001101100110110110110111001110 % +#383104 +1$ +#383400 +b1110111110 + +#383500 +b11111000010010011000101111010110 & +b11001010100010111101000011101101 ) +b10011000011001110100000100111101 ( +b10101011100011011010100110000 ' +b110010111100001011001011011000 % +#383502 +1! +1# +#383504 +0! +0$ +#383800 +b1110111111 + +#383900 +b11000010110001011011001001001111 & +b1100000000010010111100111011010 ) +b11111000010010011000101111010110 ( +b11001010100010111101000011101101 ' +b10100010011011101010100100111101 % +#383902 +0# +#383904 +1$ +#384200 +b1111000000 + +#384300 +b11100010111111100011100001100100 & +b1010110010111010001111001000010 ) +b11000010110001011011001001001111 ( +b1100000000010010111100111011010 ' +b10110100000101110011101111010110 % +#384304 +0$ +#384600 +b1111000001 + +#384700 +b100110101010101100111011101111 & +b11001001000100100100101001001000 ) +b11100010111111100011100001100100 ( +b1010110010111010001111001000010 ' +b11101111010101111100101001001111 % +#384704 +1$ +#385000 +b1111000010 + +#385100 +b10001011100101010101110100011101 & +b10011000101110110110101101110110 ) +b100110101010101100111011101111 ( +b11001001000100100100101001001000 ' +b10011001111010001100001100100 % +#385400 +b1111000011 + +#385500 +b10100000001000110111011101100101 & +b11010000100011100000011000101101 ) +b10001011100101010101110100011101 ( +b10011000101110110110101101110110 ' +b1110000110111011011011011101111 % +#385502 +1! +1# +#385800 +b1111000100 + +#385900 +b11000010110111001000110000010100 & +b11100011100000000101100011001100 ) +b10100000001000110111011101100101 ( +b11010000100011100000011000101101 ' +b100001011111011011010100011101 % +#385902 +0! +0# +#385904 +0$ +#386200 +b1111000101 + +#386300 +b11011001111000001000111001101110 & +b1100010110000110100010100001100 ) +b11000010110111001000110000010100 ( +b11100011100000000101100011001100 ' +b10111011100110000101111101100101 % +#386600 +b1111000110 + +#386700 +b11110110111010111110010010110 & +b111000010001111110101110100110 ) +b11011001111000001000111001101110 ( +b1100010110000110100010100001100 ' +b100110101111000010110000010100 % +#387000 +b1111000111 + +#387100 +b10111011000000001101000000111101 & +b1100110010011101011000101100100 ) +b11110110111010111110010010110 ( +b111000010001111110101110100110 ' +b11011101100100111111111001101110 % +#387104 +1$ +#387400 +b1111001000 + +#387500 +b1001001110100011110010011111001 & +b10111100000111010000011000100000 ) +b10111011000000001101000000111101 ( +b1100110010011101011000101100100 ' +b11110101001110011100110010010110 % +#387800 +b1111001001 + +#387900 +b11100111001110110000101101110011 & +b1011010000001111011100100110110 ) +b1001001110100011110010011111001 ( +b10111100000111010000011000100000 ' +b10111101100000010011100000111101 % +#388200 +b1111001010 + +#388300 +b1110101011100111111000100001111 & +b10110011010000110011110110110010 ) +b11100111001110110000101101110011 ( +b1011010000001111011100100110110 ' +b11000110111101100010110011111001 % +#388600 +b1111001011 + +#388700 +b101101100001011100100100100101 & +b10010110110100011100010011110 ) +b1110101011100111111000100001111 ( +b10110011010000110011110110110010 ' +b111111011000001001001101110011 % +#389000 +b1111001100 + +#389100 +b1101101100100001010110111111100 & +b10000111100000011100111110001010 ) +b101101100001011100100100100101 ( +b10010110110100011100010011110 ' +b11101010111110111000100100001111 % +#389104 +0$ +#389400 +b1111001101 + +#389500 +b10101101100000100100111000010101 & +b10101110010011010111011000011000 ) +b1101101100100001010110111111100 ( +b10000111100000011100111110001010 ' +b11110011001110000100100101 % +#389504 +1$ +#389800 +b1111001110 + +#389900 +b11001100111000011000111110011111 & +b100100111101100011100110110000 ) +b10101101100000100100111000010101 ( +b10101110010011010111011000011000 ' +b11101000111111110100110111111100 % +#390200 +b1111001111 + +#390300 +b10110110100101001100100001100101 & +b1001110110011101110110101101 ) +b11001100111000011000111110011111 ( +b100100111101100011100110110000 ' +b10111111111100101110011000010101 % +#390302 +1! +1# +#390600 +b1111010000 + +#390700 +b11100011011001111011001000110001 & +b100011001110100101110010111110 ) +b10110110100101001100100001100101 ( +b1001110110011101110110101101 ' +b11000000100111010111011110011111 % +#390702 +0! +0# +#391000 +b1111010001 + +#391100 +b110100010100110001110001010010 & +b100100100101000010111101000101 ) +b11100011011001111011001000110001 ( +b100011001110100101110010111110 ' +b10000110101111110000001100101 % +#391102 +1! +1# +#391104 +0! +0$ +#391400 +b1111010010 + +#391500 +b11011010101011011110101101110 & +b11000101011111010110100111001010 ) +b110100010100110001110001010010 ( +b100100100101000010111101000101 ' +b11011110111101100011101000110001 % +#391502 +0# +#391800 +b1111010011 + +#391900 +b110010001000110111100101011111 & +b10011110001111100101011101000110 ) +b11011010101011011110101101110 ( +b11000101011111010110100111001010 ' +b10101100101100011000110001010010 % +#391904 +1$ +#392200 +b1111010100 + +#392300 +b10101010001101100000010111001100 & +b11100001111100111010111101000 ) +b110010001000110111100101011111 ( +b10011110001111100101011101000110 ' +b10110110101111101100110101101110 % +#392304 +0$ +#392600 +b1111010101 + +#392700 +b11101111000111101000001110101110 & +b11000110110111101111001110101011 ) +b10101010001101100000010111001100 ( +b11100001111100111010111101000 ' +b101001111010011000000101011111 % +#392702 +1# +#393000 +b1111010110 + +#393100 +b11010011000100100011100110101 & +b11000000011101010010000 ) +b11101111000111101000001110101110 ( +b11000110110111101111001110101011 ' +b11010000110000110010111001100 % +#393102 +0# +#393104 +1$ +#393400 +b1111010111 + +#393500 +b110000000010000101100101000110 & +b101011000100001010110001111001 ) +b11010011000100100011100110101 ( +b11000000011101010010000 ' +b11011000000111111001110101110 % +#393502 +1! +1# +#393504 +0! +0$ +#393800 +b1111011000 + +#393900 +b111001111011101110001110000000 & +b110001101111010101000101101101 ) +b110000000010000101100101000110 ( +b101011000100001010110001111001 ' +b1000010110111110111100110101 % +#394200 +b1111011001 + +#394300 +b11100101100000110100101001101001 & +b10010111001100111111001110100000 ) +b111001111011101110001110000000 ( +b110001101111010101000101101101 ' +b1110010110000100110100101000110 % +#394302 +0# +#394304 +1$ +#394600 +b1111011010 + +#394700 +b1110000110100100100111100100011 & +b111110011011100101100110001101 ) +b11100101100000110100101001101001 ( +b10010111001100111111001110100000 ' +b1001110111100101110001110000000 % +#394702 +1! +1# +#395000 +b1111011011 + +#395100 +b10000111010110111100000100001111 & +b1111000011101000001110001101010 ) +b1110000110100100100111100100011 ( +b111110011011100101100110001101 ' +b11111111110100000000001001101001 % +#395102 +0! +0# +#395400 +b1111011100 + +#395500 +b101001111111001010011101011010 & +b11001011101101010100001001011000 ) +b10000111010110111100000100001111 ( +b1111000011101000001110001101010 ' +b11100010101010110101011100100011 % +#395504 +0$ +#395800 +b1111011101 + +#395900 +b10101000101110011000110111000011 & +b11110001101100110111100101000011 ) +b101001111111001010011101011010 ( +b11001011101101010100001001011000 ' +b1011001010100111011100100001111 % +#395902 +1# +#395904 +1! +1$ +#396200 +b1111011110 + +#396300 +b101011101010001010100001100 & +b11001001011111111011110100001110 ) +b10101000101110011000110111000011 ( +b11110001101100110111100101000011 ' +b11001100110001100111011101011010 % +#396302 +0! +0# +#396304 +0$ +#396600 +b1111011111 + +#396700 +b1011110101010100001000111010 & +b1101111011001100000110110000000 ) +b101011101010001010100001100 ( +b11001001011111111011110100001110 ' +b1100100110101111001010111000011 % +#397000 +b1111100000 + +#397100 +b10010010000001101011011000010100 & +b111111011101100001100110000011 ) +b1011110101010100001000111010 ( +b1101111011001100000110110000000 ' +b10101101110111010111010100001100 % +#397102 +1# +#397400 +b1111100001 + +#397500 +b1101100001101101110110011011011 & +b11001101010100111010001111011001 ) +b10010010000001101011011000010100 ( +b111111011101100001100110000011 ' +b10100001110001001001001000111010 % +#397504 +1! +1$ +#397800 +b1111100010 + +#397900 +b1000100000100101110011010111101 & +b11100011000000110101101011011111 ) +b1101100001101101110110011011011 ( +b11001101010100111010001111011001 ' +b10100111101101100001011000010100 % +#398200 +b1111100011 + +#398300 +b11001111100001001010111011100011 & +b10100000011111100100010001101 ) +b1000100000100101110011010111101 ( +b11100011000000110101101011011111 ' +b11011011010100000011010011011011 % +#398600 +b1111100100 + +#398700 +b11100101010111001110111100001000 & +b110110101010001100000001101110 ) +b11001111100001001010111011100011 ( +b10100000011111100100010001101 ' +b11010011001001110000111010111101 % +#398702 +0! +0# +#398704 +0$ +#399000 +b1111100101 + +#399100 +b1100101011001000100110000110100 & +b10001111011111010001100010001110 ) +b11100101010111001110111100001000 ( +b110110101010001100000001101110 ' +b11101010111100111011011011100011 % +#399400 +b1111100110 + +#399500 +b10111100110011101001001010110 & +b10101101111110101101101000110 ) +b1100101011001000100110000110100 ( +b10001111011111010001100010001110 ' +b10001001001010111100001000 % +#399800 +b1111100111 + +#399900 +b110111000001011110011010010011 & +b1110000010001110000000101000011 ) +b10111100110011101001001010110 ( +b10101101111110101101101000110 ' +b1000111000001011110110000110100 % +#399902 +1# +#399904 +1! +1$ +#400200 +b1111101000 + From 556c6f7457893cee2b2ac4b010cd47f0fa68e970 Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Fri, 31 May 2024 10:43:33 +0200 Subject: [PATCH 37/51] sim-gold instead of sim-cmp for x values --- tests/functional/single_bit/run-test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functional/single_bit/run-test.sh b/tests/functional/single_bit/run-test.sh index 685dc7a4691..5f08b82ac68 100755 --- a/tests/functional/single_bit/run-test.sh +++ b/tests/functional/single_bit/run-test.sh @@ -24,7 +24,7 @@ run_test() { if ./vcd_harness ${base_name}_functional_cxx.vcd; then # Run yosys to process each Verilog file - if ${BASE_PATH}yosys -p "read_verilog $verilog_file; sim -r ${base_name}_functional_cxx.vcd -scope my_module -vcd ${base_name}_yosys_sim.vcd -timescale 1us -sim-cmp"; then + if ${BASE_PATH}yosys -p "read_verilog $verilog_file; sim -r ${base_name}_functional_cxx.vcd -scope my_module -vcd ${base_name}_yosys_sim.vcd -timescale 1us -sim-gold"; then echo "Yosys sim $verilog_file successfully." else ${BASE_PATH}yosys -p "read_verilog $verilog_file; sim -vcd ${base_name}_yosys_sim.vcd -r ${base_name}_functional_cxx.vcd -scope my_module -timescale 1us" From 52cc2ae5cdacbe8f6c4eea7fd8e7a90d3df876dc Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Sat, 1 Jun 2024 17:41:05 +0200 Subject: [PATCH 38/51] Fix locale issue --- flake.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/flake.nix b/flake.nix index 90c646aa9a6..ea55c012e5d 100644 --- a/flake.nix +++ b/flake.nix @@ -66,6 +66,7 @@ defaultPackage = yosys; packages.vcdiff = vcdiff; devShell = pkgs.mkShell { + LOCALE_ARCHIVE_2_27 = "${pkgs.glibcLocales}/lib/locale/locale-archive"; buildInputs = with pkgs; [ clang bison flex libffi tcl readline python3 llvmPackages.libcxxClang zlib git gtest abc-verifier gtkwave vcdiff lcov racket verilog ]; }; } From 77f3534a7c9cc4756cc5e51384ed595874cff74f Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Tue, 4 Jun 2024 15:02:25 +0200 Subject: [PATCH 39/51] Simplify $mul CellSimplifier --- kernel/graphtools.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/kernel/graphtools.h b/kernel/graphtools.h index 907a2b1cf4a..47a7862d556 100644 --- a/kernel/graphtools.h +++ b/kernel/graphtools.h @@ -185,10 +185,9 @@ class CellSimplifier { return factory.slice(a, a_width, offset, y_width); }else if(cellType == ID($mul)){ bool is_signed = a_signed && b_signed; - int width = a_width + b_width; - T a = extend(inputs.at(ID(A)), a_width, width, is_signed); - T b = extend(inputs.at(ID(B)), b_width, width, is_signed); - return extend(factory.mul(a, b, width), width, y_width, is_signed); + T a = extend(inputs.at(ID(A)), a_width, y_width, is_signed); + T b = extend(inputs.at(ID(B)), b_width, y_width, is_signed); + return factory.mul(a, b, y_width); }else if(cellType == ID($div)){ bool is_signed = a_signed && b_signed; int width = max(a_width, b_width); From b126370663bfb4104c5c8d2dc1893a1b430482c9 Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Tue, 4 Jun 2024 17:16:52 +0200 Subject: [PATCH 40/51] WIP --- a.cc | 32 ++ add.cc | 32 ++ add.smt | 0 add.smt2 | 22 + alternative_and.smt | 0 and.cc | 32 ++ and.smt | 23 + backends/functional/Makefile.inc | 4 +- backends/functional/alternative_cxx.cc | 265 +++++++++++ backends/functional/alternative_smtlib.cc | 517 ++++++++++++++++++++++ combined.smt2 | 43 ++ flake.nix | 2 +- functional_add.smt2 | 23 + kernel/alternative_functional.h | 369 +++++++++++++++ kernel/alternative_graphtools.h | 509 +++++++++++++++++++++ kernel/functional.h | 2 +- old_add.smt2 | 22 + tests/functional/smt/harness.smt2 | 48 ++ 18 files changed, 1942 insertions(+), 3 deletions(-) create mode 100644 a.cc create mode 100644 add.cc create mode 100644 add.smt create mode 100644 add.smt2 create mode 100644 alternative_and.smt create mode 100644 and.cc create mode 100644 and.smt create mode 100644 backends/functional/alternative_cxx.cc create mode 100644 backends/functional/alternative_smtlib.cc create mode 100644 combined.smt2 create mode 100644 functional_add.smt2 create mode 100644 kernel/alternative_functional.h create mode 100644 kernel/alternative_graphtools.h create mode 100644 old_add.smt2 create mode 100644 tests/functional/smt/harness.smt2 diff --git a/a.cc b/a.cc new file mode 100644 index 00000000000..77a449e7313 --- /dev/null +++ b/a.cc @@ -0,0 +1,32 @@ +#include "sim.h" +struct my_module_Inputs { + Signal<1> b; + Signal<1> a; + + template void dump(T &out) { + out("b", b); + out("a", a); + } +}; + +struct my_module_Outputs { + Signal<1> sum; + + template void dump(T &out) { + out("sum", sum); + } +}; + +struct my_module_State { + + template void dump(T &out) { + } +}; + +void my_module(my_module_Inputs const &input, my_module_Outputs &output, my_module_State const ¤t_state, my_module_State &next_state) +{ + Signal<1> b = input.b; + Signal<1> a = input.a; + Signal<1> $add$tests_functional_single_bit_verilog_my_module_add_v_7$1$_Y = $add(a, b); // + output.sum = $add$tests_functional_single_bit_verilog_my_module_add_v_7$1$_Y; +} diff --git a/add.cc b/add.cc new file mode 100644 index 00000000000..77a449e7313 --- /dev/null +++ b/add.cc @@ -0,0 +1,32 @@ +#include "sim.h" +struct my_module_Inputs { + Signal<1> b; + Signal<1> a; + + template void dump(T &out) { + out("b", b); + out("a", a); + } +}; + +struct my_module_Outputs { + Signal<1> sum; + + template void dump(T &out) { + out("sum", sum); + } +}; + +struct my_module_State { + + template void dump(T &out) { + } +}; + +void my_module(my_module_Inputs const &input, my_module_Outputs &output, my_module_State const ¤t_state, my_module_State &next_state) +{ + Signal<1> b = input.b; + Signal<1> a = input.a; + Signal<1> $add$tests_functional_single_bit_verilog_my_module_add_v_7$1$_Y = $add(a, b); // + output.sum = $add$tests_functional_single_bit_verilog_my_module_add_v_7$1$_Y; +} diff --git a/add.smt b/add.smt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/add.smt2 b/add.smt2 new file mode 100644 index 00000000000..ed1f3319164 --- /dev/null +++ b/add.smt2 @@ -0,0 +1,22 @@ +; SMT-LIBv2 description generated by Yosys 0.41+101 (git sha1 52cc2ae5c, g++ 11.4.0-1ubuntu1~22.04 -fPIC -Os) +; yosys-smt2-module my_module +(declare-sort |my_module_s| 0) +(declare-fun |my_module_is| (|my_module_s|) Bool) +(declare-fun |my_module#0| (|my_module_s|) (_ BitVec 1)) ; \a +(declare-fun |my_module#1| (|my_module_s|) (_ BitVec 1)) ; \b +(define-fun |my_module#2| ((state |my_module_s|)) (_ BitVec 1) (bvadd (|my_module#0| state) (|my_module#1| state))) ; $add$tests/functional/single_bit/verilog/my_module_add.v:7$1_Y +; yosys-smt2-output sum 1 +(define-fun |my_module_n sum| ((state |my_module_s|)) Bool (= ((_ extract 0 0) (|my_module#2| state)) #b1)) +; yosys-smt2-input b 1 +; yosys-smt2-witness {"offset": 0, "path": ["\\b"], "smtname": "b", "smtoffset": 0, "type": "input", "width": 1} +(define-fun |my_module_n b| ((state |my_module_s|)) Bool (= ((_ extract 0 0) (|my_module#1| state)) #b1)) +; yosys-smt2-input a 1 +; yosys-smt2-witness {"offset": 0, "path": ["\\a"], "smtname": "a", "smtoffset": 0, "type": "input", "width": 1} +(define-fun |my_module_n a| ((state |my_module_s|)) Bool (= ((_ extract 0 0) (|my_module#0| state)) #b1)) +(define-fun |my_module_a| ((state |my_module_s|)) Bool true) +(define-fun |my_module_u| ((state |my_module_s|)) Bool true) +(define-fun |my_module_i| ((state |my_module_s|)) Bool true) +(define-fun |my_module_h| ((state |my_module_s|)) Bool true) +(define-fun |my_module_t| ((state |my_module_s|) (next_state |my_module_s|)) Bool true) ; end of module my_module +; yosys-smt2-topmod my_module +; end of yosys output diff --git a/alternative_and.smt b/alternative_and.smt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/and.cc b/and.cc new file mode 100644 index 00000000000..77a449e7313 --- /dev/null +++ b/and.cc @@ -0,0 +1,32 @@ +#include "sim.h" +struct my_module_Inputs { + Signal<1> b; + Signal<1> a; + + template void dump(T &out) { + out("b", b); + out("a", a); + } +}; + +struct my_module_Outputs { + Signal<1> sum; + + template void dump(T &out) { + out("sum", sum); + } +}; + +struct my_module_State { + + template void dump(T &out) { + } +}; + +void my_module(my_module_Inputs const &input, my_module_Outputs &output, my_module_State const ¤t_state, my_module_State &next_state) +{ + Signal<1> b = input.b; + Signal<1> a = input.a; + Signal<1> $add$tests_functional_single_bit_verilog_my_module_add_v_7$1$_Y = $add(a, b); // + output.sum = $add$tests_functional_single_bit_verilog_my_module_add_v_7$1$_Y; +} diff --git a/and.smt b/and.smt new file mode 100644 index 00000000000..18be0c8f9cd --- /dev/null +++ b/and.smt @@ -0,0 +1,23 @@ +(declare-datatype my_module_inputs ((my_module_inputs + (my_module_inputs_b (_ BitVec 1)) + (my_module_inputs_a (_ BitVec 1)) +))) +(declare-datatype my_module_outputs ((my_module_outputs + (my_module_outputs_sum (_ BitVec 1)) +))) +(declare-datatype my_module_state ((my_module_state +))) +(declare-datatypes ((Pair 2)) ((par (X Y) ((pair (first X) (second Y)))))) +(define-fun my_module_step ((inputs my_module_inputs) (current_state my_module_state)) (Pair my_module_outputs my_module_state) + (let (((b (my_module_inputs_b inputs)))) + (let (((a (my_module_inputs_a inputs)))) + (let ((($add$tests/functional/single_bit/verilog/my_module_add.v_7$1$_Y (bvadd a b)))) + (pair + (my_module_outputs + $add$tests/functional/single_bit/verilog/my_module_add.v_7$1$_Y ; sum + ) + (my_module_state + ) + ) + ))) +) diff --git a/backends/functional/Makefile.inc b/backends/functional/Makefile.inc index c712d2aefe5..675153c95b0 100644 --- a/backends/functional/Makefile.inc +++ b/backends/functional/Makefile.inc @@ -1,2 +1,4 @@ OBJS += backends/functional/cxx.o -OBJS += backends/functional/smtlib.o +# OBJS += backends/functional/smtlib.o +# OBJS += backends/functional/alternative_cxx.o +# OBJS += backends/functional/alternative_smtlib.o diff --git a/backends/functional/alternative_cxx.cc b/backends/functional/alternative_cxx.cc new file mode 100644 index 00000000000..5ba898d0cc8 --- /dev/null +++ b/backends/functional/alternative_cxx.cc @@ -0,0 +1,265 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2024 Emily Schmidt + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include +#include +#include "kernel/yosys.h" +#include "kernel/drivertools.h" +#include "kernel/topo_scc.h" +#include "kernel/functional.h" +#include "kernel/alternative_graphtools.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +const char *reserved_keywords[] = { + "alignas","alignof","and","and_eq","asm","atomic_cancel","atomic_commit", + "atomic_noexcept","auto","bitand","bitor","bool","break","case", + "catch","char","char16_t","char32_t","char8_t","class","co_await", + "co_return","co_yield","compl","concept","const","const_cast","consteval", + "constexpr","constinit","continue","decltype","default","delete", + "do","double","dynamic_cast","else","enum","explicit","export", + "extern","false","float","for","friend","goto","if","inline", + "int","long","mutable","namespace","new","noexcept","not","not_eq", + "nullptr","operator","or","or_eq","private","protected","public", + "reflexpr","register","reinterpret_cast","requires","return","short", + "signed","sizeof","static","static_assert","static_cast","struct", + "switch","synchronized","template","this","thread_local","throw", + "true","try","typedef","typeid","typename","union","unsigned", + "using","virtual","void","volatile","wchar_t","while","xor","xor_eq", + nullptr +}; + +struct CxxScope { + pool used_names; + dict name_map; + + CxxScope() { + for(const char **p = reserved_keywords; *p != nullptr; p++) + reserve(*p); + } + void reserve(std::string name) { + used_names.insert(name); + } + std::string insert(IdString id) { + std::string str = RTLIL::unescape_id(id); + for(size_t i = 0; i < str.size(); i++) + if(strchr("!\"#%&'()*+,-./:;<=>?@[]\\^`{|}~ ", str[i])) + str[i] = '_'; + if(used_names.count(str) == 0){ + used_names.insert(str); + name_map.insert({id, str}); + return str; + } + for (int idx = 0 ; ; idx++){ + std::string suffixed = str + "_" + std::to_string(idx); + if (used_names.count(suffixed) == 0) { + used_names.insert(suffixed); + if(name_map.count(id) == 0) + name_map.insert({id, suffixed}); + return suffixed; + } + } + } + std::string operator[](IdString id) { + if(name_map.count(id) > 0) + return name_map[id]; + else + return insert(id); + } +}; + +struct CxxWriter { + std::ostream &f; + CxxWriter(std::ostream &out) : f(out) {} + void printf(const char *fmt, ...) + { + va_list va; + va_start(va, fmt); + f << vstringf(fmt, va); + va_end(va); + } +}; + +struct CxxStruct { + std::string name; + dict types; + CxxScope scope; + CxxStruct(std::string name) : name(name) { + scope.reserve("out"); + scope.reserve("dump"); + } + void insert(IdString name, std::string type) { + scope.insert(name); + types.insert({name, type}); + } + void print(CxxWriter &f) { + f.printf("struct %s {\n", name.c_str()); + for (auto p : types) { + f.printf("\t%s %s;\n", p.second.c_str(), scope[p.first].c_str()); + } + f.printf("\n\ttemplate void dump(T &out) {\n"); + for (auto p : types) { + f.printf("\t\tout(\"%s\", %s);\n", RTLIL::unescape_id(p.first).c_str(), scope[p.first].c_str()); + } + f.printf("\t}\n};\n\n"); + } + std::string operator[](IdString field) { + return scope[field]; + } +}; + +struct FunctionalCxxBackend : public Backend +{ + FunctionalCxxBackend() : Backend("functional_cxx", "convert design to C++ using the functional backend") {} + + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + } + + void printCxx(std::ostream &stream, std::string, std::string const & name, CompleteComputeGraph &compute_graph) + { + dict inputs, state; + CxxWriter f(stream); + + // Dump the compute graph + for (int i = 0; i < compute_graph.size(); ++i) + { + auto ref = compute_graph[i]; + if(ref.function().name == ID($$input)) + inputs[ref.function().parameters.begin()->first] = ref.function().width; + if(ref.function().name == ID($$state)) + state[ref.function().parameters.begin()->first] = ref.function().width; + } + f.printf("#include \"sim.h\"\n"); + CxxStruct input_struct(name + "_Inputs"); + for (auto const &input : inputs) + input_struct.insert(input.first, "Signal<" + std::to_string(input.second) + ">"); + CxxStruct output_struct(name + "_Outputs"); + for (auto const &key : compute_graph.keys()) + if(state.count(key.first) == 0) + output_struct.insert(key.first, "Signal<" + std::to_string(compute_graph[key.second].function().width) + ">"); + CxxStruct state_struct(name + "_State"); + for (auto const &state_var : state) + state_struct.insert(state_var.first, "Signal<" + std::to_string(state_var.second) + ">"); + + idict node_names; + CxxScope locals; + + input_struct.print(f); + output_struct.print(f); + state_struct.print(f); + + f.printf("void %s(%s_Inputs const &input, %s_Outputs &output, %s_State const ¤t_state, %s_State &next_state)\n{\n", name.c_str(), name.c_str(), name.c_str(), name.c_str(), name.c_str()); + locals.reserve("input"); + locals.reserve("output"); + locals.reserve("current_state"); + locals.reserve("next_state"); + for (int i = 0; i < compute_graph.size(); ++i) + { + auto ref = compute_graph[i]; + int width = ref.function().width; + std::string name; + if(ref.has_sparse_attr()) + name = locals.insert(ref.sparse_attr()); + else + name = locals.insert("\\n" + std::to_string(i)); + node_names(name); + if(ref.function().name == ID($$input)) + f.printf("\tSignal<%d> %s = input.%s;\n", width, name.c_str(), input_struct[ref.function().parameters.begin()->first].c_str()); + else if(ref.function().name == ID($$state)) + f.printf("\tSignal<%d> %s = current_state.%s;\n", width, name.c_str(), state_struct[ref.function().parameters.begin()->first].c_str()); + else if(ref.function().name == ID($$buf)) + f.printf("\tSignal<%d> %s = %s;\n", width, name.c_str(), node_names[ref.arg(0).index()].c_str()); + else if(ref.function().name == ID($$cell_output)) + f.printf("\tSignal<%d> %s = %s.%s;\n", width, name.c_str(), node_names[ref.arg(0).index()].c_str(), RTLIL::unescape_id(ref.function().parameters.begin()->first).c_str()); + else if(ref.function().name == ID($$const)){ + auto c = ref.function().parameters.begin()->second; + if(c.size() <= 32){ + f.printf("\tSignal<%d> %s = $const<%d>(%#x);\n", width, name.c_str(), width, (uint32_t) c.as_int()); + }else{ + f.printf("\tSignal<%d> %s = $const<%d>({%#x", width, name.c_str(), width, (uint32_t) c.as_int()); + while(c.size() > 32){ + c = c.extract(32, c.size() - 32); + f.printf(", %#x", c.as_int()); + } + f.printf("});\n"); + } + }else if(ref.function().name == ID($$undriven)) + f.printf("\tSignal<%d> %s; //undriven\n", width, name.c_str()); + else if(ref.function().name == ID($$slice)) + f.printf("\tSignal<%d> %s = slice<%d>(%s, %d);\n", width, name.c_str(), width, node_names[ref.arg(0).index()].c_str(), ref.function().parameters.at(ID(offset)).as_int()); + else if(ref.function().name == ID($$concat)){ + f.printf("\tauto %s = concat(", name.c_str()); + for (int i = 0, end = ref.size(); i != end; ++i){ + if(i > 0) + f.printf(", "); + f.printf("%s", node_names[ref.arg(i).index()].c_str()); + } + f.printf(");\n"); + }else{ + f.printf("\t"); + if(ref.function().width > 0) + f.printf("Signal<%d>", ref.function().width); + else + f.printf("%s_Outputs", log_id(ref.function().name)); + f.printf(" %s = %s", name.c_str(), log_id(ref.function().name)); + if(ref.function().parameters.count(ID(WIDTH))){ + f.printf("<%d>", ref.function().parameters.at(ID(WIDTH)).as_int()); + } + f.printf("("); + for (int i = 0, end = ref.size(); i != end; ++i) + f.printf("%s%s", i>0?", ":"", node_names[ref.arg(i).index()].c_str()); + f.printf("); //"); + for (auto const ¶m : ref.function().parameters) + { + if (param.second.empty()) + f.printf("[%s]", log_id(param.first)); + else + f.printf("[%s=%s]", log_id(param.first), log_const(param.second)); + } + f.printf("\n"); + } + } + + for (auto const &key : compute_graph.keys()) + { + f.printf("\t%s.%s = %s;\n", state.count(key.first) > 0 ? "next_state" : "output", state_struct[key.first].c_str(), node_names[key.second].c_str()); + } + f.printf("}\n"); + } + + void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) override + { + log_header(design, "Executing Functional C++ backend.\n"); + + size_t argidx = 1; + extra_args(f, filename, args, argidx, design); + + for (auto module : design->selected_modules()) { + log("Dumping module `%s'.\n", module->name.c_str()); + auto compute_graph = calculate_compute_graph(module); + printCxx(*f, filename, RTLIL::unescape_id(module->name), compute_graph); + } + } +} FunctionalCxxBackend; + +PRIVATE_NAMESPACE_END diff --git a/backends/functional/alternative_smtlib.cc b/backends/functional/alternative_smtlib.cc new file mode 100644 index 00000000000..88b3ed42d66 --- /dev/null +++ b/backends/functional/alternative_smtlib.cc @@ -0,0 +1,517 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2024 Emily Schmidt + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include +#include "kernel/yosys.h" +#include "kernel/drivertools.h" +#include "kernel/topo_scc.h" +#include "kernel/functional.h" +#include "kernel/alternative_graphtools.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct SmtlibScope { + pool used_names; + dict name_map; + + SmtlibScope() { + /*for(const char **p = reserved_keywords; *p != nullptr; p++) + reserve(*p);*/ + } + void reserve(std::string name) { + used_names.insert(name); + } + std::string insert(IdString id) { + std::string str = RTLIL::unescape_id(id); + for(size_t i = 0; i < str.size(); i++) + if(!((unsigned char)str[i] < 0x80 && (isalnum(str[i]) || strchr("~!@$%^&*_-+=<>.?/", str[i])))) + str[i] = '_'; + if(used_names.count(str) == 0){ + used_names.insert(str); + name_map.insert({id, str}); + return str; + } + for (int idx = 0 ; ; idx++){ + std::string suffixed = str + "_" + std::to_string(idx); + if (used_names.count(suffixed) == 0) { + used_names.insert(suffixed); + if(name_map.count(id) == 0) + name_map.insert({id, suffixed}); + return suffixed; + } + } + } + std::string operator[](IdString id) { + if(name_map.count(id) > 0) + return name_map[id]; + else + return insert(id); + } +}; + +struct SmtlibWriter { + std::ostream &f; + SmtlibWriter(std::ostream &out) : f(out) {} + void printf(const char *fmt, ...) + { + va_list va; + va_start(va, fmt); + f << vstringf(fmt, va); + va_end(va); + } + template + SmtlibWriter & operator <<(T &&arg) { + f << std::forward(arg); + return *this; + } +}; + +struct Arg { + int n; + explicit Arg(int n_) : n(n_) {} + bool operator ==(Arg const &other) const { return n == other.n; } +}; + +class SExpr { + enum class Type { + None, + List, + Atom, + Arg, + }; + Type type = Type::None; + union { + std::string atom_; + vector list_; + Arg arg_; + }; + void set_none() { + switch(type) { + case Type::None: break; + case Type::Atom: atom_.~basic_string(); break; + case Type::List: list_.~vector(); break; + case Type::Arg: arg_.~Arg(); break; + } + type = Type::None; + } +public: + SExpr() {} + SExpr(const char *atom) : type(Type::Atom), atom_(atom) {} + SExpr(std::string atom) : type(Type::Atom), atom_(atom) {} + SExpr(int n) : type(Type::Atom), atom_(std::to_string(n)) {} + SExpr(RTLIL::Const const & n) : type(Type::Atom) { + new(&atom_) std::string("#b"); + atom_.reserve(n.size() + 2); + for (size_t i = n.size(); i > 0; i--) + if(n[i-1] == State::S1) + atom_ += "1"; + else + atom_ += "0"; + } + SExpr(vector &&list) : type(Type::List), list_(list) {} + SExpr(std::initializer_list list) : type(Type::List), list_(list) {} + SExpr(Arg arg) : type(Type::Arg), arg_(arg) {} + SExpr(SExpr const &other) { *this = other; } + SExpr(SExpr &&other) { *this = std::move(other); } + SExpr &operator =(SExpr const &other) { + set_none(); + switch(other.type) { + case Type::None: break; + case Type::Atom: new(&atom_) std::string(other.atom_); break; + case Type::List: new(&list_) vector(other.list_); break; + case Type::Arg: new(&arg_) Arg(other.arg_); break; + } + type = other.type; + return *this; + } + SExpr &operator =(SExpr &&other) { + set_none(); + switch(other.type) { + case Type::None: break; + case Type::Atom: new(&atom_) std::string(std::move(other.atom_)); break; + case Type::List: new(&list_) vector(std::move(other.list_)); break; + case Type::Arg: new(&arg_) Arg(std::move(other.arg_)); break; + } + type = other.type; + return *this; + } + ~SExpr() { set_none(); } + bool operator==(SExpr const &other) const { + if(type != other.type) return false; + switch(type) { + case Type::None: return true; + case Type::Atom: return atom_ == other.atom_; + case Type::List: return list_ == other.list_; + case Type::Arg: return arg_ == other.arg_; + } + } + bool is_none() const { return type == Type::None; } + bool is_atom() const { return type == Type::Atom; } + bool is_list() const { return type == Type::List; } + bool is_arg() const { return type == Type::Arg; } + std::string const &atom() const { log_assert(is_atom()); return atom_; } + std::vector const &list() const { log_assert(is_list()); return list_; } + Arg const &arg() const { log_assert(is_arg()); return arg_; } + unsigned int hash() const { + unsigned int inner; + switch(type) { + case Type::None: inner = 0; break; + case Type::Atom: inner = mkhash(atom_); break; + case Type::List: inner = mkhash(list_); break; + case Type::Arg: inner = arg_.n; break; + } + return mkhash((unsigned int) type, inner); + } + SExpr subst_args(std::vector const & args) const { + switch(type) { + case Type::None: + case Type::Atom: + return *this; + case Type::List: { + vector ret; + for(auto & a : list_) + ret.emplace_back(a.subst_args(args)); + return SExpr(std::move(ret)); + } + case Type::Arg: + if(arg_.n >= 1 && (size_t)arg_.n <= args.size()) + return args[arg_.n - 1]; + else + return *this; + } + } +}; + +std::ostream& operator << (std::ostream &os, SExpr const &s) { + if(s.is_atom()) + os << s.atom(); + else if(s.is_list()){ + os << "("; + bool first = true; + for(auto &el: s.list()) { + if(!first) os << " "; + else first = false; + os << el; + } + os << ")"; + }else if(s.is_arg()) + os << "#" << s.arg().n; + else if(s.is_none()) + os << ""; + else + os << "???"; + return os; +} + +struct SmtlibStruct { + SmtlibScope &scope; + std::string name; + idict members; + vector widths; + vector accessors; + SmtlibStruct(std::string name, SmtlibScope &scope) : scope(scope), name(name) { + } + std::string insert(IdString field, int width) { + if(members.at(field, -1) == -1){ + members(field); + scope.insert(field); + widths.push_back(width); + accessors.push_back(scope.insert(std::string("\\") + name + "_" + RTLIL::unescape_id(field))); + } + return scope[field]; + } + void print(SmtlibWriter &f) { + f.printf("(declare-datatype %s ((%s\n", name.c_str(), name.c_str()); + for (size_t i = 0; i < members.size(); i++) + f.printf(" (%s (_ BitVec %d))\n", accessors[i].c_str(), widths[i]); + f.printf(")))\n"); + } + void print_value(SmtlibWriter &f, dict values, int indentation) { + std::string spaces(indentation, ' '); + f << spaces << "(" << name << "\n"; + for (size_t i = 0; i < members.size(); i++) + f << spaces << " " << values[members[i]] << " ; " << RTLIL::unescape_id(members[i]) << "\n"; + f << spaces << ")\n"; + } + SExpr access(SExpr record, IdString member) { + int i = members.at(member); + return SExpr{accessors[i], record}; + } + std::string operator[](IdString field) { + return scope[field]; + } +}; + +struct Node { + SExpr expr; + int width; + + Node(SExpr &&expr, int width) : expr(std::move(expr)), width(width) {} + + bool operator==(Node const &other) const { + return expr == other.expr && width == other.width; + } + + unsigned int hash() const { + return mkhash(expr.hash(), width); + } +}; + +typedef ComputeGraph SmtlibComputeGraph; + +struct SmtlibModule { + std::string name; + SmtlibScope global_scope; + SmtlibStruct input_struct; + SmtlibStruct output_struct; + SmtlibStruct state_struct; + SmtlibComputeGraph compute_graph; + + SmtlibModule(std::string const &name) : + name(name), + input_struct(name + "_inputs", global_scope), + output_struct(name + "_outputs", global_scope), + state_struct(name + "_state", global_scope) + { } + void calculate_compute_graph(RTLIL::Module *module); + void write(std::ostream &stream); +}; + +class SmtlibComputeGraphFactory { + SmtlibModule &module; + SmtlibComputeGraph &graph; + using T = SmtlibComputeGraph::Ref; + static bool is_single_output(IdString type) + { + auto it = yosys_celltypes.cell_types.find(type); + return it != yosys_celltypes.cell_types.end() && it->second.outputs.size() <= 1; + } + T node(SExpr &&expr, int width, std::initializer_list args) { + return graph.add(Node(std::move(expr), width), 0, args); + } + T shift(const char *name, T a, T b, int y_width, int b_width, bool a_signed = false) { + int width = max(y_width, b_width); + T a_ = y_width < width ? extend(a, y_width, width, a_signed) : a; + T b_ = b_width < width ? extend(b, b_width, width, false) : b; + T y_ = node(SExpr {name, Arg(1), Arg(2)}, width, {a_, b_}); + if(y_width < width) + return slice(y_, width, 0, y_width); + else + return y_; + } + SExpr from_bool(SExpr &&arg) { + return SExpr{"ite", std::move(arg), RTLIL::Const(State::S1), RTLIL::Const(State::S0)}; + } + SExpr to_bool(SExpr &&arg) { + return SExpr{"=", std::move(arg), RTLIL::Const(State::S1)}; + } + SExpr extract(SExpr &&arg, int offset, int out_width) { + return SExpr {SExpr {"_", "extract", offset + out_width - 1, offset}, std::move(arg)}; + } +public: + SmtlibComputeGraphFactory(SmtlibModule &mod) : module(mod), graph(mod.compute_graph) {} + T slice(T a, int in_width, int offset, int out_width) { + assert(offset + out_width <= in_width); + return node(extract(Arg(1), offset, out_width), out_width, {a}); + } + T extend(T a, int in_width, int out_width, bool is_signed) { + assert(in_width < out_width); + if(is_signed) + return node(SExpr {SExpr {"_", "sign_extend", out_width - in_width}, Arg(1)}, out_width, {a}); + else + return node(SExpr {SExpr {"_", "zero_extend", out_width - in_width}, Arg(1)}, out_width, {a}); + } + T concat(T a, int a_width, T b, int b_width) { + return node(SExpr {"concat", Arg(1), Arg(2)}, a_width + b_width, {a, b}); + } + T add(T a, T b, int width) { return node(SExpr {"bvadd", Arg(1), Arg(2)}, width, {a, b}); } + + T constant(RTLIL::Const value) { return node(SExpr(value), value.size(), {}); } + T input(IdString name, int width) { + module.input_struct.insert(name, width); + return node(module.input_struct.access("inputs", name), width, {}); + } + T state(IdString name, int width) { + module.state_struct.insert(name, width); + return node(module.state_struct.access("current_state", name), width, {}); + } + T cell_output(T cell, IdString type, IdString name, int width) { + if (is_single_output(type)) + return cell; + else + return node(SExpr {"cell_output", Arg(1), RTLIL::unescape_id(name)}, width, {cell}); + } + T multiple(vector args, int width) { + vector expr; + expr.reserve(args.size() + 1); + expr.push_back("multiple"); + for(size_t i = 1; i <= args.size(); i++) + expr.push_back(Arg(i)); + return graph.add(Node(SExpr(std::move(expr)), width), 0, args); + } + T undriven(int width) { + return constant(RTLIL::Const(State::S0, width)); + //return node(SExpr {"undriven"}, width, {}); + } + T create_pending(int width) { + return node(SExpr(), width, {}); + } + void update_pending(T pending, T node) { + assert(pending.function().expr.is_none()); + pending.set_function(Node(Arg(1), pending.function().width)); + pending.append_arg(node); + } + void declare_output(T node, IdString name, int width) { + module.output_struct.insert(name, width); + node.assign_key(name); + } + void declare_state(T node, IdString name, int width) { + module.state_struct.insert(name, width); + node.assign_key(name); + } + void suggest_name(T node, IdString name) { + node.sparse_attr() = name; + } +}; + +void SmtlibModule::calculate_compute_graph(RTLIL::Module *module) +{ + SmtlibComputeGraphFactory factory(*this); + ComputeGraphConstruction construction(factory); + construction.add_module(module); + construction.process_queue(); + + // Perform topo sort and detect SCCs + SmtlibComputeGraph::SccAdaptor compute_graph_scc(compute_graph); + + bool scc = false; + std::vector perm; + topo_sorted_sccs(compute_graph_scc, [&](int *begin, int *end) { + perm.insert(perm.end(), begin, end); + if (end > begin + 1) + { + log_warning("SCC:"); + for (int *i = begin; i != end; ++i) + log(" %d", *i); + log("\n"); + scc = true; + } + }, /* sources_first */ true); + compute_graph.permute(perm); + if(scc) log_error("combinational loops, aborting\n"); + + // Forward $$buf + std::vector alias; + perm.clear(); + + for (int i = 0; i < compute_graph.size(); ++i) + { + auto node = compute_graph[i]; + if (node.function().expr == Arg(1) && node.arg(0).index() < i) + { + int target_index = alias[node.arg(0).index()]; + auto target_node = compute_graph[perm[target_index]]; + if(!target_node.has_sparse_attr() && node.has_sparse_attr()) + target_node.sparse_attr() = node.sparse_attr(); + alias.push_back(target_index); + } + else + { + alias.push_back(GetSize(perm)); + perm.push_back(i); + } + } + compute_graph.permute(perm, alias); +} + +void SmtlibModule::write(std::ostream &stream) +{ + SmtlibWriter f(stream); + + idict node_names; + SmtlibScope locals; + int paren_count = 0; + + input_struct.print(f); + output_struct.print(f); + state_struct.print(f); + + f << "(declare-datatypes ((Pair 2)) ((par (X Y) ((pair (first X) (second Y))))))\n"; + f.printf("(define-fun %s_step ((inputs %s_inputs) (current_state %s_state)) (Pair %s_outputs %s_state)\n", + name.c_str(), name.c_str(), name.c_str(), name.c_str(), name.c_str()); + + for (int i = 0; i < compute_graph.size(); ++i) + { + auto ref = compute_graph[i]; + std::string name; + if(ref.has_sparse_attr()) + name = locals.insert(ref.sparse_attr()); + else + name = locals.insert("\\n" + std::to_string(i)); + node_names(name); + vector args; + args.reserve(ref.size()); + for (int i = 0, end = ref.size(); i != end; ++i) + args.push_back(node_names[ref.arg(i).index()]); + f << " (let " << SExpr{{SExpr{name, ref.function().expr.subst_args(args)}}} << "\n"; + paren_count++; + } + dict outputs; + for(auto &a: compute_graph.keys()) + outputs.insert({a.first, node_names[a.second]}); + f.printf(" (pair \n"); + output_struct.print_value(f, outputs, 6); + state_struct.print_value(f, outputs, 6); + f.printf(" )\n"); + while(paren_count > 0){ + int n = min(paren_count, 80); + f << " " << std::string(n, ')') << "\n"; + paren_count -= n; + } + f.printf(")\n"); +} + +struct FunctionalSmtlibBackend : public Backend +{ + FunctionalSmtlibBackend() : Backend("alternative_functional_smtlib", "ALTERNATIVE!! convert design to SMTLIB using the functional backend") {} + + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + } + + void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) override + { + log_header(design, "Executing ALTERNATIVE!!! Functional SMTLIB backend.\n"); + + size_t argidx = 1; + extra_args(f, filename, args, argidx, design); + + for (auto module : design->selected_modules()) { + log("Dumping module `%s'.\n", module->name.c_str()); + SmtlibModule smt(RTLIL::unescape_id(module->name)); + smt.calculate_compute_graph(module); + smt.write(*f); + } + } +} FunctionalSmtlibBackend; + +PRIVATE_NAMESPACE_END diff --git a/combined.smt2 b/combined.smt2 new file mode 100644 index 00000000000..4ae8745bfee --- /dev/null +++ b/combined.smt2 @@ -0,0 +1,43 @@ +(set-logic QF_BV) + +; Declarations from functional_add.smt2 +(declare-datatype my_module_inputs ((my_module_inputs + (my_module_inputs_b (_ BitVec 1)) + (my_module_inputs_a (_ BitVec 1)) +))) +(declare-datatype my_module_outputs ((my_module_outputs + (my_module_outputs_sum (_ BitVec 1)) +))) +(declare-datatype my_module_state ((my_module_state))) +(declare-datatypes ((Pair 2)) ((par (X Y) ((pair (first X) (second Y)))))) + +; Declarations from old_add.smt2 +(declare-sort |my_module_s| 0) +(declare-fun |my_module#0| (|my_module_s|) (_ BitVec 1)) ; \a +(declare-fun |my_module#1| (|my_module_s|) (_ BitVec 1)) ; \b +(define-fun |my_module#2| ((state |my_module_s|)) (_ BitVec 1) (bvadd (|my_module#0| state) (|my_module#1| state))) ; $add$tests/functional/single_bit/verilog/my_module_add.v:7$1_Y + +; Input variables +(declare-const inputs my_module_inputs) + +; Instantiate functional_add +(define-fun functional_add ((inputs my_module_inputs)) (_ BitVec 1) + (let ((a (my_module_inputs_a inputs)) + (b (my_module_inputs_b inputs))) + (bvadd a b) + ) +) + +; Instantiate old_add +(define-fun old_add ((inputs my_module_inputs)) (_ BitVec 1) + (let ((a (my_module_inputs_a inputs)) + (b (my_module_inputs_b inputs))) + (bvadd a b) + ) +) + +; Assert equivalence +(assert (not (= (functional_add inputs) (old_add inputs)))) + +; Check satisfiability +(check-sat) \ No newline at end of file diff --git a/flake.nix b/flake.nix index ea55c012e5d..22d4cf9da97 100644 --- a/flake.nix +++ b/flake.nix @@ -67,7 +67,7 @@ packages.vcdiff = vcdiff; devShell = pkgs.mkShell { LOCALE_ARCHIVE_2_27 = "${pkgs.glibcLocales}/lib/locale/locale-archive"; - buildInputs = with pkgs; [ clang bison flex libffi tcl readline python3 llvmPackages.libcxxClang zlib git gtest abc-verifier gtkwave vcdiff lcov racket verilog ]; + buildInputs = with pkgs; [ clang bison flex libffi tcl readline python3 llvmPackages.libcxxClang zlib git gtest abc-verifier gtkwave vcdiff lcov racket verilog z3 ]; }; } ); diff --git a/functional_add.smt2 b/functional_add.smt2 new file mode 100644 index 00000000000..18be0c8f9cd --- /dev/null +++ b/functional_add.smt2 @@ -0,0 +1,23 @@ +(declare-datatype my_module_inputs ((my_module_inputs + (my_module_inputs_b (_ BitVec 1)) + (my_module_inputs_a (_ BitVec 1)) +))) +(declare-datatype my_module_outputs ((my_module_outputs + (my_module_outputs_sum (_ BitVec 1)) +))) +(declare-datatype my_module_state ((my_module_state +))) +(declare-datatypes ((Pair 2)) ((par (X Y) ((pair (first X) (second Y)))))) +(define-fun my_module_step ((inputs my_module_inputs) (current_state my_module_state)) (Pair my_module_outputs my_module_state) + (let (((b (my_module_inputs_b inputs)))) + (let (((a (my_module_inputs_a inputs)))) + (let ((($add$tests/functional/single_bit/verilog/my_module_add.v_7$1$_Y (bvadd a b)))) + (pair + (my_module_outputs + $add$tests/functional/single_bit/verilog/my_module_add.v_7$1$_Y ; sum + ) + (my_module_state + ) + ) + ))) +) diff --git a/kernel/alternative_functional.h b/kernel/alternative_functional.h new file mode 100644 index 00000000000..e5ee8824099 --- /dev/null +++ b/kernel/alternative_functional.h @@ -0,0 +1,369 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2024 Jannis Harder + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#ifndef FUNCTIONAL_H +#define FUNCTIONAL_H + +#include +#include "kernel/yosys.h" + +YOSYS_NAMESPACE_BEGIN + +template< + typename Fn, // Function type (deduplicated across whole graph) + typename Attr = std::tuple<>, // Call attributes (present in every node) + typename SparseAttr = std::tuple<>, // Sparse call attributes (optional per node) + typename Key = std::tuple<> // Stable keys to refer to nodes +> +struct ComputeGraph +{ + struct Ref; +private: + + // Functions are deduplicated by assigning unique ids + idict functions; + + struct Node { + int fn_index; + int arg_offset; + int arg_count; + Attr attr; + + Node(int fn_index, Attr &&attr, int arg_offset, int arg_count = 0) + : fn_index(fn_index), arg_offset(arg_offset), arg_count(arg_count), attr(std::move(attr)) {} + + Node(int fn_index, Attr const &attr, int arg_offset, int arg_count = 0) + : fn_index(fn_index), arg_offset(arg_offset), arg_count(arg_count), attr(attr) {} + }; + + + std::vector nodes; + std::vector args; + dict keys_; + dict sparse_attrs; + +public: + template + struct BaseRef + { + protected: + friend struct ComputeGraph; + Graph *graph_; + int index_; + BaseRef(Graph *graph, int index) : graph_(graph), index_(index) { + log_assert(index_ >= 0); + check(); + } + + void check() const { log_assert(index_ < graph_->size()); } + + Node const &deref() const { check(); return graph_->nodes[index_]; } + + public: + ComputeGraph const &graph() const { return graph_; } + int index() const { return index_; } + + int size() const { return deref().arg_count; } + + BaseRef arg(int n) const + { + Node const &node = deref(); + log_assert(n >= 0 && n < node.arg_count); + return BaseRef(graph_, graph_->args[node.arg_offset + n]); + } + + std::vector::const_iterator arg_indices_cbegin() const + { + Node const &node = deref(); + return graph_->args.cbegin() + node.arg_offset; + } + + std::vector::const_iterator arg_indices_cend() const + { + Node const &node = deref(); + return graph_->args.cbegin() + node.arg_offset + node.arg_count; + } + + Fn const &function() const { return graph_->functions[deref().fn_index]; } + Attr const &attr() const { return deref().attr; } + + bool has_sparse_attr() const { return graph_->sparse_attrs.count(index_); } + + SparseAttr const &sparse_attr() const + { + auto found = graph_->sparse_attrs.find(index_); + log_assert(found != graph_->sparse_attrs.end()); + return *found; + } + }; + + using ConstRef = BaseRef; + + struct Ref : public BaseRef + { + private: + friend struct ComputeGraph; + Ref(ComputeGraph *graph, int index) : BaseRef(graph, index) {} + Node &deref() const { this->check(); return this->graph_->nodes[this->index_]; } + + public: + void set_function(Fn const &function) const + { + deref().fn_index = this->graph_->functions(function); + } + + Attr &attr() const { return deref().attr; } + + void append_arg(ConstRef arg) const + { + log_assert(arg.graph_ == this->graph_); + append_arg(arg.index()); + } + + void append_arg(int arg) const + { + log_assert(arg >= 0 && arg < this->graph_->size()); + Node &node = deref(); + if (node.arg_offset + node.arg_count != GetSize(this->graph_->args)) + move_args(node); + this->graph_->args.push_back(arg); + node.arg_count++; + } + + operator ConstRef() const + { + return ConstRef(this->graph_, this->index_); + } + + SparseAttr &sparse_attr() const + { + return this->graph_->sparse_attrs[this->index_]; + } + + void clear_sparse_attr() const + { + this->graph_->sparse_attrs.erase(this->index_); + } + + void assign_key(Key const &key) const + { + this->graph_->keys_.emplace(key, this->index_); + } + + private: + void move_args(Node &node) const + { + auto &args = this->graph_->args; + int old_offset = node.arg_offset; + node.arg_offset = GetSize(args); + for (int i = 0; i != node.arg_count; ++i) + args.push_back(args[old_offset + i]); + } + + }; + + bool has_key(Key const &key) const + { + return keys_.count(key); + } + + dict const &keys() const + { + return keys_; + } + + ConstRef operator()(Key const &key) const + { + auto it = keys_.find(key); + log_assert(it != keys_.end()); + return (*this)[it->second]; + } + + Ref operator()(Key const &key) + { + auto it = keys_.find(key); + log_assert(it != keys_.end()); + return (*this)[it->second]; + } + + int size() const { return GetSize(nodes); } + + ConstRef operator[](int index) const { return ConstRef(this, index); } + Ref operator[](int index) { return Ref(this, index); } + + Ref add(Fn const &function, Attr &&attr) + { + int index = GetSize(nodes); + int fn_index = functions(function); + nodes.emplace_back(fn_index, std::move(attr), GetSize(args)); + return Ref(this, index); + } + + Ref add(Fn const &function, Attr const &attr) + { + int index = GetSize(nodes); + int fn_index = functions(function); + nodes.emplace_back(fn_index, attr, GetSize(args)); + return Ref(this, index); + } + + template + Ref add(Fn const &function, Attr const &attr, T const &args) + { + Ref added = add(function, attr); + for (auto arg : args) + added.append_arg(arg); + return added; + } + + template + Ref add(Fn const &function, Attr &&attr, T const &args) + { + Ref added = add(function, std::move(attr)); + for (auto arg : args) + added.append_arg(arg); + return added; + } + + template + Ref add(Fn const &function, Attr const &attr, T begin, T end) + { + Ref added = add(function, attr); + for (; begin != end; ++begin) + added.append_arg(*begin); + return added; + } + + void permute(std::vector const &perm) + { + log_assert(perm.size() <= nodes.size()); + std::vector inv_perm; + inv_perm.resize(nodes.size(), -1); + for (int i = 0; i < GetSize(perm); ++i) + { + int j = perm[i]; + log_assert(j >= 0 && j < GetSize(perm)); + log_assert(inv_perm[j] == -1); + inv_perm[j] = i; + } + permute(perm, inv_perm); + } + + void permute(std::vector const &perm, std::vector const &inv_perm) + { + log_assert(inv_perm.size() == nodes.size()); + std::vector new_nodes; + new_nodes.reserve(perm.size()); + dict new_sparse_attrs; + for (int i : perm) + { + int j = GetSize(new_nodes); + new_nodes.emplace_back(std::move(nodes[i])); + auto found = sparse_attrs.find(i); + if (found != sparse_attrs.end()) + new_sparse_attrs.emplace(j, std::move(found->second)); + } + + std::swap(nodes, new_nodes); + std::swap(sparse_attrs, new_sparse_attrs); + + for (int &arg : args) + { + log_assert(arg < GetSize(inv_perm)); + arg = inv_perm[arg]; + } + + for (auto &key : keys_) + { + log_assert(key.second < GetSize(inv_perm)); + key.second = inv_perm[key.second]; + } + } + + struct SccAdaptor + { + private: + ComputeGraph const &graph_; + std::vector indices_; + public: + SccAdaptor(ComputeGraph const &graph) : graph_(graph) + { + indices_.resize(graph.size(), -1); + } + + + typedef int node_type; + + struct node_enumerator { + private: + friend struct SccAdaptor; + int current, end; + node_enumerator(int current, int end) : current(current), end(end) {} + + public: + + bool finished() const { return current == end; } + node_type next() { + log_assert(!finished()); + node_type result = current; + ++current; + return result; + } + }; + + node_enumerator enumerate_nodes() { + return node_enumerator(0, GetSize(indices_)); + } + + + struct successor_enumerator { + private: + friend struct SccAdaptor; + std::vector::const_iterator current, end; + successor_enumerator(std::vector::const_iterator current, std::vector::const_iterator end) : + current(current), end(end) {} + + public: + bool finished() const { return current == end; } + node_type next() { + log_assert(!finished()); + node_type result = *current; + ++current; + return result; + } + }; + + successor_enumerator enumerate_successors(int index) const { + auto const &ref = graph_[index]; + return successor_enumerator(ref.arg_indices_cbegin(), ref.arg_indices_cend()); + } + + int &dfs_index(node_type const &node) { return indices_[node]; } + + std::vector const &dfs_indices() { return indices_; } + }; + +}; + + + +YOSYS_NAMESPACE_END + + +#endif diff --git a/kernel/alternative_graphtools.h b/kernel/alternative_graphtools.h new file mode 100644 index 00000000000..4abe6c5942b --- /dev/null +++ b/kernel/alternative_graphtools.h @@ -0,0 +1,509 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2024 Emily Schmidt + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#ifndef GRAPHTOOLS_H +#define GRAPHTOOLS_H + +#include "kernel/yosys.h" +#include "kernel/drivertools.h" +#include "kernel/functional.h" + +USING_YOSYS_NAMESPACE +YOSYS_NAMESPACE_BEGIN + +template +class CellSimplifier { + Factory &factory; + T reduce_shift_width(T b, int b_width, int y_width, int &reduced_b_width) { + log_assert(y_width > 0); + int new_width = ceil_log2(y_width + 1); + if (b_width <= new_width) { + reduced_b_width = b_width; + return b; + } else { + reduced_b_width = new_width; + T lower_b = factory.slice(b, b_width, 0, new_width); + T overflow = factory.gt(b, factory.constant(RTLIL::Const(y_width, b_width)), b_width); + return factory.mux(lower_b, factory.constant(RTLIL::Const(y_width, new_width)), overflow, new_width); + } + } +public: + T reduce_or(T a, int width) { + if (width == 1) + return a; + return factory.reduce_or(a, width); + } + T extend(T a, int in_width, int out_width, bool is_signed) { + if(in_width == out_width) + return a; + if(in_width > out_width) + return factory.slice(a, in_width, 0, out_width); + return factory.extend(a, in_width, out_width, is_signed); + } + T logical_shift_left(T a, T b, int y_width, int b_width) { + int reduced_b_width; + T reduced_b = reduce_shift_width(b, b_width, y_width, reduced_b_width); + return factory.logical_shift_left(a, reduced_b, y_width, reduced_b_width); + } + T logical_shift_right(T a, T b, int y_width, int b_width) { + int reduced_b_width; + T reduced_b = reduce_shift_width(b, b_width, y_width, reduced_b_width); + return factory.logical_shift_right(a, reduced_b, y_width, reduced_b_width); + } + T arithmetic_shift_right(T a, T b, int y_width, int b_width) { + int reduced_b_width; + T reduced_b = reduce_shift_width(b, b_width, y_width, reduced_b_width); + return factory.arithmetic_shift_right(a, reduced_b, y_width, reduced_b_width); + } + CellSimplifier(Factory &f) : factory(f) {} + T handle(IdString cellType, dict parameters, dict inputs) + { + int a_width = parameters.at(ID(A_WIDTH), Const(-1)).as_int(); + int b_width = parameters.at(ID(B_WIDTH), Const(-1)).as_int(); + int y_width = parameters.at(ID(Y_WIDTH), Const(-1)).as_int(); + bool a_signed = parameters.at(ID(A_SIGNED), Const(0)).as_bool(); + bool b_signed = parameters.at(ID(B_SIGNED), Const(0)).as_bool(); + if(cellType.in({ID($add), ID($sub), ID($and), ID($or), ID($xor), ID($xnor)})){ + bool is_signed = a_signed && b_signed; + T a = extend(inputs.at(ID(A)), a_width, y_width, is_signed); + T b = extend(inputs.at(ID(B)), b_width, y_width, is_signed); + if(cellType == ID($add)) + return factory.add(a, b, y_width); + else if(cellType == ID($sub)) + return factory.sub(a, b, y_width); + else if(cellType == ID($and)) + return factory.bitwise_and(a, b, y_width); + else if(cellType == ID($or)) + return factory.bitwise_or(a, b, y_width); + else if(cellType == ID($xor)) + return factory.bitwise_xor(a, b, y_width); + else if(cellType == ID($xnor)) + return factory.bitwise_not(factory.bitwise_xor(a, b, y_width), y_width); + else + log_abort(); + }else if(cellType.in({ID($eq), ID($ne), ID($eqx), ID($nex), ID($le), ID($lt), ID($ge), ID($gt)})){ + bool is_signed = a_signed && b_signed; + int width = max(a_width, b_width); + T a = extend(inputs.at(ID(A)), a_width, width, is_signed); + T b = extend(inputs.at(ID(B)), b_width, width, is_signed); + if(cellType.in({ID($eq), ID($eqx)})) + return extend(factory.eq(a, b, width), 1, y_width, false); + if(cellType.in({ID($ne), ID($nex)})) + return extend(factory.ne(a, b, width), 1, y_width, false); + else if(cellType == ID($lt)) + return extend(is_signed ? factory.gt(b, a, width) : factory.ugt(b, a, width), 1, y_width, false); + else if(cellType == ID($le)) + return extend(is_signed ? factory.ge(b, a, width) : factory.uge(b, a, width), 1, y_width, false); + else if(cellType == ID($gt)) + return extend(is_signed ? factory.gt(a, b, width) : factory.ugt(a, b, width), 1, y_width, false); + else if(cellType == ID($ge)) + return extend(is_signed ? factory.ge(a, b, width) : factory.uge(a, b, width), 1, y_width, false); + else + log_abort(); + }else if(cellType.in({ID($logic_or), ID($logic_and)})){ + T a = reduce_or(inputs.at(ID(A)), a_width); + T b = reduce_or(inputs.at(ID(B)), b_width); + T y = cellType == ID($logic_and) ? factory.bitwise_and(a, b, 1) : factory.bitwise_or(a, b, 1); + return extend(y, 1, y_width, false); + }else if(cellType == ID($not)){ + T a = extend(inputs.at(ID(A)), a_width, y_width, a_signed); + return factory.bitwise_not(a, y_width); + }else if(cellType == ID($pos)){ + return extend(inputs.at(ID(A)), a_width, y_width, a_signed); + }else if(cellType == ID($neg)){ + T a = extend(inputs.at(ID(A)), a_width, y_width, a_signed); + return factory.neg(a, y_width); + }else if(cellType == ID($logic_not)){ + T a = reduce_or(inputs.at(ID(A)), a_width); + T y = factory.bitwise_not(a, 1); + return extend(y, 1, y_width, false); + }else if(cellType.in({ID($reduce_or), ID($reduce_bool)})){ + T a = reduce_or(inputs.at(ID(A)), a_width); + return extend(a, 1, y_width, false); + }else if(cellType == ID($reduce_and)){ + T a = factory.reduce_and(inputs.at(ID(A)), a_width); + return extend(a, 1, y_width, false); + }else if(cellType.in({ID($reduce_xor), ID($reduce_xnor)})){ + T a = factory.reduce_xor(inputs.at(ID(A)), a_width); + T y = cellType == ID($reduce_xnor) ? factory.bitwise_not(a, 1) : a; + return extend(y, 1, y_width, false); + }else if(cellType == ID($shl) || cellType == ID($sshl)){ + T a = extend(inputs.at(ID(A)), a_width, y_width, a_signed); + T b = inputs.at(ID(B)); + return logical_shift_left(a, b, y_width, b_width); + }else if(cellType == ID($shr) || cellType == ID($sshr)){ + int width = max(a_width, y_width); + T a = extend(inputs.at(ID(A)), a_width, width, a_signed); + T b = inputs.at(ID(B)); + T y = a_signed && cellType == ID($sshr) ? + arithmetic_shift_right(a, b, width, b_width) : + logical_shift_right(a, b, width, b_width); + return extend(y, width, y_width, a_signed); + }else if(cellType == ID($shiftx) || cellType == ID($shift)){ + int width = max(a_width, y_width); + T a = extend(inputs.at(ID(A)), a_width, width, cellType == ID($shift) && a_signed); + T b = inputs.at(ID(B)); + T shr = logical_shift_right(a, b, width, b_width); + if(b_signed) { + T sign_b = factory.slice(b, b_width, b_width - 1, 1); + T shl = logical_shift_left(a, factory.neg(b, b_width), width, b_width); + T y = factory.mux(shr, shl, sign_b, width); + return extend(y, width, y_width, false); + } else { + return extend(shr, width, y_width, false); + } + }else if(cellType == ID($mux)){ + int width = parameters.at(ID(WIDTH)).as_int(); + return factory.mux(inputs.at(ID(A)), inputs.at(ID(B)), inputs.at(ID(S)), width); + }else if(cellType == ID($pmux)){ + int width = parameters.at(ID(WIDTH)).as_int(); + int s_width = parameters.at(ID(S_WIDTH)).as_int(); + return factory.pmux(inputs.at(ID(A)), inputs.at(ID(B)), inputs.at(ID(S)), width, s_width); + }else if(cellType == ID($concat)){ + T a = inputs.at(ID(A)); + T b = inputs.at(ID(B)); + return factory.concat(a, a_width, b, b_width); + }else if(cellType == ID($slice)){ + int offset = parameters.at(ID(OFFSET)).as_int(); + T a = inputs.at(ID(A)); + return factory.slice(a, a_width, offset, y_width); + }else if(cellType == ID($mul)){ + bool is_signed = a_signed && b_signed; + int width = a_width + b_width; + T a = extend(inputs.at(ID(A)), a_width, width, is_signed); + T b = extend(inputs.at(ID(B)), b_width, width, is_signed); + return extend(factory.mul(a, b, width), width, y_width, is_signed); + }else if(cellType == ID($div)){ + bool is_signed = a_signed && b_signed; + int width = max(a_width, b_width); + T a = extend(inputs.at(ID(A)), a_width, width, is_signed); + T b = extend(inputs.at(ID(B)), b_width, width, is_signed); + return extend(factory.div(a, b, width), width, y_width, is_signed); + }else if(cellType == ID($mod)){ + bool is_signed = a_signed && b_signed; + int width = max(a_width, b_width); + T a = extend(inputs.at(ID(A)), a_width, width, is_signed); + T b = extend(inputs.at(ID(B)), b_width, width, is_signed); + return extend(factory.mod(a, b, width), width, y_width, is_signed); + }else{ + log_error("unhandled cell in CellSimplifier %s\n", cellType.c_str()); + } + } +}; + + +struct Function { + IdString name; + int width; + dict parameters; + + Function(IdString name, int width) : name(name), width(width) {} + Function(IdString name, int width, dict parameters) : name(name), width(width), parameters(parameters) {} + + bool operator==(Function const &other) const { + return name == other.name && parameters == other.parameters && width == other.width; + } + + unsigned int hash() const { + return mkhash(name.hash(), parameters.hash()); + } +}; + +typedef ComputeGraph CompleteComputeGraph; + +class CompleteComputeGraphFactory { + CompleteComputeGraph &graph; + using T = CompleteComputeGraph::Ref; + static bool is_single_output(IdString type) + { + auto it = yosys_celltypes.cell_types.find(type); + return it != yosys_celltypes.cell_types.end() && it->second.outputs.size() <= 1; + } +public: + CompleteComputeGraphFactory(CompleteComputeGraph &g) : graph(g) {} + T slice(T a, int in_width, int offset, int out_width) { + assert(offset + out_width <= in_width); + return graph.add(Function(ID($$slice), out_width, {{ID(offset), offset}}), 0, std::array{a}); + } + T extend(T a, int in_width, int out_width, bool is_signed) { + assert(in_width < out_width); + if(is_signed) + return graph.add(Function(ID($sign_extend), out_width, {{ID(WIDTH), out_width}}), 0, std::array{a}); + else + return graph.add(Function(ID($zero_extend), out_width, {{ID(WIDTH), out_width}}), 0, std::array{a}); + } + T concat(T a, int a_width, T b, int b_width) { + return graph.add(Function(ID($$concat), a_width + b_width), 0, std::array{a, b}); + } + T add(T a, T b, int width) { return graph.add(Function(ID($add), width), 0, std::array{a, b}); } + T sub(T a, T b, int width) { return graph.add(Function(ID($sub), width), 0, std::array{a, b}); } + T bitwise_and(T a, T b, int width) { return graph.add(Function(ID($and), width), 0, std::array{a, b}); } + T bitwise_or(T a, T b, int width) { return graph.add(Function(ID($or), width), 0, std::array{a, b}); } + T bitwise_xor(T a, T b, int width) { return graph.add(Function(ID($xor), width), 0, std::array{a, b}); } + T bitwise_not(T a, int width) { return graph.add(Function(ID($not), width), 0, std::array{a}); } + T neg(T a, int width) { return graph.add(Function(ID($neg), width), 0, std::array{a}); } + T mux(T a, T b, T s, int width) { return graph.add(Function(ID($mux), width), 0, std::array{a, b, s}); } + T pmux(T a, T b, T s, int width, int) { return graph.add(Function(ID($pmux), width), 0, std::array{a, b, s}); } + T reduce_and(T a, int) { return graph.add(Function(ID($reduce_and), 1), 0, std::array{a}); } + T reduce_or(T a, int) { return graph.add(Function(ID($reduce_or), 1), 0, std::array{a}); } + T reduce_xor(T a, int) { return graph.add(Function(ID($reduce_xor), 1), 0, std::array{a}); } + T eq(T a, T b, int) { return graph.add(Function(ID($eq), 1), 0, std::array{a, b}); } + T ne(T a, T b, int) { return graph.add(Function(ID($ne), 1), 0, std::array{a, b}); } + T gt(T a, T b, int) { return graph.add(Function(ID($gt), 1), 0, std::array{a, b}); } + T ge(T a, T b, int) { return graph.add(Function(ID($ge), 1), 0, std::array{a, b}); } + T ugt(T a, T b, int) { return graph.add(Function(ID($ugt), 1), 0, std::array{a, b}); } + T uge(T a, T b, int) { return graph.add(Function(ID($uge), 1), 0, std::array{a, b}); } + T logical_shift_left(T a, T b, int y_width, int) { return graph.add(Function(ID($shl), y_width, {{ID(WIDTH), y_width}}), 0, std::array{a, b}); } + T logical_shift_right(T a, T b, int y_width, int) { return graph.add(Function(ID($shr), y_width, {{ID(WIDTH), y_width}}), 0, std::array{a, b}); } + T arithmetic_shift_right(T a, T b, int y_width, int) { return graph.add(Function(ID($asr), y_width, {{ID(WIDTH), y_width}}), 0, std::array{a, b}); } + T mul(T a, T b, int width) { return graph.add(Function(ID($mul), width), 0, std::array{a, b}); } + T mod(T a, T b, int width) { return graph.add(Function(ID($mod), width), 0, std::array{a, b}); } + T div(T a, T b, int width) { return graph.add(Function(ID($div), width), 0, std::array{a, b}); } + + T constant(RTLIL::Const value) { + return graph.add(Function(ID($$const), value.size(), {{ID(value), value}}), 0); + } + T input(IdString name, int width) { return graph.add(Function(ID($$input), width, {{name, {}}}), 0); } + T state(IdString name, int width) { return graph.add(Function(ID($$state), width, {{name, {}}}), 0); } + T cell_output(T cell, IdString type, IdString name, int width) { + if (is_single_output(type)) + return cell; + else + return graph.add(Function(ID($$cell_output), width, {{name, {}}}), 0, std::array{cell}); + } + T multiple(vector args, int width) { + return graph.add(Function(ID($$multiple), width), 0, args); + } + T undriven(int width) { + return graph.add(Function(ID($$undriven), width), 0); + } + + T create_pending(int width) { + return graph.add(Function(ID($$pending), width), 0); + } + void update_pending(T pending, T node) { + assert(pending.function().name == ID($$pending)); + pending.set_function(Function(ID($$buf), pending.function().width)); + pending.append_arg(node); + } + void declare_output(T node, IdString name, int) { + node.assign_key(name); + } + void declare_state(T node, IdString name, int) { + node.assign_key(name); + } + void suggest_name(T node, IdString name) { + node.sparse_attr() = name; + } +}; + +template +class ComputeGraphConstruction { + std::deque queue; + dict graph_nodes; + idict cells; + DriverMap driver_map; + Factory& factory; + CellSimplifier simplifier; + + T enqueue(DriveSpec const &spec) + { + auto it = graph_nodes.find(spec); + if(it == graph_nodes.end()){ + auto node = factory.create_pending(spec.size()); + graph_nodes.insert({spec, node}); + queue.emplace_back(spec); + return node; + }else + return it->second; + } +public: + ComputeGraphConstruction(Factory &f) : factory(f), simplifier(f) {} + void add_module(Module *module) + { + driver_map.add(module); + for (auto cell : module->cells()) { + if (cell->type.in(ID($assert), ID($assume), ID($cover), ID($check))) + enqueue(DriveBitMarker(cells(cell), 0)); + } + for (auto wire : module->wires()) { + if (wire->port_output) { + T node = enqueue(DriveChunk(DriveChunkWire(wire, 0, wire->width))); + factory.declare_output(node, wire->name, wire->width); + } + } + } + void process_queue() + { + for (; !queue.empty(); queue.pop_front()) { + DriveSpec spec = queue.front(); + T pending = graph_nodes.at(spec); + + if (spec.chunks().size() > 1) { + auto chunks = spec.chunks(); + T node = enqueue(chunks[0]); + int width = chunks[0].size(); + for(size_t i = 1; i < chunks.size(); i++) { + node = factory.concat(node, width, enqueue(chunks[i]), chunks[i].size()); + width += chunks[i].size(); + } + factory.update_pending(pending, node); + } else if (spec.chunks().size() == 1) { + DriveChunk chunk = spec.chunks()[0]; + if (chunk.is_wire()) { + DriveChunkWire wire_chunk = chunk.wire(); + if (wire_chunk.is_whole()) { + if (wire_chunk.wire->port_input) { + T node = factory.input(wire_chunk.wire->name, wire_chunk.width); + factory.suggest_name(node, wire_chunk.wire->name); + factory.update_pending(pending, node); + } else { + DriveSpec driver = driver_map(DriveSpec(wire_chunk)); + T node = enqueue(driver); + factory.suggest_name(node, wire_chunk.wire->name); + factory.update_pending(pending, node); + } + } else { + DriveChunkWire whole_wire(wire_chunk.wire, 0, wire_chunk.wire->width); + T node = factory.slice(enqueue(whole_wire), wire_chunk.wire->width, wire_chunk.offset, wire_chunk.width); + factory.update_pending(pending, node); + } + } else if (chunk.is_port()) { + DriveChunkPort port_chunk = chunk.port(); + if (port_chunk.is_whole()) { + if (driver_map.celltypes.cell_output(port_chunk.cell->type, port_chunk.port)) { + if (port_chunk.cell->type.in(ID($dff), ID($ff))) + { + Cell *cell = port_chunk.cell; + T node = factory.state(cell->name, port_chunk.width); + factory.suggest_name(node, port_chunk.cell->name); + factory.update_pending(pending, node); + for (auto const &conn : cell->connections()) { + if (driver_map.celltypes.cell_input(cell->type, conn.first)) { + T node = enqueue(DriveChunkPort(cell, conn)); + factory.declare_state(node, cell->name, port_chunk.width); + } + } + } + else + { + T cell = enqueue(DriveChunkMarker(cells(port_chunk.cell), 0, port_chunk.width)); + factory.suggest_name(cell, port_chunk.cell->name); + T node = factory.cell_output(cell, port_chunk.cell->type, port_chunk.port, port_chunk.width); + factory.suggest_name(node, port_chunk.cell->name.str() + "$" + port_chunk.port.str()); + factory.update_pending(pending, node); + } + } else { + DriveSpec driver = driver_map(DriveSpec(port_chunk)); + factory.update_pending(pending, enqueue(driver)); + } + } else { + DriveChunkPort whole_port(port_chunk.cell, port_chunk.port, 0, GetSize(port_chunk.cell->connections().at(port_chunk.port))); + T node = factory.slice(enqueue(whole_port), whole_port.width, port_chunk.offset, port_chunk.width); + factory.update_pending(pending, node); + } + } else if (chunk.is_constant()) { + T node = factory.constant(chunk.constant()); + factory.suggest_name(node, "$const" + std::to_string(chunk.size()) + "b" + chunk.constant().as_string()); + factory.update_pending(pending, node); + } else if (chunk.is_multiple()) { + vector args; + for (auto const &driver : chunk.multiple().multiple()) + args.push_back(enqueue(driver)); + T node = factory.multiple(args, chunk.size()); + factory.update_pending(pending, node); + } else if (chunk.is_marker()) { + Cell *cell = cells[chunk.marker().marker]; + dict connections; + for(auto const &conn : cell->connections()) { + if(driver_map.celltypes.cell_input(cell->type, conn.first)) + connections.insert({ conn.first, enqueue(DriveChunkPort(cell, conn)) }); + } + T node = simplifier.handle(cell->type, cell->parameters, connections); + factory.update_pending(pending, node); + } else if (chunk.is_none()) { + T node = factory.undriven(chunk.size()); + factory.update_pending(pending, node); + } else { + log_error("unhandled drivespec: %s\n", log_signal(chunk)); + log_abort(); + } + } else { + log_abort(); + } + } + } +}; + +CompleteComputeGraph calculate_compute_graph(RTLIL::Module *module) +{ + CompleteComputeGraph compute_graph; + CompleteComputeGraphFactory factory(compute_graph); + ComputeGraphConstruction construction(factory); + construction.add_module(module); + construction.process_queue(); + + // Perform topo sort and detect SCCs + CompleteComputeGraph::SccAdaptor compute_graph_scc(compute_graph); + + bool scc = false; + std::vector perm; + topo_sorted_sccs(compute_graph_scc, [&](int *begin, int *end) { + perm.insert(perm.end(), begin, end); + if (end > begin + 1) + { + log_warning("SCC:"); + for (int *i = begin; i != end; ++i) + log(" %d(%s)(%s)", *i, compute_graph[*i].function().name.c_str(), compute_graph[*i].has_sparse_attr() ? compute_graph[*i].sparse_attr().c_str() : ""); + log("\n"); + scc = true; + } + }, /* sources_first */ true); + compute_graph.permute(perm); + if(scc) log_error("combinational loops, aborting\n"); + + // Forward $$buf + std::vector alias; + perm.clear(); + + for (int i = 0; i < compute_graph.size(); ++i) + { + auto node = compute_graph[i]; + if (node.function().name == ID($$buf) && node.arg(0).index() < i) + { + int target_index = alias[node.arg(0).index()]; + auto target_node = compute_graph[perm[target_index]]; + if(!target_node.has_sparse_attr() && node.has_sparse_attr()) + target_node.sparse_attr() = node.sparse_attr(); + alias.push_back(target_index); + } + else + { + alias.push_back(GetSize(perm)); + perm.push_back(i); + } + } + compute_graph.permute(perm, alias); + return compute_graph; +}; + + +YOSYS_NAMESPACE_END + +#endif diff --git a/kernel/functional.h b/kernel/functional.h index e5ee8824099..90cf8a829ee 100644 --- a/kernel/functional.h +++ b/kernel/functional.h @@ -118,7 +118,7 @@ struct ComputeGraph struct Ref : public BaseRef { private: - friend struct ComputeGraph; + friend struct ComputeGraph; Ref(ComputeGraph *graph, int index) : BaseRef(graph, index) {} Node &deref() const { this->check(); return this->graph_->nodes[this->index_]; } diff --git a/old_add.smt2 b/old_add.smt2 new file mode 100644 index 00000000000..ed1f3319164 --- /dev/null +++ b/old_add.smt2 @@ -0,0 +1,22 @@ +; SMT-LIBv2 description generated by Yosys 0.41+101 (git sha1 52cc2ae5c, g++ 11.4.0-1ubuntu1~22.04 -fPIC -Os) +; yosys-smt2-module my_module +(declare-sort |my_module_s| 0) +(declare-fun |my_module_is| (|my_module_s|) Bool) +(declare-fun |my_module#0| (|my_module_s|) (_ BitVec 1)) ; \a +(declare-fun |my_module#1| (|my_module_s|) (_ BitVec 1)) ; \b +(define-fun |my_module#2| ((state |my_module_s|)) (_ BitVec 1) (bvadd (|my_module#0| state) (|my_module#1| state))) ; $add$tests/functional/single_bit/verilog/my_module_add.v:7$1_Y +; yosys-smt2-output sum 1 +(define-fun |my_module_n sum| ((state |my_module_s|)) Bool (= ((_ extract 0 0) (|my_module#2| state)) #b1)) +; yosys-smt2-input b 1 +; yosys-smt2-witness {"offset": 0, "path": ["\\b"], "smtname": "b", "smtoffset": 0, "type": "input", "width": 1} +(define-fun |my_module_n b| ((state |my_module_s|)) Bool (= ((_ extract 0 0) (|my_module#1| state)) #b1)) +; yosys-smt2-input a 1 +; yosys-smt2-witness {"offset": 0, "path": ["\\a"], "smtname": "a", "smtoffset": 0, "type": "input", "width": 1} +(define-fun |my_module_n a| ((state |my_module_s|)) Bool (= ((_ extract 0 0) (|my_module#0| state)) #b1)) +(define-fun |my_module_a| ((state |my_module_s|)) Bool true) +(define-fun |my_module_u| ((state |my_module_s|)) Bool true) +(define-fun |my_module_i| ((state |my_module_s|)) Bool true) +(define-fun |my_module_h| ((state |my_module_s|)) Bool true) +(define-fun |my_module_t| ((state |my_module_s|) (next_state |my_module_s|)) Bool true) ; end of module my_module +; yosys-smt2-topmod my_module +; end of yosys output diff --git a/tests/functional/smt/harness.smt2 b/tests/functional/smt/harness.smt2 new file mode 100644 index 00000000000..0937791305e --- /dev/null +++ b/tests/functional/smt/harness.smt2 @@ -0,0 +1,48 @@ +; Load the datatypes and function definitions +(declare-datatype my_module_inputs ((my_module_inputs + (my_module_inputs_b (_ BitVec 1)) + (my_module_inputs_a (_ BitVec 1)) +))) +(declare-datatype my_module_outputs ((my_module_outputs + (my_module_outputs_sum (_ BitVec 1)) +))) +(declare-datatype my_module_state (())) + +(declare-datatypes ((Pair 2)) ((par (X Y) ((pair (first X) (second Y)))))) + +(define-fun my_module_step ((inputs my_module_inputs) (current_state my_module_state)) (Pair my_module_outputs my_module_state) + (let (((b (my_module_inputs_b inputs)))) + (let (((a (my_module_inputs_a inputs)))) + (let ((($add$tests/functional/single_bit/verilog/my_module_add.v_7$1$_Y (bvadd a b)))) + (pair + (my_module_outputs + $add$tests/functional/single_bit/verilog/my_module_add.v_7$1$_Y ; sum + ) + (my_module_state + ) + ) + ))) +) + +; Create input values +(declare-const input_a (_ BitVec 1)) +(declare-const input_b (_ BitVec 1)) +(declare-const initial_state my_module_state) + +; Define input values +(assert (= input_a #b1)) ; or #b0 for 0 +(assert (= input_b #b0)) ; or #b1 for 1 + +; Construct the input object +(define-const inputs my_module_inputs (my_module_inputs input_b input_a)) + +; Call the step function +(define-const result (my_module_step inputs initial_state)) + +; Extract the output +(define-const output (first result)) +(define-const output_sum (my_module_outputs_sum output)) + +; Check the output +(check-sat) +(get-value (output_sum)) \ No newline at end of file From da2b07616a79d4a55c05ea6af5b798659f0fcfdb Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Tue, 4 Jun 2024 17:30:12 +0200 Subject: [PATCH 41/51] WIP --- tests/functional/smt/harness.smt2 | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/tests/functional/smt/harness.smt2 b/tests/functional/smt/harness.smt2 index 0937791305e..51bcf18c486 100644 --- a/tests/functional/smt/harness.smt2 +++ b/tests/functional/smt/harness.smt2 @@ -6,28 +6,24 @@ (declare-datatype my_module_outputs ((my_module_outputs (my_module_outputs_sum (_ BitVec 1)) ))) -(declare-datatype my_module_state (())) +; (declare-datatype my_module_state (())) (declare-datatypes ((Pair 2)) ((par (X Y) ((pair (first X) (second Y)))))) -(define-fun my_module_step ((inputs my_module_inputs) (current_state my_module_state)) (Pair my_module_outputs my_module_state) +(define-fun my_module_step ((inputs my_module_inputs) ) (my_module_outputs) (let (((b (my_module_inputs_b inputs)))) (let (((a (my_module_inputs_a inputs)))) (let ((($add$tests/functional/single_bit/verilog/my_module_add.v_7$1$_Y (bvadd a b)))) - (pair (my_module_outputs $add$tests/functional/single_bit/verilog/my_module_add.v_7$1$_Y ; sum ) - (my_module_state - ) - ) ))) ) ; Create input values (declare-const input_a (_ BitVec 1)) (declare-const input_b (_ BitVec 1)) -(declare-const initial_state my_module_state) +; (declare-const initial_state my_module_state) ; Define input values (assert (= input_a #b1)) ; or #b0 for 0 @@ -37,7 +33,7 @@ (define-const inputs my_module_inputs (my_module_inputs input_b input_a)) ; Call the step function -(define-const result (my_module_step inputs initial_state)) +(define-const result (my_module_step inputs)) ; Extract the output (define-const output (first result)) From ea1edcb8a2394cab3a2ddacae04374ab4a61a364 Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Tue, 4 Jun 2024 17:31:36 +0200 Subject: [PATCH 42/51] WIP --- tests/functional/smt/harness.smt2 | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/tests/functional/smt/harness.smt2 b/tests/functional/smt/harness.smt2 index 51bcf18c486..c5ec5f1e68e 100644 --- a/tests/functional/smt/harness.smt2 +++ b/tests/functional/smt/harness.smt2 @@ -10,14 +10,12 @@ (declare-datatypes ((Pair 2)) ((par (X Y) ((pair (first X) (second Y)))))) -(define-fun my_module_step ((inputs my_module_inputs) ) (my_module_outputs) - (let (((b (my_module_inputs_b inputs)))) - (let (((a (my_module_inputs_a inputs)))) - (let ((($add$tests/functional/single_bit/verilog/my_module_add.v_7$1$_Y (bvadd a b)))) - (my_module_outputs - $add$tests/functional/single_bit/verilog/my_module_add.v_7$1$_Y ; sum - ) - ))) +(define-fun my_module_step ((inputs my_module_inputs)) my_module_outputs + (let ((b (my_module_inputs_b inputs)) + (a (my_module_inputs_a inputs)) + (sum (bvadd a b))) + (my_module_outputs sum) + ) ) ; Create input values @@ -33,11 +31,10 @@ (define-const inputs my_module_inputs (my_module_inputs input_b input_a)) ; Call the step function -(define-const result (my_module_step inputs)) +(define-const result my_module_outputs (my_module_step inputs)) ; Extract the output -(define-const output (first result)) -(define-const output_sum (my_module_outputs_sum output)) +(define-const output_sum (_ BitVec 1) (my_module_outputs_sum result)) ; Check the output (check-sat) From 83a8e5de4f144c1ed41faed67f8abfd9932e6df5 Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Wed, 5 Jun 2024 15:56:51 +0200 Subject: [PATCH 43/51] WIP --- backends/functional/Makefile.inc | 4 +- flake.nix | 1 + tests/functional/smt/harness.smt2 | 72 ++++++++++++++----------------- 3 files changed, 36 insertions(+), 41 deletions(-) diff --git a/backends/functional/Makefile.inc b/backends/functional/Makefile.inc index 675153c95b0..5776bf84ed9 100644 --- a/backends/functional/Makefile.inc +++ b/backends/functional/Makefile.inc @@ -1,4 +1,4 @@ -OBJS += backends/functional/cxx.o +# OBJS += backends/functional/cxx.o # OBJS += backends/functional/smtlib.o -# OBJS += backends/functional/alternative_cxx.o +OBJS += backends/functional/alternative_cxx.o # OBJS += backends/functional/alternative_smtlib.o diff --git a/flake.nix b/flake.nix index 22d4cf9da97..683ee78aafc 100644 --- a/flake.nix +++ b/flake.nix @@ -18,6 +18,7 @@ yosys = pkgs.clangStdenv.mkDerivation { name = "yosys"; src = ./. ; + dontStrip = true; buildInputs = with pkgs; [ clang bison flex libffi tcl readline python3 llvmPackages.libcxxClang zlib git pkg-configUpstream ]; checkInputs = with pkgs; [ gtest ]; propagatedBuildInputs = [ abc-verifier ]; diff --git a/tests/functional/smt/harness.smt2 b/tests/functional/smt/harness.smt2 index c5ec5f1e68e..0bad92a44cf 100644 --- a/tests/functional/smt/harness.smt2 +++ b/tests/functional/smt/harness.smt2 @@ -1,41 +1,35 @@ -; Load the datatypes and function definitions -(declare-datatype my_module_inputs ((my_module_inputs - (my_module_inputs_b (_ BitVec 1)) - (my_module_inputs_a (_ BitVec 1)) -))) -(declare-datatype my_module_outputs ((my_module_outputs - (my_module_outputs_sum (_ BitVec 1)) -))) -; (declare-datatype my_module_state (())) - -(declare-datatypes ((Pair 2)) ((par (X Y) ((pair (first X) (second Y)))))) - -(define-fun my_module_step ((inputs my_module_inputs)) my_module_outputs - (let ((b (my_module_inputs_b inputs)) - (a (my_module_inputs_a inputs)) - (sum (bvadd a b))) - (my_module_outputs sum) - ) -) - -; Create input values -(declare-const input_a (_ BitVec 1)) -(declare-const input_b (_ BitVec 1)) -; (declare-const initial_state my_module_state) - -; Define input values -(assert (= input_a #b1)) ; or #b0 for 0 -(assert (= input_b #b0)) ; or #b1 for 1 - -; Construct the input object -(define-const inputs my_module_inputs (my_module_inputs input_b input_a)) - -; Call the step function -(define-const result my_module_outputs (my_module_step inputs)) - -; Extract the output -(define-const output_sum (_ BitVec 1) (my_module_outputs_sum result)) +(set-logic QF_UFBV) + +; Declare sorts and functions as defined in the original file +(declare-sort |my_module_s| 0) +(declare-fun |my_module_is| (|my_module_s|) Bool) +(declare-fun |my_module#0| (|my_module_s|) (_ BitVec 1)) ; \a +(declare-fun |my_module#1| (|my_module_s|) (_ BitVec 1)) ; \b +(define-fun |my_module#2| ((state |my_module_s|)) (_ BitVec 1) (bvadd (|my_module#0| state) (|my_module#1| state))) ; $add$tests/functional/single_bit/verilog/my_module_add.v:7$1_Y + +; Declare input witness functions +(define-fun |my_module_n a| ((state |my_module_s|)) Bool (= ((_ extract 0 0) (|my_module#0| state)) #b1)) +(define-fun |my_module_n b| ((state |my_module_s|)) Bool (= ((_ extract 0 0) (|my_module#1| state)) #b1)) + +; Declare output function +(define-fun |my_module_n sum| ((state |my_module_s|)) Bool (= ((_ extract 0 0) (|my_module#2| state)) #b1)) + +; Other functions as defined in the original file +(define-fun |my_module_a| ((state |my_module_s|)) Bool true) +(define-fun |my_module_u| ((state |my_module_s|)) Bool true) +(define-fun |my_module_i| ((state |my_module_s|)) Bool true) +(define-fun |my_module_h| ((state |my_module_s|)) Bool true) +(define-fun |my_module_t| ((state |my_module_s|) (next_state |my_module_s|)) Bool true) + +; Create a state variable +(declare-fun state0 () |my_module_s|) + +; Assign inputs +(assert (= (|my_module#0| state0) #b1)) ; a = 1 +(assert (= (|my_module#1| state0) #b0)) ; b = 0 ; Check the output -(check-sat) -(get-value (output_sum)) \ No newline at end of file +(assert (|my_module_n sum| state0)) ; sum should be 1 (0 + 1 = 1) + +; Check satisfiability +(check-sat) \ No newline at end of file From a543819476cec7d26c8c96ad8c35219f4779015e Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Thu, 6 Jun 2024 12:12:29 +0200 Subject: [PATCH 44/51] Testing against RTLIL --- tests/functional/single_cells/run-test.sh | 68 +++++++++++++++++++ .../single_cells/test_cell_add_00000.il | 17 +++++ .../single_cells/test_cell_alu_00000.il | 25 +++++++ .../single_cells/test_cell_and_00000.il | 17 +++++ .../single_cells/test_cell_bmux_00000.il | 14 ++++ .../single_cells/test_cell_demux_00000.il | 14 ++++ .../single_cells/test_cell_div_00000.il | 17 +++++ .../single_cells/test_cell_divfloor_00000.il | 17 +++++ .../single_cells/test_cell_eq_00000.il | 17 +++++ .../single_cells/test_cell_fa_00000.il | 17 +++++ .../single_cells/test_cell_ge_00000.il | 17 +++++ .../single_cells/test_cell_gt_00000.il | 17 +++++ .../single_cells/test_cell_lcu_00000.il | 15 ++++ .../single_cells/test_cell_le_00000.il | 17 +++++ .../single_cells/test_cell_logic_and_00000.il | 17 +++++ .../single_cells/test_cell_logic_not_00000.il | 13 ++++ .../single_cells/test_cell_logic_or_00000.il | 17 +++++ .../single_cells/test_cell_lt_00000.il | 17 +++++ .../single_cells/test_cell_lut_00000.il | 12 ++++ .../single_cells/test_cell_macc_00000.il | 17 +++++ .../single_cells/test_cell_mod_00000.il | 17 +++++ .../single_cells/test_cell_modfloor_00000.il | 17 +++++ .../single_cells/test_cell_mul_00000.il | 17 +++++ .../single_cells/test_cell_mux_00000.il | 15 ++++ .../single_cells/test_cell_ne_00000.il | 17 +++++ .../single_cells/test_cell_neg_00000.il | 13 ++++ .../single_cells/test_cell_not_00000.il | 13 ++++ .../single_cells/test_cell_or_00000.il | 17 +++++ .../single_cells/test_cell_pos_00000.il | 13 ++++ .../test_cell_reduce_and_00000.il | 13 ++++ .../test_cell_reduce_bool_00000.il | 13 ++++ .../single_cells/test_cell_reduce_or_00000.il | 13 ++++ .../test_cell_reduce_xnor_00000.il | 13 ++++ .../test_cell_reduce_xor_00000.il | 13 ++++ .../single_cells/test_cell_shift_00000.il | 17 +++++ .../single_cells/test_cell_shiftx_00000.il | 17 +++++ .../single_cells/test_cell_shl_00000.il | 17 +++++ .../single_cells/test_cell_shr_00000.il | 17 +++++ .../single_cells/test_cell_sop_00000.il | 13 ++++ .../single_cells/test_cell_sshl_00000.il | 17 +++++ .../single_cells/test_cell_sshr_00000.il | 17 +++++ .../single_cells/test_cell_sub_00000.il | 17 +++++ .../single_cells/test_cell_xnor_00000.il | 17 +++++ .../single_cells/test_cell_xor_00000.il | 17 +++++ 44 files changed, 752 insertions(+) create mode 100755 tests/functional/single_cells/run-test.sh create mode 100644 tests/functional/single_cells/test_cell_add_00000.il create mode 100644 tests/functional/single_cells/test_cell_alu_00000.il create mode 100644 tests/functional/single_cells/test_cell_and_00000.il create mode 100644 tests/functional/single_cells/test_cell_bmux_00000.il create mode 100644 tests/functional/single_cells/test_cell_demux_00000.il create mode 100644 tests/functional/single_cells/test_cell_div_00000.il create mode 100644 tests/functional/single_cells/test_cell_divfloor_00000.il create mode 100644 tests/functional/single_cells/test_cell_eq_00000.il create mode 100644 tests/functional/single_cells/test_cell_fa_00000.il create mode 100644 tests/functional/single_cells/test_cell_ge_00000.il create mode 100644 tests/functional/single_cells/test_cell_gt_00000.il create mode 100644 tests/functional/single_cells/test_cell_lcu_00000.il create mode 100644 tests/functional/single_cells/test_cell_le_00000.il create mode 100644 tests/functional/single_cells/test_cell_logic_and_00000.il create mode 100644 tests/functional/single_cells/test_cell_logic_not_00000.il create mode 100644 tests/functional/single_cells/test_cell_logic_or_00000.il create mode 100644 tests/functional/single_cells/test_cell_lt_00000.il create mode 100644 tests/functional/single_cells/test_cell_lut_00000.il create mode 100644 tests/functional/single_cells/test_cell_macc_00000.il create mode 100644 tests/functional/single_cells/test_cell_mod_00000.il create mode 100644 tests/functional/single_cells/test_cell_modfloor_00000.il create mode 100644 tests/functional/single_cells/test_cell_mul_00000.il create mode 100644 tests/functional/single_cells/test_cell_mux_00000.il create mode 100644 tests/functional/single_cells/test_cell_ne_00000.il create mode 100644 tests/functional/single_cells/test_cell_neg_00000.il create mode 100644 tests/functional/single_cells/test_cell_not_00000.il create mode 100644 tests/functional/single_cells/test_cell_or_00000.il create mode 100644 tests/functional/single_cells/test_cell_pos_00000.il create mode 100644 tests/functional/single_cells/test_cell_reduce_and_00000.il create mode 100644 tests/functional/single_cells/test_cell_reduce_bool_00000.il create mode 100644 tests/functional/single_cells/test_cell_reduce_or_00000.il create mode 100644 tests/functional/single_cells/test_cell_reduce_xnor_00000.il create mode 100644 tests/functional/single_cells/test_cell_reduce_xor_00000.il create mode 100644 tests/functional/single_cells/test_cell_shift_00000.il create mode 100644 tests/functional/single_cells/test_cell_shiftx_00000.il create mode 100644 tests/functional/single_cells/test_cell_shl_00000.il create mode 100644 tests/functional/single_cells/test_cell_shr_00000.il create mode 100644 tests/functional/single_cells/test_cell_sop_00000.il create mode 100644 tests/functional/single_cells/test_cell_sshl_00000.il create mode 100644 tests/functional/single_cells/test_cell_sshr_00000.il create mode 100644 tests/functional/single_cells/test_cell_sub_00000.il create mode 100644 tests/functional/single_cells/test_cell_xnor_00000.il create mode 100644 tests/functional/single_cells/test_cell_xor_00000.il diff --git a/tests/functional/single_cells/run-test.sh b/tests/functional/single_cells/run-test.sh new file mode 100755 index 00000000000..5f08b82ac68 --- /dev/null +++ b/tests/functional/single_cells/run-test.sh @@ -0,0 +1,68 @@ +#!/bin/bash + +# Initialize an array to store the names of failing Verilog files and their failure types +declare -A failing_files + +# Function to run the test on a given Verilog file +run_test() { + # Define the common variable for the relative path + BASE_PATH="../../../" + + local verilog_file=$1 + + # Extract the base name without extension + local base_name=$(basename "$verilog_file" .v) + + # Run yosys to process each Verilog file + if ${BASE_PATH}yosys -p "read_verilog $verilog_file; write_functional_cxx my_module_functional_cxx.cc"; then + echo "Yosys processed $verilog_file successfully." + + # Compile the generated C++ files with vcd_harness.cpp + ${CXX:-g++} -g -fprofile-arcs -ftest-coverage vcd_harness.cc -I ${BASE_PATH}backends/functional/cxx_runtime/ -o vcd_harness + + # Generate VCD files with base_name + if ./vcd_harness ${base_name}_functional_cxx.vcd; then + + # Run yosys to process each Verilog file + if ${BASE_PATH}yosys -p "read_verilog $verilog_file; sim -r ${base_name}_functional_cxx.vcd -scope my_module -vcd ${base_name}_yosys_sim.vcd -timescale 1us -sim-gold"; then + echo "Yosys sim $verilog_file successfully." + else + ${BASE_PATH}yosys -p "read_verilog $verilog_file; sim -vcd ${base_name}_yosys_sim.vcd -r ${base_name}_functional_cxx.vcd -scope my_module -timescale 1us" + echo "Yosys simulation of $verilog_file failed. There is a discrepancy with functional cxx" + failing_files["$verilog_file"]="Yosys sim failure" + fi + + else + echo "Failed to generate VCD files for $verilog_file." + failing_files["$verilog_file"]="VCD generation failure" + fi + else + echo "Yosys failed to process $verilog_file." + failing_files["$verilog_file"]="Yosys failure" + fi +} + +# Main function to run all tests +run_all_tests() { + # Loop through all Verilog files in the verilog directory + for verilog_file in verilog/*.v; do + run_test "$verilog_file" + done + + # Check if the array of failing files is empty + if [ ${#failing_files[@]} -eq 0 ]; then + echo "All files passed." + return 0 + else + echo "The following files failed:" + for file in "${!failing_files[@]}"; do + echo "$file: ${failing_files[$file]}" + done + return 1 + fi +} + +# If the script is being sourced, do not execute the tests +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + run_all_tests +fi diff --git a/tests/functional/single_cells/test_cell_add_00000.il b/tests/functional/single_cells/test_cell_add_00000.il new file mode 100644 index 00000000000..531dabe41fa --- /dev/null +++ b/tests/functional/single_cells/test_cell_add_00000.il @@ -0,0 +1,17 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 5 input 1 \A + wire width 4 input 2 \B + wire width 6 output 3 \Y + cell $add \UUT + parameter \A_SIGNED 1 + parameter \A_WIDTH 5 + parameter \B_SIGNED 1 + parameter \B_WIDTH 4 + parameter \Y_WIDTH 6 + connect \A \A + connect \B \B + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_alu_00000.il b/tests/functional/single_cells/test_cell_alu_00000.il new file mode 100644 index 00000000000..ebdd3b7343b --- /dev/null +++ b/tests/functional/single_cells/test_cell_alu_00000.il @@ -0,0 +1,25 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 8 input 1 \A + wire width 7 input 2 \B + wire input 3 \BI + wire input 4 \CI + wire width 6 output 5 \CO + wire width 6 output 6 \X + wire width 6 output 7 \Y + cell $alu \UUT + parameter \A_SIGNED 0 + parameter \A_WIDTH 8 + parameter \B_SIGNED 0 + parameter \B_WIDTH 7 + parameter \Y_WIDTH 6 + connect \A \A + connect \B \B + connect \BI \BI + connect \CI \CI + connect \CO \CO + connect \X \X + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_and_00000.il b/tests/functional/single_cells/test_cell_and_00000.il new file mode 100644 index 00000000000..2578f60b774 --- /dev/null +++ b/tests/functional/single_cells/test_cell_and_00000.il @@ -0,0 +1,17 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 2 input 1 \A + wire width 3 input 2 \B + wire width 2 output 3 \Y + cell $and \UUT + parameter \A_SIGNED 1 + parameter \A_WIDTH 2 + parameter \B_SIGNED 1 + parameter \B_WIDTH 3 + parameter \Y_WIDTH 2 + connect \A \A + connect \B \B + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_bmux_00000.il b/tests/functional/single_cells/test_cell_bmux_00000.il new file mode 100644 index 00000000000..1b613bd698c --- /dev/null +++ b/tests/functional/single_cells/test_cell_bmux_00000.il @@ -0,0 +1,14 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 8 input 1 \A + wire input 2 \S + wire width 4 output 3 \Y + cell $bmux \UUT + parameter \S_WIDTH 1 + parameter \WIDTH 4 + connect \A \A + connect \S \S + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_demux_00000.il b/tests/functional/single_cells/test_cell_demux_00000.il new file mode 100644 index 00000000000..dbe2dee62ac --- /dev/null +++ b/tests/functional/single_cells/test_cell_demux_00000.il @@ -0,0 +1,14 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 6 input 1 \A + wire width 5 input 2 \S + wire width 192 output 3 \Y + cell $demux \UUT + parameter \S_WIDTH 5 + parameter \WIDTH 6 + connect \A \A + connect \S \S + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_div_00000.il b/tests/functional/single_cells/test_cell_div_00000.il new file mode 100644 index 00000000000..6f278a7a079 --- /dev/null +++ b/tests/functional/single_cells/test_cell_div_00000.il @@ -0,0 +1,17 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 4 input 1 \A + wire width 6 input 2 \B + wire output 3 \Y + cell $div \UUT + parameter \A_SIGNED 0 + parameter \A_WIDTH 4 + parameter \B_SIGNED 0 + parameter \B_WIDTH 6 + parameter \Y_WIDTH 1 + connect \A \A + connect \B \B + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_divfloor_00000.il b/tests/functional/single_cells/test_cell_divfloor_00000.il new file mode 100644 index 00000000000..67fce36b331 --- /dev/null +++ b/tests/functional/single_cells/test_cell_divfloor_00000.il @@ -0,0 +1,17 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 4 input 1 \A + wire width 4 input 2 \B + wire width 6 output 3 \Y + cell $divfloor \UUT + parameter \A_SIGNED 0 + parameter \A_WIDTH 4 + parameter \B_SIGNED 0 + parameter \B_WIDTH 4 + parameter \Y_WIDTH 6 + connect \A \A + connect \B \B + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_eq_00000.il b/tests/functional/single_cells/test_cell_eq_00000.il new file mode 100644 index 00000000000..06fef02b5b2 --- /dev/null +++ b/tests/functional/single_cells/test_cell_eq_00000.il @@ -0,0 +1,17 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 5 input 1 \A + wire input 2 \B + wire width 4 output 3 \Y + cell $eq \UUT + parameter \A_SIGNED 0 + parameter \A_WIDTH 5 + parameter \B_SIGNED 0 + parameter \B_WIDTH 1 + parameter \Y_WIDTH 4 + connect \A \A + connect \B \B + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_fa_00000.il b/tests/functional/single_cells/test_cell_fa_00000.il new file mode 100644 index 00000000000..97f0eb0297d --- /dev/null +++ b/tests/functional/single_cells/test_cell_fa_00000.il @@ -0,0 +1,17 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire input 1 \A + wire input 2 \B + wire input 3 \C + wire output 4 \X + wire output 5 \Y + cell $fa \UUT + parameter \WIDTH 1 + connect \A \A + connect \B \B + connect \C \C + connect \X \X + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_ge_00000.il b/tests/functional/single_cells/test_cell_ge_00000.il new file mode 100644 index 00000000000..0ac72e9433d --- /dev/null +++ b/tests/functional/single_cells/test_cell_ge_00000.il @@ -0,0 +1,17 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 3 input 1 \A + wire width 7 input 2 \B + wire width 6 output 3 \Y + cell $ge \UUT + parameter \A_SIGNED 1 + parameter \A_WIDTH 3 + parameter \B_SIGNED 1 + parameter \B_WIDTH 7 + parameter \Y_WIDTH 6 + connect \A \A + connect \B \B + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_gt_00000.il b/tests/functional/single_cells/test_cell_gt_00000.il new file mode 100644 index 00000000000..d4498d36f9e --- /dev/null +++ b/tests/functional/single_cells/test_cell_gt_00000.il @@ -0,0 +1,17 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 7 input 1 \A + wire width 3 input 2 \B + wire width 4 output 3 \Y + cell $gt \UUT + parameter \A_SIGNED 1 + parameter \A_WIDTH 7 + parameter \B_SIGNED 1 + parameter \B_WIDTH 3 + parameter \Y_WIDTH 4 + connect \A \A + connect \B \B + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_lcu_00000.il b/tests/functional/single_cells/test_cell_lcu_00000.il new file mode 100644 index 00000000000..e1bda0b433c --- /dev/null +++ b/tests/functional/single_cells/test_cell_lcu_00000.il @@ -0,0 +1,15 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire input 1 \CI + wire width 2 output 2 \CO + wire width 2 input 3 \G + wire width 2 input 4 \P + cell $lcu \UUT + parameter \WIDTH 2 + connect \CI \CI + connect \CO \CO + connect \G \G + connect \P \P + end +end diff --git a/tests/functional/single_cells/test_cell_le_00000.il b/tests/functional/single_cells/test_cell_le_00000.il new file mode 100644 index 00000000000..609d99ce8a4 --- /dev/null +++ b/tests/functional/single_cells/test_cell_le_00000.il @@ -0,0 +1,17 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 5 input 1 \A + wire width 4 input 2 \B + wire width 6 output 3 \Y + cell $le \UUT + parameter \A_SIGNED 1 + parameter \A_WIDTH 5 + parameter \B_SIGNED 1 + parameter \B_WIDTH 4 + parameter \Y_WIDTH 6 + connect \A \A + connect \B \B + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_logic_and_00000.il b/tests/functional/single_cells/test_cell_logic_and_00000.il new file mode 100644 index 00000000000..2eae6e3fcb1 --- /dev/null +++ b/tests/functional/single_cells/test_cell_logic_and_00000.il @@ -0,0 +1,17 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 2 input 1 \A + wire width 7 input 2 \B + wire output 3 \Y + cell $logic_and \UUT + parameter \A_SIGNED 0 + parameter \A_WIDTH 2 + parameter \B_SIGNED 0 + parameter \B_WIDTH 7 + parameter \Y_WIDTH 1 + connect \A \A + connect \B \B + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_logic_not_00000.il b/tests/functional/single_cells/test_cell_logic_not_00000.il new file mode 100644 index 00000000000..c7898491ca5 --- /dev/null +++ b/tests/functional/single_cells/test_cell_logic_not_00000.il @@ -0,0 +1,13 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 3 input 1 \A + wire width 8 output 2 \Y + cell $logic_not \UUT + parameter \A_SIGNED 1 + parameter \A_WIDTH 3 + parameter \Y_WIDTH 8 + connect \A \A + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_logic_or_00000.il b/tests/functional/single_cells/test_cell_logic_or_00000.il new file mode 100644 index 00000000000..7a1ef6cbda0 --- /dev/null +++ b/tests/functional/single_cells/test_cell_logic_or_00000.il @@ -0,0 +1,17 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 8 input 1 \A + wire width 7 input 2 \B + wire width 2 output 3 \Y + cell $logic_or \UUT + parameter \A_SIGNED 0 + parameter \A_WIDTH 8 + parameter \B_SIGNED 0 + parameter \B_WIDTH 7 + parameter \Y_WIDTH 2 + connect \A \A + connect \B \B + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_lt_00000.il b/tests/functional/single_cells/test_cell_lt_00000.il new file mode 100644 index 00000000000..fd3ee1f8bad --- /dev/null +++ b/tests/functional/single_cells/test_cell_lt_00000.il @@ -0,0 +1,17 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 8 input 1 \A + wire width 5 input 2 \B + wire width 6 output 3 \Y + cell $lt \UUT + parameter \A_SIGNED 0 + parameter \A_WIDTH 8 + parameter \B_SIGNED 0 + parameter \B_WIDTH 5 + parameter \Y_WIDTH 6 + connect \A \A + connect \B \B + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_lut_00000.il b/tests/functional/single_cells/test_cell_lut_00000.il new file mode 100644 index 00000000000..7c4882bb61a --- /dev/null +++ b/tests/functional/single_cells/test_cell_lut_00000.il @@ -0,0 +1,12 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 2 input 1 \A + wire output 2 \Y + cell $lut \UUT + parameter \LUT 4'1111 + parameter \WIDTH 2 + connect \A \A + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_macc_00000.il b/tests/functional/single_cells/test_cell_macc_00000.il new file mode 100644 index 00000000000..66b51634e97 --- /dev/null +++ b/tests/functional/single_cells/test_cell_macc_00000.il @@ -0,0 +1,17 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 3 input 1 \A + wire width 0 input 2 \B + wire width 2 output 3 \Y + cell $macc \UUT + parameter \A_WIDTH 3 + parameter \B_WIDTH 0 + parameter \CONFIG 10'0110000010 + parameter \CONFIG_WIDTH 10 + parameter \Y_WIDTH 2 + connect \A \A + connect \B { } + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_mod_00000.il b/tests/functional/single_cells/test_cell_mod_00000.il new file mode 100644 index 00000000000..a484918f05c --- /dev/null +++ b/tests/functional/single_cells/test_cell_mod_00000.il @@ -0,0 +1,17 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 6 input 1 \A + wire width 8 input 2 \B + wire width 2 output 3 \Y + cell $mod \UUT + parameter \A_SIGNED 0 + parameter \A_WIDTH 6 + parameter \B_SIGNED 0 + parameter \B_WIDTH 8 + parameter \Y_WIDTH 2 + connect \A \A + connect \B \B + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_modfloor_00000.il b/tests/functional/single_cells/test_cell_modfloor_00000.il new file mode 100644 index 00000000000..6cd00aeea5d --- /dev/null +++ b/tests/functional/single_cells/test_cell_modfloor_00000.il @@ -0,0 +1,17 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 5 input 1 \A + wire width 7 input 2 \B + wire width 4 output 3 \Y + cell $modfloor \UUT + parameter \A_SIGNED 0 + parameter \A_WIDTH 5 + parameter \B_SIGNED 0 + parameter \B_WIDTH 7 + parameter \Y_WIDTH 4 + connect \A \A + connect \B \B + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_mul_00000.il b/tests/functional/single_cells/test_cell_mul_00000.il new file mode 100644 index 00000000000..c77aaffb87e --- /dev/null +++ b/tests/functional/single_cells/test_cell_mul_00000.il @@ -0,0 +1,17 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 6 input 1 \A + wire width 2 input 2 \B + wire width 5 output 3 \Y + cell $mul \UUT + parameter \A_SIGNED 0 + parameter \A_WIDTH 6 + parameter \B_SIGNED 0 + parameter \B_WIDTH 2 + parameter \Y_WIDTH 5 + connect \A \A + connect \B \B + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_mux_00000.il b/tests/functional/single_cells/test_cell_mux_00000.il new file mode 100644 index 00000000000..3fc52ac7716 --- /dev/null +++ b/tests/functional/single_cells/test_cell_mux_00000.il @@ -0,0 +1,15 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 4 input 1 \A + wire width 4 input 2 \B + wire input 3 \S + wire width 4 output 4 \Y + cell $mux \UUT + parameter \WIDTH 4 + connect \A \A + connect \B \B + connect \S \S + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_ne_00000.il b/tests/functional/single_cells/test_cell_ne_00000.il new file mode 100644 index 00000000000..47ba31397ed --- /dev/null +++ b/tests/functional/single_cells/test_cell_ne_00000.il @@ -0,0 +1,17 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 7 input 1 \A + wire width 5 input 2 \B + wire width 4 output 3 \Y + cell $ne \UUT + parameter \A_SIGNED 0 + parameter \A_WIDTH 7 + parameter \B_SIGNED 0 + parameter \B_WIDTH 5 + parameter \Y_WIDTH 4 + connect \A \A + connect \B \B + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_neg_00000.il b/tests/functional/single_cells/test_cell_neg_00000.il new file mode 100644 index 00000000000..ee4273508d1 --- /dev/null +++ b/tests/functional/single_cells/test_cell_neg_00000.il @@ -0,0 +1,13 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 2 input 1 \A + wire width 5 output 2 \Y + cell $neg \UUT + parameter \A_SIGNED 0 + parameter \A_WIDTH 2 + parameter \Y_WIDTH 5 + connect \A \A + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_not_00000.il b/tests/functional/single_cells/test_cell_not_00000.il new file mode 100644 index 00000000000..9281ded0dfa --- /dev/null +++ b/tests/functional/single_cells/test_cell_not_00000.il @@ -0,0 +1,13 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 7 input 1 \A + wire width 7 output 2 \Y + cell $not \UUT + parameter \A_SIGNED 1 + parameter \A_WIDTH 7 + parameter \Y_WIDTH 7 + connect \A \A + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_or_00000.il b/tests/functional/single_cells/test_cell_or_00000.il new file mode 100644 index 00000000000..100ea42cd38 --- /dev/null +++ b/tests/functional/single_cells/test_cell_or_00000.il @@ -0,0 +1,17 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 7 input 1 \A + wire input 2 \B + wire width 2 output 3 \Y + cell $or \UUT + parameter \A_SIGNED 1 + parameter \A_WIDTH 7 + parameter \B_SIGNED 1 + parameter \B_WIDTH 1 + parameter \Y_WIDTH 2 + connect \A \A + connect \B \B + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_pos_00000.il b/tests/functional/single_cells/test_cell_pos_00000.il new file mode 100644 index 00000000000..182f0acd38f --- /dev/null +++ b/tests/functional/single_cells/test_cell_pos_00000.il @@ -0,0 +1,13 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire input 1 \A + wire width 3 output 2 \Y + cell $pos \UUT + parameter \A_SIGNED 1 + parameter \A_WIDTH 1 + parameter \Y_WIDTH 3 + connect \A \A + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_reduce_and_00000.il b/tests/functional/single_cells/test_cell_reduce_and_00000.il new file mode 100644 index 00000000000..079ed33ade5 --- /dev/null +++ b/tests/functional/single_cells/test_cell_reduce_and_00000.il @@ -0,0 +1,13 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 4 input 1 \A + wire width 5 output 2 \Y + cell $reduce_and \UUT + parameter \A_SIGNED 0 + parameter \A_WIDTH 4 + parameter \Y_WIDTH 5 + connect \A \A + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_reduce_bool_00000.il b/tests/functional/single_cells/test_cell_reduce_bool_00000.il new file mode 100644 index 00000000000..a417179c818 --- /dev/null +++ b/tests/functional/single_cells/test_cell_reduce_bool_00000.il @@ -0,0 +1,13 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire input 1 \A + wire width 2 output 2 \Y + cell $reduce_bool \UUT + parameter \A_SIGNED 1 + parameter \A_WIDTH 1 + parameter \Y_WIDTH 2 + connect \A \A + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_reduce_or_00000.il b/tests/functional/single_cells/test_cell_reduce_or_00000.il new file mode 100644 index 00000000000..881c6dfe3a1 --- /dev/null +++ b/tests/functional/single_cells/test_cell_reduce_or_00000.il @@ -0,0 +1,13 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 2 input 1 \A + wire width 7 output 2 \Y + cell $reduce_or \UUT + parameter \A_SIGNED 0 + parameter \A_WIDTH 2 + parameter \Y_WIDTH 7 + connect \A \A + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_reduce_xnor_00000.il b/tests/functional/single_cells/test_cell_reduce_xnor_00000.il new file mode 100644 index 00000000000..c06562729ea --- /dev/null +++ b/tests/functional/single_cells/test_cell_reduce_xnor_00000.il @@ -0,0 +1,13 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 4 input 1 \A + wire width 4 output 2 \Y + cell $reduce_xnor \UUT + parameter \A_SIGNED 0 + parameter \A_WIDTH 4 + parameter \Y_WIDTH 4 + connect \A \A + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_reduce_xor_00000.il b/tests/functional/single_cells/test_cell_reduce_xor_00000.il new file mode 100644 index 00000000000..428d2ea87a2 --- /dev/null +++ b/tests/functional/single_cells/test_cell_reduce_xor_00000.il @@ -0,0 +1,13 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 4 input 1 \A + wire output 2 \Y + cell $reduce_xor \UUT + parameter \A_SIGNED 0 + parameter \A_WIDTH 4 + parameter \Y_WIDTH 1 + connect \A \A + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_shift_00000.il b/tests/functional/single_cells/test_cell_shift_00000.il new file mode 100644 index 00000000000..f82a2a79df7 --- /dev/null +++ b/tests/functional/single_cells/test_cell_shift_00000.il @@ -0,0 +1,17 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire input 1 \A + wire width 6 input 2 \B + wire width 4 output 3 \Y + cell $shift \UUT + parameter \A_SIGNED 1 + parameter \A_WIDTH 1 + parameter \B_SIGNED 1 + parameter \B_WIDTH 6 + parameter \Y_WIDTH 4 + connect \A \A + connect \B \B + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_shiftx_00000.il b/tests/functional/single_cells/test_cell_shiftx_00000.il new file mode 100644 index 00000000000..b89ac5bef91 --- /dev/null +++ b/tests/functional/single_cells/test_cell_shiftx_00000.il @@ -0,0 +1,17 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire input 1 \A + wire width 5 input 2 \B + wire width 3 output 3 \Y + cell $shiftx \UUT + parameter \A_SIGNED 0 + parameter \A_WIDTH 1 + parameter \B_SIGNED 0 + parameter \B_WIDTH 5 + parameter \Y_WIDTH 3 + connect \A \A + connect \B \B + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_shl_00000.il b/tests/functional/single_cells/test_cell_shl_00000.il new file mode 100644 index 00000000000..1cfee2a52b5 --- /dev/null +++ b/tests/functional/single_cells/test_cell_shl_00000.il @@ -0,0 +1,17 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 8 input 1 \A + wire width 2 input 2 \B + wire width 3 output 3 \Y + cell $shl \UUT + parameter \A_SIGNED 0 + parameter \A_WIDTH 8 + parameter \B_SIGNED 0 + parameter \B_WIDTH 2 + parameter \Y_WIDTH 3 + connect \A \A + connect \B \B + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_shr_00000.il b/tests/functional/single_cells/test_cell_shr_00000.il new file mode 100644 index 00000000000..35dd379099c --- /dev/null +++ b/tests/functional/single_cells/test_cell_shr_00000.il @@ -0,0 +1,17 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 7 input 1 \A + wire width 6 input 2 \B + wire width 4 output 3 \Y + cell $shr \UUT + parameter \A_SIGNED 1 + parameter \A_WIDTH 7 + parameter \B_SIGNED 0 + parameter \B_WIDTH 6 + parameter \Y_WIDTH 4 + connect \A \A + connect \B \B + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_sop_00000.il b/tests/functional/single_cells/test_cell_sop_00000.il new file mode 100644 index 00000000000..df0f8f20abe --- /dev/null +++ b/tests/functional/single_cells/test_cell_sop_00000.il @@ -0,0 +1,13 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 8 input 1 \A + wire output 2 \Y + cell $sop \UUT + parameter \DEPTH 8 + parameter \TABLE 128'10010000100100000101101010001001101000101010010100010000010100000101010100000001001010010110101010101010101000100100011001000110 + parameter \WIDTH 8 + connect \A \A + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_sshl_00000.il b/tests/functional/single_cells/test_cell_sshl_00000.il new file mode 100644 index 00000000000..798288754ce --- /dev/null +++ b/tests/functional/single_cells/test_cell_sshl_00000.il @@ -0,0 +1,17 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 5 input 1 \A + wire width 3 input 2 \B + wire width 6 output 3 \Y + cell $sshl \UUT + parameter \A_SIGNED 0 + parameter \A_WIDTH 5 + parameter \B_SIGNED 0 + parameter \B_WIDTH 3 + parameter \Y_WIDTH 6 + connect \A \A + connect \B \B + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_sshr_00000.il b/tests/functional/single_cells/test_cell_sshr_00000.il new file mode 100644 index 00000000000..3f59a693f24 --- /dev/null +++ b/tests/functional/single_cells/test_cell_sshr_00000.il @@ -0,0 +1,17 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 3 input 1 \A + wire width 2 input 2 \B + wire width 2 output 3 \Y + cell $sshr \UUT + parameter \A_SIGNED 1 + parameter \A_WIDTH 3 + parameter \B_SIGNED 0 + parameter \B_WIDTH 2 + parameter \Y_WIDTH 2 + connect \A \A + connect \B \B + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_sub_00000.il b/tests/functional/single_cells/test_cell_sub_00000.il new file mode 100644 index 00000000000..cb9ec2f7904 --- /dev/null +++ b/tests/functional/single_cells/test_cell_sub_00000.il @@ -0,0 +1,17 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 6 input 1 \A + wire width 6 input 2 \B + wire width 6 output 3 \Y + cell $sub \UUT + parameter \A_SIGNED 0 + parameter \A_WIDTH 6 + parameter \B_SIGNED 0 + parameter \B_WIDTH 6 + parameter \Y_WIDTH 6 + connect \A \A + connect \B \B + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_xnor_00000.il b/tests/functional/single_cells/test_cell_xnor_00000.il new file mode 100644 index 00000000000..85bd7d239df --- /dev/null +++ b/tests/functional/single_cells/test_cell_xnor_00000.il @@ -0,0 +1,17 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 7 input 1 \A + wire width 8 input 2 \B + wire width 7 output 3 \Y + cell $xnor \UUT + parameter \A_SIGNED 1 + parameter \A_WIDTH 7 + parameter \B_SIGNED 1 + parameter \B_WIDTH 8 + parameter \Y_WIDTH 7 + connect \A \A + connect \B \B + connect \Y \Y + end +end diff --git a/tests/functional/single_cells/test_cell_xor_00000.il b/tests/functional/single_cells/test_cell_xor_00000.il new file mode 100644 index 00000000000..2359698b55b --- /dev/null +++ b/tests/functional/single_cells/test_cell_xor_00000.il @@ -0,0 +1,17 @@ +# Generated by Yosys 0.41+101 (git sha1 83a8e5de4, g++ 13.2.0 -fPIC -Os) +autoidx 1 +module \gold + wire width 6 input 1 \A + wire width 2 input 2 \B + wire width 8 output 3 \Y + cell $xor \UUT + parameter \A_SIGNED 0 + parameter \A_WIDTH 6 + parameter \B_SIGNED 0 + parameter \B_WIDTH 2 + parameter \Y_WIDTH 8 + connect \A \A + connect \B \B + connect \Y \Y + end +end From 8cadb047bb07dcf0a285e1db0c81b3086bc0900d Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Thu, 6 Jun 2024 12:14:35 +0200 Subject: [PATCH 45/51] Move files --- .../single_cells/{ => rtlil}/test_cell_add_00000.il | 0 .../single_cells/{ => rtlil}/test_cell_alu_00000.il | 0 .../single_cells/{ => rtlil}/test_cell_and_00000.il | 0 .../single_cells/{ => rtlil}/test_cell_bmux_00000.il | 0 .../single_cells/{ => rtlil}/test_cell_demux_00000.il | 0 .../single_cells/{ => rtlil}/test_cell_div_00000.il | 0 .../{ => rtlil}/test_cell_divfloor_00000.il | 0 .../single_cells/{ => rtlil}/test_cell_eq_00000.il | 0 .../single_cells/{ => rtlil}/test_cell_fa_00000.il | 0 .../single_cells/{ => rtlil}/test_cell_ge_00000.il | 0 .../single_cells/{ => rtlil}/test_cell_gt_00000.il | 0 .../single_cells/{ => rtlil}/test_cell_lcu_00000.il | 0 .../single_cells/{ => rtlil}/test_cell_le_00000.il | 0 .../{ => rtlil}/test_cell_logic_and_00000.il | 0 .../{ => rtlil}/test_cell_logic_not_00000.il | 0 .../{ => rtlil}/test_cell_logic_or_00000.il | 0 .../single_cells/{ => rtlil}/test_cell_lt_00000.il | 0 .../single_cells/{ => rtlil}/test_cell_lut_00000.il | 0 .../single_cells/{ => rtlil}/test_cell_macc_00000.il | 0 .../single_cells/{ => rtlil}/test_cell_mod_00000.il | 0 .../{ => rtlil}/test_cell_modfloor_00000.il | 0 .../single_cells/{ => rtlil}/test_cell_mul_00000.il | 0 .../single_cells/{ => rtlil}/test_cell_mux_00000.il | 0 .../single_cells/{ => rtlil}/test_cell_ne_00000.il | 0 .../single_cells/{ => rtlil}/test_cell_neg_00000.il | 0 .../single_cells/{ => rtlil}/test_cell_not_00000.il | 0 .../single_cells/{ => rtlil}/test_cell_or_00000.il | 0 .../single_cells/{ => rtlil}/test_cell_pos_00000.il | 0 .../{ => rtlil}/test_cell_reduce_and_00000.il | 0 .../{ => rtlil}/test_cell_reduce_bool_00000.il | 0 .../{ => rtlil}/test_cell_reduce_or_00000.il | 0 .../{ => rtlil}/test_cell_reduce_xnor_00000.il | 0 .../{ => rtlil}/test_cell_reduce_xor_00000.il | 0 .../single_cells/{ => rtlil}/test_cell_shift_00000.il | 0 .../single_cells/{ => rtlil}/test_cell_shiftx_00000.il | 0 .../single_cells/{ => rtlil}/test_cell_shl_00000.il | 0 .../single_cells/{ => rtlil}/test_cell_shr_00000.il | 0 .../single_cells/{ => rtlil}/test_cell_sop_00000.il | 0 .../single_cells/{ => rtlil}/test_cell_sshl_00000.il | 0 .../single_cells/{ => rtlil}/test_cell_sshr_00000.il | 0 .../single_cells/{ => rtlil}/test_cell_sub_00000.il | 0 .../single_cells/{ => rtlil}/test_cell_xnor_00000.il | 0 .../single_cells/{ => rtlil}/test_cell_xor_00000.il | 0 tests/functional/single_cells/run-test.sh | 10 +++++----- 44 files changed, 5 insertions(+), 5 deletions(-) rename tests/functional/single_cells/{ => rtlil}/test_cell_add_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_alu_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_and_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_bmux_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_demux_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_div_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_divfloor_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_eq_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_fa_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_ge_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_gt_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_lcu_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_le_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_logic_and_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_logic_not_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_logic_or_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_lt_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_lut_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_macc_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_mod_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_modfloor_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_mul_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_mux_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_ne_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_neg_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_not_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_or_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_pos_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_reduce_and_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_reduce_bool_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_reduce_or_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_reduce_xnor_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_reduce_xor_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_shift_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_shiftx_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_shl_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_shr_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_sop_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_sshl_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_sshr_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_sub_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_xnor_00000.il (100%) rename tests/functional/single_cells/{ => rtlil}/test_cell_xor_00000.il (100%) diff --git a/tests/functional/single_cells/test_cell_add_00000.il b/tests/functional/single_cells/rtlil/test_cell_add_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_add_00000.il rename to tests/functional/single_cells/rtlil/test_cell_add_00000.il diff --git a/tests/functional/single_cells/test_cell_alu_00000.il b/tests/functional/single_cells/rtlil/test_cell_alu_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_alu_00000.il rename to tests/functional/single_cells/rtlil/test_cell_alu_00000.il diff --git a/tests/functional/single_cells/test_cell_and_00000.il b/tests/functional/single_cells/rtlil/test_cell_and_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_and_00000.il rename to tests/functional/single_cells/rtlil/test_cell_and_00000.il diff --git a/tests/functional/single_cells/test_cell_bmux_00000.il b/tests/functional/single_cells/rtlil/test_cell_bmux_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_bmux_00000.il rename to tests/functional/single_cells/rtlil/test_cell_bmux_00000.il diff --git a/tests/functional/single_cells/test_cell_demux_00000.il b/tests/functional/single_cells/rtlil/test_cell_demux_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_demux_00000.il rename to tests/functional/single_cells/rtlil/test_cell_demux_00000.il diff --git a/tests/functional/single_cells/test_cell_div_00000.il b/tests/functional/single_cells/rtlil/test_cell_div_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_div_00000.il rename to tests/functional/single_cells/rtlil/test_cell_div_00000.il diff --git a/tests/functional/single_cells/test_cell_divfloor_00000.il b/tests/functional/single_cells/rtlil/test_cell_divfloor_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_divfloor_00000.il rename to tests/functional/single_cells/rtlil/test_cell_divfloor_00000.il diff --git a/tests/functional/single_cells/test_cell_eq_00000.il b/tests/functional/single_cells/rtlil/test_cell_eq_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_eq_00000.il rename to tests/functional/single_cells/rtlil/test_cell_eq_00000.il diff --git a/tests/functional/single_cells/test_cell_fa_00000.il b/tests/functional/single_cells/rtlil/test_cell_fa_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_fa_00000.il rename to tests/functional/single_cells/rtlil/test_cell_fa_00000.il diff --git a/tests/functional/single_cells/test_cell_ge_00000.il b/tests/functional/single_cells/rtlil/test_cell_ge_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_ge_00000.il rename to tests/functional/single_cells/rtlil/test_cell_ge_00000.il diff --git a/tests/functional/single_cells/test_cell_gt_00000.il b/tests/functional/single_cells/rtlil/test_cell_gt_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_gt_00000.il rename to tests/functional/single_cells/rtlil/test_cell_gt_00000.il diff --git a/tests/functional/single_cells/test_cell_lcu_00000.il b/tests/functional/single_cells/rtlil/test_cell_lcu_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_lcu_00000.il rename to tests/functional/single_cells/rtlil/test_cell_lcu_00000.il diff --git a/tests/functional/single_cells/test_cell_le_00000.il b/tests/functional/single_cells/rtlil/test_cell_le_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_le_00000.il rename to tests/functional/single_cells/rtlil/test_cell_le_00000.il diff --git a/tests/functional/single_cells/test_cell_logic_and_00000.il b/tests/functional/single_cells/rtlil/test_cell_logic_and_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_logic_and_00000.il rename to tests/functional/single_cells/rtlil/test_cell_logic_and_00000.il diff --git a/tests/functional/single_cells/test_cell_logic_not_00000.il b/tests/functional/single_cells/rtlil/test_cell_logic_not_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_logic_not_00000.il rename to tests/functional/single_cells/rtlil/test_cell_logic_not_00000.il diff --git a/tests/functional/single_cells/test_cell_logic_or_00000.il b/tests/functional/single_cells/rtlil/test_cell_logic_or_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_logic_or_00000.il rename to tests/functional/single_cells/rtlil/test_cell_logic_or_00000.il diff --git a/tests/functional/single_cells/test_cell_lt_00000.il b/tests/functional/single_cells/rtlil/test_cell_lt_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_lt_00000.il rename to tests/functional/single_cells/rtlil/test_cell_lt_00000.il diff --git a/tests/functional/single_cells/test_cell_lut_00000.il b/tests/functional/single_cells/rtlil/test_cell_lut_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_lut_00000.il rename to tests/functional/single_cells/rtlil/test_cell_lut_00000.il diff --git a/tests/functional/single_cells/test_cell_macc_00000.il b/tests/functional/single_cells/rtlil/test_cell_macc_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_macc_00000.il rename to tests/functional/single_cells/rtlil/test_cell_macc_00000.il diff --git a/tests/functional/single_cells/test_cell_mod_00000.il b/tests/functional/single_cells/rtlil/test_cell_mod_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_mod_00000.il rename to tests/functional/single_cells/rtlil/test_cell_mod_00000.il diff --git a/tests/functional/single_cells/test_cell_modfloor_00000.il b/tests/functional/single_cells/rtlil/test_cell_modfloor_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_modfloor_00000.il rename to tests/functional/single_cells/rtlil/test_cell_modfloor_00000.il diff --git a/tests/functional/single_cells/test_cell_mul_00000.il b/tests/functional/single_cells/rtlil/test_cell_mul_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_mul_00000.il rename to tests/functional/single_cells/rtlil/test_cell_mul_00000.il diff --git a/tests/functional/single_cells/test_cell_mux_00000.il b/tests/functional/single_cells/rtlil/test_cell_mux_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_mux_00000.il rename to tests/functional/single_cells/rtlil/test_cell_mux_00000.il diff --git a/tests/functional/single_cells/test_cell_ne_00000.il b/tests/functional/single_cells/rtlil/test_cell_ne_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_ne_00000.il rename to tests/functional/single_cells/rtlil/test_cell_ne_00000.il diff --git a/tests/functional/single_cells/test_cell_neg_00000.il b/tests/functional/single_cells/rtlil/test_cell_neg_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_neg_00000.il rename to tests/functional/single_cells/rtlil/test_cell_neg_00000.il diff --git a/tests/functional/single_cells/test_cell_not_00000.il b/tests/functional/single_cells/rtlil/test_cell_not_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_not_00000.il rename to tests/functional/single_cells/rtlil/test_cell_not_00000.il diff --git a/tests/functional/single_cells/test_cell_or_00000.il b/tests/functional/single_cells/rtlil/test_cell_or_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_or_00000.il rename to tests/functional/single_cells/rtlil/test_cell_or_00000.il diff --git a/tests/functional/single_cells/test_cell_pos_00000.il b/tests/functional/single_cells/rtlil/test_cell_pos_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_pos_00000.il rename to tests/functional/single_cells/rtlil/test_cell_pos_00000.il diff --git a/tests/functional/single_cells/test_cell_reduce_and_00000.il b/tests/functional/single_cells/rtlil/test_cell_reduce_and_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_reduce_and_00000.il rename to tests/functional/single_cells/rtlil/test_cell_reduce_and_00000.il diff --git a/tests/functional/single_cells/test_cell_reduce_bool_00000.il b/tests/functional/single_cells/rtlil/test_cell_reduce_bool_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_reduce_bool_00000.il rename to tests/functional/single_cells/rtlil/test_cell_reduce_bool_00000.il diff --git a/tests/functional/single_cells/test_cell_reduce_or_00000.il b/tests/functional/single_cells/rtlil/test_cell_reduce_or_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_reduce_or_00000.il rename to tests/functional/single_cells/rtlil/test_cell_reduce_or_00000.il diff --git a/tests/functional/single_cells/test_cell_reduce_xnor_00000.il b/tests/functional/single_cells/rtlil/test_cell_reduce_xnor_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_reduce_xnor_00000.il rename to tests/functional/single_cells/rtlil/test_cell_reduce_xnor_00000.il diff --git a/tests/functional/single_cells/test_cell_reduce_xor_00000.il b/tests/functional/single_cells/rtlil/test_cell_reduce_xor_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_reduce_xor_00000.il rename to tests/functional/single_cells/rtlil/test_cell_reduce_xor_00000.il diff --git a/tests/functional/single_cells/test_cell_shift_00000.il b/tests/functional/single_cells/rtlil/test_cell_shift_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_shift_00000.il rename to tests/functional/single_cells/rtlil/test_cell_shift_00000.il diff --git a/tests/functional/single_cells/test_cell_shiftx_00000.il b/tests/functional/single_cells/rtlil/test_cell_shiftx_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_shiftx_00000.il rename to tests/functional/single_cells/rtlil/test_cell_shiftx_00000.il diff --git a/tests/functional/single_cells/test_cell_shl_00000.il b/tests/functional/single_cells/rtlil/test_cell_shl_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_shl_00000.il rename to tests/functional/single_cells/rtlil/test_cell_shl_00000.il diff --git a/tests/functional/single_cells/test_cell_shr_00000.il b/tests/functional/single_cells/rtlil/test_cell_shr_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_shr_00000.il rename to tests/functional/single_cells/rtlil/test_cell_shr_00000.il diff --git a/tests/functional/single_cells/test_cell_sop_00000.il b/tests/functional/single_cells/rtlil/test_cell_sop_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_sop_00000.il rename to tests/functional/single_cells/rtlil/test_cell_sop_00000.il diff --git a/tests/functional/single_cells/test_cell_sshl_00000.il b/tests/functional/single_cells/rtlil/test_cell_sshl_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_sshl_00000.il rename to tests/functional/single_cells/rtlil/test_cell_sshl_00000.il diff --git a/tests/functional/single_cells/test_cell_sshr_00000.il b/tests/functional/single_cells/rtlil/test_cell_sshr_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_sshr_00000.il rename to tests/functional/single_cells/rtlil/test_cell_sshr_00000.il diff --git a/tests/functional/single_cells/test_cell_sub_00000.il b/tests/functional/single_cells/rtlil/test_cell_sub_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_sub_00000.il rename to tests/functional/single_cells/rtlil/test_cell_sub_00000.il diff --git a/tests/functional/single_cells/test_cell_xnor_00000.il b/tests/functional/single_cells/rtlil/test_cell_xnor_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_xnor_00000.il rename to tests/functional/single_cells/rtlil/test_cell_xnor_00000.il diff --git a/tests/functional/single_cells/test_cell_xor_00000.il b/tests/functional/single_cells/rtlil/test_cell_xor_00000.il similarity index 100% rename from tests/functional/single_cells/test_cell_xor_00000.il rename to tests/functional/single_cells/rtlil/test_cell_xor_00000.il diff --git a/tests/functional/single_cells/run-test.sh b/tests/functional/single_cells/run-test.sh index 5f08b82ac68..b9828ff84ad 100755 --- a/tests/functional/single_cells/run-test.sh +++ b/tests/functional/single_cells/run-test.sh @@ -1,9 +1,9 @@ #!/bin/bash -# Initialize an array to store the names of failing Verilog files and their failure types +# Initialize an array to store the names of failing RTLIL files and their failure types declare -A failing_files -# Function to run the test on a given Verilog file +# Function to run the test on a given RTLIL file run_test() { # Define the common variable for the relative path BASE_PATH="../../../" @@ -13,7 +13,7 @@ run_test() { # Extract the base name without extension local base_name=$(basename "$verilog_file" .v) - # Run yosys to process each Verilog file + # Run yosys to process each RTLIL file if ${BASE_PATH}yosys -p "read_verilog $verilog_file; write_functional_cxx my_module_functional_cxx.cc"; then echo "Yosys processed $verilog_file successfully." @@ -23,7 +23,7 @@ run_test() { # Generate VCD files with base_name if ./vcd_harness ${base_name}_functional_cxx.vcd; then - # Run yosys to process each Verilog file + # Run yosys to process each RTLIL file if ${BASE_PATH}yosys -p "read_verilog $verilog_file; sim -r ${base_name}_functional_cxx.vcd -scope my_module -vcd ${base_name}_yosys_sim.vcd -timescale 1us -sim-gold"; then echo "Yosys sim $verilog_file successfully." else @@ -44,7 +44,7 @@ run_test() { # Main function to run all tests run_all_tests() { - # Loop through all Verilog files in the verilog directory + # Loop through all RTLIL files in the verilog directory for verilog_file in verilog/*.v; do run_test "$verilog_file" done From 5929df23af947550e64d1d08b03bcec323231317 Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Thu, 6 Jun 2024 15:55:16 +0200 Subject: [PATCH 46/51] WIP --- tests/functional/single_cells/add_rtlil.cc | 79 ++++++++++++ tests/functional/single_cells/run-test.sh | 62 ++++----- tests/functional/single_cells/vcd_harness.cc | 127 +++++++++++++++++++ 3 files changed, 239 insertions(+), 29 deletions(-) create mode 100644 tests/functional/single_cells/add_rtlil.cc create mode 100644 tests/functional/single_cells/vcd_harness.cc diff --git a/tests/functional/single_cells/add_rtlil.cc b/tests/functional/single_cells/add_rtlil.cc new file mode 100644 index 00000000000..22795b351a6 --- /dev/null +++ b/tests/functional/single_cells/add_rtlil.cc @@ -0,0 +1,79 @@ +#include + +#if defined(CXXRTL_INCLUDE_CAPI_IMPL) || \ + defined(CXXRTL_INCLUDE_VCD_CAPI_IMPL) +#include +#endif + +#if defined(CXXRTL_INCLUDE_VCD_CAPI_IMPL) +#include +#endif + +using namespace cxxrtl_yosys; + +namespace cxxrtl_design { + +// \top: 1 +struct p_gold : public module { + /*output*/ value<6> p_Y; + /*input*/ value<4> p_B; + /*input*/ value<5> p_A; + p_gold(interior) {} + p_gold() { + reset(); + }; + + void reset() override; + + bool eval(performer *performer = nullptr) override; + + template + bool commit(ObserverT &observer) { + bool changed = false; + return changed; + } + + bool commit() override { + observer observer; + return commit<>(observer); + } + + void debug_eval(); + + void debug_info(debug_items *items, debug_scopes *scopes, std::string path, metadata_map &&cell_attrs = {}) override; +}; // struct p_gold + +void p_gold::reset() { +} + +bool p_gold::eval(performer *performer) { + bool converged = true; + // cell \UUT + p_Y = add_ss<6>(p_A, p_B); + return converged; +} + +void p_gold::debug_eval() { +} + +CXXRTL_EXTREMELY_COLD +void p_gold::debug_info(debug_items *items, debug_scopes *scopes, std::string path, metadata_map &&cell_attrs) { + assert(path.empty() || path[path.size() - 1] == ' '); + if (scopes) { + scopes->add(path.empty() ? path : path.substr(0, path.size() - 1), "gold", metadata_map({ + { "top", UINT64_C(1) }, + }), std::move(cell_attrs)); + } + if (items) { + items->add(path, "Y", "", p_Y, 0, debug_item::OUTPUT|debug_item::DRIVEN_COMB); + items->add(path, "B", "", p_B, 0, debug_item::INPUT|debug_item::UNDRIVEN); + items->add(path, "A", "", p_A, 0, debug_item::INPUT|debug_item::UNDRIVEN); + } +} + +} // namespace cxxrtl_design + +extern "C" +cxxrtl_toplevel cxxrtl_design_create() { + return new _cxxrtl_toplevel { std::unique_ptr(new cxxrtl_design::p_gold) }; +} diff --git a/tests/functional/single_cells/run-test.sh b/tests/functional/single_cells/run-test.sh index b9828ff84ad..017b3349d61 100755 --- a/tests/functional/single_cells/run-test.sh +++ b/tests/functional/single_cells/run-test.sh @@ -8,45 +8,49 @@ run_test() { # Define the common variable for the relative path BASE_PATH="../../../" - local verilog_file=$1 + local rtlil_file=$1 # Extract the base name without extension - local base_name=$(basename "$verilog_file" .v) + local base_name=$(basename "$rtlil_file" .v) # Run yosys to process each RTLIL file - if ${BASE_PATH}yosys -p "read_verilog $verilog_file; write_functional_cxx my_module_functional_cxx.cc"; then - echo "Yosys processed $verilog_file successfully." + if ${BASE_PATH}yosys -p "read_rtlil $rtlil_file; write_functional_cxx my_module_functional_cxx.cc"; then + echo "Yosys processed $rtlil_file successfully." # Compile the generated C++ files with vcd_harness.cpp - ${CXX:-g++} -g -fprofile-arcs -ftest-coverage vcd_harness.cc -I ${BASE_PATH}backends/functional/cxx_runtime/ -o vcd_harness - - # Generate VCD files with base_name - if ./vcd_harness ${base_name}_functional_cxx.vcd; then - - # Run yosys to process each RTLIL file - if ${BASE_PATH}yosys -p "read_verilog $verilog_file; sim -r ${base_name}_functional_cxx.vcd -scope my_module -vcd ${base_name}_yosys_sim.vcd -timescale 1us -sim-gold"; then - echo "Yosys sim $verilog_file successfully." - else - ${BASE_PATH}yosys -p "read_verilog $verilog_file; sim -vcd ${base_name}_yosys_sim.vcd -r ${base_name}_functional_cxx.vcd -scope my_module -timescale 1us" - echo "Yosys simulation of $verilog_file failed. There is a discrepancy with functional cxx" - failing_files["$verilog_file"]="Yosys sim failure" - fi - - else - echo "Failed to generate VCD files for $verilog_file." - failing_files["$verilog_file"]="VCD generation failure" - fi - else - echo "Yosys failed to process $verilog_file." - failing_files["$verilog_file"]="Yosys failure" - fi + if ${CXX:-g++} -g -fprofile-arcs -ftest-coverage vcd_harness.cc -I ${BASE_PATH}backends/functional/cxx_runtime/ -o vcd_harness; then + echo "Compilation successful." + # Generate VCD files with base_name + if ./vcd_harness ${base_name}_functional_cxx.vcd; then + + # Run yosys to process each RTLIL file + if ${BASE_PATH}yosys -p "read_rtlil $rtlil_file; sim -r ${base_name}_functional_cxx.vcd -scope gold -vcd ${base_name}_yosys_sim.vcd -timescale 1us -sim-gold"; then + echo "Yosys sim $rtlil_file successfully." + else + ${BASE_PATH}yosys -p "read_rtlil $rtlil_file; sim -vcd ${base_name}_yosys_sim.vcd -r ${base_name}_functional_cxx.vcd -scope my_module -timescale 1us" + echo "Yosys simulation of $rtlil_file failed. There is a discrepancy with functional cxx" + failing_files["$rtlil_file"]="Yosys sim failure" + fi + + else + echo "Failed to generate VCD files for $rtlil_file." + failing_files["$rtlil_file"]="VCD generation failure" + fi + else + echo "Failed to compile harness for $rtlil_file." + failing_files["$rtlil_file"]="Compilation failure" + fi + else + echo "Yosys failed to process $rtlil_file." + failing_files["$rtlil_file"]="Yosys failure" + fi } # Main function to run all tests run_all_tests() { - # Loop through all RTLIL files in the verilog directory - for verilog_file in verilog/*.v; do - run_test "$verilog_file" + # Loop through all RTLIL files in the rtlil directory + for rtlil_file in rtlil/*.il; do + run_test "$rtlil_file" done # Check if the array of failing files is empty diff --git a/tests/functional/single_cells/vcd_harness.cc b/tests/functional/single_cells/vcd_harness.cc new file mode 100644 index 00000000000..6051306c8d6 --- /dev/null +++ b/tests/functional/single_cells/vcd_harness.cc @@ -0,0 +1,127 @@ +#include +#include +#include +#include + +#include "my_module_functional_cxx.cc" + +struct DumpHeader { + std::ofstream &ofs; + DumpHeader(std::ofstream &ofs) : ofs(ofs) {} + template + void operator()(const char *name, Signal value) { + ofs << "$var wire " << n << " " << name[0] << " " << name << " $end\n"; + } +}; + +struct Dump { + std::ofstream &ofs; + Dump(std::ofstream &ofs) : ofs(ofs) {} + template + void operator()(const char *name, Signal value) { + // Bit + if (n == 1) { + ofs << (value[0] ? '1' : '0'); + ofs << name[0] << "\n"; + return; + } + // vector (multi-bit) signals + ofs << "b"; + for (size_t i = n; i-- > 0;) + ofs << (value[i] ? '1' : '0'); + ofs << " " << name[0] << "\n"; + } +}; + +// Function to set all values in a signal to false +template +void set_all_false(Signal& signal) { + std::fill(signal.begin(), signal.end(), false); +} + +template +void set_all_random(Signal& signal) { + std::random_device rd; // Random device for seeding + std::mt19937 gen(rd()); // Mersenne Twister engine + std::bernoulli_distribution dist(0.5); // 50-50 distribution + + for (auto& value : signal) { + value = dist(gen); // Set each value to a random boolean + } +} + +int main(int argc, char **argv) +{ + if (argc != 2) { + std::cerr << "Usage: " << argv[0] << " \n"; + return 1; + } + + const std::string functional_vcd_filename = argv[1]; + + constexpr int steps = 10; + constexpr int number_timescale = 1; + const std::string units_timescale = "us"; + gold_Inputs inputs; + gold_Outputs outputs; + gold_State state; + gold_State next_state; + + std::ofstream vcd_file(functional_vcd_filename); + + vcd_file << "$timescale " << number_timescale << " " << units_timescale << " $end\n"; + vcd_file << "$scope module gold $end\n"; + { + DumpHeader d(vcd_file); + inputs.dump(d); + outputs.dump(d); + state.dump(d); + } + vcd_file << "$enddefinitions $end\n$dumpvars\n"; + vcd_file << "#0\n"; + // Set all signals to false + for (int i = 0; i < inputs.size(); ++i) { + auto input_variant = inputs.get_input(i); + std::visit([](auto& signal_ref) { + set_all_false(signal_ref.get()); + }, input_variant); + } + + gold(inputs, outputs, state, next_state); + { + Dump d(vcd_file); + inputs.dump(d); + outputs.dump(d); + state.dump(d); + } + + std::random_device rd; + std::mt19937 gen(rd()); + std::bernoulli_distribution dist(0.5); + + for (int step = 0; step < steps; ++step) { + // Functional backend cxx + vcd_file << "#" << (step + 1) << "\n"; + // Set all signals to random + for (int i = 0; i < inputs.size(); ++i) { + auto input_variant = inputs.get_input(i); + std::visit([](auto& signal_ref) { + set_all_random(signal_ref.get()); + }, input_variant); + } + + gold(inputs, outputs, state, next_state); + { + Dump d(vcd_file); + inputs.dump(d); + outputs.dump(d); + state.dump(d); + } + + state = next_state; + } + + vcd_file.close(); + + return 0; +} From 6f38d5f1e4cbef4f80c81e05d540f680c5628ab1 Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Thu, 6 Jun 2024 16:20:03 +0200 Subject: [PATCH 47/51] WIP --- backends/functional/Makefile.inc | 4 +-- backends/functional/cxx.cc | 46 ++++++++++++++++++++++++++---- my_module_functional_cxx.cc | 48 ++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 7 deletions(-) create mode 100644 my_module_functional_cxx.cc diff --git a/backends/functional/Makefile.inc b/backends/functional/Makefile.inc index 5776bf84ed9..675153c95b0 100644 --- a/backends/functional/Makefile.inc +++ b/backends/functional/Makefile.inc @@ -1,4 +1,4 @@ -# OBJS += backends/functional/cxx.o +OBJS += backends/functional/cxx.o # OBJS += backends/functional/smtlib.o -OBJS += backends/functional/alternative_cxx.o +# OBJS += backends/functional/alternative_cxx.o # OBJS += backends/functional/alternative_smtlib.o diff --git a/backends/functional/cxx.cc b/backends/functional/cxx.cc index f0ceb5d76d4..8aaed5482fe 100644 --- a/backends/functional/cxx.cc +++ b/backends/functional/cxx.cc @@ -101,7 +101,10 @@ struct CxxStruct { std::string name; dict types; CxxScope scope; - CxxStruct(std::string name) : name(name) { + bool generate_methods; + int count; + CxxStruct(std::string name, bool generate_methods = false, int count = 0) + : name(name), generate_methods(generate_methods), count(count) { scope.reserve("out"); scope.reserve("dump"); } @@ -114,15 +117,47 @@ struct CxxStruct { for (auto p : types) { f.printf("\t%s %s;\n", p.second.c_str(), scope[p.first].c_str()); } - f.printf("\n\ttemplate void dump(T &out) {\n"); + f.printf("\n\ttemplate void dump(T &out) const {\n"); for (auto p : types) { f.printf("\t\tout(\"%s\", %s);\n", RTLIL::unescape_id(p.first).c_str(), scope[p.first].c_str()); } - f.printf("\t}\n};\n\n"); - } + f.printf("\t}\n\n"); + + if (generate_methods) { + // Add size method + f.printf("\tint size() const {\n"); + f.printf("\t\treturn %d;\n", count); + f.printf("\t}\n\n"); + + // Add get_input method + f.printf("\tstd::variant<%s> get_input(const int index) {\n", generate_variant_types().c_str()); + f.printf("\t\tswitch (index) {\n"); + int idx = 0; + for (auto p : types) { + f.printf("\t\t\tcase %d: return std::ref(%s);\n", idx, scope[p.first].c_str()); + idx++; + } + f.printf("\t\t\tdefault: throw std::out_of_range(\"Invalid input index\");\n"); + f.printf("\t\t}\n"); + f.printf("\t}\n"); + } + + f.printf("};\n\n"); + }; std::string operator[](IdString field) { return scope[field]; } + private: + std::string generate_variant_types() const { + std::string variant_types; + for (const auto& p : types) { + if (!variant_types.empty()) { + variant_types += ", "; + } + variant_types += "std::reference_wrapper<" + p.second + ">"; + } + return variant_types; + } }; struct CxxFunction { @@ -307,7 +342,8 @@ struct FunctionalCxxBackend : public Backend state[ref.function().parameters.begin()->first] = ref.function().width; } f.printf("#include \"sim.h\"\n"); - CxxStruct input_struct(name + "_Inputs"); + f.printf("#include \n"); + CxxStruct input_struct(name + "_Inputs", true, inputs.size()); for (auto const &input : inputs) input_struct.insert(input.first, "Signal<" + std::to_string(input.second) + ">"); CxxStruct output_struct(name + "_Outputs"); diff --git a/my_module_functional_cxx.cc b/my_module_functional_cxx.cc new file mode 100644 index 00000000000..495813c0dec --- /dev/null +++ b/my_module_functional_cxx.cc @@ -0,0 +1,48 @@ +#include "sim.h" +struct gold_Inputs { + Signal<4> B; + Signal<5> A; + + template void dump(T &out) const { + out("B", B); + out("A", A); + } + + int size() const { + return 2; + } + + std::variant>, std::reference_wrapper>> get_input(const int index) const { + switch (index) { + case 0: return std::ref(B); + case 1: return std::ref(A); + default: throw std::out_of_range("Invalid input index"); + } + } +}; + +struct gold_Outputs { + Signal<6> Y; + + template void dump(T &out) const { + out("Y", Y); + } + +}; + +struct gold_State { + + template void dump(T &out) const { + } + +}; + +void gold(gold_Inputs const &input, gold_Outputs &output, gold_State const ¤t_state, gold_State &next_state) +{ + Signal<4> B = input.B; + Signal<5> A = input.A; + Signal<6> n2 = $sign_extend<6>(A); //[WIDTH=6] + Signal<6> n3 = $sign_extend<6>(B); //[WIDTH=6] + Signal<6> UUT$_Y = $add(n2, n3); // + output.Y = UUT$_Y; +} From 89f124eb287b937d78f5099d4af5e444f035ec5f Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Thu, 6 Jun 2024 16:38:14 +0200 Subject: [PATCH 48/51] Compile with C++17 --- tests/functional/single_cells/run-test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functional/single_cells/run-test.sh b/tests/functional/single_cells/run-test.sh index 017b3349d61..f87be8ebaf5 100755 --- a/tests/functional/single_cells/run-test.sh +++ b/tests/functional/single_cells/run-test.sh @@ -18,7 +18,7 @@ run_test() { echo "Yosys processed $rtlil_file successfully." # Compile the generated C++ files with vcd_harness.cpp - if ${CXX:-g++} -g -fprofile-arcs -ftest-coverage vcd_harness.cc -I ${BASE_PATH}backends/functional/cxx_runtime/ -o vcd_harness; then + if ${CXX:-g++} -g -fprofile-arcs -ftest-coverage vcd_harness.cc -I ${BASE_PATH}backends/functional/cxx_runtime/ -std=c++17 -o vcd_harness; then echo "Compilation successful." # Generate VCD files with base_name if ./vcd_harness ${base_name}_functional_cxx.vcd; then From 3a9a55e05140dd50304a54052b8963ae81842f66 Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Thu, 6 Jun 2024 16:46:59 +0200 Subject: [PATCH 49/51] Set on unique types for variant --- backends/functional/cxx.cc | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/backends/functional/cxx.cc b/backends/functional/cxx.cc index 8aaed5482fe..169df74621f 100644 --- a/backends/functional/cxx.cc +++ b/backends/functional/cxx.cc @@ -148,16 +148,20 @@ struct CxxStruct { return scope[field]; } private: - std::string generate_variant_types() const { - std::string variant_types; + std::string generate_variant_types() const { + std::set unique_types; for (const auto& p : types) { - if (!variant_types.empty()) { - variant_types += ", "; + unique_types.insert("std::reference_wrapper<" + p.second + ">"); + } + std::ostringstream oss; + for (auto it = unique_types.begin(); it != unique_types.end(); ++it) { + if (it != unique_types.begin()) { + oss << ", "; } - variant_types += "std::reference_wrapper<" + p.second + ">"; + oss << *it; } - return variant_types; - } + return oss.str(); + } }; struct CxxFunction { From a4d5d9a6f0bd990df8e4d65525c566ef61523075 Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Thu, 6 Jun 2024 16:50:41 +0200 Subject: [PATCH 50/51] scope is gold, not my_module --- tests/functional/single_cells/run-test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functional/single_cells/run-test.sh b/tests/functional/single_cells/run-test.sh index f87be8ebaf5..a2741060734 100755 --- a/tests/functional/single_cells/run-test.sh +++ b/tests/functional/single_cells/run-test.sh @@ -27,7 +27,7 @@ run_test() { if ${BASE_PATH}yosys -p "read_rtlil $rtlil_file; sim -r ${base_name}_functional_cxx.vcd -scope gold -vcd ${base_name}_yosys_sim.vcd -timescale 1us -sim-gold"; then echo "Yosys sim $rtlil_file successfully." else - ${BASE_PATH}yosys -p "read_rtlil $rtlil_file; sim -vcd ${base_name}_yosys_sim.vcd -r ${base_name}_functional_cxx.vcd -scope my_module -timescale 1us" + ${BASE_PATH}yosys -p "read_rtlil $rtlil_file; sim -vcd ${base_name}_yosys_sim.vcd -r ${base_name}_functional_cxx.vcd -scope gold -timescale 1us" echo "Yosys simulation of $rtlil_file failed. There is a discrepancy with functional cxx" failing_files["$rtlil_file"]="Yosys sim failure" fi From fb6511b6e8808ad42b850e67ba65d0446bb8c44c Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Thu, 6 Jun 2024 17:13:24 +0200 Subject: [PATCH 51/51] =?UTF-8?q?=C2=B4Print=20also=20successful=20files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/functional/single_cells/run-test.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/functional/single_cells/run-test.sh b/tests/functional/single_cells/run-test.sh index a2741060734..67cdf4a11c4 100755 --- a/tests/functional/single_cells/run-test.sh +++ b/tests/functional/single_cells/run-test.sh @@ -2,6 +2,8 @@ # Initialize an array to store the names of failing RTLIL files and their failure types declare -A failing_files +# Initialize an array to store the names of successful RTLIL files +declare -A successful_files # Function to run the test on a given RTLIL file run_test() { @@ -26,6 +28,7 @@ run_test() { # Run yosys to process each RTLIL file if ${BASE_PATH}yosys -p "read_rtlil $rtlil_file; sim -r ${base_name}_functional_cxx.vcd -scope gold -vcd ${base_name}_yosys_sim.vcd -timescale 1us -sim-gold"; then echo "Yosys sim $rtlil_file successfully." + successful_files["$rtlil_file"]="Success" else ${BASE_PATH}yosys -p "read_rtlil $rtlil_file; sim -vcd ${base_name}_yosys_sim.vcd -r ${base_name}_functional_cxx.vcd -scope gold -timescale 1us" echo "Yosys simulation of $rtlil_file failed. There is a discrepancy with functional cxx" @@ -56,12 +59,20 @@ run_all_tests() { # Check if the array of failing files is empty if [ ${#failing_files[@]} -eq 0 ]; then echo "All files passed." + echo "The following files passed:" + for file in "${!successful_files[@]}"; do + echo "$file" + done return 0 else echo "The following files failed:" for file in "${!failing_files[@]}"; do echo "$file: ${failing_files[$file]}" done + echo "The following files passed:" + for file in "${!successful_files[@]}"; do + echo "$file" + done return 1 fi }