Merge pull request #243 from lnis-uofu/dev
Bug fix for truth table creation for wired LUT created by repacking
This commit is contained in:
commit
bcd8256c59
|
@ -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(),
|
||||
|
|
|
@ -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<AtomNetId>& 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
|
||||
***************************************************************************************/
|
||||
|
@ -157,6 +132,13 @@ void build_physical_pb_lut_truth_tables(PhysicalPb& physical_pb,
|
|||
|
||||
std::vector<int> rotated_pin_map = generate_lut_rotated_input_pin_map(input_nets, atom_ctx, atom_blk, device_annotation, circuit_lib, pb_graph_node);
|
||||
adapt_tt = lut_truth_table_adaption(orig_tt, rotated_pin_map);
|
||||
|
||||
VTR_LOGV(verbose, "Driver atom block: '%ld'\n", size_t(atom_blk));
|
||||
VTR_LOGV(verbose, "Pb atom blocks:");
|
||||
for (const AtomBlockId& pb_atom_blk : physical_pb.atom_blocks(lut_pb_id)) {
|
||||
VTR_LOGV(verbose, "'%ld', ", size_t(pb_atom_blk));
|
||||
}
|
||||
VTR_LOGV(verbose, "\n");
|
||||
}
|
||||
|
||||
/* Adapt the truth table for fracturable lut implementation and add to physical pb */
|
||||
|
@ -184,6 +166,12 @@ void build_physical_pb_lut_truth_tables(PhysicalPb& physical_pb,
|
|||
VTR_ASSERT(AtomNetId::INVALID() != output_net);
|
||||
VTR_LOGV(verbose, "Output net: %s\n", atom_ctx.nlist.net_name(output_net).c_str());
|
||||
|
||||
VTR_LOGV(verbose,
|
||||
"Truth table before adaption to fracturable LUT'\n");
|
||||
for (const std::string& tt_line : truth_table_to_string(adapt_tt)) {
|
||||
VTR_LOGV(verbose, "\t%s\n", tt_line.c_str());
|
||||
}
|
||||
|
||||
VTR_LOGV(verbose,
|
||||
"Add following truth table to pb_graph_pin '%s[%d]'\n",
|
||||
output_pin->port->name, output_pin->pin_number);
|
||||
|
|
|
@ -695,6 +695,44 @@ 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 AtomContext& atom_ctx,
|
||||
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, atom_ctx, 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 +750,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 +765,16 @@ 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,
|
||||
atom_ctx,
|
||||
clustering_ctx,
|
||||
device_annotation,
|
||||
circuit_lib,
|
||||
verbose);
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -505,5 +505,28 @@ std::vector<bool> 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<AtomNetId>& 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 */
|
||||
|
|
|
@ -39,6 +39,9 @@ std::vector<bool> build_frac_lut_bitstream(const CircuitLibrary& circuit_lib,
|
|||
const std::map<const t_pb_graph_pin*, AtomNetlist::TruthTable>& truth_tables,
|
||||
const size_t& default_sram_bit_value);
|
||||
|
||||
bool is_wired_lut(const std::vector<AtomNetId>& input_nets,
|
||||
const AtomNetId& output_net);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
* Function to perform fundamental operation for the physical pb using
|
||||
* data structures
|
||||
***********************************************************************/
|
||||
#include <algorithm>
|
||||
|
||||
/* Headers from vtrutil library */
|
||||
#include "vtr_assert.h"
|
||||
#include "vtr_log.h"
|
||||
|
@ -10,6 +12,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 +402,132 @@ 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
|
||||
*
|
||||
* A practical example of wire LUT that is created by VPR packer:
|
||||
*
|
||||
* LUT
|
||||
* +------------+
|
||||
* | |
|
||||
* netA ---->+----+ |
|
||||
* | |-------+-----> netC
|
||||
* netB ---->+----+ |
|
||||
* | |
|
||||
* netC ---->+------------+-----> netC
|
||||
* | |
|
||||
* +------------+
|
||||
*
|
||||
* A fracturable LUT may be mapped to two functions:
|
||||
* - a function which involves netA, netB and netC
|
||||
* the function is defined in an atom block atomA
|
||||
* In this case, netC's driver block in atom context is atomA
|
||||
* - a function which just wire netC through the LUT
|
||||
* the function is NOT defined in any atom block
|
||||
* Such wire LUT is created by VPR's packer
|
||||
*
|
||||
* THIS CASE IS WHAT THIS FUNCTION IS HANDLING
|
||||
* A practical example of wire LUT that is created by repacker:
|
||||
*
|
||||
* LUT
|
||||
* +------------+
|
||||
* | |
|
||||
* netA ---->+----+ |
|
||||
* | |-------+-----> netC
|
||||
* netB ---->+----+ |
|
||||
* | |
|
||||
* netD ---->+------------+-----> netD
|
||||
* | |
|
||||
* +------------+
|
||||
*
|
||||
* A fracturable LUT may be mapped to two functions:
|
||||
* - a function which involves netA, netB and netC
|
||||
* the function is defined in an atom block atomA
|
||||
* In this case, netC's driver block in atom context is atomA
|
||||
* - a function which just wire netD through the LUT
|
||||
* the function is NOT defined in any atom block
|
||||
* netD is driven by another atom block atomB which is not mapped to the LUT
|
||||
* Such wire LUT is created by repacker
|
||||
*
|
||||
* 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 AtomContext& atom_ctx,
|
||||
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<AtomNetId> 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;
|
||||
}
|
||||
/* Exclude all the LUTs that
|
||||
* - have been used as wires
|
||||
* - the driver atom block of the output_net is part of the atom blocks
|
||||
* If so, the driver atom block is already mapped to this pb
|
||||
* and the LUT is not used for wiring
|
||||
*/
|
||||
if (true == physical_pb.is_wire_lut_output(lut_pb_id, output_pin)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::vector<AtomBlockId> pb_atom_blocks = physical_pb.atom_blocks(lut_pb_id);
|
||||
|
||||
if (pb_atom_blocks.end() != std::find(pb_atom_blocks.begin(), pb_atom_blocks.end(), atom_ctx.nlist.net_driver_block(output_net))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Bypass the net is NOT routed through the LUT */
|
||||
if (false == is_wired_lut(input_nets, output_net)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
|
|
|
@ -10,8 +10,10 @@
|
|||
#include <vector>
|
||||
#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,13 @@ 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 AtomContext& atom_ctx,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const bool& verbose);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -20,3 +20,6 @@ run-task fpga_bitstream/generate_bitstream/device_96x96 --debug --show_thread_lo
|
|||
|
||||
echo -e "Testing loading architecture bitstream from an external file";
|
||||
run-task fpga_bitstream/load_external_architecture_bitstream --debug --show_thread_logs
|
||||
|
||||
echo -e "Testing repacker capability in identifying wire LUTs";
|
||||
run-task fpga_bitstream/repack_wire_lut --debug --show_thread_logs
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||
# Configuration file for running experiments
|
||||
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||
# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs
|
||||
# Each job execute fpga_flow script on combination of architecture & benchmark
|
||||
# timeout_each_job is timeout for each job
|
||||
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||
|
||||
[GENERAL]
|
||||
run_engine=openfpga_shell
|
||||
power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml
|
||||
power_analysis = true
|
||||
spice_output=false
|
||||
verilog_output=true
|
||||
# Runtime of this bitstream generation should not exceed 6 minutes as a QoR requirement
|
||||
timeout_each_job = 1*60
|
||||
fpga_flow=vpr_blif
|
||||
|
||||
[OpenFPGA_SHELL]
|
||||
openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/generate_bitstream_fix_device_example_script.openfpga
|
||||
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k6_frac_N10_adder_register_scan_chain_depop50_40nm_openfpga.xml
|
||||
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
|
||||
openfpga_vpr_route_chan_width=200
|
||||
openfpga_vpr_device_layout=auto
|
||||
|
||||
[ARCHITECTURES]
|
||||
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k6_frac_N10_tileable_adder_register_scan_chain_depop50_40nm.xml
|
||||
|
||||
[BENCHMARKS]
|
||||
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/FIR_filter/FIR_filter_firBlock_left_debug.blif
|
||||
|
||||
[SYNTHESIS_PARAM]
|
||||
bench0_top=FIR_filter_firBlock_left
|
||||
bench0_act=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/FIR_filter/FIR_filter_firBlock_left_ace_out_debug.act
|
||||
bench0_verilog=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/FIR_filter/FIR_filter_firBlock_left_output_verilog_debug.v
|
||||
|
||||
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
|
Loading…
Reference in New Issue