add truth table build up for physical LUTs
This commit is contained in:
parent
2dd80e4830
commit
4024ed63cb
|
@ -5,7 +5,7 @@
|
|||
#include "vtr_time.h"
|
||||
#include "vtr_log.h"
|
||||
|
||||
#include "verilog_api.h"
|
||||
#include "build_physical_truth_table.h"
|
||||
#include "repack.h"
|
||||
#include "openfpga_repack.h"
|
||||
|
||||
|
@ -29,6 +29,12 @@ void repack(OpenfpgaContext& openfpga_ctx,
|
|||
openfpga_ctx.mutable_vpr_device_annotation(),
|
||||
openfpga_ctx.mutable_vpr_clustering_annotation(),
|
||||
cmd_context.option_enable(cmd, opt_verbose));
|
||||
|
||||
build_physical_lut_truth_tables(openfpga_ctx.mutable_vpr_clustering_annotation(),
|
||||
g_vpr_ctx.atom(),
|
||||
g_vpr_ctx.clustering(),
|
||||
openfpga_ctx.vpr_device_annotation(),
|
||||
openfpga_ctx.arch().circuit_lib);
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
|
|
@ -0,0 +1,170 @@
|
|||
/***************************************************************************************
|
||||
* This file includes functions that are used to build truth tables of
|
||||
* the physical implementation of LUTs
|
||||
***************************************************************************************/
|
||||
|
||||
/* Headers from vtrutil library */
|
||||
#include "vtr_log.h"
|
||||
#include "vtr_assert.h"
|
||||
#include "vtr_time.h"
|
||||
|
||||
#include "openfpga_naming.h"
|
||||
|
||||
#include "lut_utils.h"
|
||||
#include "physical_pb.h"
|
||||
#include "build_physical_truth_table.h"
|
||||
|
||||
/* 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
|
||||
***************************************************************************************/
|
||||
static
|
||||
std::vector<int> generate_lut_rotated_input_pin_map(const std::vector<AtomNetId>& input_nets,
|
||||
const AtomContext& atom_ctx,
|
||||
const AtomBlockId& atom_blk,
|
||||
const t_pb_graph_node* pb_graph_node) {
|
||||
/* Find the pin rotation status and record it ,
|
||||
* Note that some LUT inputs may not be used, we set them to be open by default
|
||||
*/
|
||||
std::vector<int> rotated_pin_map(input_nets.size(), -1);
|
||||
|
||||
VTR_ASSERT(1 == pb_graph_node->num_input_ports);
|
||||
for (int ipin = 0; ipin < pb_graph_node->num_input_pins[0]; ++ipin) {
|
||||
/* Port exists (some LUTs may have no input and hence no port in the atom netlist) */
|
||||
AtomPortId atom_port = atom_ctx.nlist.find_atom_port(atom_blk, pb_graph_node->input_pins[0][ipin].port->model_port);
|
||||
if (!atom_port) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (AtomPinId atom_pin : atom_ctx.nlist.port_pins(atom_port)) {
|
||||
AtomNetId atom_pin_net = atom_ctx.nlist.pin_net(atom_pin);
|
||||
if (atom_pin_net == input_nets[ipin]) {
|
||||
rotated_pin_map[ipin] = atom_ctx.nlist.pin_port_bit(atom_pin);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return rotated_pin_map;
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
* This function will iterate over all the inputs and outputs of the LUT pb
|
||||
* and find truth tables that are mapped to each output pins
|
||||
* Note that a physical LUT may have multiple truth tables to be considered
|
||||
* as they may be fracturable
|
||||
***************************************************************************************/
|
||||
static
|
||||
void build_physical_pb_lut_truth_tables(PhysicalPb& physical_pb,
|
||||
const PhysicalPbId& lut_pb_id,
|
||||
const AtomContext& atom_ctx,
|
||||
const VprDeviceAnnotation& device_annotation,
|
||||
const CircuitLibrary& circuit_lib) {
|
||||
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;
|
||||
VTR_ASSERT(1 == pb_graph_node->num_input_ports);
|
||||
for (int ipin = 0; ipin < pb_graph_node->num_input_pins[0]; ++ipin) {
|
||||
input_nets.push_back(physical_pb.pb_graph_pin_atom_net(lut_pb_id, &(pb_graph_node->input_pins[0][ipin])));
|
||||
}
|
||||
|
||||
|
||||
/* Find all the nets mapped to each outputs */
|
||||
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) {
|
||||
const t_pb_graph_pin* output_pin = &(pb_graph_node->output_pins[iport][ipin]);
|
||||
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 (true == is_wired_lut(input_nets, output_net)) {
|
||||
AtomNetlist::TruthTable wire_tt = build_wired_lut_truth_table(input_nets.size(), std::find(input_nets.begin(), input_nets.end(), output_net) - input_nets.begin());
|
||||
physical_pb.set_truth_table(lut_pb_id, output_pin, wire_tt);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Find the truth table from atom block which drives the atom net */
|
||||
const AtomBlockId& atom_blk = atom_ctx.nlist.net_driver_block(output_net);
|
||||
VTR_ASSERT(true == atom_ctx.nlist.valid_block_id(atom_blk));
|
||||
const AtomNetlist::TruthTable& orig_tt = atom_ctx.nlist.block_truth_table(atom_blk);
|
||||
|
||||
std::vector<int> rotated_pin_map = generate_lut_rotated_input_pin_map(input_nets, atom_ctx, atom_blk, pb_graph_node);
|
||||
const AtomNetlist::TruthTable& adapt_tt = lut_truth_table_adaption(orig_tt, rotated_pin_map);
|
||||
|
||||
/* Adapt the truth table for fracturable lut implementation and add to physical pb */
|
||||
CircuitPortId lut_model_output_port = device_annotation.pb_circuit_port(output_pin->port);
|
||||
size_t lut_frac_level = circuit_lib.port_lut_frac_level(lut_model_output_port);
|
||||
if (size_t(-1) == lut_frac_level) {
|
||||
lut_frac_level = input_nets.size();
|
||||
}
|
||||
size_t lut_output_mask = circuit_lib.port_lut_output_mask(lut_model_output_port)[output_pin->pin_number];
|
||||
const AtomNetlist::TruthTable& frac_lut_tt = adapt_truth_table_for_frac_lut(lut_frac_level, lut_output_mask, adapt_tt);
|
||||
physical_pb.set_truth_table(lut_pb_id, output_pin, frac_lut_tt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
* This function will iterate over all the physical pb that are
|
||||
* binded to clustered blocks and build the truth tables for the
|
||||
* physical Look-Up Table (LUT) implementations.
|
||||
* Note that the truth table built here is different from the atom
|
||||
* netlists in VPR context. We consider fracturable LUT features
|
||||
* and LUTs operating as wires
|
||||
***************************************************************************************/
|
||||
void build_physical_lut_truth_tables(VprClusteringAnnotation& cluster_annotation,
|
||||
const AtomContext& atom_ctx,
|
||||
const ClusteringContext& cluster_ctx,
|
||||
const VprDeviceAnnotation& device_annotation,
|
||||
const CircuitLibrary& circuit_lib) {
|
||||
vtr::ScopedStartFinishTimer timer("Build truth tables for physical LUTs");
|
||||
|
||||
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 truth tables that mapped to the LUT */
|
||||
build_physical_pb_lut_truth_tables(physical_pb, primitive_pb, atom_ctx, device_annotation, circuit_lib);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef BUILD_PHYSICAL_TRUTH_TABLE_H
|
||||
#define BUILD_PHYSICAL_TRUTH_TABLE_H
|
||||
|
||||
/********************************************************************
|
||||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
#include "vpr_context.h"
|
||||
#include "vpr_device_annotation.h"
|
||||
#include "vpr_clustering_annotation.h"
|
||||
#include "circuit_library.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
*******************************************************************/
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
void build_physical_lut_truth_tables(VprClusteringAnnotation& cluster_annotation,
|
||||
const AtomContext& atom_ctx,
|
||||
const ClusteringContext& cluster_ctx,
|
||||
const VprDeviceAnnotation& device_annotation,
|
||||
const CircuitLibrary& circuit_lib);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
#endif
|
|
@ -32,6 +32,11 @@ std::string PhysicalPb::name(const PhysicalPbId& pb) const {
|
|||
return names_[pb];
|
||||
}
|
||||
|
||||
const t_pb_graph_node* PhysicalPb::pb_graph_node(const PhysicalPbId& pb) const {
|
||||
VTR_ASSERT(true == valid_pb_id(pb));
|
||||
return pb_graph_nodes_[pb];
|
||||
}
|
||||
|
||||
/* Find the module id by a given name, return invalid if not found */
|
||||
PhysicalPbId PhysicalPb::find_pb(const t_pb_graph_node* pb_graph_node) const {
|
||||
if (type2id_map_.find(pb_graph_node) != type2id_map_.end()) {
|
||||
|
@ -76,7 +81,7 @@ AtomNetId PhysicalPb::pb_graph_pin_atom_net(const PhysicalPbId& pb,
|
|||
return AtomNetId::INVALID();
|
||||
}
|
||||
|
||||
AtomNetlist::TruthTable PhysicalPb::truth_table(const PhysicalPbId& pb) const {
|
||||
std::map<const t_pb_graph_pin*, AtomNetlist::TruthTable> PhysicalPb::truth_tables(const PhysicalPbId& pb) const {
|
||||
VTR_ASSERT(true == valid_pb_id(pb));
|
||||
return truth_tables_[pb];
|
||||
}
|
||||
|
@ -109,6 +114,7 @@ PhysicalPbId PhysicalPb::create_pb(const t_pb_graph_node* pb_graph_node) {
|
|||
child_pbs_.emplace_back();
|
||||
parent_pbs_.emplace_back();
|
||||
|
||||
truth_tables_.emplace_back();
|
||||
mode_bits_.emplace_back();
|
||||
|
||||
/* Register in the name2id map */
|
||||
|
@ -136,10 +142,16 @@ void PhysicalPb::add_child(const PhysicalPbId& parent,
|
|||
}
|
||||
|
||||
void PhysicalPb::set_truth_table(const PhysicalPbId& pb,
|
||||
const t_pb_graph_pin* pb_graph_pin,
|
||||
const AtomNetlist::TruthTable& truth_table) {
|
||||
VTR_ASSERT(true == valid_pb_id(pb));
|
||||
|
||||
if (0 < truth_tables_[pb].count(pb_graph_pin)) {
|
||||
VTR_LOG_WARN("Overwrite truth tables mapped to pb_graph_pin '%s[%ld]!\n",
|
||||
pb_graph_pin->port->name, pb_graph_pin->pin_number);
|
||||
}
|
||||
|
||||
truth_tables_[pb] = truth_table;
|
||||
truth_tables_[pb][pb_graph_pin] = truth_table;
|
||||
}
|
||||
|
||||
void PhysicalPb::set_mode_bits(const PhysicalPbId& pb,
|
||||
|
|
|
@ -41,6 +41,7 @@ class PhysicalPb {
|
|||
physical_pb_range pbs() const;
|
||||
std::vector<PhysicalPbId> primitive_pbs() const;
|
||||
std::string name(const PhysicalPbId& pb) const;
|
||||
const t_pb_graph_node* pb_graph_node(const PhysicalPbId& pb) const;
|
||||
PhysicalPbId find_pb(const t_pb_graph_node* name) const;
|
||||
PhysicalPbId parent(const PhysicalPbId& pb) const;
|
||||
PhysicalPbId child(const PhysicalPbId& pb,
|
||||
|
@ -49,7 +50,7 @@ class PhysicalPb {
|
|||
std::vector<AtomBlockId> atom_blocks(const PhysicalPbId& pb) const;
|
||||
AtomNetId pb_graph_pin_atom_net(const PhysicalPbId& pb,
|
||||
const t_pb_graph_pin* pb_graph_pin) const;
|
||||
AtomNetlist::TruthTable truth_table(const PhysicalPbId& pb) const;
|
||||
std::map<const t_pb_graph_pin*, AtomNetlist::TruthTable> truth_tables(const PhysicalPbId& pb) const;
|
||||
std::vector<size_t> mode_bits(const PhysicalPbId& pb) const;
|
||||
public: /* Public mutators */
|
||||
PhysicalPbId create_pb(const t_pb_graph_node* pb_graph_node);
|
||||
|
@ -59,6 +60,7 @@ class PhysicalPb {
|
|||
void add_atom_block(const PhysicalPbId& pb,
|
||||
const AtomBlockId& atom_block);
|
||||
void set_truth_table(const PhysicalPbId& pb,
|
||||
const t_pb_graph_pin* pb_graph_pin,
|
||||
const AtomNetlist::TruthTable& truth_table);
|
||||
void set_mode_bits(const PhysicalPbId& pb,
|
||||
const std::vector<size_t>& mode_bits);
|
||||
|
@ -82,7 +84,7 @@ class PhysicalPb {
|
|||
/* configuration bits
|
||||
* Truth tables and mode selection
|
||||
*/
|
||||
vtr::vector<PhysicalPbId, AtomNetlist::TruthTable> truth_tables_;
|
||||
vtr::vector<PhysicalPbId, std::map<const t_pb_graph_pin*, AtomNetlist::TruthTable>> truth_tables_;
|
||||
|
||||
vtr::vector<PhysicalPbId, std::vector<size_t>> mode_bits_;
|
||||
|
||||
|
|
|
@ -131,8 +131,8 @@ std::vector<std::string> truth_table_to_string(const AtomNetlist::TruthTable& tt
|
|||
* --1- 1
|
||||
*
|
||||
********************************************************************/
|
||||
AtomNetlist::TruthTable build_post_routing_wired_lut_truth_table(const size_t& lut_size,
|
||||
const size_t& wire_input_id) {
|
||||
AtomNetlist::TruthTable build_wired_lut_truth_table(const size_t& lut_size,
|
||||
const size_t& wire_input_id) {
|
||||
AtomNetlist::TruthTable tt;
|
||||
|
||||
/* There is always only one line in this truth table */
|
||||
|
|
|
@ -24,8 +24,8 @@ AtomNetlist::TruthTable lut_truth_table_adaption(const AtomNetlist::TruthTable&
|
|||
|
||||
std::vector<std::string> truth_table_to_string(const AtomNetlist::TruthTable& tt);
|
||||
|
||||
AtomNetlist::TruthTable build_post_routing_wired_lut_truth_table(const size_t& lut_size,
|
||||
const size_t& wire_input_id);
|
||||
AtomNetlist::TruthTable build_wired_lut_truth_table(const size_t& lut_size,
|
||||
const size_t& wire_input_id);
|
||||
|
||||
AtomNetlist::TruthTable adapt_truth_table_for_frac_lut(const size_t& lut_frac_level,
|
||||
const size_t& lut_output_mask,
|
||||
|
|
Loading…
Reference in New Issue