diff --git a/openfpga/src/base/openfpga_repack.cpp b/openfpga/src/base/openfpga_repack.cpp index 8e8a79141..17bba43a7 100644 --- a/openfpga/src/base/openfpga_repack.cpp +++ b/openfpga/src/base/openfpga_repack.cpp @@ -47,6 +47,7 @@ int repack(OpenfpgaContext& openfpga_ctx, openfpga_ctx.mutable_vpr_clustering_annotation(), openfpga_ctx.vpr_bitstream_annotation(), repack_design_constraints, + openfpga_ctx.arch().circuit_lib, cmd_context.option_enable(cmd, opt_verbose)); build_physical_lut_truth_tables(openfpga_ctx.mutable_vpr_clustering_annotation(), diff --git a/openfpga/src/repack/build_physical_truth_table.cpp b/openfpga/src/repack/build_physical_truth_table.cpp index 5a39b86bf..cc1e32018 100644 --- a/openfpga/src/repack/build_physical_truth_table.cpp +++ b/openfpga/src/repack/build_physical_truth_table.cpp @@ -18,31 +18,6 @@ /* begin namespace openfpga */ namespace openfpga { -/*************************************************************************************** - * Identify if LUT is used as wiring - * In this case, LUT functions as a buffer - * +------+ - * in0 -->|--- | - * | \ | - * in1 -->| --|--->out - * ... - * - * Note that this function judge the LUT operating mode from the input nets and output - * nets that are mapped to inputs and outputs. - * If the output net appear in the list of input nets, this LUT is used as a wire - ***************************************************************************************/ -static -bool is_wired_lut(const std::vector& input_nets, - const AtomNetId& output_net) { - for (const AtomNetId& input_net : input_nets) { - if (input_net == output_net) { - return true; - } - } - - return false; -} - /*************************************************************************************** * Create pin rotation map for a LUT ***************************************************************************************/ @@ -149,11 +124,6 @@ void build_physical_pb_lut_truth_tables(PhysicalPb& physical_pb, /* Double check: ensure that the output nets appear in the input net !!! */ VTR_ASSERT(true == is_wired_lut(input_nets, output_net)); adapt_tt = build_wired_lut_truth_table(input_nets.size(), std::find(input_nets.begin(), input_nets.end(), output_net) - input_nets.begin()); - } else if (true == is_wired_lut(input_nets, output_net)) { - /* Another round of check: - * new wired LUTs may be created during repacking rather than original packing results - */ - adapt_tt = build_wired_lut_truth_table(input_nets.size(), std::find(input_nets.begin(), input_nets.end(), output_net) - input_nets.begin()); } else { /* Find the truth table from atom block which drives the atom net */ const AtomBlockId& atom_blk = atom_ctx.nlist.net_driver_block(output_net); diff --git a/openfpga/src/repack/repack.cpp b/openfpga/src/repack/repack.cpp index e737991b8..5a7d5ecdd 100644 --- a/openfpga/src/repack/repack.cpp +++ b/openfpga/src/repack/repack.cpp @@ -695,6 +695,43 @@ void repack_clusters(const AtomContext& atom_ctx, } } +/*************************************************************************************** + * VPR's packer may create wire LUTs for routing + * Repacker will not remove these wire LUTs + * But repacker may create more wire LUTs for routing + * by exploiting the routability of the physical mode of a programmable block + * This is why this annotation is required + ***************************************************************************************/ +static +void identify_physical_pb_wire_lut_created_by_repack(VprClusteringAnnotation& cluster_annotation, + const ClusteringContext& cluster_ctx, + const VprDeviceAnnotation& device_annotation, + const CircuitLibrary& circuit_lib, + const bool& verbose) { + vtr::ScopedStartFinishTimer timer("Identify wire LUTs created by repacking"); + int wire_lut_counter = 0; + + for (auto blk_id : cluster_ctx.clb_nlist.blocks()) { + PhysicalPb& physical_pb = cluster_annotation.mutable_physical_pb(blk_id); + /* Find the LUT physical pb id */ + for (const PhysicalPbId& primitive_pb : physical_pb.primitive_pbs()) { + CircuitModelId circuit_model = device_annotation.pb_type_circuit_model(physical_pb.pb_graph_node(primitive_pb)->pb_type); + VTR_ASSERT(true == circuit_lib.valid_model_id(circuit_model)); + if (CIRCUIT_MODEL_LUT != circuit_lib.model_type(circuit_model)) { + continue; + } + + /* Reach here, we have a LUT to deal with. Find the wire LUT that mapped to the LUT */ + wire_lut_counter += identify_one_physical_pb_wire_lut_created_by_repack(physical_pb, primitive_pb, device_annotation, circuit_lib, verbose); + } + } + + VTR_LOG("Identified %d wire LUTs created by repacker\n", + wire_lut_counter); +} + + + /*************************************************************************************** * Top-level function to pack physical pb_graph * This function will do : @@ -712,6 +749,7 @@ void pack_physical_pbs(const DeviceContext& device_ctx, VprClusteringAnnotation& clustering_annotation, const VprBitstreamAnnotation& bitstream_annotation, const RepackDesignConstraints& design_constraints, + const CircuitLibrary& circuit_lib, const bool& verbose) { /* build the routing resource graph for each logical tile */ @@ -726,6 +764,15 @@ void pack_physical_pbs(const DeviceContext& device_ctx, bitstream_annotation, design_constraints, verbose); + + /* Annnotate wire LUTs that are ONLY created by repacker!!! + * This is a MUST RUN! + */ + identify_physical_pb_wire_lut_created_by_repack(clustering_annotation, + clustering_ctx, + device_annotation, + circuit_lib, + verbose); } } /* end namespace openfpga */ diff --git a/openfpga/src/repack/repack.h b/openfpga/src/repack/repack.h index feb48a578..1a9167bc3 100644 --- a/openfpga/src/repack/repack.h +++ b/openfpga/src/repack/repack.h @@ -10,6 +10,7 @@ #include "vpr_routing_annotation.h" #include "vpr_bitstream_annotation.h" #include "repack_design_constraints.h" +#include "circuit_library.h" /******************************************************************** * Function declaration @@ -25,6 +26,7 @@ void pack_physical_pbs(const DeviceContext& device_ctx, VprClusteringAnnotation& clustering_annotation, const VprBitstreamAnnotation& bitstream_annotation, const RepackDesignConstraints& design_constraints, + const CircuitLibrary& circuit_lib, const bool& verbose); } /* end namespace openfpga */ diff --git a/openfpga/src/utils/lut_utils.cpp b/openfpga/src/utils/lut_utils.cpp index 35f613c73..bcf3703f9 100644 --- a/openfpga/src/utils/lut_utils.cpp +++ b/openfpga/src/utils/lut_utils.cpp @@ -505,5 +505,28 @@ std::vector build_frac_lut_bitstream(const CircuitLibrary& circuit_lib, return lut_bitstream; } +/*************************************************************************************** + * Identify if LUT is used as wiring + * In this case, LUT functions as a buffer + * +------+ + * in0 -->|--- | + * | \ | + * in1 -->| --|--->out + * ... + * + * Note that this function judge the LUT operating mode from the input nets and output + * nets that are mapped to inputs and outputs. + * If the output net appear in the list of input nets, this LUT is used as a wire + ***************************************************************************************/ +bool is_wired_lut(const std::vector& input_nets, + const AtomNetId& output_net) { + for (const AtomNetId& input_net : input_nets) { + if (input_net == output_net) { + return true; + } + } + + return false; +} } /* end namespace openfpga */ diff --git a/openfpga/src/utils/lut_utils.h b/openfpga/src/utils/lut_utils.h index 4b2f8bd58..fb79a0f94 100644 --- a/openfpga/src/utils/lut_utils.h +++ b/openfpga/src/utils/lut_utils.h @@ -39,6 +39,9 @@ std::vector build_frac_lut_bitstream(const CircuitLibrary& circuit_lib, const std::map& truth_tables, const size_t& default_sram_bit_value); +bool is_wired_lut(const std::vector& input_nets, + const AtomNetId& output_net); + } /* end namespace openfpga */ #endif diff --git a/openfpga/src/utils/physical_pb_utils.cpp b/openfpga/src/utils/physical_pb_utils.cpp index 9f3cbf087..a5096fbb4 100644 --- a/openfpga/src/utils/physical_pb_utils.cpp +++ b/openfpga/src/utils/physical_pb_utils.cpp @@ -10,6 +10,7 @@ #include "openfpga_tokenizer.h" #include "openfpga_naming.h" +#include "lut_utils.h" #include "pb_type_utils.h" #include "physical_pb_utils.h" @@ -399,4 +400,70 @@ void rec_update_physical_pb_from_operating_pb(PhysicalPb& phy_pb, } } +/*************************************************************************************** + * This function will identify all the wire LUTs that is created by repacker only + * under a physical pb + * Return the number of wire LUTs that are found + ***************************************************************************************/ +int identify_one_physical_pb_wire_lut_created_by_repack(PhysicalPb& physical_pb, + const PhysicalPbId& lut_pb_id, + const VprDeviceAnnotation& device_annotation, + const CircuitLibrary& circuit_lib, + const bool& verbose) { + int wire_lut_counter = 0; + const t_pb_graph_node* pb_graph_node = physical_pb.pb_graph_node(lut_pb_id); + + CircuitModelId lut_model = device_annotation.pb_type_circuit_model(physical_pb.pb_graph_node(lut_pb_id)->pb_type); + VTR_ASSERT(CIRCUIT_MODEL_LUT == circuit_lib.model_type(lut_model)); + + /* Find all the nets mapped to each inputs */ + std::vector input_nets; + for (int iport = 0; iport < pb_graph_node->num_input_ports; ++iport) { + for (int ipin = 0; ipin < pb_graph_node->num_input_pins[iport]; ++ipin) { + /* Skip the input pin that do not drive by LUT MUXes */ + CircuitPortId circuit_port = device_annotation.pb_circuit_port(pb_graph_node->input_pins[iport][ipin].port); + if (true == circuit_lib.port_is_harden_lut_port(circuit_port)) { + continue; + } + input_nets.push_back(physical_pb.pb_graph_pin_atom_net(lut_pb_id, &(pb_graph_node->input_pins[iport][ipin]))); + } + } + + /* Find all the nets mapped to each outputs */ + for (int iport = 0; iport < pb_graph_node->num_output_ports; ++iport) { + for (int ipin = 0; ipin < pb_graph_node->num_output_pins[iport]; ++ipin) { + const t_pb_graph_pin* output_pin = &(pb_graph_node->output_pins[iport][ipin]); + /* Skip the output ports that are not driven by LUT MUXes */ + CircuitPortId circuit_port = device_annotation.pb_circuit_port(output_pin->port); + if (true == circuit_lib.port_is_harden_lut_port(circuit_port)) { + continue; + } + + AtomNetId output_net = physical_pb.pb_graph_pin_atom_net(lut_pb_id, output_pin); + /* Bypass unmapped pins */ + if (AtomNetId::INVALID() == output_net) { + continue; + } + /* Check if this is a LUT used as wiring */ + if ( (false == physical_pb.is_wire_lut_output(lut_pb_id, output_pin)) + && (true == physical_pb.atom_blocks(lut_pb_id).empty()) + && (true == is_wired_lut(input_nets, output_net))) { + /* Print debug info */ + VTR_LOGV(verbose, + "Identify physical pb_graph pin '%s.%s[%d]' as wire LUT output created by repacker\n", + output_pin->parent_node->pb_type->name, + output_pin->port->name, + output_pin->pin_number); + + /* Label the pins in physical_pb as driven by wired LUT*/ + physical_pb.set_wire_lut_output(lut_pb_id, output_pin, true); + wire_lut_counter++; + } + } + } + + return wire_lut_counter; +} + + } /* end namespace openfpga */ diff --git a/openfpga/src/utils/physical_pb_utils.h b/openfpga/src/utils/physical_pb_utils.h index faa18bc91..d5787da13 100644 --- a/openfpga/src/utils/physical_pb_utils.h +++ b/openfpga/src/utils/physical_pb_utils.h @@ -10,8 +10,10 @@ #include #include "physical_types.h" #include "vpr_device_annotation.h" +#include "vpr_clustering_annotation.h" #include "vpr_bitstream_annotation.h" #include "vpr_context.h" +#include "circuit_library.h" #include "physical_pb.h" /******************************************************************** @@ -33,6 +35,12 @@ void rec_update_physical_pb_from_operating_pb(PhysicalPb& phy_pb, const VprBitstreamAnnotation& bitstream_annotation, const bool& verbose); +int identify_one_physical_pb_wire_lut_created_by_repack(PhysicalPb& physical_pb, + const PhysicalPbId& lut_pb_id, + const VprDeviceAnnotation& device_annotation, + const CircuitLibrary& circuit_lib, + const bool& verbose); + } /* end namespace openfpga */ #endif