@@ -217,26 +217,73 @@ std::string FasmWriterVisitor::build_clb_prefix(const t_pb *pb, const t_pb_graph
217217 return clb_prefix;
218218}
219219
220- static const t_pb_graph_pin* is_node_used (const t_pb_routes &top_pb_route, const t_pb_graph_node* pb_graph_node) {
221- // Is the node used at all?
222- const t_pb_graph_pin* pin = nullptr ;
223- for (int port_index = 0 ; port_index < pb_graph_node->num_output_ports ; ++port_index) {
224- for (int pin_index = 0 ; pin_index < pb_graph_node->num_output_pins [port_index]; ++pin_index) {
225- pin = &pb_graph_node->output_pins [port_index][pin_index];
226- if (top_pb_route.count (pin->pin_count_in_cluster ) > 0 && top_pb_route[pin->pin_count_in_cluster ].atom_net_id != AtomNetId::INVALID ()) {
227- return pin;
220+ /* *
221+ * @brief Returns true if the given pin is used (i.e. is not "open").
222+ */
223+ static bool is_pin_used (const t_pb_graph_pin* pin, const t_pb_routes &top_pb_route) {
224+ // A pin is used if it has a pb_route that is connected to an atom net.
225+ if (top_pb_route.count (pin->pin_count_in_cluster ) == 0 )
226+ return false ;
227+ if (!top_pb_route[pin->pin_count_in_cluster ].atom_net_id .is_valid ())
228+ return false ;
229+ return true ;
230+ }
231+
232+ /* *
233+ * @brief Returns the input pin for the given wire.
234+ *
235+ * Wires in VPR are a special primitive which is a LUT which acts like a wire
236+ * pass-through. Only one input of this LUT should be used.
237+ *
238+ * @param top_pb_route
239+ * The top pb route for the cluster that contains the wire.
240+ * @param pb_graph_node
241+ * The pb_graph_node of the wire primitive that we are getting the input
242+ * pin for.
243+ */
244+ 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) {
245+ const t_pb_graph_pin* wire_input_pin = nullptr ;
246+ for (int port_index = 0 ; port_index < pb_graph_node->num_input_ports ; ++port_index) {
247+ for (int pin_index = 0 ; pin_index < pb_graph_node->num_input_pins [port_index]; ++pin_index) {
248+ const t_pb_graph_pin* pin = &pb_graph_node->input_pins [port_index][pin_index];
249+ if (is_pin_used (pin, top_pb_route)) {
250+ VTR_ASSERT_MSG (wire_input_pin == nullptr ,
251+ " Wire found with more than 1 used input" );
252+ wire_input_pin = pin;
228253 }
229254 }
230255 }
231- for (int port_index = 0 ; port_index < pb_graph_node->num_input_ports ; ++port_index) {
232- for (int pin_index = 0 ; pin_index < pb_graph_node->num_input_pins [port_index]; ++pin_index) {
233- pin = &pb_graph_node->input_pins [port_index][pin_index];
234- if (top_pb_route.count (pin->pin_count_in_cluster ) > 0 && top_pb_route[pin->pin_count_in_cluster ].atom_net_id != AtomNetId::INVALID ()) {
235- return pin;
256+ return wire_input_pin;
257+ }
258+
259+ /* *
260+ * @brief Returns true if the given wire is used.
261+ *
262+ * A wire is used if it has a used output pin.
263+ *
264+ * @param top_pb_route
265+ * The top pb route for the cluster that contains the wire.
266+ * @param pb_graph_node
267+ * The pb_graph_node of the wire primitive that we are checking is used.
268+ */
269+ static bool is_wire_used (const t_pb_routes &top_pb_route, const t_pb_graph_node* pb_graph_node) {
270+ // A wire is used if it has a used output pin.
271+ const t_pb_graph_pin* wire_output_pin = nullptr ;
272+ for (int port_index = 0 ; port_index < pb_graph_node->num_output_ports ; ++port_index) {
273+ for (int pin_index = 0 ; pin_index < pb_graph_node->num_output_pins [port_index]; ++pin_index) {
274+ const t_pb_graph_pin* pin = &pb_graph_node->output_pins [port_index][pin_index];
275+ if (is_pin_used (pin, top_pb_route)) {
276+ VTR_ASSERT_MSG (wire_output_pin == nullptr ,
277+ " Wire found with more than 1 used output" );
278+ wire_output_pin = pin;
236279 }
237280 }
238281 }
239- return nullptr ;
282+
283+ if (wire_output_pin != nullptr )
284+ return true ;
285+
286+ return false ;
240287}
241288
242289void FasmWriterVisitor::check_features (const t_metadata_dict *meta) const {
@@ -278,14 +325,31 @@ void FasmWriterVisitor::visit_all_impl(const t_pb_routes &pb_routes, const t_pb*
278325 }
279326
280327 if (mode != nullptr && std::string (mode->name ) == " wire" ) {
281- auto io_pin = is_node_used (pb_routes, pb_graph_node);
282- if (io_pin != nullptr ) {
283- const auto & route = pb_routes.at (io_pin->pin_count_in_cluster );
328+ // Check if the wire is used. If the wire is unused (i.e. it does not connect
329+ // to anything), it does not need to be created.
330+ if (is_wire_used (pb_routes, pb_graph_node)) {
331+ // Get the input pin of the LUT that feeds the wire. There should be one
332+ // and only one.
333+ const t_pb_graph_pin* wire_input_pin = get_wire_input_pin (pb_routes, pb_graph_node);
334+ VTR_ASSERT_MSG (wire_input_pin != nullptr ,
335+ " Wire found with no used input pins" );
336+
337+ // Get the route going into this pin.
338+ const auto & route = pb_routes.at (wire_input_pin->pin_count_in_cluster );
339+
340+ // Find the lut definition for the parent of this wire.
284341 const int num_inputs = *route.pb_graph_pin ->parent_node ->num_input_pins ;
285342 const auto *lut_definition = find_lut (route.pb_graph_pin ->parent_node );
286343 VTR_ASSERT (lut_definition->num_inputs == num_inputs);
287344
345+ // Create a wire implementation for the LUT.
288346 output_fasm_features (lut_definition->CreateWire (route.pb_graph_pin ->pin_number ));
347+ } else {
348+ // If the wire is not used, ensure that the inputs to the wire are also
349+ // unused. This is just a sanity check to ensure that all wires are
350+ // either completely unused or have one input and one output.
351+ VTR_ASSERT_MSG (get_wire_input_pin (pb_routes, pb_graph_node) == nullptr ,
352+ " Wire found with a used input pin, but no used output pin" );
289353 }
290354 }
291355
0 commit comments