Merge pull request #700 from antmicro/vpr-merged-netlist-writer
VPR: add second netlist writer for merged multi-bits ports
This commit is contained in:
commit
26fce2511c
|
@ -524,10 +524,14 @@ static void SetupAnalysisOpts(const t_options& Options, t_analysis_opts& analysi
|
|||
}
|
||||
|
||||
analysis_opts.gen_post_synthesis_netlist = Options.Generate_Post_Synthesis_Netlist;
|
||||
analysis_opts.gen_post_implementation_merged_netlist = Options.Generate_Post_Implementation_Merged_Netlist;
|
||||
|
||||
analysis_opts.timing_report_npaths = Options.timing_report_npaths;
|
||||
analysis_opts.timing_report_detail = Options.timing_report_detail;
|
||||
analysis_opts.timing_report_skew = Options.timing_report_skew;
|
||||
|
||||
analysis_opts.post_synth_netlist_unconn_input_handling = Options.post_synth_netlist_unconn_input_handling;
|
||||
analysis_opts.post_synth_netlist_unconn_output_handling = Options.post_synth_netlist_unconn_output_handling;
|
||||
}
|
||||
|
||||
static void SetupPowerOpts(const t_options& Options, t_power_opts* power_opts, t_arch* Arch) {
|
||||
|
|
|
@ -384,6 +384,31 @@ static void ShowNetlistOpts(const t_netlist_opts& NetlistOpts) {
|
|||
|
||||
static void ShowAnalysisOpts(const t_analysis_opts& AnalysisOpts) {
|
||||
VTR_LOG("AnalysisOpts.gen_post_synthesis_netlist: %s\n", (AnalysisOpts.gen_post_synthesis_netlist) ? "true" : "false");
|
||||
|
||||
const auto opts = {
|
||||
std::make_tuple(&AnalysisOpts.post_synth_netlist_unconn_input_handling, "post_synth_netlist_unconn_input_handling"),
|
||||
std::make_tuple(&AnalysisOpts.post_synth_netlist_unconn_output_handling, "post_synth_netlist_unconn_output_handling"),
|
||||
};
|
||||
for (const auto& opt : opts) {
|
||||
auto value = *std::get<0>(opt);
|
||||
VTR_LOG("AnalysisOpts.%s: ", std::get<1>(opt));
|
||||
switch (value) {
|
||||
case e_post_synth_netlist_unconn_handling::UNCONNECTED:
|
||||
VTR_LOG("UNCONNECTED\n");
|
||||
break;
|
||||
case e_post_synth_netlist_unconn_handling::NETS:
|
||||
VTR_LOG("NETS\n");
|
||||
break;
|
||||
case e_post_synth_netlist_unconn_handling::GND:
|
||||
VTR_LOG("GND\n");
|
||||
break;
|
||||
case e_post_synth_netlist_unconn_handling::VCC:
|
||||
VTR_LOG("VCC\n");
|
||||
break;
|
||||
default:
|
||||
VPR_FATAL_ERROR(VPR_ERROR_UNKNOWN, "Unknown post_synth_netlist_unconn_handling\n");
|
||||
}
|
||||
}
|
||||
VTR_LOG("\n");
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <memory>
|
||||
#include <unordered_set>
|
||||
#include <cmath>
|
||||
#include <regex>
|
||||
|
||||
#include "vtr_assert.h"
|
||||
#include "vtr_util.h"
|
||||
|
@ -111,7 +112,7 @@ std::string indent(size_t depth);
|
|||
double get_delay_ps(double delay_sec);
|
||||
|
||||
void print_blif_port(std::ostream& os, size_t& unconn_count, const std::string& port_name, const std::vector<std::string>& nets, int depth);
|
||||
void print_verilog_port(std::ostream& os, size_t& unconn_count, const std::string& port_name, const std::vector<std::string>& nets, PortType type, int depth);
|
||||
void print_verilog_port(std::ostream& os, size_t& unconn_count, const std::string& port_name, const std::vector<std::string>& nets, PortType type, int depth, struct t_analysis_opts& opts);
|
||||
|
||||
std::string create_unconn_net(size_t& unconn_count);
|
||||
std::string escape_verilog_identifier(const std::string id);
|
||||
|
@ -125,6 +126,9 @@ std::string join_identifier(std::string lhs, std::string rhs);
|
|||
//
|
||||
//
|
||||
|
||||
// Unconnected net prefix
|
||||
const std::string unconn_prefix = "__vpr__unconn";
|
||||
|
||||
//A combinational timing arc
|
||||
class Arc {
|
||||
public:
|
||||
|
@ -201,13 +205,15 @@ class LutInst : public Instance {
|
|||
LogicVec lut_mask, ///<The LUT mask representing the logic function
|
||||
std::string inst_name, ///<The name of this instance
|
||||
std::map<std::string, std::vector<std::string>> port_conns, ///<The port connections of this instance. Key: port name, Value: connected nets
|
||||
std::vector<Arc> timing_arc_values) ///<The timing arcs of this instance
|
||||
std::vector<Arc> timing_arc_values, ///<The timing arcs of this instance
|
||||
struct t_analysis_opts opts)
|
||||
: type_("LUT_K")
|
||||
, lut_size_(lut_size)
|
||||
, lut_mask_(lut_mask)
|
||||
, inst_name_(inst_name)
|
||||
, port_conns_(port_conns)
|
||||
, timing_arcs_(timing_arc_values) {
|
||||
, timing_arcs_(timing_arc_values)
|
||||
, opts_(opts) {
|
||||
}
|
||||
|
||||
//Accessors
|
||||
|
@ -232,10 +238,10 @@ class LutInst : public Instance {
|
|||
VTR_ASSERT(port_conns_.count("out"));
|
||||
VTR_ASSERT(port_conns_.size() == 2);
|
||||
|
||||
print_verilog_port(os, unconn_count, "in", port_conns_["in"], PortType::INPUT, depth + 1);
|
||||
print_verilog_port(os, unconn_count, "in", port_conns_["in"], PortType::INPUT, depth + 1, opts_);
|
||||
os << ","
|
||||
<< "\n";
|
||||
print_verilog_port(os, unconn_count, "out", port_conns_["out"], PortType::OUTPUT, depth + 1);
|
||||
print_verilog_port(os, unconn_count, "out", port_conns_["out"], PortType::OUTPUT, depth + 1, opts_);
|
||||
os << "\n";
|
||||
|
||||
os << indent(depth) << ");\n\n";
|
||||
|
@ -377,6 +383,7 @@ class LutInst : public Instance {
|
|||
std::string inst_name_;
|
||||
std::map<std::string, std::vector<std::string>> port_conns_;
|
||||
std::vector<Arc> timing_arcs_;
|
||||
struct t_analysis_opts opts_;
|
||||
};
|
||||
|
||||
class LatchInst : public Instance {
|
||||
|
@ -561,7 +568,8 @@ class BlackBoxInst : public Instance {
|
|||
std::vector<Arc> timing_arcs, ///<Combinational timing arcs
|
||||
std::map<std::string, sequential_port_delay_pair> ports_tsu, ///<Port setup checks
|
||||
std::map<std::string, sequential_port_delay_pair> ports_thld, ///<Port hold checks
|
||||
std::map<std::string, sequential_port_delay_pair> ports_tcq) ///<Port clock-to-q delays
|
||||
std::map<std::string, sequential_port_delay_pair> ports_tcq, ///<Port clock-to-q delays
|
||||
struct t_analysis_opts opts)
|
||||
: type_name_(type_name)
|
||||
, inst_name_(inst_name)
|
||||
, params_(params)
|
||||
|
@ -571,7 +579,8 @@ class BlackBoxInst : public Instance {
|
|||
, timing_arcs_(timing_arcs)
|
||||
, ports_tsu_(ports_tsu)
|
||||
, ports_thld_(ports_thld)
|
||||
, ports_tcq_(ports_tcq) {}
|
||||
, ports_tcq_(ports_tcq)
|
||||
, opts_(opts) {}
|
||||
|
||||
void print_blif(std::ostream& os, size_t& unconn_count, int depth = 0) override {
|
||||
os << indent(depth) << ".subckt " << type_name_ << " \\"
|
||||
|
@ -634,7 +643,7 @@ class BlackBoxInst : public Instance {
|
|||
for (auto iter = input_port_conns_.begin(); iter != input_port_conns_.end(); ++iter) {
|
||||
auto& port_name = iter->first;
|
||||
auto& nets = iter->second;
|
||||
print_verilog_port(os, unconn_count, port_name, nets, PortType::INPUT, depth + 1);
|
||||
print_verilog_port(os, unconn_count, port_name, nets, PortType::INPUT, depth + 1, opts_);
|
||||
if (!(iter == --input_port_conns_.end() && output_port_conns_.empty())) {
|
||||
os << ",";
|
||||
}
|
||||
|
@ -645,7 +654,7 @@ class BlackBoxInst : public Instance {
|
|||
for (auto iter = output_port_conns_.begin(); iter != output_port_conns_.end(); ++iter) {
|
||||
auto& port_name = iter->first;
|
||||
auto& nets = iter->second;
|
||||
print_verilog_port(os, unconn_count, port_name, nets, PortType::OUTPUT, depth + 1);
|
||||
print_verilog_port(os, unconn_count, port_name, nets, PortType::OUTPUT, depth + 1, opts_);
|
||||
if (!(iter == --output_port_conns_.end())) {
|
||||
os << ",";
|
||||
}
|
||||
|
@ -679,12 +688,12 @@ class BlackBoxInst : public Instance {
|
|||
os << indent(depth + 3) << "(IOPATH ";
|
||||
os << escape_sdf_identifier(arc.source_name());
|
||||
if (find_port_size(arc.source_name()) > 1) {
|
||||
os << "[" << arc.source_ipin() << "]";
|
||||
os << "\\[" << arc.source_ipin() << "\\]";
|
||||
}
|
||||
os << " ";
|
||||
os << escape_sdf_identifier(arc.sink_name());
|
||||
if (find_port_size(arc.sink_name()) > 1) {
|
||||
os << "[" << arc.sink_ipin() << "]";
|
||||
os << "\\[" << arc.sink_ipin() << "\\]";
|
||||
}
|
||||
os << " ";
|
||||
os << delay_triple.str();
|
||||
|
@ -756,6 +765,7 @@ class BlackBoxInst : public Instance {
|
|||
std::map<std::string, sequential_port_delay_pair> ports_tsu_;
|
||||
std::map<std::string, sequential_port_delay_pair> ports_thld_;
|
||||
std::map<std::string, sequential_port_delay_pair> ports_tcq_;
|
||||
struct t_analysis_opts opts_;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -774,6 +784,11 @@ class Assignment {
|
|||
void print_verilog(std::ostream& os, std::string indent) {
|
||||
os << indent << "assign " << escape_verilog_identifier(lval_) << " = " << escape_verilog_identifier(rval_) << ";\n";
|
||||
}
|
||||
|
||||
void print_merged_verilog(std::ostream& os, std::string indent) {
|
||||
os << indent << "assign " << lval_ << " = " << rval_ << ";\n";
|
||||
}
|
||||
|
||||
void print_blif(std::ostream& os, std::string indent) {
|
||||
os << indent << ".names " << rval_ << " " << lval_ << "\n";
|
||||
os << indent << "1 1\n";
|
||||
|
@ -794,11 +809,13 @@ class NetlistWriterVisitor : public NetlistVisitor {
|
|||
NetlistWriterVisitor(std::ostream& verilog_os, ///<Output stream for verilog netlist
|
||||
std::ostream& blif_os, ///<Output stream for blif netlist
|
||||
std::ostream& sdf_os, ///<Output stream for SDF
|
||||
std::shared_ptr<const AnalysisDelayCalculator> delay_calc)
|
||||
std::shared_ptr<const AnalysisDelayCalculator> delay_calc,
|
||||
struct t_analysis_opts opts)
|
||||
: verilog_os_(verilog_os)
|
||||
, blif_os_(blif_os)
|
||||
, sdf_os_(sdf_os)
|
||||
, delay_calc_(delay_calc) {
|
||||
, delay_calc_(delay_calc)
|
||||
, opts_(opts) {
|
||||
auto& atom_ctx = g_vpr_ctx.atom();
|
||||
|
||||
//Initialize the pin to tnode look-up
|
||||
|
@ -867,12 +884,8 @@ class NetlistWriterVisitor : public NetlistVisitor {
|
|||
print_sdf();
|
||||
}
|
||||
|
||||
private: //Internal Helper functions
|
||||
///@brief Writes out the verilog netlist
|
||||
void print_verilog(int depth = 0) {
|
||||
verilog_os_ << indent(depth) << "//Verilog generated by VPR " << vtr::VERSION << " from post-place-and-route implementation\n";
|
||||
verilog_os_ << indent(depth) << "module " << top_module_name_ << " (\n";
|
||||
|
||||
protected:
|
||||
virtual void print_primary_io(int depth) {
|
||||
//Primary Inputs
|
||||
for (auto iter = inputs_.begin(); iter != inputs_.end(); ++iter) {
|
||||
verilog_os_ << indent(depth + 1) << "input " << escape_verilog_identifier(*iter);
|
||||
|
@ -881,7 +894,6 @@ class NetlistWriterVisitor : public NetlistVisitor {
|
|||
}
|
||||
verilog_os_ << "\n";
|
||||
}
|
||||
|
||||
//Primary Outputs
|
||||
for (auto iter = outputs_.begin(); iter != outputs_.end(); ++iter) {
|
||||
verilog_os_ << indent(depth + 1) << "output " << escape_verilog_identifier(*iter);
|
||||
|
@ -890,6 +902,22 @@ class NetlistWriterVisitor : public NetlistVisitor {
|
|||
}
|
||||
verilog_os_ << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
virtual void print_assignments(int depth) {
|
||||
verilog_os_ << "\n";
|
||||
verilog_os_ << indent(depth + 1) << "//IO assignments\n";
|
||||
for (auto& assign : assignments_) {
|
||||
assign.print_verilog(verilog_os_, indent(depth + 1));
|
||||
}
|
||||
}
|
||||
|
||||
///@brief Writes out the verilog netlist
|
||||
void print_verilog(int depth = 0) {
|
||||
verilog_os_ << indent(depth) << "//Verilog generated by VPR " << vtr::VERSION << " from post-place-and-route implementation\n";
|
||||
verilog_os_ << indent(depth) << "module " << top_module_name_ << " (\n";
|
||||
|
||||
print_primary_io(depth);
|
||||
verilog_os_ << indent(depth) << ");\n";
|
||||
|
||||
//Wire declarations
|
||||
|
@ -905,11 +933,7 @@ class NetlistWriterVisitor : public NetlistVisitor {
|
|||
}
|
||||
|
||||
//connections between primary I/Os and their internal wires
|
||||
verilog_os_ << "\n";
|
||||
verilog_os_ << indent(depth + 1) << "//IO assignments\n";
|
||||
for (auto& assign : assignments_) {
|
||||
assign.print_verilog(verilog_os_, indent(depth + 1));
|
||||
}
|
||||
print_assignments(depth);
|
||||
|
||||
//Interconnect between cell instances
|
||||
verilog_os_ << "\n";
|
||||
|
@ -937,10 +961,21 @@ class NetlistWriterVisitor : public NetlistVisitor {
|
|||
inst->print_verilog(verilog_os_, unconn_count, depth + 1);
|
||||
}
|
||||
|
||||
//Unconnected wires
|
||||
if (unconn_count) {
|
||||
verilog_os_ << "\n";
|
||||
verilog_os_ << indent(depth + 1) << "//Unconnected wires\n";
|
||||
for (size_t i = 0; i < unconn_count; ++i) {
|
||||
auto name = unconn_prefix + std::to_string(i);
|
||||
verilog_os_ << indent(depth + 1) << "wire " << escape_verilog_identifier(name) << ";\n";
|
||||
}
|
||||
}
|
||||
|
||||
verilog_os_ << "\n";
|
||||
verilog_os_ << indent(depth) << "endmodule\n";
|
||||
}
|
||||
|
||||
private: //Internal Helper functions
|
||||
///@brief Writes out the blif netlist
|
||||
void print_blif(int depth = 0) {
|
||||
blif_os_ << indent(depth) << "#BLIF generated by VPR " << vtr::VERSION << " from post-place-and-route implementation\n";
|
||||
|
@ -1045,47 +1080,6 @@ class NetlistWriterVisitor : public NetlistVisitor {
|
|||
sdf_os_ << indent(depth) << ")\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the name of a wire connecting a primitive and global net.
|
||||
*
|
||||
* The wire is recorded and instantiated by the top level output routines.
|
||||
*/
|
||||
std::string make_inst_wire(AtomNetId atom_net_id, ///<The id of the net in the atom netlist
|
||||
tatum::NodeId tnode_id, ///<The tnode associated with the primitive pin
|
||||
std::string inst_name, ///<The name of the instance associated with the pin
|
||||
PortType port_type, ///<The port direction
|
||||
int port_idx, ///<The instance port index
|
||||
int pin_idx) { ///<The instance pin index
|
||||
|
||||
std::string wire_name = inst_name;
|
||||
if (port_type == PortType::INPUT) {
|
||||
wire_name = join_identifier(wire_name, "input");
|
||||
} else if (port_type == PortType::CLOCK) {
|
||||
wire_name = join_identifier(wire_name, "clock");
|
||||
} else {
|
||||
VTR_ASSERT(port_type == PortType::OUTPUT);
|
||||
wire_name = join_identifier(wire_name, "output");
|
||||
}
|
||||
|
||||
wire_name = join_identifier(wire_name, std::to_string(port_idx));
|
||||
wire_name = join_identifier(wire_name, std::to_string(pin_idx));
|
||||
|
||||
auto value = std::make_pair(wire_name, tnode_id);
|
||||
if (port_type == PortType::INPUT || port_type == PortType::CLOCK) {
|
||||
//Add the sink
|
||||
logical_net_sinks_[atom_net_id].push_back(value);
|
||||
|
||||
} else {
|
||||
//Add the driver
|
||||
VTR_ASSERT(port_type == PortType::OUTPUT);
|
||||
|
||||
auto ret = logical_net_drivers_.insert(std::make_pair(atom_net_id, value));
|
||||
VTR_ASSERT(ret.second); //Was inserted, drivers are unique
|
||||
}
|
||||
|
||||
return wire_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the name of a circuit-level Input/Output
|
||||
*
|
||||
|
@ -1141,6 +1135,48 @@ class NetlistWriterVisitor : public NetlistVisitor {
|
|||
return io_name;
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Returns the name of a wire connecting a primitive and global net.
|
||||
*
|
||||
* The wire is recorded and instantiated by the top level output routines.
|
||||
*/
|
||||
std::string make_inst_wire(AtomNetId atom_net_id, ///<The id of the net in the atom netlist
|
||||
tatum::NodeId tnode_id, ///<The tnode associated with the primitive pin
|
||||
std::string inst_name, ///<The name of the instance associated with the pin
|
||||
PortType port_type, ///<The port direction
|
||||
int port_idx, ///<The instance port index
|
||||
int pin_idx) { ///<The instance pin index
|
||||
|
||||
std::string wire_name = inst_name;
|
||||
if (port_type == PortType::INPUT) {
|
||||
wire_name = join_identifier(wire_name, "input");
|
||||
} else if (port_type == PortType::CLOCK) {
|
||||
wire_name = join_identifier(wire_name, "clock");
|
||||
} else {
|
||||
VTR_ASSERT(port_type == PortType::OUTPUT);
|
||||
wire_name = join_identifier(wire_name, "output");
|
||||
}
|
||||
|
||||
wire_name = join_identifier(wire_name, std::to_string(port_idx));
|
||||
wire_name = join_identifier(wire_name, std::to_string(pin_idx));
|
||||
|
||||
auto value = std::make_pair(wire_name, tnode_id);
|
||||
if (port_type == PortType::INPUT || port_type == PortType::CLOCK) {
|
||||
//Add the sink
|
||||
logical_net_sinks_[atom_net_id].push_back(value);
|
||||
|
||||
} else {
|
||||
//Add the driver
|
||||
VTR_ASSERT(port_type == PortType::OUTPUT);
|
||||
|
||||
auto ret = logical_net_drivers_.insert(std::make_pair(atom_net_id, value));
|
||||
VTR_ASSERT(ret.second); //Was inserted, drivers are unique
|
||||
}
|
||||
|
||||
return wire_name;
|
||||
}
|
||||
|
||||
///@brief Returns an Instance object representing the LUT
|
||||
std::shared_ptr<Instance> make_lut_instance(const t_pb* atom) {
|
||||
//Determine what size LUT
|
||||
|
@ -1213,7 +1249,7 @@ class NetlistWriterVisitor : public NetlistVisitor {
|
|||
port_conns["out"].push_back(net);
|
||||
}
|
||||
|
||||
auto inst = std::make_shared<LutInst>(lut_size, lut_mask, inst_name, port_conns, timing_arcs);
|
||||
auto inst = std::make_shared<LutInst>(lut_size, lut_mask, inst_name, port_conns, timing_arcs, opts_);
|
||||
|
||||
return inst;
|
||||
}
|
||||
|
@ -1413,7 +1449,7 @@ class NetlistWriterVisitor : public NetlistVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
return std::make_shared<BlackBoxInst>(type, inst_name, params, attrs, input_port_conns, output_port_conns, timing_arcs, ports_tsu, ports_thld, ports_tcq);
|
||||
return std::make_shared<BlackBoxInst>(type, inst_name, params, attrs, input_port_conns, output_port_conns, timing_arcs, ports_tsu, ports_thld, ports_tcq, opts_);
|
||||
}
|
||||
|
||||
///@brief Returns an Instance object representing a Multiplier
|
||||
|
@ -1509,7 +1545,7 @@ class NetlistWriterVisitor : public NetlistVisitor {
|
|||
|
||||
VTR_ASSERT(pb_graph_node->num_clock_ports == 0); //No clocks
|
||||
|
||||
return std::make_shared<BlackBoxInst>(type_name, inst_name, params, attrs, input_port_conns, output_port_conns, timing_arcs, ports_tsu, ports_thld, ports_tcq);
|
||||
return std::make_shared<BlackBoxInst>(type_name, inst_name, params, attrs, input_port_conns, output_port_conns, timing_arcs, ports_tsu, ports_thld, ports_tcq, opts_);
|
||||
}
|
||||
|
||||
///@brief Returns an Instance object representing an Adder
|
||||
|
@ -1609,7 +1645,7 @@ class NetlistWriterVisitor : public NetlistVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
return std::make_shared<BlackBoxInst>(type_name, inst_name, params, attrs, input_port_conns, output_port_conns, timing_arcs, ports_tsu, ports_thld, ports_tcq);
|
||||
return std::make_shared<BlackBoxInst>(type_name, inst_name, params, attrs, input_port_conns, output_port_conns, timing_arcs, ports_tsu, ports_thld, ports_tcq, opts_);
|
||||
}
|
||||
|
||||
std::shared_ptr<Instance> make_blackbox_instance(const t_pb* atom) {
|
||||
|
@ -1747,7 +1783,7 @@ class NetlistWriterVisitor : public NetlistVisitor {
|
|||
attrs[attr.first] = attr.second;
|
||||
}
|
||||
|
||||
return std::make_shared<BlackBoxInst>(type_name, inst_name, params, attrs, input_port_conns, output_port_conns, timing_arcs, ports_tsu, ports_thld, ports_tcq);
|
||||
return std::make_shared<BlackBoxInst>(type_name, inst_name, params, attrs, input_port_conns, output_port_conns, timing_arcs, ports_tsu, ports_thld, ports_tcq, opts_);
|
||||
}
|
||||
|
||||
///@brief Returns the top level pb_route associated with the given pb
|
||||
|
@ -1756,18 +1792,6 @@ class NetlistWriterVisitor : public NetlistVisitor {
|
|||
return top_pb->pb_route;
|
||||
}
|
||||
|
||||
///@brief Returns the top complex block which contains the given pb
|
||||
const t_pb* find_top_cb(const t_pb* curr) {
|
||||
//Walk up through the pb graph until curr
|
||||
//has no parent, at which point it will be the top pb
|
||||
const t_pb* parent = curr->parent_pb;
|
||||
while (parent != nullptr) {
|
||||
curr = parent;
|
||||
parent = curr->parent_pb;
|
||||
}
|
||||
return curr;
|
||||
}
|
||||
|
||||
///@brief Returns the tnode ID of the given atom's connected cluster pin
|
||||
tatum::NodeId find_tnode(const t_pb* atom, int cluster_pin_idx) {
|
||||
auto& atom_ctx = g_vpr_ctx.atom();
|
||||
|
@ -1785,6 +1809,19 @@ class NetlistWriterVisitor : public NetlistVisitor {
|
|||
return tnode_id;
|
||||
}
|
||||
|
||||
private:
|
||||
///@brief Returns the top complex block which contains the given pb
|
||||
const t_pb* find_top_cb(const t_pb* curr) {
|
||||
//Walk up through the pb graph until curr
|
||||
//has no parent, at which point it will be the top pb
|
||||
const t_pb* parent = curr->parent_pb;
|
||||
while (parent != nullptr) {
|
||||
curr = parent;
|
||||
parent = curr->parent_pb;
|
||||
}
|
||||
return curr;
|
||||
}
|
||||
|
||||
///@brief Returns a LogicVec representing the LUT mask of the given LUT atom
|
||||
LogicVec load_lut_mask(size_t num_inputs, //LUT size
|
||||
const t_pb* atom) { //LUT primitive
|
||||
|
@ -2042,13 +2079,15 @@ class NetlistWriterVisitor : public NetlistVisitor {
|
|||
return ::get_delay_ps(delay_sec); //Class overload hides file-scope by default
|
||||
}
|
||||
|
||||
private: //Data
|
||||
std::string top_module_name_; ///<Name of the top level module (i.e. the circuit)
|
||||
private: //Data
|
||||
std::string top_module_name_; ///<Name of the top level module (i.e. the circuit)
|
||||
protected:
|
||||
std::vector<std::string> inputs_; ///<Name of circuit inputs
|
||||
std::vector<std::string> outputs_; ///<Name of circuit outputs
|
||||
std::vector<Assignment> assignments_; ///<Set of assignments (i.e. net-to-net connections)
|
||||
std::vector<std::shared_ptr<Instance>> cell_instances_; ///<Set of cell instances
|
||||
|
||||
private:
|
||||
//Drivers of logical nets.
|
||||
// Key: logic net id, Value: pair of wire_name and tnode_id
|
||||
std::map<AtomNetId, std::pair<std::string, tatum::NodeId>> logical_net_drivers_;
|
||||
|
@ -2059,7 +2098,10 @@ class NetlistWriterVisitor : public NetlistVisitor {
|
|||
std::map<std::string, float> logical_net_sink_delays_;
|
||||
|
||||
//Output streams
|
||||
protected:
|
||||
std::ostream& verilog_os_;
|
||||
|
||||
private:
|
||||
std::ostream& blif_os_;
|
||||
std::ostream& sdf_os_;
|
||||
|
||||
|
@ -2067,14 +2109,196 @@ class NetlistWriterVisitor : public NetlistVisitor {
|
|||
std::map<std::pair<ClusterBlockId, int>, tatum::NodeId> pin_id_to_tnode_lookup_;
|
||||
|
||||
std::shared_ptr<const AnalysisDelayCalculator> delay_calc_;
|
||||
struct t_analysis_opts opts_;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A class which writes post-implementation merged netlists (Verilog)
|
||||
*
|
||||
* It implements the NetlistVisitor interface used by NetlistWalker (see netlist_walker.h)
|
||||
*/
|
||||
class MergedNetlistWriterVisitor : public NetlistWriterVisitor {
|
||||
public: //Public interface
|
||||
MergedNetlistWriterVisitor(std::ostream& verilog_os, ///<Output stream for verilog netlist
|
||||
std::ostream& blif_os, ///<Output stream for blif netlist
|
||||
std::ostream& sdf_os, ///<Output stream for SDF
|
||||
std::shared_ptr<const AnalysisDelayCalculator> delay_calc,
|
||||
struct t_analysis_opts opts)
|
||||
: NetlistWriterVisitor(verilog_os, blif_os, sdf_os, delay_calc, opts) {}
|
||||
|
||||
std::map<std::string, int> portmap;
|
||||
|
||||
void visit_atom_impl(const t_pb* atom) override {
|
||||
auto& atom_ctx = g_vpr_ctx.atom();
|
||||
|
||||
auto atom_pb = atom_ctx.lookup.pb_atom(atom);
|
||||
if (atom_pb == AtomBlockId::INVALID()) {
|
||||
return;
|
||||
}
|
||||
const t_model* model = atom_ctx.nlist.block_model(atom_pb);
|
||||
|
||||
if (model->name == std::string(MODEL_INPUT)) {
|
||||
auto merged_io_name = make_io(atom, PortType::INPUT);
|
||||
if (merged_io_name != "")
|
||||
inputs_.emplace_back(merged_io_name);
|
||||
} else if (model->name == std::string(MODEL_OUTPUT)) {
|
||||
auto merged_io_name = make_io(atom, PortType::OUTPUT);
|
||||
if (merged_io_name != "")
|
||||
outputs_.emplace_back(merged_io_name);
|
||||
} else if (model->name == std::string(MODEL_NAMES)) {
|
||||
cell_instances_.push_back(make_lut_instance(atom));
|
||||
} else if (model->name == std::string(MODEL_LATCH)) {
|
||||
cell_instances_.push_back(make_latch_instance(atom));
|
||||
} else if (model->name == std::string("single_port_ram")) {
|
||||
cell_instances_.push_back(make_ram_instance(atom));
|
||||
} else if (model->name == std::string("dual_port_ram")) {
|
||||
cell_instances_.push_back(make_ram_instance(atom));
|
||||
} else if (model->name == std::string("multiply")) {
|
||||
cell_instances_.push_back(make_multiply_instance(atom));
|
||||
} else if (model->name == std::string("adder")) {
|
||||
cell_instances_.push_back(make_adder_instance(atom));
|
||||
} else {
|
||||
cell_instances_.push_back(make_blackbox_instance(atom));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the name of circuit-level Input/Output ports with multi-bit
|
||||
* ports merged into one.
|
||||
*
|
||||
* The I/O is recorded and instantiated by the top level output routines
|
||||
* @param atom The implementation primitive representing the I/O
|
||||
* @param dir The IO direction
|
||||
* @param portmap Map for keeping port names and width
|
||||
*/
|
||||
std::string make_io(const t_pb* atom,
|
||||
PortType dir) {
|
||||
const t_pb_graph_node* pb_graph_node = atom->pb_graph_node;
|
||||
|
||||
std::string io_name;
|
||||
std::string indexed_io_name;
|
||||
int cluster_pin_idx = -1;
|
||||
// regex for matching 3 groups:
|
||||
// * 'out:' - optional
|
||||
// * verilog identifier - mandatory
|
||||
// * index - optional
|
||||
std::string rgx = "(out:)?([a-zA-Z$_]+[a-zA-Z0-9$_]*)(\\[[0-9]+\\])?$";
|
||||
std::string name(atom->name);
|
||||
std::regex regex(rgx);
|
||||
std::smatch matches;
|
||||
|
||||
if (dir == PortType::INPUT) {
|
||||
VTR_ASSERT(pb_graph_node->num_output_ports == 1); //One output port
|
||||
VTR_ASSERT(pb_graph_node->num_output_pins[0] == 1); //One output pin
|
||||
cluster_pin_idx = pb_graph_node->output_pins[0][0].pin_count_in_cluster; //Unique pin index in cluster
|
||||
|
||||
io_name = "";
|
||||
indexed_io_name = atom->name;
|
||||
|
||||
if (std::regex_match(name, matches, regex)) {
|
||||
if (std::find(inputs_.begin(), inputs_.end(), matches[2]) == inputs_.end()) { //Skip already existing multi-bit port names
|
||||
io_name = matches[2];
|
||||
portmap[matches[2]] = 0;
|
||||
} else {
|
||||
portmap[matches[2]]++;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
VTR_ASSERT(pb_graph_node->num_input_ports == 1); //One input port
|
||||
VTR_ASSERT(pb_graph_node->num_input_pins[0] == 1); //One input pin
|
||||
cluster_pin_idx = pb_graph_node->input_pins[0][0].pin_count_in_cluster; //Unique pin index in cluster
|
||||
|
||||
//Strip off the starting 'out:' that vpr adds to uniqify outputs
|
||||
//this makes the port names match the input blif file
|
||||
|
||||
io_name = "";
|
||||
indexed_io_name = atom->name + 4;
|
||||
|
||||
if (std::regex_search(name, matches, regex)) {
|
||||
if (std::find(outputs_.begin(), outputs_.end(), matches[2]) == outputs_.end()) { //Skip already existing multi-bit port names
|
||||
portmap[matches[2]] = 0;
|
||||
io_name = matches[2];
|
||||
} else {
|
||||
portmap[matches[2]]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const auto& top_pb_route = find_top_pb_route(atom);
|
||||
|
||||
if (top_pb_route.count(cluster_pin_idx)) {
|
||||
//Net exists
|
||||
auto atom_net_id = top_pb_route[cluster_pin_idx].atom_net_id; //Connected net in atom netlist
|
||||
|
||||
//Port direction is inverted (inputs drive internal nets, outputs sink internal nets)
|
||||
PortType wire_dir = (dir == PortType::INPUT) ? PortType::OUTPUT : PortType::INPUT;
|
||||
|
||||
//Look up the tnode associated with this pin (used for delay calculation)
|
||||
tatum::NodeId tnode_id = find_tnode(atom, cluster_pin_idx);
|
||||
|
||||
auto wire_name = make_inst_wire(atom_net_id, tnode_id, indexed_io_name, wire_dir, 0, 0);
|
||||
|
||||
//Connect the wires to to I/Os with assign statements
|
||||
if (wire_dir == PortType::INPUT) {
|
||||
assignments_.emplace_back(indexed_io_name, escape_verilog_identifier(wire_name));
|
||||
} else {
|
||||
assignments_.emplace_back(escape_verilog_identifier(wire_name), indexed_io_name);
|
||||
}
|
||||
}
|
||||
|
||||
return io_name;
|
||||
}
|
||||
|
||||
void print_primary_io(int depth) {
|
||||
//Primary Inputs
|
||||
for (auto iter = inputs_.begin(); iter != inputs_.end(); ++iter) {
|
||||
//verilog_os_ << indent(depth + 1) << "input " << escape_verilog_identifier(*iter);
|
||||
std::string range;
|
||||
if (portmap[*iter] > 0)
|
||||
verilog_os_ << indent(depth + 1) << "input [" << portmap[*iter] << ":0] " << *iter;
|
||||
else
|
||||
verilog_os_ << indent(depth + 1) << "input " << *iter;
|
||||
if (iter + 1 != inputs_.end() || outputs_.size() > 0) {
|
||||
verilog_os_ << ",";
|
||||
}
|
||||
verilog_os_ << "\n";
|
||||
}
|
||||
|
||||
//Primary Outputs
|
||||
for (auto iter = outputs_.begin(); iter != outputs_.end(); ++iter) {
|
||||
std::string range;
|
||||
if (portmap[*iter] > 0)
|
||||
verilog_os_ << indent(depth + 1) << "output [" << portmap[*iter] << ":0] " << *iter;
|
||||
else
|
||||
verilog_os_ << indent(depth + 1) << "output " << *iter;
|
||||
if (iter + 1 != outputs_.end()) {
|
||||
verilog_os_ << ",";
|
||||
}
|
||||
verilog_os_ << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
void print_assignments(int depth) {
|
||||
verilog_os_ << "\n";
|
||||
verilog_os_ << indent(depth + 1) << "//IO assignments\n";
|
||||
for (auto& assign : assignments_) {
|
||||
assign.print_merged_verilog(verilog_os_, indent(depth + 1));
|
||||
}
|
||||
}
|
||||
|
||||
void finish_impl() override {
|
||||
// Don't write to blif and sdf streams
|
||||
print_verilog();
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// Externally Accessible Functions
|
||||
//
|
||||
|
||||
///@brief Main routing for this file. See netlist_writer.h for details.
|
||||
void netlist_writer(const std::string basename, std::shared_ptr<const AnalysisDelayCalculator> delay_calc) {
|
||||
///@brief Main routine for this file. See netlist_writer.h for details.
|
||||
void netlist_writer(const std::string basename, std::shared_ptr<const AnalysisDelayCalculator> delay_calc, struct t_analysis_opts opts) {
|
||||
std::string verilog_filename = basename + "_post_synthesis.v";
|
||||
std::string blif_filename = basename + "_post_synthesis.blif";
|
||||
std::string sdf_filename = basename + "_post_synthesis.sdf";
|
||||
|
@ -2087,13 +2311,30 @@ void netlist_writer(const std::string basename, std::shared_ptr<const AnalysisDe
|
|||
std::ofstream blif_os(blif_filename);
|
||||
std::ofstream sdf_os(sdf_filename);
|
||||
|
||||
NetlistWriterVisitor visitor(verilog_os, blif_os, sdf_os, delay_calc);
|
||||
NetlistWriterVisitor visitor(verilog_os, blif_os, sdf_os, delay_calc, opts);
|
||||
|
||||
NetlistWalker nl_walker(visitor);
|
||||
|
||||
nl_walker.walk();
|
||||
}
|
||||
|
||||
///@brief Main routine for this file. See netlist_writer.h for details.
|
||||
void merged_netlist_writer(const std::string basename, std::shared_ptr<const AnalysisDelayCalculator> delay_calc, struct t_analysis_opts opts) {
|
||||
std::string verilog_filename = basename + "_merged_post_implementation.v";
|
||||
|
||||
VTR_LOG("Writing Implementation Netlist: %s\n", verilog_filename.c_str());
|
||||
|
||||
std::ofstream verilog_os(verilog_filename);
|
||||
// Don't write blif and sdf, pass dummy streams
|
||||
std::ofstream blif_os;
|
||||
std::ofstream sdf_os;
|
||||
|
||||
MergedNetlistWriterVisitor visitor(verilog_os, blif_os, sdf_os, delay_calc, opts);
|
||||
|
||||
NetlistWalker nl_walker(visitor);
|
||||
|
||||
nl_walker.walk();
|
||||
}
|
||||
//
|
||||
// File-scope function implementations
|
||||
//
|
||||
|
@ -2117,7 +2358,7 @@ double get_delay_ps(double delay_sec) {
|
|||
std::string create_unconn_net(size_t& unconn_count) {
|
||||
//We increment unconn_count by reference so each
|
||||
//call generates a unique name
|
||||
return "__vpr__unconn" + std::to_string(unconn_count++);
|
||||
return unconn_prefix + std::to_string(unconn_count++);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2159,7 +2400,31 @@ void print_blif_port(std::ostream& os, size_t& unconn_count, const std::string&
|
|||
*
|
||||
* Handles special cases like multi-bit and disconnected ports
|
||||
*/
|
||||
void print_verilog_port(std::ostream& os, size_t& unconn_count, const std::string& port_name, const std::vector<std::string>& nets, PortType type, int depth) {
|
||||
void print_verilog_port(std::ostream& os, size_t& unconn_count, const std::string& port_name, const std::vector<std::string>& nets, PortType type, int depth, struct t_analysis_opts& opts) {
|
||||
auto unconn_inp_name = [&]() {
|
||||
switch (opts.post_synth_netlist_unconn_input_handling) {
|
||||
case e_post_synth_netlist_unconn_handling::GND:
|
||||
return std::string("1'b0");
|
||||
case e_post_synth_netlist_unconn_handling::VCC:
|
||||
return std::string("1'b1");
|
||||
case e_post_synth_netlist_unconn_handling::NETS:
|
||||
return create_unconn_net(unconn_count);
|
||||
case e_post_synth_netlist_unconn_handling::UNCONNECTED:
|
||||
default:
|
||||
return std::string("1'bX");
|
||||
}
|
||||
};
|
||||
|
||||
auto unconn_out_name = [&]() {
|
||||
switch (opts.post_synth_netlist_unconn_output_handling) {
|
||||
case e_post_synth_netlist_unconn_handling::NETS:
|
||||
return create_unconn_net(unconn_count);
|
||||
case e_post_synth_netlist_unconn_handling::UNCONNECTED:
|
||||
default:
|
||||
return std::string();
|
||||
}
|
||||
};
|
||||
|
||||
//Port name
|
||||
os << indent(depth) << "." << port_name << "(";
|
||||
|
||||
|
@ -2169,40 +2434,58 @@ void print_verilog_port(std::ostream& os, size_t& unconn_count, const std::strin
|
|||
if (nets[0].empty()) {
|
||||
//Disconnected
|
||||
if (type == PortType::INPUT || type == PortType::CLOCK) {
|
||||
os << "1'b0";
|
||||
os << unconn_inp_name();
|
||||
} else {
|
||||
VTR_ASSERT(type == PortType::OUTPUT);
|
||||
os << create_unconn_net(unconn_count);
|
||||
os << unconn_out_name();
|
||||
}
|
||||
} else {
|
||||
//Connected
|
||||
os << escape_verilog_identifier(nets[0]);
|
||||
}
|
||||
} else {
|
||||
//A multi-bit port, we explicitly concat the single-bit nets to build the port,
|
||||
//taking care to print MSB on left and LSB on right
|
||||
os << "{"
|
||||
<< "\n";
|
||||
for (int ipin = (int)nets.size() - 1; ipin >= 0; --ipin) { //Reverse order to match endianess
|
||||
os << indent(depth + 1);
|
||||
if (nets[ipin].empty()) {
|
||||
//Disconnected
|
||||
if (type == PortType::INPUT || type == PortType::CLOCK) {
|
||||
os << "1'b0";
|
||||
} else {
|
||||
VTR_ASSERT(type == PortType::OUTPUT);
|
||||
os << create_unconn_net(unconn_count);
|
||||
}
|
||||
} else {
|
||||
//Connected
|
||||
os << escape_verilog_identifier(nets[ipin]);
|
||||
}
|
||||
if (ipin != 0) {
|
||||
os << ",";
|
||||
os << "\n";
|
||||
// Check if all pins are unconnected
|
||||
bool all_unconnected = true;
|
||||
for (size_t i = 0; i < nets.size(); ++i) {
|
||||
if (!nets[i].empty()) {
|
||||
all_unconnected = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
os << "}";
|
||||
|
||||
|
||||
//A multi-bit port, we explicitly concat the single-bit nets to build the port,
|
||||
//taking care to print MSB on left and LSB on right
|
||||
if (all_unconnected && type == PortType::OUTPUT && opts.post_synth_netlist_unconn_output_handling == e_post_synth_netlist_unconn_handling::UNCONNECTED) {
|
||||
// Empty connection
|
||||
} else {
|
||||
// Individual bits
|
||||
os << "{"
|
||||
<< "\n";
|
||||
for (int ipin = (int)nets.size() - 1; ipin >= 0; --ipin) { //Reverse order to match endianess
|
||||
os << indent(depth + 1);
|
||||
if (nets[ipin].empty()) {
|
||||
//Disconnected
|
||||
if (type == PortType::INPUT || type == PortType::CLOCK) {
|
||||
os << unconn_inp_name();
|
||||
} else {
|
||||
VTR_ASSERT(type == PortType::OUTPUT);
|
||||
// When concatenating output connection there cannot
|
||||
// be an empty placeholder so we have to create a
|
||||
// dummy net.
|
||||
os << create_unconn_net(unconn_count);
|
||||
}
|
||||
} else {
|
||||
//Connected
|
||||
os << escape_verilog_identifier(nets[ipin]);
|
||||
}
|
||||
if (ipin != 0) {
|
||||
os << ",";
|
||||
}
|
||||
os << "\n";
|
||||
}
|
||||
os << indent(depth) + " }";
|
||||
}
|
||||
}
|
||||
os << ")";
|
||||
}
|
||||
|
|
|
@ -15,6 +15,16 @@
|
|||
* All written filenames end in {basename}_post_synthesis.{fmt} where {basename} is the
|
||||
* basename argument and {fmt} is the file format (e.g. v, blif, sdf)
|
||||
*/
|
||||
void netlist_writer(const std::string basename, std::shared_ptr<const AnalysisDelayCalculator> delay_calc);
|
||||
void netlist_writer(const std::string basename, std::shared_ptr<const AnalysisDelayCalculator> delay_calc, struct t_analysis_opts opts);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Writes out the post implementation netlist in Verilog format.
|
||||
* It has its top module ports merged into multi-bit ones.
|
||||
*
|
||||
* Written filename ends in {basename}_merged_post_implementation.v where {basename} is the
|
||||
* basename argument.
|
||||
*/
|
||||
void merged_netlist_writer(const std::string basename, std::shared_ptr<const AnalysisDelayCalculator> delay_calc, struct t_analysis_opts opts);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -755,6 +755,75 @@ struct ParseReducer {
|
|||
return {"min", "max", "median", "arithmean", "geomean"};
|
||||
}
|
||||
};
|
||||
struct ParsePostSynthNetlistUnconnInputHandling {
|
||||
ConvertedValue<e_post_synth_netlist_unconn_handling> from_str(std::string str) {
|
||||
ConvertedValue<e_post_synth_netlist_unconn_handling> conv_value;
|
||||
if (str == "unconnected")
|
||||
conv_value.set_value(e_post_synth_netlist_unconn_handling::UNCONNECTED);
|
||||
else if (str == "nets")
|
||||
conv_value.set_value(e_post_synth_netlist_unconn_handling::NETS);
|
||||
else if (str == "gnd")
|
||||
conv_value.set_value(e_post_synth_netlist_unconn_handling::GND);
|
||||
else if (str == "vcc")
|
||||
conv_value.set_value(e_post_synth_netlist_unconn_handling::VCC);
|
||||
else {
|
||||
std::stringstream msg;
|
||||
msg << "Invalid conversion from '" << str << "' to e_post_synth_netlist_unconn_handling (expected one of: " << argparse::join(default_choices(), ", ") << ")";
|
||||
conv_value.set_error(msg.str());
|
||||
}
|
||||
return conv_value;
|
||||
}
|
||||
|
||||
ConvertedValue<std::string> to_str(e_post_synth_netlist_unconn_handling val) {
|
||||
ConvertedValue<std::string> conv_value;
|
||||
if (val == e_post_synth_netlist_unconn_handling::NETS)
|
||||
conv_value.set_value("nets");
|
||||
else if (val == e_post_synth_netlist_unconn_handling::GND)
|
||||
conv_value.set_value("gnd");
|
||||
else if (val == e_post_synth_netlist_unconn_handling::VCC)
|
||||
conv_value.set_value("vcc");
|
||||
else {
|
||||
VTR_ASSERT(val == e_post_synth_netlist_unconn_handling::UNCONNECTED);
|
||||
conv_value.set_value("unconnected");
|
||||
}
|
||||
return conv_value;
|
||||
}
|
||||
|
||||
std::vector<std::string> default_choices() {
|
||||
return {"unconnected", "nets", "gnd", "vcc"};
|
||||
}
|
||||
};
|
||||
|
||||
struct ParsePostSynthNetlistUnconnOutputHandling {
|
||||
ConvertedValue<e_post_synth_netlist_unconn_handling> from_str(std::string str) {
|
||||
ConvertedValue<e_post_synth_netlist_unconn_handling> conv_value;
|
||||
if (str == "unconnected")
|
||||
conv_value.set_value(e_post_synth_netlist_unconn_handling::UNCONNECTED);
|
||||
else if (str == "nets")
|
||||
conv_value.set_value(e_post_synth_netlist_unconn_handling::NETS);
|
||||
else {
|
||||
std::stringstream msg;
|
||||
msg << "Invalid conversion from '" << str << "' to e_post_synth_netlist_unconn_handling (expected one of: " << argparse::join(default_choices(), ", ") << ")";
|
||||
conv_value.set_error(msg.str());
|
||||
}
|
||||
return conv_value;
|
||||
}
|
||||
|
||||
ConvertedValue<std::string> to_str(e_post_synth_netlist_unconn_handling val) {
|
||||
ConvertedValue<std::string> conv_value;
|
||||
if (val == e_post_synth_netlist_unconn_handling::NETS)
|
||||
conv_value.set_value("nets");
|
||||
else {
|
||||
VTR_ASSERT(val == e_post_synth_netlist_unconn_handling::UNCONNECTED);
|
||||
conv_value.set_value("unconnected");
|
||||
}
|
||||
return conv_value;
|
||||
}
|
||||
|
||||
std::vector<std::string> default_choices() {
|
||||
return {"unconnected", "nets"};
|
||||
}
|
||||
};
|
||||
|
||||
argparse::ArgumentParser create_arg_parser(std::string prog_name, t_options& args) {
|
||||
std::string description =
|
||||
|
@ -1656,6 +1725,13 @@ argparse::ArgumentParser create_arg_parser(std::string prog_name, t_options& arg
|
|||
.default_value("off")
|
||||
.show_in(argparse::ShowIn::HELP_ONLY);
|
||||
|
||||
analysis_grp.add_argument<bool, ParseOnOff>(args.Generate_Post_Implementation_Merged_Netlist, "--gen_post_implementation_merged_netlist")
|
||||
.help(
|
||||
"Generates the post-implementation netlist with merged top module ports"
|
||||
" Used for post-implementation simulation and verification")
|
||||
.default_value("off")
|
||||
.show_in(argparse::ShowIn::HELP_ONLY);
|
||||
|
||||
analysis_grp.add_argument(args.timing_report_npaths, "--timing_report_npaths")
|
||||
.help("Controls how many timing paths are reported.")
|
||||
.default_value("100")
|
||||
|
@ -1675,6 +1751,28 @@ argparse::ArgumentParser create_arg_parser(std::string prog_name, t_options& arg
|
|||
.default_value("off")
|
||||
.show_in(argparse::ShowIn::HELP_ONLY);
|
||||
|
||||
analysis_grp.add_argument<e_post_synth_netlist_unconn_handling, ParsePostSynthNetlistUnconnInputHandling>(args.post_synth_netlist_unconn_input_handling, "--post_synth_netlist_unconn_inputs")
|
||||
.help(
|
||||
"Controls how unconnected input cell ports are handled in the post-synthesis netlist\n"
|
||||
" * unconnected: leave unconnected\n"
|
||||
" * nets: connect each unconnected input pin to its own separate\n"
|
||||
" undriven net named: __vpr__unconn<ID>, where <ID> is index\n"
|
||||
" assigned to this occurrence of unconnected port in design\n"
|
||||
" * gnd: tie all to ground (1'b0)\n"
|
||||
" * vcc: tie all to VCC (1'b1)\n")
|
||||
.default_value("unconnected")
|
||||
.show_in(argparse::ShowIn::HELP_ONLY);
|
||||
|
||||
analysis_grp.add_argument<e_post_synth_netlist_unconn_handling, ParsePostSynthNetlistUnconnOutputHandling>(args.post_synth_netlist_unconn_output_handling, "--post_synth_netlist_unconn_outputs")
|
||||
.help(
|
||||
"Controls how unconnected output cell ports are handled in the post-synthesis netlist\n"
|
||||
" * unconnected: leave unconnected\n"
|
||||
" * nets: connect each unconnected input pin to its own separate\n"
|
||||
" undriven net named: __vpr__unconn<ID>, where <ID> is index\n"
|
||||
" assigned to this occurrence of unconnected port in design\n")
|
||||
.default_value("unconnected")
|
||||
.show_in(argparse::ShowIn::HELP_ONLY);
|
||||
|
||||
auto& power_grp = parser.add_argument_group("power analysis options");
|
||||
|
||||
power_grp.add_argument<bool, ParseOnOff>(args.do_power, "--power")
|
||||
|
|
|
@ -156,9 +156,12 @@ struct t_options {
|
|||
/* Analysis options */
|
||||
argparse::ArgValue<bool> full_stats;
|
||||
argparse::ArgValue<bool> Generate_Post_Synthesis_Netlist;
|
||||
argparse::ArgValue<bool> Generate_Post_Implementation_Merged_Netlist;
|
||||
argparse::ArgValue<int> timing_report_npaths;
|
||||
argparse::ArgValue<e_timing_report_detail> timing_report_detail;
|
||||
argparse::ArgValue<bool> timing_report_skew;
|
||||
argparse::ArgValue<e_post_synth_netlist_unconn_handling> post_synth_netlist_unconn_input_handling;
|
||||
argparse::ArgValue<e_post_synth_netlist_unconn_handling> post_synth_netlist_unconn_output_handling;
|
||||
};
|
||||
|
||||
argparse::ArgumentParser create_arg_parser(std::string prog_name, t_options& args);
|
||||
|
|
|
@ -1195,7 +1195,13 @@ void vpr_analysis(t_vpr_setup& vpr_setup, const t_arch& Arch, const RouteStatus&
|
|||
|
||||
//Write the post-syntesis netlist
|
||||
if (vpr_setup.AnalysisOpts.gen_post_synthesis_netlist) {
|
||||
netlist_writer(atom_ctx.nlist.netlist_name().c_str(), analysis_delay_calc);
|
||||
netlist_writer(atom_ctx.nlist.netlist_name().c_str(), analysis_delay_calc,
|
||||
vpr_setup.AnalysisOpts);
|
||||
}
|
||||
|
||||
//Write the post-implementation merged netlist
|
||||
if (vpr_setup.AnalysisOpts.gen_post_implementation_merged_netlist) {
|
||||
merged_netlist_writer(atom_ctx.nlist.netlist_name().c_str(), analysis_delay_calc, vpr_setup.AnalysisOpts);
|
||||
}
|
||||
|
||||
//Do power analysis
|
||||
|
|
|
@ -900,6 +900,13 @@ enum class e_timing_report_detail {
|
|||
DETAILED_ROUTING, //Show inter-block routing resources used
|
||||
};
|
||||
|
||||
enum class e_post_synth_netlist_unconn_handling {
|
||||
UNCONNECTED, // Leave unrouted ports unconnected
|
||||
NETS, // Leave unrouted ports unconnected but add new named nets to each of them
|
||||
GND, // Tie unrouted ports to ground (only for input ports)
|
||||
VCC // Tie unrouted ports to VCC (only for input ports)
|
||||
};
|
||||
|
||||
enum class e_incr_reroute_delay_ripup {
|
||||
ON,
|
||||
OFF,
|
||||
|
@ -959,6 +966,9 @@ struct t_analysis_opts {
|
|||
e_stage_action doAnalysis;
|
||||
|
||||
bool gen_post_synthesis_netlist;
|
||||
bool gen_post_implementation_merged_netlist;
|
||||
e_post_synth_netlist_unconn_handling post_synth_netlist_unconn_input_handling;
|
||||
e_post_synth_netlist_unconn_handling post_synth_netlist_unconn_output_handling;
|
||||
|
||||
int timing_report_npaths;
|
||||
e_timing_report_detail timing_report_detail;
|
||||
|
|
Loading…
Reference in New Issue