|
|
|
@ -10,6 +10,7 @@
|
|
|
|
|
#include <memory>
|
|
|
|
|
#include <unordered_set>
|
|
|
|
|
#include <cmath>
|
|
|
|
|
#include <regex>
|
|
|
|
|
|
|
|
|
|
#include "vtr_assert.h"
|
|
|
|
|
#include "vtr_util.h"
|
|
|
|
@ -687,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();
|
|
|
|
@ -783,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";
|
|
|
|
@ -878,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);
|
|
|
|
@ -892,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);
|
|
|
|
@ -901,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
|
|
|
|
@ -916,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";
|
|
|
|
@ -962,6 +975,7 @@ class NetlistWriterVisitor : public NetlistVisitor {
|
|
|
|
|
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";
|
|
|
|
@ -1066,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
|
|
|
|
|
*
|
|
|
|
@ -1162,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
|
|
|
|
@ -1777,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();
|
|
|
|
@ -1806,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
|
|
|
|
@ -2063,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_;
|
|
|
|
@ -2080,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_;
|
|
|
|
|
|
|
|
|
@ -2091,11 +2112,192 @@ class NetlistWriterVisitor : public NetlistVisitor {
|
|
|
|
|
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.
|
|
|
|
|
///@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";
|
|
|
|
@ -2116,6 +2318,23 @@ void netlist_writer(const std::string basename, std::shared_ptr<const AnalysisDe
|
|
|
|
|
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
|
|
|
|
|
//
|
|
|
|
|