add functionality of LUT truth table fix-up
This commit is contained in:
parent
99f5a86b49
commit
ed9e038845
|
@ -31,6 +31,16 @@ ClusterNetId VprClusteringAnnotation::net(const ClusterBlockId& block_id, const
|
|||
return net_names_.at(block_id).at(pin_index);
|
||||
}
|
||||
|
||||
bool VprClusteringAnnotation::is_truth_table_adapted(t_pb* pb) const {
|
||||
/* Ensure that the block_id is in the list */
|
||||
return (block_truth_tables_.end() != block_truth_tables_.find(pb));
|
||||
}
|
||||
|
||||
AtomNetlist::TruthTable VprClusteringAnnotation::truth_table(t_pb* pb) const {
|
||||
VTR_ASSERT(true == is_truth_table_adapted(pb));
|
||||
return block_truth_tables_.at(pb);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Public mutators
|
||||
***********************************************************************/
|
||||
|
@ -46,4 +56,15 @@ void VprClusteringAnnotation::rename_net(const ClusterBlockId& block_id, const i
|
|||
net_names_[block_id][pin_index] = net_id;
|
||||
}
|
||||
|
||||
void VprClusteringAnnotation::adapt_truth_table(t_pb* pb,
|
||||
const AtomNetlist::TruthTable& tt) {
|
||||
/* Warn any override attempt */
|
||||
if (block_truth_tables_.end() != block_truth_tables_.find(pb)) {
|
||||
VTR_LOG_WARN("Override the truth table for pb '%s' in clustering context annotation!\n",
|
||||
pb->name);
|
||||
}
|
||||
|
||||
block_truth_tables_[pb] = tt;
|
||||
}
|
||||
|
||||
} /* End namespace openfpga*/
|
||||
|
|
|
@ -25,14 +25,22 @@ class VprClusteringAnnotation {
|
|||
public: /* Constructor */
|
||||
VprClusteringAnnotation();
|
||||
public: /* Public accessors */
|
||||
/* Xifan Tang: I created two functions for each data query in purpose!
|
||||
* As this is an annotation, some net/block may be changed to invalid id
|
||||
* In this case, return an invalid value does not mean that a net is not renamed
|
||||
*/
|
||||
bool is_net_renamed(const ClusterBlockId& block_id, const int& pin_index) const;
|
||||
ClusterNetId net(const ClusterBlockId& block_id, const int& pin_index) const;
|
||||
bool is_truth_table_adapted(t_pb* pb) const;
|
||||
AtomNetlist::TruthTable truth_table(t_pb* pb) const;
|
||||
public: /* Public mutators */
|
||||
void rename_net(const ClusterBlockId& block_id, const int& pin_index,
|
||||
const ClusterNetId& net_id);
|
||||
void adapt_truth_table(t_pb* pb, const AtomNetlist::TruthTable& tt);
|
||||
private: /* Internal data */
|
||||
/* Pair a regular pb_type to its physical pb_type */
|
||||
std::map<ClusterBlockId, std::map<int, ClusterNetId>> net_names_;
|
||||
std::map<t_pb*, AtomNetlist::TruthTable> block_truth_tables_;
|
||||
};
|
||||
|
||||
} /* End namespace openfpga*/
|
||||
|
|
|
@ -0,0 +1,185 @@
|
|||
/********************************************************************
|
||||
* This file includes functions to fix up the pb pin mapping results
|
||||
* after routing optimization
|
||||
*******************************************************************/
|
||||
/* Headers from vtrutil library */
|
||||
#include "vtr_time.h"
|
||||
#include "vtr_assert.h"
|
||||
#include "vtr_log.h"
|
||||
|
||||
/* Headers from vpr library */
|
||||
#include "vpr_utils.h"
|
||||
|
||||
#include "pb_type_utils.h"
|
||||
#include "lut_utils.h"
|
||||
#include "openfpga_lut_truth_table_fixup.h"
|
||||
|
||||
/* Include global variables of VPR */
|
||||
#include "globals.h"
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
/********************************************************************
|
||||
* Apply the fix-up to truth table of LUT according to its pin
|
||||
* rotation status by packer
|
||||
*
|
||||
* Note:
|
||||
* - pb must represents a LUT pb in the graph and it should be primitive
|
||||
*******************************************************************/
|
||||
static
|
||||
void fix_up_lut_atom_block_truth_table(const AtomContext& atom_ctx,
|
||||
t_pb* pb,
|
||||
const t_pb_routes& pb_route,
|
||||
VprClusteringAnnotation& vpr_clustering_annotation,
|
||||
const bool& verbose) {
|
||||
t_pb_graph_node* pb_graph_node = pb->pb_graph_node;
|
||||
t_pb_type* pb_type = pb->pb_graph_node->pb_type;
|
||||
|
||||
VTR_ASSERT(LUT_CLASS == pb_type->class_type);
|
||||
|
||||
for (int iport = 0; iport < pb_type->num_ports; ++iport) {
|
||||
/* We only care about input ports whose pins are equivalent */
|
||||
if (IN_PORT != pb_type->ports[iport].type || true == pb_type->ports[iport].is_clock) {
|
||||
continue;
|
||||
}
|
||||
if (pb_type->ports[iport].equivalent == PortEquivalence::NONE) {
|
||||
continue;
|
||||
}
|
||||
/* Reach here, we have to apply a fix-up */
|
||||
AtomBlockId atom_blk = atom_ctx.nlist.find_block(pb->name);
|
||||
VTR_ASSERT(atom_blk);
|
||||
|
||||
/* 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_type->ports[iport].model_port);
|
||||
if (atom_port) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 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(pb_type->ports[iport].num_pins, -1);
|
||||
for (int ipin = 0; ipin < pb_type->ports[iport].num_pins; ++ipin) {
|
||||
int node_index = pb_graph_node->input_pins[iport][ipin].pin_count_in_cluster;
|
||||
if (pb_route.count(node_index)) {
|
||||
/* The pin is mapped to a net, find the original pin in the atom netlist */
|
||||
AtomNetId atom_net = pb_route[node_index].atom_net_id;
|
||||
|
||||
VTR_ASSERT(atom_net);
|
||||
|
||||
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 == atom_net) {
|
||||
rotated_pin_map[ipin] = atom_ctx.nlist.pin_port_bit(atom_pin);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* We can apply truth table adaption now
|
||||
* For unused inputs : insert dont care
|
||||
* For used inputs : find the bit in the truth table rows and move it by the given mapping
|
||||
*/
|
||||
const AtomNetlist::TruthTable& orig_tt = atom_ctx.nlist.block_truth_table(atom_blk);
|
||||
const AtomNetlist::TruthTable& adapt_tt = lut_truth_table_adaption(orig_tt, rotated_pin_map);
|
||||
vpr_clustering_annotation.adapt_truth_table(pb, adapt_tt);
|
||||
|
||||
/* Print info is in the verbose mode */
|
||||
VTR_LOGV(verbose, "Original truth table\n");
|
||||
for (const std::string& tt_line : truth_table_to_string(orig_tt)) {
|
||||
VTR_LOGV(verbose, "\t%s\n", tt_line.c_str());
|
||||
}
|
||||
VTR_LOGV(verbose, "\n");
|
||||
VTR_LOGV(verbose, "Adapt truth table\n");
|
||||
VTR_LOGV(verbose, "-----------------\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, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* This function recursively visits the pb graph until we reach a
|
||||
* LUT pb_type (primitive node in the pb_graph with a class type
|
||||
* of LUT_CLASS
|
||||
* Once we find a LUT node, we will apply the fix-up
|
||||
*******************************************************************/
|
||||
static
|
||||
void rec_adapt_lut_pb_tt(const AtomContext& atom_ctx,
|
||||
t_pb* pb,
|
||||
const t_pb_routes& pb_route,
|
||||
VprClusteringAnnotation& vpr_clustering_annotation,
|
||||
const bool& verbose) {
|
||||
t_pb_graph_node* pb_graph_node = pb->pb_graph_node;
|
||||
|
||||
/* If we reach a primitive pb_graph node, we return */
|
||||
if (true == is_primitive_pb_type(pb_graph_node->pb_type)) {
|
||||
if (LUT_CLASS == pb_graph_node->pb_type->class_type) {
|
||||
/* Do fix-up here */
|
||||
fix_up_lut_atom_block_truth_table(atom_ctx, pb, pb_route, vpr_clustering_annotation, verbose);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Recursively visit all the used pbs in the graph */
|
||||
t_mode* mapped_mode = &(pb_graph_node->pb_type->modes[pb->mode]);
|
||||
for (int ipb = 0; ipb < mapped_mode->num_pb_type_children; ++ipb) {
|
||||
/* Each child may exist multiple times in the hierarchy*/
|
||||
for (int jpb = 0; jpb < mapped_mode->pb_type_children[ipb].num_pb; ++jpb) {
|
||||
/* See if we still have any pb children to walk through */
|
||||
if ((pb->child_pbs[ipb] != nullptr) && (pb->child_pbs[ipb][jpb].name != nullptr)) {
|
||||
rec_adapt_lut_pb_tt(atom_ctx, &(pb->child_pbs[ipb][jpb]), pb_route, vpr_clustering_annotation, verbose);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Main function to fix up truth table for each LUT used in FPGA
|
||||
* This function will walk through each clustered block
|
||||
*******************************************************************/
|
||||
static
|
||||
void update_lut_tt_with_post_packing_results(const AtomContext& atom_ctx,
|
||||
const ClusteringContext& clustering_ctx,
|
||||
VprClusteringAnnotation& vpr_clustering_annotation,
|
||||
const bool& verbose) {
|
||||
for (auto blk_id : clustering_ctx.clb_nlist.blocks()) {
|
||||
rec_adapt_lut_pb_tt(atom_ctx,
|
||||
clustering_ctx.clb_nlist.block_pb(blk_id),
|
||||
clustering_ctx.clb_nlist.block_pb(blk_id)->pb_route,
|
||||
vpr_clustering_annotation, verbose);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Top-level function to fix up the lut truth table results after packing is done
|
||||
* The problem comes from a mismatch between the packing results and
|
||||
* original truth tables in users' BLIF file
|
||||
* As LUT inputs are equivalent in nature, the router of packer will try
|
||||
* to swap the net mapping among these pins so as to achieve best
|
||||
* routing optimization.
|
||||
* However, it will cause the original truth table out-of-date when packing is done.
|
||||
* This function aims to fix the mess after packing so that the truth table
|
||||
* can be synchronized
|
||||
*******************************************************************/
|
||||
void lut_truth_table_fixup(OpenfpgaContext& openfpga_context,
|
||||
const Command& cmd, const CommandContext& cmd_context) {
|
||||
|
||||
vtr::ScopedStartFinishTimer timer("Fix up LUT truth tables after packing optimization");
|
||||
|
||||
CommandOptionId opt_verbose = cmd.option("verbose");
|
||||
|
||||
/* Apply fix-up to each packed block */
|
||||
update_lut_tt_with_post_packing_results(g_vpr_ctx.atom(),
|
||||
g_vpr_ctx.clustering(),
|
||||
openfpga_context.mutable_vpr_clustering_annotation(),
|
||||
cmd_context.option_enable(cmd, opt_verbose));
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef OPENFPGA_LUT_TRUTH_TABLE_FIXUP_H
|
||||
#define OPENFPGA_LUT_TRUTH_TABLE_FIXUP_H
|
||||
|
||||
/********************************************************************
|
||||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
#include "command.h"
|
||||
#include "command_context.h"
|
||||
#include "openfpga_context.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
*******************************************************************/
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
void lut_truth_table_fixup(OpenfpgaContext& openfpga_context,
|
||||
const Command& cmd, const CommandContext& cmd_context);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
#endif
|
|
@ -6,6 +6,7 @@
|
|||
#include "openfpga_read_arch.h"
|
||||
#include "openfpga_link_arch.h"
|
||||
#include "openfpga_pb_pin_fixup.h"
|
||||
#include "openfpga_lut_truth_table_fixup.h"
|
||||
#include "check_netlist_naming_conflict.h"
|
||||
#include "openfpga_setup_command.h"
|
||||
|
||||
|
@ -100,6 +101,23 @@ void add_openfpga_setup_commands(openfpga::Shell<OpenfpgaContext>& shell) {
|
|||
cmd_dependency_pb_pin_fixup.push_back(shell_cmd_read_arch_id);
|
||||
cmd_dependency_pb_pin_fixup.push_back(shell_cmd_vpr_id);
|
||||
shell.set_command_dependency(shell_cmd_pb_pin_fixup_id, cmd_dependency_pb_pin_fixup);
|
||||
|
||||
/********************************
|
||||
* Command 'lut_truth_table_fixup'
|
||||
*/
|
||||
Command shell_cmd_lut_truth_table_fixup("lut_truth_table_fixup");
|
||||
/* Add an option '--verbose' */
|
||||
shell_cmd_lut_truth_table_fixup.add_option("verbose", false, "Show verbose outputs");
|
||||
|
||||
/* Add command 'lut_truth_table_fixup' to the Shell */
|
||||
ShellCommandId shell_cmd_lut_truth_table_fixup_id = shell.add_command(shell_cmd_lut_truth_table_fixup, "Fix up the truth table of Look-Up Tables due to pin swapping during packing stage");
|
||||
shell.set_command_class(shell_cmd_lut_truth_table_fixup_id, openfpga_setup_cmd_class);
|
||||
shell.set_command_execute_function(shell_cmd_lut_truth_table_fixup_id, lut_truth_table_fixup);
|
||||
/* The 'pb_pin_fixup' command should NOT be executed before 'read_openfpga_arch' and 'vpr' */
|
||||
std::vector<ShellCommandId> cmd_dependency_lut_truth_table_fixup;
|
||||
cmd_dependency_lut_truth_table_fixup.push_back(shell_cmd_read_arch_id);
|
||||
cmd_dependency_lut_truth_table_fixup.push_back(shell_cmd_vpr_id);
|
||||
shell.set_command_dependency(shell_cmd_lut_truth_table_fixup_id, cmd_dependency_lut_truth_table_fixup);
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
/********************************************************************
|
||||
* This file includes most utilized functions to manipulate LUTs,
|
||||
* especially their truth tables, in the OpenFPGA context
|
||||
*******************************************************************/
|
||||
/* Headers from vtrutil library */
|
||||
#include "vtr_assert.h"
|
||||
#include "vtr_log.h"
|
||||
|
||||
#include "lut_utils.h"
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
/********************************************************************
|
||||
* This function aims to adapt the truth table to a mapped physical LUT
|
||||
* subject to a pin rotation map
|
||||
* The modification is applied to line by line
|
||||
* - For unused inputs : insert dont care
|
||||
* - For used inputs : find the bit in the truth table rows and move it by the given mapping
|
||||
*
|
||||
* The rotated pin map is the reference to adapt the truth table.
|
||||
* Each element of the map represents the input index in the original truth table
|
||||
* The sequence of the rotate pin map is the final sequence of how
|
||||
* each line of the original truth table should be shuffled
|
||||
* Example:
|
||||
* output_value(we do not modify)
|
||||
* |
|
||||
* v
|
||||
* Truth table line: 00111
|
||||
* rotated_pin_map: 2310
|
||||
* Adapt truth table line: 11001
|
||||
*******************************************************************/
|
||||
AtomNetlist::TruthTable lut_truth_table_adaption(const AtomNetlist::TruthTable& orig_tt,
|
||||
const std::vector<int>& rotated_pin_map) {
|
||||
AtomNetlist::TruthTable tt;
|
||||
|
||||
for (auto row : orig_tt) {
|
||||
VTR_ASSERT(row.size() - 1 == rotated_pin_map.size());
|
||||
|
||||
std::vector<vtr::LogicValue> tt_line;
|
||||
/* We do not care about the last digit, which is the output value */
|
||||
for (size_t i = 0; i < row.size() - 1; ++i) {
|
||||
if (-1 == rotated_pin_map[i]) {
|
||||
tt_line.push_back(vtr::LogicValue::DONT_CARE);
|
||||
} else {
|
||||
/* Ensure we never access the last digit, i.e., the output value! */
|
||||
VTR_ASSERT((size_t)rotated_pin_map[i] < row.size() - 1);
|
||||
tt_line.push_back(row[rotated_pin_map[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Do not miss the last digit in the final result */
|
||||
tt_line.push_back(row.back());
|
||||
tt.push_back(tt_line);
|
||||
}
|
||||
|
||||
return tt;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Convert a truth table to strings, which are ready to be printed out
|
||||
*******************************************************************/
|
||||
std::vector<std::string> truth_table_to_string(const AtomNetlist::TruthTable& tt) {
|
||||
std::vector<std::string> tt_str;
|
||||
for (auto row : tt) {
|
||||
std::string row_str;
|
||||
for (size_t i = 0; i < row.size(); ++i) {
|
||||
/* Add a gap between inputs and outputs */
|
||||
if (i == row.size() - 1) {
|
||||
row_str += std::string(" ");
|
||||
}
|
||||
switch (row[i]) {
|
||||
case vtr::LogicValue::TRUE:
|
||||
row_str += std::string("1");
|
||||
break;
|
||||
case vtr::LogicValue::FALSE:
|
||||
row_str += std::string("0");
|
||||
break;
|
||||
case vtr::LogicValue::DONT_CARE:
|
||||
row_str += std::string("-");
|
||||
break;
|
||||
default:
|
||||
VTR_ASSERT_MSG(false, "Valid single-output cover logic value");
|
||||
}
|
||||
}
|
||||
tt_str.push_back(row_str);
|
||||
}
|
||||
|
||||
return tt_str;
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef LUT_UTILS_H
|
||||
#define LUT_UTILS_H
|
||||
|
||||
/********************************************************************
|
||||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "atom_netlist.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
*******************************************************************/
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
AtomNetlist::TruthTable lut_truth_table_adaption(const AtomNetlist::TruthTable& orig_tt,
|
||||
const std::vector<int>& rotated_pin_map);
|
||||
|
||||
std::vector<std::string> truth_table_to_string(const AtomNetlist::TruthTable& tt);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
#endif
|
|
@ -13,5 +13,8 @@ check_netlist_naming_conflict --fix --report ./netlist_renaming.xml
|
|||
# Apply fix-up to clustering nets based on routing results
|
||||
pb_pin_fixup --verbose
|
||||
|
||||
# Apply fix-up to Look-Up Table truth tables based on packing results
|
||||
lut_truth_table_fixup --verbose
|
||||
|
||||
# Finish and exit OpenFPGA
|
||||
exit
|
||||
|
|
Loading…
Reference in New Issue