Skip to content

[FASM] Fixed Bug With Wire Creation #3067

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 81 additions & 17 deletions utils/fasm/src/fasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -217,26 +217,73 @@ std::string FasmWriterVisitor::build_clb_prefix(const t_pb *pb, const t_pb_graph
return clb_prefix;
}

static const t_pb_graph_pin* is_node_used(const t_pb_routes &top_pb_route, const t_pb_graph_node* pb_graph_node) {
// Is the node used at all?
const t_pb_graph_pin* pin = nullptr;
for(int port_index = 0; port_index < pb_graph_node->num_output_ports; ++port_index) {
for(int pin_index = 0; pin_index < pb_graph_node->num_output_pins[port_index]; ++pin_index) {
pin = &pb_graph_node->output_pins[port_index][pin_index];
if (top_pb_route.count(pin->pin_count_in_cluster) > 0 && top_pb_route[pin->pin_count_in_cluster].atom_net_id != AtomNetId::INVALID()) {
return pin;
/**
* @brief Returns true if the given pin is used (i.e. is not "open").
*/
static bool is_pin_used(const t_pb_graph_pin* pin, const t_pb_routes &top_pb_route) {
// A pin is used if it has a pb_route that is connected to an atom net.
if (top_pb_route.count(pin->pin_count_in_cluster) == 0)
return false;
if (!top_pb_route[pin->pin_count_in_cluster].atom_net_id.is_valid())
return false;
return true;
}

/**
* @brief Returns the input pin for the given wire.
*
* Wires in VPR are a special primitive which is a LUT which acts like a wire
* pass-through. Only one input of this LUT should be used.
*
* @param top_pb_route
* The top pb route for the cluster that contains the wire.
* @param pb_graph_node
* The pb_graph_node of the wire primitive that we are getting the input
* pin for.
*/
static const t_pb_graph_pin* get_wire_input_pin(const t_pb_routes &top_pb_route, const t_pb_graph_node* pb_graph_node) {
const t_pb_graph_pin* wire_input_pin = nullptr;
for(int port_index = 0; port_index < pb_graph_node->num_input_ports; ++port_index) {
for(int pin_index = 0; pin_index < pb_graph_node->num_input_pins[port_index]; ++pin_index) {
const t_pb_graph_pin* pin = &pb_graph_node->input_pins[port_index][pin_index];
if (is_pin_used(pin, top_pb_route)) {
VTR_ASSERT_MSG(wire_input_pin == nullptr,
"Wire found with more than 1 used input");
wire_input_pin = pin;
}
}
}
for(int port_index = 0; port_index < pb_graph_node->num_input_ports; ++port_index) {
for(int pin_index = 0; pin_index < pb_graph_node->num_input_pins[port_index]; ++pin_index) {
pin = &pb_graph_node->input_pins[port_index][pin_index];
if (top_pb_route.count(pin->pin_count_in_cluster) > 0 && top_pb_route[pin->pin_count_in_cluster].atom_net_id != AtomNetId::INVALID()) {
return pin;
return wire_input_pin;
}

/**
* @brief Returns true if the given wire is used.
*
* A wire is used if it has a used output pin.
*
* @param top_pb_route
* The top pb route for the cluster that contains the wire.
* @param pb_graph_node
* The pb_graph_node of the wire primitive that we are checking is used.
*/
static bool is_wire_used(const t_pb_routes &top_pb_route, const t_pb_graph_node* pb_graph_node) {
// A wire is used if it has a used output pin.
const t_pb_graph_pin* wire_output_pin = nullptr;
for(int port_index = 0; port_index < pb_graph_node->num_output_ports; ++port_index) {
for(int pin_index = 0; pin_index < pb_graph_node->num_output_pins[port_index]; ++pin_index) {
const t_pb_graph_pin* pin = &pb_graph_node->output_pins[port_index][pin_index];
if (is_pin_used(pin, top_pb_route)) {
VTR_ASSERT_MSG(wire_output_pin == nullptr,
"Wire found with more than 1 used output");
wire_output_pin = pin;
}
}
}
return nullptr;

if (wire_output_pin != nullptr)
return true;

return false;
}

void FasmWriterVisitor::check_features(const t_metadata_dict *meta) const {
Expand Down Expand Up @@ -278,14 +325,31 @@ void FasmWriterVisitor::visit_all_impl(const t_pb_routes &pb_routes, const t_pb*
}

if(mode != nullptr && std::string(mode->name) == "wire") {
auto io_pin = is_node_used(pb_routes, pb_graph_node);
if(io_pin != nullptr) {
const auto& route = pb_routes.at(io_pin->pin_count_in_cluster);
// Check if the wire is used. If the wire is unused (i.e. it does not connect
// to anything), it does not need to be created.
if (is_wire_used(pb_routes, pb_graph_node)) {
// Get the input pin of the LUT that feeds the wire. There should be one
// and only one.
const t_pb_graph_pin* wire_input_pin = get_wire_input_pin(pb_routes, pb_graph_node);
VTR_ASSERT_MSG(wire_input_pin != nullptr,
"Wire found with no used input pins");

// Get the route going into this pin.
const auto& route = pb_routes.at(wire_input_pin->pin_count_in_cluster);

// Find the lut definition for the parent of this wire.
const int num_inputs = *route.pb_graph_pin->parent_node->num_input_pins;
const auto *lut_definition = find_lut(route.pb_graph_pin->parent_node);
VTR_ASSERT(lut_definition->num_inputs == num_inputs);

// Create a wire implementation for the LUT.
output_fasm_features(lut_definition->CreateWire(route.pb_graph_pin->pin_number));
} else {
// If the wire is not used, ensure that the inputs to the wire are also
// unused. This is just a sanity check to ensure that all wires are
// either completely unused or have one input and one output.
VTR_ASSERT_MSG(get_wire_input_pin(pb_routes, pb_graph_node) == nullptr,
"Wire found with a used input pin, but no used output pin");
}
}

Expand Down
1 change: 1 addition & 0 deletions vpr/src/base/read_netlist.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,7 @@ static void processPorts(pugi::xml_node Parent, t_pb* pb, t_pb_routes& pb_route,
pb_route.insert(std::make_pair(rr_node_index, t_pb_route()));
pb_route[rr_node_index].driver_pb_pin_id = pin_node[0][0]->pin_count_in_cluster;
pb_route[rr_node_index].pb_graph_pin = pb_gpin;
VTR_ASSERT(pb_route[rr_node_index].pb_graph_pin->pin_number == i);

found = false;
for (j = 0; j < pin_node[0][0]->num_output_edges; j++) {
Expand Down
3 changes: 0 additions & 3 deletions vpr/src/route/route_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,7 @@
#include "route_tree.h"
#include "rr_graph.h"
#include "tatum/TimingReporter.hpp"

#ifdef VPR_USE_TBB
#include "stats.h"
#endif // VPR_USE_TBB

bool check_net_delays(const Netlist<>& net_list, NetPinsMatrix<float>& net_delay) {
constexpr float ERROR_TOL = 0.0001;
Expand Down