From 638a476bb3cea75ca3fcc179840d18fe84f5fe27 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Fri, 28 Oct 2022 16:13:13 +0200 Subject: [PATCH 01/55] Libarchfpga: add 'edge' attribute to under Signed-off-by: Pawel Czarnecki --- libs/libarchfpga/src/logic_types.h | 8 ++++++++ libs/libarchfpga/src/physical_types.h | 4 ++++ libs/libarchfpga/src/read_xml_arch_file.cpp | 20 ++++++++++++++++++++ 3 files changed, 32 insertions(+) diff --git a/libs/libarchfpga/src/logic_types.h b/libs/libarchfpga/src/logic_types.h index 4427b85016f..89a26754621 100644 --- a/libs/libarchfpga/src/logic_types.h +++ b/libs/libarchfpga/src/logic_types.h @@ -25,12 +25,20 @@ enum PORTS { ERR_PORT }; +enum TriggeringEdge { + RISING_EDGE, + FALLING_EDGE, + DONT_CARE, + ERROR_EDGE +}; + struct t_model_ports { enum PORTS dir = ERR_PORT; /* port direction */ char* name = nullptr; /* name of this port */ int size = 0; /* maximum number of pins */ int min_size = 0; /* minimum number of pins */ bool is_clock = false; /* clock? */ + enum TriggeringEdge trigg_edge = DONT_CARE; /* triggering edge of the clock port */ bool is_non_clock_global = false; /* not a clock but is a special, global, control signal (eg global asynchronous reset, etc) */ std::string clock; /* The clock associated with this pin (if the pin is sequential) */ std::vector combinational_sink_ports; /* The other ports on this model which are combinationally driven by this port */ diff --git a/libs/libarchfpga/src/physical_types.h b/libs/libarchfpga/src/physical_types.h index 55c99e23752..922bf1f7ec7 100644 --- a/libs/libarchfpga/src/physical_types.h +++ b/libs/libarchfpga/src/physical_types.h @@ -787,6 +787,7 @@ struct t_physical_pin { * Data members: * name: name of the port * is_clock: whether or not this port is a clock + * trigg_edge: triggering edge of the clock port * is_non_clock_global: Applies to top level pb_type, this pin is not a clock but * is a global signal (useful for stuff like global reset signals, * perhaps useful for VCC and GND) @@ -803,6 +804,7 @@ struct t_physical_tile_port { char* name; enum PORTS type; bool is_clock; + enum TriggeringEdge trigg_edge; bool is_non_clock_global; int num_pins; PortEquivalence equivalent; @@ -1035,6 +1037,7 @@ struct t_interconnect { * name: name of the port * model_port: associated model port * is_clock: whether or not this port is a clock + * trigg_edge: triggering edge of the clock port * is_non_clock_global: Applies to top level pb_type, this pin is not a clock but * is a global signal (useful for stuff like global reset signals, * perhaps useful for VCC and GND) @@ -1050,6 +1053,7 @@ struct t_port { t_model_ports* model_port; enum PORTS type; bool is_clock; + enum TriggeringEdge trigg_edge; bool is_non_clock_global; int num_pins; PortEquivalence equivalent; diff --git a/libs/libarchfpga/src/read_xml_arch_file.cpp b/libs/libarchfpga/src/read_xml_arch_file.cpp index cd1b8a0002a..632bf2f54b4 100644 --- a/libs/libarchfpga/src/read_xml_arch_file.cpp +++ b/libs/libarchfpga/src/read_xml_arch_file.cpp @@ -267,6 +267,9 @@ std::string inst_port_to_port_name(std::string inst_port); static bool attribute_to_bool(const pugi::xml_node node, const pugi::xml_attribute attr, const pugiutil::loc_data& loc_data); +static TriggeringEdge attribute_to_trigg_edge(const pugi::xml_node node, + const pugi::xml_attribute attr, + const pugiutil::loc_data& loc_data); int find_switch_by_name(const t_arch& arch, std::string switch_name); e_side string_to_side(std::string side_str); @@ -2314,6 +2317,9 @@ static void ProcessModelPorts(pugi::xml_node port_group, t_model* model, std::se } else if (attr.name() == std::string("is_clock")) { model_port->is_clock = attribute_to_bool(port, attr, loc_data); + } else if (attr.name() == std::string("edge")) { + model_port->trigg_edge = attribute_to_trigg_edge(port, attr, loc_data); + } else if (attr.name() == std::string("is_non_clock_global")) { model_port->is_non_clock_global = attribute_to_bool(port, attr, loc_data); @@ -4787,6 +4793,20 @@ static bool attribute_to_bool(const pugi::xml_node node, return false; } +static TriggeringEdge attribute_to_trigg_edge(const pugi::xml_node node, + const pugi::xml_attribute attr, + const pugiutil::loc_data& loc_data) { + if (attr.value() == std::string("rising")) { + return TriggeringEdge::RISING_EDGE; + } else if (attr.value() == std::string("falling")) { + return TriggeringEdge::FALLING_EDGE; + } else { + bad_attribute_value(attr, node, loc_data, {"rising", "falling"}); + } + + return ERROR_EDGE; +} + int find_switch_by_name(const t_arch& arch, std::string switch_name) { for (int iswitch = 0; iswitch < arch.num_switches; ++iswitch) { const t_arch_switch_inf& arch_switch = arch.Switches[iswitch]; From 00c53c082c197a7e3208f0c7e8ae5ab02d4b1aa7 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Tue, 15 Nov 2022 15:42:38 +0100 Subject: [PATCH 02/55] Tatum: store triggering edge info in TimingGraph Signed-off-by: Pawel Czarnecki --- .../libtatum/libtatum/tatum/TimingGraph.cpp | 30 ++++++++++++++++++- .../libtatum/libtatum/tatum/TimingGraph.hpp | 20 +++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/libs/EXTERNAL/libtatum/libtatum/tatum/TimingGraph.cpp b/libs/EXTERNAL/libtatum/libtatum/tatum/TimingGraph.cpp index 33392a6e8d1..57a7fd68eb3 100644 --- a/libs/EXTERNAL/libtatum/libtatum/tatum/TimingGraph.cpp +++ b/libs/EXTERNAL/libtatum/libtatum/tatum/TimingGraph.cpp @@ -198,6 +198,32 @@ NodeId TimingGraph::add_node(const NodeType type) { return node_id; } +NodeId TimingGraph::add_node(const NodeType type, int trigg_edge) { + //Invalidate the levelization + is_levelized_ = false; + + //Reserve an ID + NodeId node_id = NodeId(node_ids_.size()); + node_ids_.push_back(node_id); + + //Type + node_types_.push_back(type); + + //Triggering Edge + trigg_edges_.push_back(trigg_edge); + + //Edges + node_out_edges_.push_back(std::vector()); + node_in_edges_.push_back(std::vector()); + + //Verify sizes + TATUM_ASSERT(node_types_.size() == node_out_edges_.size()); + TATUM_ASSERT(node_types_.size() == node_in_edges_.size()); + + //Return the ID of the added node + return node_id; +} + EdgeId TimingGraph::add_edge(const EdgeType type, const NodeId src_node, const NodeId sink_node) { //We require that the source/sink node must already be in the graph, // so we can update them with thier edge references @@ -556,6 +582,7 @@ void TimingGraph::remap_nodes(const tatum::util::linear_map& node node_types_ = clean_and_reorder_values(node_types_, node_id_map); node_in_edges_ = clean_and_reorder_values(node_in_edges_, node_id_map); node_out_edges_ = clean_and_reorder_values(node_out_edges_, node_id_map); + trigg_edges_ = clean_and_reorder_values(trigg_edges_, node_id_map); //Update references edge_src_nodes_ = update_all_refs(edge_src_nodes_, node_id_map); @@ -597,7 +624,8 @@ bool TimingGraph::validate_sizes() const { if ( node_ids_.size() != node_types_.size() || node_ids_.size() != node_in_edges_.size() || node_ids_.size() != node_out_edges_.size() - || node_ids_.size() != node_levels_.size()) { + || node_ids_.size() != node_levels_.size() + || node_ids_.size() != trigg_edges_.size()) { throw tatum::Error("Inconsistent node attribute sizes"); } diff --git a/libs/EXTERNAL/libtatum/libtatum/tatum/TimingGraph.hpp b/libs/EXTERNAL/libtatum/libtatum/tatum/TimingGraph.hpp index 72a05cad9da..c46cfab8274 100644 --- a/libs/EXTERNAL/libtatum/libtatum/tatum/TimingGraph.hpp +++ b/libs/EXTERNAL/libtatum/libtatum/tatum/TimingGraph.hpp @@ -84,6 +84,24 @@ class TimingGraph { ///\returns The type of the node NodeType node_type(const NodeId id) const { return node_types_[id]; } + int trigg_edge(const NodeId id) const { return trigg_edges_[id]; } + std::string trigg_edge_str(const NodeId id) const { + switch(trigg_edges_[id]) { + case 0: + return "RISING"; + break; + case 1: + return "FALLING"; + break; + case 2: + return "DONT_CARE"; + break; + default: + return "ERROR"; + break; + } + } + ///\param id The node id ///\returns A range of all out-going edges the node drives edge_range node_out_edges(const NodeId id) const { return tatum::util::make_range(node_out_edges_[id].begin(), node_out_edges_[id].end()); } @@ -198,6 +216,7 @@ class TimingGraph { ///\param type The type of the node to be added ///\warning Graph will likely need to be re-levelized after modification NodeId add_node(const NodeType type); + NodeId add_node(const NodeType type, int trigg_edge); ///Adds an edge to the timing graph ///\param type The edge's type @@ -282,6 +301,7 @@ class TimingGraph { //Node data tatum::util::linear_map node_ids_; //The node IDs in the graph tatum::util::linear_map node_types_; //Type of node + tatum::util::linear_map trigg_edges_; //Triggering edge of the clock tatum::util::linear_map> node_in_edges_; //Incomiing edge IDs for node tatum::util::linear_map> node_out_edges_; //Out going edge IDs for node tatum::util::linear_map node_levels_; //Out going edge IDs for node From b9d570da8240a059664c1a3d6764e6726b67bcd5 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Wed, 23 Nov 2022 10:54:59 +0100 Subject: [PATCH 03/55] TimingGraph builder: write triggering edge info to TimingGraph Signed-off-by: Pawel Czarnecki --- vpr/src/timing/timing_graph_builder.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/vpr/src/timing/timing_graph_builder.cpp b/vpr/src/timing/timing_graph_builder.cpp index c0462429648..ddba0d47fe3 100644 --- a/vpr/src/timing/timing_graph_builder.cpp +++ b/vpr/src/timing/timing_graph_builder.cpp @@ -351,7 +351,10 @@ void TimingGraphBuilder::add_io_to_timing_graph(const AtomBlockId blk) { } } - NodeId tnode = tg_->add_node(node_type); + AtomPortId port = netlist_.pin_port(pin); + const t_model_ports* model_port = netlist_.port_model(port); + + NodeId tnode = tg_->add_node(node_type, model_port->trigg_edge); netlist_lookup_.set_atom_pin_tnode(pin, tnode, BlockTnode::EXTERNAL); } @@ -413,21 +416,21 @@ std::set TimingGraphBuilder::create_block_timing_nodes(const Atom VTR_ASSERT(!model_port->is_clock); if (model_port->clock.empty()) { //No clock => combinational input - tnode = tg_->add_node(NodeType::IPIN); + tnode = tg_->add_node(NodeType::IPIN, model_port->trigg_edge); //A combinational pin is really both internal and external, mark it internal here //and external in the default case below netlist_lookup_.set_atom_pin_tnode(input_pin, tnode, BlockTnode::INTERNAL); } else { //This is a sequential data input (i.e. a sequential data capture point/timing path end-point) - tnode = tg_->add_node(NodeType::SINK); + tnode = tg_->add_node(NodeType::SINK, model_port->trigg_edge); if (!model_port->combinational_sink_ports.empty()) { //There is an internal combinational connection starting at this sequential input //pin. This is a new timing path and hence we must create a new SOURCE node. //Create the internal source - NodeId internal_tnode = tg_->add_node(NodeType::SOURCE); + NodeId internal_tnode = tg_->add_node(NodeType::SOURCE, model_port->trigg_edge); netlist_lookup_.set_atom_pin_tnode(input_pin, internal_tnode, BlockTnode::INTERNAL); } } @@ -452,7 +455,7 @@ std::set TimingGraphBuilder::create_block_timing_nodes(const Atom VTR_ASSERT(model_port->is_clock); VTR_ASSERT(model_port->clock.empty()); - NodeId tnode = tg_->add_node(NodeType::CPIN); + NodeId tnode = tg_->add_node(NodeType::CPIN, model_port->trigg_edge); netlist_lookup_.set_atom_pin_tnode(clock_pin, tnode, BlockTnode::EXTERNAL); } @@ -468,7 +471,7 @@ std::set TimingGraphBuilder::create_block_timing_nodes(const Atom NodeId tnode; if (is_netlist_clock_source(output_pin)) { //A generated clock source - tnode = tg_->add_node(NodeType::SOURCE); + tnode = tg_->add_node(NodeType::SOURCE, model_port->trigg_edge); clock_generator_tnodes.insert(tnode); @@ -488,7 +491,7 @@ std::set TimingGraphBuilder::create_block_timing_nodes(const Atom if (model_port->clock.empty()) { //No clock => combinational output - tnode = tg_->add_node(NodeType::OPIN); + tnode = tg_->add_node(NodeType::OPIN, model_port->trigg_edge); //A combinational pin is really both internal and external, mark it internal here //and external in the default case below @@ -497,13 +500,13 @@ std::set TimingGraphBuilder::create_block_timing_nodes(const Atom } else { VTR_ASSERT(!model_port->clock.empty()); //Has an associated clock => sequential output - tnode = tg_->add_node(NodeType::SOURCE); + tnode = tg_->add_node(NodeType::SOURCE, model_port->trigg_edge); if (output_ports_used_as_combinational_sinks.count(model_port->name)) { //There is a combinational path within the primitive terminating at this sequential output //Create the internal sink node - NodeId internal_tnode = tg_->add_node(NodeType::SINK); + NodeId internal_tnode = tg_->add_node(NodeType::SINK, model_port->trigg_edge); netlist_lookup_.set_atom_pin_tnode(output_pin, internal_tnode, BlockTnode::INTERNAL); } } From af819017b3b34b11edef37f4f39c97105620244c Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Wed, 23 Nov 2022 10:25:44 +0100 Subject: [PATCH 04/55] Tatum: show triggering clock edge in TimingGraph visualization Signed-off-by: Pawel Czarnecki --- .../libtatum/libtatum/tatum/report/graphviz_dot_writer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/EXTERNAL/libtatum/libtatum/tatum/report/graphviz_dot_writer.cpp b/libs/EXTERNAL/libtatum/libtatum/tatum/report/graphviz_dot_writer.cpp index 807a0eb963c..638f7590e6e 100644 --- a/libs/EXTERNAL/libtatum/libtatum/tatum/report/graphviz_dot_writer.cpp +++ b/libs/EXTERNAL/libtatum/libtatum/tatum/report/graphviz_dot_writer.cpp @@ -120,7 +120,7 @@ void GraphvizDotWriter::write_dot_node(std::ostream& os, os << "\t"; os << node_name(node); os << "[label=\""; - os << "{" << node << " (" << tg_.node_type(node) << ")"; + os << "{" << node << " (" << tg_.node_type(node) << ") TEdge(" << tg_.trigg_edge_str(node) << ")"; for(const auto& tag_set : {tags, slacks}) { for(const auto& tag : tag_set) { From b4af78f826209efb9d1965e12d7ce236c6a45603 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Thu, 17 Nov 2022 14:38:42 +0100 Subject: [PATCH 05/55] vpr: base: read_blif: add support for parsing falling edge clocked FFs Signed-off-by: Pawel Czarnecki --- vpr/src/base/read_blif.cpp | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/vpr/src/base/read_blif.cpp b/vpr/src/base/read_blif.cpp index 2425a18d239..e921d8deeaa 100644 --- a/vpr/src/base/read_blif.cpp +++ b/vpr/src/base/read_blif.cpp @@ -194,15 +194,20 @@ struct BlifAllocCallback : public blifparse::Callback { void latch(std::string input, std::string output, blifparse::LatchType type, std::string control, blifparse::LogicValue init) override { if (type == blifparse::LatchType::UNSPECIFIED) { VTR_LOGF_WARN(filename_.c_str(), lineno_, "Treating latch '%s' of unspecified type as rising edge triggered\n", output.c_str()); - } else if (type != blifparse::LatchType::RISING_EDGE) { - vpr_throw(VPR_ERROR_BLIF_F, filename_.c_str(), lineno_, "Only rising edge latches supported\n"); + } else if (type != blifparse::LatchType::RISING_EDGE && type != blifparse::LatchType::FALLING_EDGE) { + vpr_throw(VPR_ERROR_BLIF_F, filename_.c_str(), lineno_, "Only rising and falling edge latches supported\n"); } if (control.empty()) { vpr_throw(VPR_ERROR_BLIF_F, filename_.c_str(), lineno_, "Latch must have a clock\n"); } - const t_model* blk_model = find_model(MODEL_LATCH); + TriggeringEdge t_edge; + if (type == blifparse::LatchType::FALLING_EDGE) + t_edge = TriggeringEdge::FALLING_EDGE; + else + t_edge = TriggeringEdge::RISING_EDGE; + const t_model* blk_model = find_latch_model(t_edge); VTR_ASSERT_MSG(blk_model->inputs, "Has one input port"); VTR_ASSERT_MSG(blk_model->inputs->next, "Has two input port"); @@ -211,7 +216,7 @@ struct BlifAllocCallback : public blifparse::Callback { VTR_ASSERT_MSG(!blk_model->outputs->next, "Has no more than one input port"); const t_model_ports* d_model_port = blk_model->inputs; - const t_model_ports* clk_model_port = blk_model->inputs->next; + t_model_ports* clk_model_port = blk_model->inputs->next; const t_model_ports* q_model_port = blk_model->outputs; VTR_ASSERT(d_model_port->name == std::string("D")); @@ -466,6 +471,31 @@ struct BlifAllocCallback : public blifparse::Callback { return arch_model; } + const t_model* find_latch_model(TriggeringEdge t_edge) { + const t_model* arch_model = nullptr; + for (const t_model* arch_models : {user_arch_models_, library_arch_models_}) { + arch_model = arch_models; + while (arch_model) { + if (strcmp(MODEL_LATCH, arch_model->name) == 0) { + if (t_edge == arch_model->inputs[1].trigg_edge) { + //Found it + break; + } + } + arch_model = arch_model->next; + } + if (arch_model) { + //Found it + break; + } + } + if (!arch_model) { + vpr_throw(VPR_ERROR_BLIF_F, filename_.c_str(), lineno_, "Failed to find matching architecture model for '%s' with edge: %d\n", + MODEL_LATCH, t_edge); + } + return arch_model; + } + const t_model_ports* find_model_port(const t_model* blk_model, std::string port_name) { //We need to handle both single, and multi-bit port names // From c653664fd49f564f1dacf7e0a06578d1ae8f6914 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Wed, 23 Nov 2022 10:33:55 +0100 Subject: [PATCH 06/55] vpr: base: atom_netlist_utils: add support for printing netlist with falling edge clocked FFs as blif Signed-off-by: Pawel Czarnecki --- vpr/src/base/atom_netlist_utils.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/vpr/src/base/atom_netlist_utils.cpp b/vpr/src/base/atom_netlist_utils.cpp index cbfed079c25..807bea63474 100644 --- a/vpr/src/base/atom_netlist_utils.cpp +++ b/vpr/src/base/atom_netlist_utils.cpp @@ -189,8 +189,16 @@ void print_netlist_as_blif(FILE* f, const AtomNetlist& netlist) { clk_net = make_unconn(unconn_count, PinType::SINK); } - //Latch type: VPR always assumes rising edge - auto type = "re"; + //Latch type + auto type = "xy"; + if ((blk_model->name == std::string(MODEL_LATCH)) && (blk_model->inputs[1].is_clock)) { + if (blk_model->inputs[1].trigg_edge == TriggeringEdge::FALLING_EDGE) { + type = "fe"; + } else { + //Always assume rising edge + type = "re"; + } + } //Latch initial value int init_val = 3; //Unkown or unspecified From f1089f7ac69a741af7815cb6ccc7c53a8891d18a Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Mon, 21 Nov 2022 17:57:13 +0100 Subject: [PATCH 07/55] Libarchfpga: add internal falling edge clocked .latch model Signed-off-by: Pawel Czarnecki --- libs/libarchfpga/src/arch_util.cpp | 71 +++++++++++++++++++++++++----- 1 file changed, 59 insertions(+), 12 deletions(-) diff --git a/libs/libarchfpga/src/arch_util.cpp b/libs/libarchfpga/src/arch_util.cpp index a8d89c91ed5..614eda785f5 100644 --- a/libs/libarchfpga/src/arch_util.cpp +++ b/libs/libarchfpga/src/arch_util.cpp @@ -172,7 +172,7 @@ void free_arch(t_arch* arch) { vtr::free(arch->architecture_id); if (arch->model_library) { - for (int i = 0; i < 4; ++i) { + for (int i = 0; i < 5; ++i) { vtr::t_linked_vptr* vptr = arch->model_library[i].pb_types; while (vptr) { vtr::t_linked_vptr* vptr_prev = vptr; @@ -194,10 +194,16 @@ void free_arch(t_arch* arch) { vtr::free(arch->model_library[2].outputs->name); delete[] arch->model_library[2].outputs; vtr::free(arch->model_library[3].name); - vtr::free(arch->model_library[3].inputs->name); + vtr::free(arch->model_library[3].inputs[0].name); + vtr::free(arch->model_library[3].inputs[1].name); delete[] arch->model_library[3].inputs; vtr::free(arch->model_library[3].outputs->name); delete[] arch->model_library[3].outputs; + vtr::free(arch->model_library[4].name); + vtr::free(arch->model_library[4].inputs->name); + delete[] arch->model_library[4].inputs; + vtr::free(arch->model_library[4].outputs->name); + delete[] arch->model_library[4].outputs; delete[] arch->model_library; } @@ -1002,7 +1008,7 @@ e_power_estimation_method power_method_inherited(e_power_estimation_method paren void CreateModelLibrary(t_arch* arch) { t_model* model_library; - model_library = new t_model[4]; + model_library = new t_model[5]; //INPAD model_library[0].name = vtr::strdup(MODEL_INPUT); @@ -1034,7 +1040,7 @@ void CreateModelLibrary(t_arch* arch) { model_library[1].next = &model_library[2]; model_library[1].outputs = nullptr; - //LATCH + //LATCH triggered at RISING EDGE model_library[2].name = vtr::strdup(MODEL_LATCH); model_library[2].index = 2; model_library[2].inputs = new t_model_ports[2]; @@ -1047,6 +1053,7 @@ void CreateModelLibrary(t_arch* arch) { model_library[2].inputs[0].index = 0; model_library[2].inputs[0].is_clock = false; model_library[2].inputs[0].clock = "clk"; + model_library[2].inputs[0].trigg_edge = TriggeringEdge::RISING_EDGE; model_library[2].inputs[1].dir = IN_PORT; model_library[2].inputs[1].name = vtr::strdup("clk"); @@ -1055,6 +1062,7 @@ void CreateModelLibrary(t_arch* arch) { model_library[2].inputs[1].min_size = 1; model_library[2].inputs[1].index = 0; model_library[2].inputs[1].is_clock = true; + model_library[2].inputs[1].trigg_edge = TriggeringEdge::RISING_EDGE; model_library[2].instances = nullptr; model_library[2].next = &model_library[3]; @@ -1068,32 +1076,71 @@ void CreateModelLibrary(t_arch* arch) { model_library[2].outputs[0].index = 0; model_library[2].outputs[0].is_clock = false; model_library[2].outputs[0].clock = "clk"; + model_library[2].outputs[0].trigg_edge = TriggeringEdge::RISING_EDGE; - //NAMES - model_library[3].name = vtr::strdup(MODEL_NAMES); + //LATCH triggered at FALLING EDGE + model_library[3].name = vtr::strdup(MODEL_LATCH); model_library[3].index = 3; + model_library[3].inputs = new t_model_ports[2]; - model_library[3].inputs = new t_model_ports[1]; model_library[3].inputs[0].dir = IN_PORT; - model_library[3].inputs[0].name = vtr::strdup("in"); - model_library[3].inputs[0].next = nullptr; + model_library[3].inputs[0].name = vtr::strdup("D"); + model_library[3].inputs[0].next = &model_library[3].inputs[1]; model_library[3].inputs[0].size = 1; model_library[3].inputs[0].min_size = 1; model_library[3].inputs[0].index = 0; model_library[3].inputs[0].is_clock = false; - model_library[3].inputs[0].combinational_sink_ports = {"out"}; + model_library[3].inputs[0].clock = "clk"; + model_library[3].inputs[0].trigg_edge = TriggeringEdge::FALLING_EDGE; + + model_library[3].inputs[1].dir = IN_PORT; + model_library[3].inputs[1].name = vtr::strdup("clk"); + model_library[3].inputs[1].next = nullptr; + model_library[3].inputs[1].size = 1; + model_library[3].inputs[1].min_size = 1; + model_library[3].inputs[1].index = 0; + model_library[3].inputs[1].is_clock = true; + model_library[3].inputs[1].trigg_edge = TriggeringEdge::FALLING_EDGE; model_library[3].instances = nullptr; - model_library[3].next = nullptr; + model_library[3].next = &model_library[4]; model_library[3].outputs = new t_model_ports[1]; model_library[3].outputs[0].dir = OUT_PORT; - model_library[3].outputs[0].name = vtr::strdup("out"); + model_library[3].outputs[0].name = vtr::strdup("Q"); model_library[3].outputs[0].next = nullptr; model_library[3].outputs[0].size = 1; model_library[3].outputs[0].min_size = 1; model_library[3].outputs[0].index = 0; model_library[3].outputs[0].is_clock = false; + model_library[3].outputs[0].clock = "clk"; + model_library[3].outputs[0].trigg_edge = TriggeringEdge::FALLING_EDGE; + + //NAMES + model_library[4].name = vtr::strdup(MODEL_NAMES); + model_library[4].index = 4; + + model_library[4].inputs = new t_model_ports[1]; + model_library[4].inputs[0].dir = IN_PORT; + model_library[4].inputs[0].name = vtr::strdup("in"); + model_library[4].inputs[0].next = nullptr; + model_library[4].inputs[0].size = 1; + model_library[4].inputs[0].min_size = 1; + model_library[4].inputs[0].index = 0; + model_library[4].inputs[0].is_clock = false; + model_library[4].inputs[0].combinational_sink_ports = {"out"}; + + model_library[4].instances = nullptr; + model_library[4].next = nullptr; + + model_library[4].outputs = new t_model_ports[1]; + model_library[4].outputs[0].dir = OUT_PORT; + model_library[4].outputs[0].name = vtr::strdup("out"); + model_library[4].outputs[0].next = nullptr; + model_library[4].outputs[0].size = 1; + model_library[4].outputs[0].min_size = 1; + model_library[4].outputs[0].index = 0; + model_library[4].outputs[0].is_clock = false; arch->model_library = model_library; } From 4253fac020c554a51e95b31bfa6294d7b95433a8 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Fri, 9 Dec 2022 12:36:00 +0100 Subject: [PATCH 08/55] vpr: test_interchange_device: expect second latch model in internal library Signed-off-by: Pawel Czarnecki --- vpr/test/test_interchange_device.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/vpr/test/test_interchange_device.cpp b/vpr/test/test_interchange_device.cpp index 5a0d727558f..7a9e787e72e 100644 --- a/vpr/test/test_interchange_device.cpp +++ b/vpr/test/test_interchange_device.cpp @@ -29,13 +29,14 @@ TEST_CASE("read_interchange_models", "[vpr]") { REQUIRE(models.size() == 0); - std::unordered_set lib_models = {MODEL_INPUT, MODEL_OUTPUT, MODEL_LATCH, MODEL_NAMES}; + std::vector lib_models = {MODEL_INPUT, MODEL_OUTPUT, MODEL_LATCH, MODEL_LATCH, MODEL_NAMES}; // Check that there are exactly the expected models for (auto* model = arch.model_library; model != nullptr; model = model->next) { std::string name = model->name; - REQUIRE(lib_models.find(name) != lib_models.end()); - lib_models.erase(name); + auto it = std::find(lib_models.begin(), lib_models.end(), name); + REQUIRE(it != lib_models.end()); + lib_models.erase(it); } REQUIRE(lib_models.size() == 0); From 560e5ee73c93c727a0d6129d922d137abc1dcb18 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Wed, 23 Nov 2022 10:35:14 +0100 Subject: [PATCH 09/55] vpr: utils: add second variant of primitive_type_feasible() check Signed-off-by: Pawel Czarnecki --- vpr/src/util/vpr_utils.cpp | 86 ++++++++++++++++++++++++++++++++++++++ vpr/src/util/vpr_utils.h | 1 + 2 files changed, 87 insertions(+) diff --git a/vpr/src/util/vpr_utils.cpp b/vpr/src/util/vpr_utils.cpp index fde540f78c2..ba3a26ea7fa 100644 --- a/vpr/src/util/vpr_utils.cpp +++ b/vpr/src/util/vpr_utils.cpp @@ -905,6 +905,92 @@ bool primitive_type_feasible(const AtomBlockId blk_id, const t_pb_type* cur_pb_t //Feasible return true; } +bool primitive_type_feasible(const AtomBlockId blk_id, t_pb_graph_node* curr_pb_graph_node) { + t_pb_type* cur_pb_type = curr_pb_graph_node->pb_type; + + if (cur_pb_type == nullptr) { + return false; + } + + auto& atom_ctx = g_vpr_ctx.atom(); + if (cur_pb_type->model != atom_ctx.nlist.block_model(blk_id)) { + if ((strcmp(atom_ctx.nlist.block_model(blk_id)->name, MODEL_LATCH) == 0) && + (strcmp(atom_ctx.nlist.block_model(blk_id)->name, cur_pb_type->model->name) == 0)) { + /** + * Special case for .latch: this model exists in 2 variations which are + * defined one after another in linked list, check if the second variant match + */ + + if (cur_pb_type->model->next == atom_ctx.nlist.block_model(blk_id) && atom_ctx.nlist.block_model(blk_id)->inputs[1].trigg_edge == TriggeringEdge::FALLING_EDGE) { + //Next primitive match atom - add secondary references + if (!curr_pb_graph_node->has_secondary) + curr_pb_graph_node->update_pins(); + } else { + //Next primitive and atom do not match + return false; + } + } else { + //Primitive and atom do not match + return false; + } + } + + VTR_ASSERT_MSG(atom_ctx.nlist.is_compressed(), "This function assumes a compressed/non-dirty netlist"); + + //Keep track of how many atom ports were checked. + // + //We need to do this since we iterate over the pb's ports and + //may miss some atom ports if there is a mismatch + size_t checked_ports = 0; + + //Look at each port on the pb and find the associated port on the + //atom. To be feasible the pb must have as many pins on each port + //as the atom requires + for (int iport = 0; iport < cur_pb_type->num_ports; ++iport) { + t_port* pb_port; + if(curr_pb_graph_node->has_secondary) + pb_port = &cur_pb_type->ports_sec[iport]; + else + pb_port = &cur_pb_type->ports[iport]; + + const t_model_ports* pb_model_port = pb_port->model_port; + + //Find the matching port on the atom + auto port_id = atom_ctx.nlist.find_atom_port(blk_id, pb_model_port); + + if (port_id) { //Port is used by the atom + + //In compressed form the atom netlist stores only in-use pins, + //so we can query the number of required pins directly + int required_atom_pins = atom_ctx.nlist.port_pins(port_id).size(); + + int available_pb_pins = pb_port->num_pins; + + if (available_pb_pins < required_atom_pins) { + //Too many pins required + return false; + } + + //Note that this port was checked + ++checked_ports; + } + } + + //Similarly to pins, only in-use ports are stored in the compressed + //atom netlist, so we can figure out how many ports should have been + //checked directly + size_t atom_ports = atom_ctx.nlist.block_ports(blk_id).size(); + + //See if all the atom ports were checked + if (checked_ports != atom_ports) { + VTR_ASSERT(checked_ports < atom_ports); + //Required atom port was missing from physical primitive + return false; + } + + //Feasible + return true; +} //Returns the sibling atom of a memory slice pb // Note that the pb must be part of a MEMORY_CLASS diff --git a/vpr/src/util/vpr_utils.h b/vpr/src/util/vpr_utils.h index c4c61692399..924abbdd2ef 100644 --- a/vpr/src/util/vpr_utils.h +++ b/vpr/src/util/vpr_utils.h @@ -109,6 +109,7 @@ int get_max_primitives_in_pb_type(t_pb_type* pb_type); int get_max_depth_of_pb_type(t_pb_type* pb_type); int get_max_nets_in_pb_type(const t_pb_type* pb_type); bool primitive_type_feasible(AtomBlockId blk_id, const t_pb_type* cur_pb_type); +bool primitive_type_feasible(AtomBlockId blk_id, t_pb_graph_node* curr_pb_graph_node); t_pb_graph_pin* get_pb_graph_node_pin_from_model_port_pin(const t_model_ports* model_port, const int model_pin, const t_pb_graph_node* pb_graph_node); const t_pb_graph_pin* find_pb_graph_pin(const AtomNetlist& netlist, const AtomLookup& netlist_lookup, const AtomPinId pin_id); t_pb_graph_pin* get_pb_graph_node_pin_from_block_pin(ClusterBlockId iblock, int ipin); From a82d8d4a9b0fa74cf1127297a3fb804756e21869 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Wed, 7 Dec 2022 14:47:48 +0100 Subject: [PATCH 10/55] vpr: pack: use second primitive_type_feasible() check Signed-off-by: Pawel Czarnecki --- vpr/src/pack/cluster_placement.cpp | 4 ++-- vpr/src/pack/cluster_util.cpp | 2 +- vpr/src/pack/prepack.cpp | 2 +- vpr/src/util/vpr_utils.cpp | 23 +++++++++++------------ 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/vpr/src/pack/cluster_placement.cpp b/vpr/src/pack/cluster_placement.cpp index 602d6696909..3739da4657c 100644 --- a/vpr/src/pack/cluster_placement.cpp +++ b/vpr/src/pack/cluster_placement.cpp @@ -138,7 +138,7 @@ bool get_next_primitive_list(t_cluster_placement_stats* cluster_placement_stats, continue; /* no more primitives of this type available */ } if (primitive_type_feasible(molecule->atom_block_ids[molecule->root], - cluster_placement_stats->valid_primitives[i]->next_primitive->pb_graph_node->pb_type)) { + cluster_placement_stats->valid_primitives[i]->next_primitive->pb_graph_node)) { prev = cluster_placement_stats->valid_primitives[i]; cur = cluster_placement_stats->valid_primitives[i]->next_primitive; while (cur) { @@ -397,7 +397,7 @@ static float try_place_molecule(const t_pack_molecule* molecule, list_size = get_array_size_of_molecule(molecule); if (primitive_type_feasible(molecule->atom_block_ids[molecule->root], - root->pb_type)) { + root)) { if (root->cluster_placement_primitive->valid == true) { for (i = 0; i < list_size; i++) { primitives_list[i] = nullptr; diff --git a/vpr/src/pack/cluster_util.cpp b/vpr/src/pack/cluster_util.cpp index 3a91d13ed40..10dc988b46d 100644 --- a/vpr/src/pack/cluster_util.cpp +++ b/vpr/src/pack/cluster_util.cpp @@ -631,7 +631,7 @@ bool primitive_feasible(const AtomBlockId blk_id, t_pb* cur_pb) { } //Generic feasibility check - return primitive_type_feasible(blk_id, cur_pb_type); + return primitive_type_feasible(blk_id, cur_pb->pb_graph_node); } bool primitive_memory_sibling_feasible(const AtomBlockId blk_id, const t_pb_type* cur_pb_type, const AtomBlockId sibling_blk_id) { diff --git a/vpr/src/pack/prepack.cpp b/vpr/src/pack/prepack.cpp index 3307472ac79..fdd404bbc86 100644 --- a/vpr/src/pack/prepack.cpp +++ b/vpr/src/pack/prepack.cpp @@ -1237,7 +1237,7 @@ static t_pb_graph_node* get_expected_lowest_cost_primitive_for_atom_block_in_pb_ } if (curr_pb_graph_node->pb_type->blif_model != nullptr) { - if (primitive_type_feasible(blk_id, curr_pb_graph_node->pb_type)) { + if (primitive_type_feasible(blk_id, curr_pb_graph_node)) { cur_cost = compute_primitive_base_cost(curr_pb_graph_node); if (best_cost == UNDEFINED || best_cost > cur_cost) { best_cost = cur_cost; diff --git a/vpr/src/util/vpr_utils.cpp b/vpr/src/util/vpr_utils.cpp index ba3a26ea7fa..9efdab006b0 100644 --- a/vpr/src/util/vpr_utils.cpp +++ b/vpr/src/util/vpr_utils.cpp @@ -914,24 +914,23 @@ bool primitive_type_feasible(const AtomBlockId blk_id, t_pb_graph_node* curr_pb_ auto& atom_ctx = g_vpr_ctx.atom(); if (cur_pb_type->model != atom_ctx.nlist.block_model(blk_id)) { - if ((strcmp(atom_ctx.nlist.block_model(blk_id)->name, MODEL_LATCH) == 0) && - (strcmp(atom_ctx.nlist.block_model(blk_id)->name, cur_pb_type->model->name) == 0)) { - /** - * Special case for .latch: this model exists in 2 variations which are - * defined one after another in linked list, check if the second variant match - */ + if ((strcmp(atom_ctx.nlist.block_model(blk_id)->name, MODEL_LATCH) == 0) && (strcmp(atom_ctx.nlist.block_model(blk_id)->name, cur_pb_type->model->name) == 0)) { + /** + * Special case for .latch: this model exists in 2 variations which are + * defined one after another in linked list, check if the second variant match + */ if (cur_pb_type->model->next == atom_ctx.nlist.block_model(blk_id) && atom_ctx.nlist.block_model(blk_id)->inputs[1].trigg_edge == TriggeringEdge::FALLING_EDGE) { //Next primitive match atom - add secondary references if (!curr_pb_graph_node->has_secondary) - curr_pb_graph_node->update_pins(); + curr_pb_graph_node->update_pins(); } else { //Next primitive and atom do not match return false; } } else { - //Primitive and atom do not match - return false; + //Primitive and atom do not match + return false; } } @@ -948,10 +947,10 @@ bool primitive_type_feasible(const AtomBlockId blk_id, t_pb_graph_node* curr_pb_ //as the atom requires for (int iport = 0; iport < cur_pb_type->num_ports; ++iport) { t_port* pb_port; - if(curr_pb_graph_node->has_secondary) - pb_port = &cur_pb_type->ports_sec[iport]; + if (curr_pb_graph_node->has_secondary) + pb_port = &cur_pb_type->ports_sec[iport]; else - pb_port = &cur_pb_type->ports[iport]; + pb_port = &cur_pb_type->ports[iport]; const t_model_ports* pb_model_port = pb_port->model_port; From a1f7c540100a8991c0282276d19e1b86864fe469 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Wed, 7 Dec 2022 14:27:11 +0100 Subject: [PATCH 11/55] libarchfpga: add secondary models to t_pb_type and t_pb_graph_node Introduce secondary t_model and t_port to t_pb_types and secondary input/output/clock_pins in t_pb_graph_node. Also fill those fields with data required for processing. Signed-off-by: Pawel Czarnecki --- libs/libarchfpga/src/arch_util.cpp | 49 ++++++++ libs/libarchfpga/src/physical_types.cpp | 126 ++++++++++++++++++++ libs/libarchfpga/src/physical_types.h | 18 ++- libs/libarchfpga/src/read_xml_arch_file.cpp | 55 +++++---- 4 files changed, 225 insertions(+), 23 deletions(-) diff --git a/libs/libarchfpga/src/arch_util.cpp b/libs/libarchfpga/src/arch_util.cpp index 614eda785f5..642bb61d791 100644 --- a/libs/libarchfpga/src/arch_util.cpp +++ b/libs/libarchfpga/src/arch_util.cpp @@ -326,6 +326,8 @@ static void free_pb_graph(t_pb_graph_node* pb_graph_node) { delete[] pb_graph_node->input_pins[i][j].parent_pin_class; } delete[] pb_graph_node->input_pins[i]; + if (pb_graph_node->has_secondary) + delete[] pb_graph_node->input_pins_sec[i]; } for (i = 0; i < pb_graph_node->num_output_ports; i++) { for (j = 0; j < pb_graph_node->num_output_pins[i]; j++) { @@ -343,6 +345,8 @@ static void free_pb_graph(t_pb_graph_node* pb_graph_node) { delete[] pb_graph_node->output_pins[i][j].num_connectable_primitive_input_pins; } delete[] pb_graph_node->output_pins[i]; + if (pb_graph_node->has_secondary) + delete[] pb_graph_node->output_pins_sec[i]; } for (i = 0; i < pb_graph_node->num_clock_ports; i++) { for (j = 0; j < pb_graph_node->num_clock_pins[i]; j++) { @@ -350,12 +354,20 @@ static void free_pb_graph(t_pb_graph_node* pb_graph_node) { delete[] pb_graph_node->clock_pins[i][j].parent_pin_class; } delete[] pb_graph_node->clock_pins[i]; + if (pb_graph_node->has_secondary) + delete[] pb_graph_node->clock_pins_sec[i]; } delete[] pb_graph_node->input_pins; delete[] pb_graph_node->output_pins; delete[] pb_graph_node->clock_pins; + if (pb_graph_node->has_secondary) { + delete[] pb_graph_node->input_pins_sec; + delete[] pb_graph_node->output_pins_sec; + delete[] pb_graph_node->clock_pins_sec; + } + delete[] pb_graph_node->num_input_pins; delete[] pb_graph_node->num_output_pins; delete[] pb_graph_node->num_clock_pins; @@ -472,14 +484,22 @@ static void free_pb_type(t_pb_type* pb_type) { for (int i = 0; i < pb_type->num_ports; ++i) { vtr::free(pb_type->ports[i].name); + if (pb_type->class_type == LATCH_CLASS) + vtr::free(pb_type->ports_sec[i].name); if (pb_type->ports[i].port_class) { vtr::free(pb_type->ports[i].port_class); + if (pb_type->class_type == LATCH_CLASS) + vtr::free(pb_type->ports_sec[i].port_class); } if (pb_type->ports[i].port_power) { vtr::free(pb_type->ports[i].port_power); + if (pb_type->class_type == LATCH_CLASS) + vtr::free(pb_type->ports_sec[i].port_power); } } vtr::free(pb_type->ports); + if (pb_type->class_type == LATCH_CLASS) + vtr::free(pb_type->ports_sec); } t_port* findPortByName(const char* name, t_pb_type* pb_type, int* high_index, int* low_index) { @@ -622,6 +642,35 @@ void alloc_and_load_default_child_for_pb_type(t_pb_type* pb_type, copy->ports[i].port_power->buffer_type = POWER_BUFFER_TYPE_NONE; } } + // Special case for latch - fill secondary data fields + if (pb_type->class_type == LATCH_CLASS) { + copy->num_ports_sec = pb_type->num_ports; + copy->ports_sec = (t_port*)vtr::calloc(pb_type->num_ports, sizeof(t_port)); + for (i = 0; i < pb_type->num_ports; i++) { + copy->ports_sec[i].is_clock = pb_type->ports[i].is_clock; + copy->ports_sec[i].model_port = pb_type->ports[i].model_port; + copy->ports_sec[i].type = pb_type->ports[i].type; + copy->ports_sec[i].num_pins = pb_type->ports[i].num_pins; + copy->ports_sec[i].parent_pb_type = copy; + copy->ports_sec[i].name = vtr::strdup(pb_type->ports[i].name); + copy->ports_sec[i].port_class = vtr::strdup(pb_type->ports[i].port_class); + copy->ports_sec[i].port_index_by_type = pb_type->ports[i].port_index_by_type; + copy->ports_sec[i].index = pb_type->ports[i].index; + copy->ports_sec[i].absolute_first_pin_index = pb_type->ports[i].absolute_first_pin_index; + + copy->ports_sec[i].port_power = (t_port_power*)vtr::calloc(1, + sizeof(t_port_power)); + //Defaults + if (copy->pb_type_power->estimation_method == POWER_METHOD_AUTO_SIZES) { + copy->ports_sec[i].port_power->wire_type = POWER_WIRE_TYPE_AUTO; + copy->ports_sec[i].port_power->buffer_type = POWER_BUFFER_TYPE_AUTO; + } else if (copy->pb_type_power->estimation_method + == POWER_METHOD_SPECIFY_SIZES) { + copy->ports_sec[i].port_power->wire_type = POWER_WIRE_TYPE_IGNORED; + copy->ports_sec[i].port_power->buffer_type = POWER_BUFFER_TYPE_NONE; + } + } + } copy->annotations = (t_pin_to_pin_annotation*)vtr::calloc(pb_type->num_annotations, sizeof(t_pin_to_pin_annotation)); copy->num_annotations = pb_type->num_annotations; diff --git a/libs/libarchfpga/src/physical_types.cpp b/libs/libarchfpga/src/physical_types.cpp index dfa110f393f..e0fe226f037 100644 --- a/libs/libarchfpga/src/physical_types.cpp +++ b/libs/libarchfpga/src/physical_types.cpp @@ -4,6 +4,7 @@ #include "vtr_log.h" #include "arch_util.h" +#include "arch_types.h" static bool switch_type_is_buffered(SwitchType type); static bool switch_type_is_configurable(SwitchType type); @@ -194,6 +195,131 @@ std::string t_pb_graph_node::hierarchical_type_name() const { return vtr::join(names.rbegin(), names.rend(), "/"); } +void t_pb_graph_node::update_pins() { + int i, j, i_input = 0, i_output = 0, i_clockport = 0; + t_port* pb_type_ports = pb_type->ports_sec; + + VTR_ASSERT(this->has_secondary == false); + this->has_secondary = true; + + int pin_count_in_cluster; + for (i = 0; i < this->pb_type->num_ports; i++) { + if (pb_type_ports[i].model_port) { + VTR_ASSERT(this->pb_type->num_modes == 0); + } else { + VTR_ASSERT(this->pb_type->num_modes != 0 || pb_type_ports[i].is_clock); + } + if (pb_type_ports[i].type == IN_PORT && !pb_type_ports[i].is_clock) { + this->input_pins_sec = new t_pb_graph_pin* [this->num_input_ports] { nullptr }; + this->input_pins_sec[i_input] = new t_pb_graph_pin[pb_type_ports[i].num_pins]; + for (j = 0; j < pb_type_ports[i].num_pins; j++) { + this->input_pins_sec[i_input][j].pin_number = j; + this->input_pins_sec[i_input][j].port = &pb_type_ports[i]; + this->input_pins_sec[i_input][j].parent_node = this; + this->input_pins_sec[i_input][j].pin_count_in_cluster = this->input_pins[i_input][j].pin_count_in_cluster; + this->input_pins_sec[i_input][j].parent_pin_class = this->input_pins[i_input][j].parent_pin_class; + if (this->pb_type->blif_model != nullptr) { + if (strcmp(this->pb_type->blif_model, MODEL_OUTPUT) == 0) { + this->input_pins_sec[i_input][j].type = PB_PIN_OUTPAD; + } else if (this->num_clock_ports != 0) { + this->input_pins_sec[i_input][j].type = PB_PIN_SEQUENTIAL; + } else { + this->input_pins_sec[i_input][j].type = PB_PIN_TERMINAL; + } + } + pin_count_in_cluster++; + + //Copy timings from primary pins + // sequential timing information + this->input_pins_sec[i_input][j].tsu = this->input_pins[i_input][j].tsu; + this->input_pins_sec[i_input][j].thld = this->input_pins[i_input][j].thld; + this->input_pins_sec[i_input][j].tco_min = this->input_pins[i_input][j].tco_min; + this->input_pins_sec[i_input][j].tco_max = this->input_pins[i_input][j].tco_max; + //this->input_pins_sec[i_input][j].t_pb_graph_pin* associated_clock_pin = nullptr; /* For sequentail elements, the associated clock */ + + // combinational timing information + this->input_pins_sec[i_input][j].num_pin_timing = this->input_pins[i_input][j].num_pin_timing; + this->input_pins_sec[i_input][j].pin_timing_del_max = this->input_pins[i_input][j].pin_timing_del_max; + this->input_pins_sec[i_input][j].pin_timing_del_min = this->input_pins[i_input][j].pin_timing_del_min; + this->input_pins_sec[i_input][j].num_pin_timing_del_max_annotated = this->input_pins[i_input][j].num_pin_timing_del_max_annotated; + this->input_pins_sec[i_input][j].num_pin_timing_del_min_annotated = this->input_pins[i_input][j].num_pin_timing_del_min_annotated; + //this->input_pins_sec[i_input][j].std::vector pin_timing; /* timing edge sink pins [0..num_pin_timing-1]*/ + } + i_input++; + } else if (pb_type_ports[i].type == OUT_PORT) { + this->output_pins_sec = new t_pb_graph_pin* [this->num_input_ports] { nullptr }; + this->output_pins_sec[i_output] = new t_pb_graph_pin[pb_type_ports[i].num_pins]; + for (j = 0; j < pb_type_ports[i].num_pins; j++) { + this->output_pins_sec[i_output][j].pin_number = j; + this->output_pins_sec[i_output][j].port = &pb_type_ports[i]; + this->output_pins_sec[i_output][j].parent_node = this; + this->output_pins_sec[i_output][j].pin_count_in_cluster = this->output_pins[i_output][j].pin_count_in_cluster; + this->output_pins_sec[i_output][j].parent_pin_class = this->output_pins[i_output][j].parent_pin_class; + this->output_pins_sec[i_output][j].list_of_connectable_input_pin_ptrs = this->output_pins[i_output][j].list_of_connectable_input_pin_ptrs; + this->output_pins_sec[i_output][j].num_connectable_primitive_input_pins = this->output_pins[i_output][j].num_connectable_primitive_input_pins; + if (this->pb_type->blif_model != nullptr) { + if (strcmp(this->pb_type->blif_model, MODEL_INPUT) == 0) { + this->output_pins_sec[i_output][j].type = PB_PIN_INPAD; + } else if (this->num_clock_ports != 0) { + this->output_pins_sec[i_output][j].type = PB_PIN_SEQUENTIAL; + } else { + this->output_pins_sec[i_output][j].type = PB_PIN_TERMINAL; + } + } + pin_count_in_cluster++; + + //Copy timings from primary pins + // sequential timing information + this->output_pins_sec[i_output][j].tsu = this->output_pins[i_output][j].tsu; + this->output_pins_sec[i_output][j].thld = this->output_pins[i_output][j].thld; + this->output_pins_sec[i_output][j].tco_min = this->output_pins[i_output][j].tco_min; + this->output_pins_sec[i_output][j].tco_max = this->output_pins[i_output][j].tco_max; + //this->output_pins_sec[i_input][j].t_pb_graph_pin* associated_clock_pin = nullptr; /* For sequentail elements, the associated clock */ + + // combinational timing information + this->output_pins_sec[i_output][j].num_pin_timing = this->output_pins[i_output][j].num_pin_timing; + this->output_pins_sec[i_output][j].pin_timing_del_max = this->output_pins[i_output][j].pin_timing_del_max; + this->output_pins_sec[i_output][j].pin_timing_del_min = this->output_pins[i_output][j].pin_timing_del_min; + this->output_pins_sec[i_output][j].num_pin_timing_del_max_annotated = this->output_pins[i_output][j].num_pin_timing_del_max_annotated; + this->output_pins_sec[i_output][j].num_pin_timing_del_min_annotated = this->output_pins[i_output][j].num_pin_timing_del_min_annotated; + //this->output_pins_sec[i_input][j].std::vector pin_timing; /* timing edge sink pins [0..num_pin_timing-1]*/ + } + i_output++; + } else { + VTR_ASSERT(pb_type_ports[i].is_clock && pb_type_ports[i].type == IN_PORT); + this->clock_pins_sec = new t_pb_graph_pin* [this->num_input_ports] { nullptr }; + this->clock_pins_sec[i_clockport] = new t_pb_graph_pin[pb_type_ports[i].num_pins]; + for (j = 0; j < pb_type_ports[i].num_pins; j++) { + this->clock_pins_sec[i_clockport][j].pin_number = j; + this->clock_pins_sec[i_clockport][j].port = &pb_type_ports[i]; + this->clock_pins_sec[i_clockport][j].parent_node = this; + this->clock_pins_sec[i_clockport][j].pin_count_in_cluster = this->clock_pins[i_clockport][j].pin_count_in_cluster; + this->clock_pins_sec[i_clockport][j].parent_pin_class = this->clock_pins[i_clockport][j].parent_pin_class; + if (this->pb_type->blif_model != nullptr) { + this->clock_pins_sec[i_clockport][j].type = PB_PIN_CLOCK; + } + pin_count_in_cluster++; + + //Copy timings from primary pins + // sequential timing information + this->clock_pins_sec[i_clockport][j].tsu = this->clock_pins[i_clockport][j].tsu; + this->clock_pins_sec[i_clockport][j].thld = this->clock_pins[i_clockport][j].thld; + this->clock_pins_sec[i_clockport][j].tco_min = this->clock_pins[i_clockport][j].tco_min; + this->clock_pins_sec[i_clockport][j].tco_max = this->clock_pins[i_clockport][j].tco_max; + //this->clock_pins_sec[i_clockport][j].t_pb_graph_pin* associated_clock_pin = nullptr; /* For sequentail elements, the associated clock */ + + // combinational timing information + this->clock_pins_sec[i_clockport][j].num_pin_timing = this->clock_pins[i_clockport][j].num_pin_timing; + this->clock_pins_sec[i_clockport][j].pin_timing_del_max = this->clock_pins[i_clockport][j].pin_timing_del_max; + this->clock_pins_sec[i_clockport][j].pin_timing_del_min = this->clock_pins[i_clockport][j].pin_timing_del_min; + this->clock_pins_sec[i_clockport][j].num_pin_timing_del_max_annotated = this->clock_pins[i_clockport][j].num_pin_timing_del_max_annotated; + this->clock_pins_sec[i_clockport][j].num_pin_timing_del_min_annotated = this->clock_pins[i_clockport][j].num_pin_timing_del_min_annotated; + //this->clock_pins_sec[i_clockport][j].std::vector pin_timing; /* timing edge sink pins [0..num_pin_timing-1]*/ + } + i_clockport++; + } + } +} /** * t_pb_graph_pin */ diff --git a/libs/libarchfpga/src/physical_types.h b/libs/libarchfpga/src/physical_types.h index 922bf1f7ec7..d43bbe38909 100644 --- a/libs/libarchfpga/src/physical_types.h +++ b/libs/libarchfpga/src/physical_types.h @@ -910,9 +910,12 @@ struct t_logical_block_type { * name: name of the physical block type * num_pb: maximum number of instances of this physical block type sharing one parent * blif_model: the string in the blif circuit that corresponds with this pb type + * model: logical model + * model_sec: secondary logical model - used for pb_types matched to 2 available .latch models * class_type: Special library name * modes: Different modes accepted * ports: I/O and clock ports + * ports_sec: secondary I/O and clock ports - used for pb_types matched to 2 available .latch models * num_clock_pins: A count of the total number of clock pins * num_input_pins: A count of the total number of input pins * num_output_pins: A count of the total number of output pins @@ -927,12 +930,15 @@ struct t_pb_type { int num_pb = 0; char* blif_model = nullptr; t_model* model = nullptr; + t_model* model_sec = nullptr; enum e_pb_type_class class_type = UNKNOWN_CLASS; t_mode* modes = nullptr; /* [0..num_modes-1] */ int num_modes = 0; t_port* ports = nullptr; /* [0..num_ports] */ int num_ports = 0; + t_port* ports_sec = nullptr; /* [0..num_ports] */ + int num_ports_sec = 0; int num_clock_pins = 0; int num_input_pins = 0; /* inputs not including clock pins */ @@ -1166,6 +1172,7 @@ struct t_pin_to_pin_annotation { class t_pb_graph_node { public: t_pb_type* pb_type; + bool has_secondary; int placement_index; @@ -1189,9 +1196,12 @@ class t_pb_graph_node { * */ std::vector illegal_modes; - t_pb_graph_pin** input_pins; /* [0..num_input_ports-1] [0..num_port_pins-1]*/ - t_pb_graph_pin** output_pins; /* [0..num_output_ports-1] [0..num_port_pins-1]*/ - t_pb_graph_pin** clock_pins; /* [0..num_clock_ports-1] [0..num_port_pins-1]*/ + t_pb_graph_pin** input_pins; /* [0..num_input_ports-1] [0..num_port_pins-1]*/ + t_pb_graph_pin** output_pins; /* [0..num_output_ports-1] [0..num_port_pins-1]*/ + t_pb_graph_pin** clock_pins; /* [0..num_clock_ports-1] [0..num_port_pins-1]*/ + t_pb_graph_pin** input_pins_sec; /* [0..num_input_ports-1] [0..num_port_pins-1]*/ + t_pb_graph_pin** output_pins_sec; /* [0..num_output_ports-1] [0..num_port_pins-1]*/ + t_pb_graph_pin** clock_pins_sec; /* [0..num_clock_ports-1] [0..num_port_pins-1]*/ int num_input_ports; int num_output_ports; @@ -1234,6 +1244,8 @@ class t_pb_graph_node { // Returns a string containing the hierarchical type name of the pb_graph_node // Ex: clb[0][default]/lab[0][default]/fle[3][n1_lut6]/ble6[0][default]/lut6[0] std::string hierarchical_type_name() const; + + void update_pins(); }; /* Identify pb pin type for timing purposes */ diff --git a/libs/libarchfpga/src/read_xml_arch_file.cpp b/libs/libarchfpga/src/read_xml_arch_file.cpp index 632bf2f54b4..e1852ae5d54 100644 --- a/libs/libarchfpga/src/read_xml_arch_file.cpp +++ b/libs/libarchfpga/src/read_xml_arch_file.cpp @@ -1191,6 +1191,8 @@ static void ProcessPb_Type(vtr::string_internment* strings, pugi::xml_node Paren num_clock_ports = count_children(Parent, "clock", loc_data, ReqOpt::OPTIONAL); num_ports = num_in_ports + num_out_ports + num_clock_ports; pb_type->ports = (t_port*)vtr::calloc(num_ports, sizeof(t_port)); + if (pb_type->class_type == LATCH_CLASS) + pb_type->ports_sec = (t_port*)vtr::calloc(num_ports, sizeof(t_port)); pb_type->num_ports = num_ports; /* Enforce VPR's definition of LUT/FF by checking number of ports */ @@ -1226,21 +1228,28 @@ static void ProcessPb_Type(vtr::string_internment* strings, pugi::xml_node Paren Cur = get_first_child(Parent, "clock", loc_data, ReqOpt::OPTIONAL); } while (Cur) { - pb_type->ports[j].parent_pb_type = pb_type; - pb_type->ports[j].index = j; - pb_type->ports[j].port_index_by_type = k; - ProcessPb_TypePort(Cur, &pb_type->ports[j], - pb_type->pb_type_power->estimation_method, is_root_pb_type, loc_data); - - pb_type->ports[j].absolute_first_pin_index = absolute_port_first_pin_index; - absolute_port_first_pin_index += pb_type->ports[j].num_pins; + t_port* pb_type_ports = pb_type->ports; + int l = 0; + do { + pb_type_ports[j].parent_pb_type = pb_type; + pb_type_ports[j].index = j; + pb_type_ports[j].port_index_by_type = k; + ProcessPb_TypePort(Cur, &pb_type_ports[j], + pb_type->pb_type_power->estimation_method, is_root_pb_type, loc_data); + + pb_type_ports[j].absolute_first_pin_index = absolute_port_first_pin_index; + absolute_port_first_pin_index += pb_type_ports[j].num_pins; + + pb_type_ports = pb_type->ports_sec; + l++; + } while ((pb_type->class_type == LATCH_CLASS) && (l <= 1)); //Check port name duplicates ret_pb_ports = pb_port_names.insert(std::pair(pb_type->ports[j].name, 0)); if (!ret_pb_ports.second) { archfpga_throw(loc_data.filename_c_str(), loc_data.line(Cur), "Duplicate port names in pb_type '%s': port '%s'\n", - pb_type->name, pb_type->ports[j].name); + pb_type->name, pb_type_ports[j].name); } /* get next iteration */ @@ -1254,18 +1263,24 @@ static void ProcessPb_Type(vtr::string_internment* strings, pugi::xml_node Paren /* Count stats on the number of each type of pin */ pb_type->num_clock_pins = pb_type->num_input_pins = pb_type->num_output_pins = 0; - for (i = 0; i < pb_type->num_ports; i++) { - if (pb_type->ports[i].type == IN_PORT - && pb_type->ports[i].is_clock == false) { - pb_type->num_input_pins += pb_type->ports[i].num_pins; - } else if (pb_type->ports[i].type == OUT_PORT) { - pb_type->num_output_pins += pb_type->ports[i].num_pins; - } else { - VTR_ASSERT(pb_type->ports[i].is_clock - && pb_type->ports[i].type == IN_PORT); - pb_type->num_clock_pins += pb_type->ports[i].num_pins; + t_port* pb_type_ports = pb_type->ports; + int l = 0; + do { + for (i = 0; i < pb_type->num_ports; i++) { + if (pb_type_ports[i].type == IN_PORT + && pb_type_ports[i].is_clock == false) { + pb_type->num_input_pins += pb_type_ports[i].num_pins; + } else if (pb_type_ports[i].type == OUT_PORT) { + pb_type->num_output_pins += pb_type_ports[i].num_pins; + } else { + VTR_ASSERT(pb_type_ports[i].is_clock + && pb_type_ports[i].type == IN_PORT); + pb_type->num_clock_pins += pb_type_ports[i].num_pins; + } } - } + pb_type_ports = pb_type->ports_sec; + l++; + } while ((pb_type->class_type == LATCH_CLASS) && (l <= 1)); pb_type->num_pins = pb_type->num_input_pins + pb_type->num_output_pins + pb_type->num_clock_pins; From 725bc6b4ccabe74b64253031cee487da101afbd5 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Wed, 7 Dec 2022 14:05:09 +0100 Subject: [PATCH 12/55] libarchfpga: SyncModelsPbTypes: sync secondary models Signed-off-by: Pawel Czarnecki --- libs/libarchfpga/src/arch_util.cpp | 155 +++++++++++++++++------------ libs/libarchfpga/src/arch_util.h | 4 + 2 files changed, 95 insertions(+), 64 deletions(-) diff --git a/libs/libarchfpga/src/arch_util.cpp b/libs/libarchfpga/src/arch_util.cpp index 642bb61d791..f9e9ac7c577 100644 --- a/libs/libarchfpga/src/arch_util.cpp +++ b/libs/libarchfpga/src/arch_util.cpp @@ -1194,6 +1194,82 @@ void CreateModelLibrary(t_arch* arch) { arch->model_library = model_library; } +void SyncModel(t_pb_type* pb_type, t_model* model_match_prim, bool is_secondary_model) { + vtr::t_linked_vptr* old; + bool found; + t_model_ports* model_port; + t_port* pb_type_ports; + int p; + + if (is_secondary_model) { + pb_type->model_sec = model_match_prim; + pb_type_ports = pb_type->ports_sec; + } else { + pb_type->model = model_match_prim; + pb_type_ports = pb_type->ports; + } + + old = model_match_prim->pb_types; + model_match_prim->pb_types = (vtr::t_linked_vptr*)vtr::malloc(sizeof(vtr::t_linked_vptr)); + model_match_prim->pb_types->next = old; + model_match_prim->pb_types->data_vptr = pb_type; + for (p = 0; p < pb_type->num_ports; p++) { + found = false; + /* TODO: Parse error checking - check if INPUT matches INPUT and OUTPUT matches OUTPUT (not yet done) */ + model_port = model_match_prim->inputs; + while (model_port && !found) { + if (strcmp(model_port->name, pb_type_ports[p].name) == 0) { + if (model_port->size < pb_type_ports[p].num_pins) { + model_port->size = pb_type_ports[p].num_pins; + } + if (model_port->min_size > pb_type_ports[p].num_pins + || model_port->min_size == -1) { + model_port->min_size = pb_type_ports[p].num_pins; + } + pb_type_ports[p].model_port = model_port; + if (pb_type_ports[p].type != model_port->dir) { + archfpga_throw(get_arch_file_name(), 0, + "Direction for port '%s' on model does not match port direction in pb_type '%s', secondary: %d\n", + pb_type_ports[p].name, pb_type->name, is_secondary_model); + } + if (pb_type_ports[p].is_clock != model_port->is_clock) { + archfpga_throw(get_arch_file_name(), 0, + "Port '%s' on model does not match is_clock in pb_type '%s', secondary: %d\n", + pb_type_ports[p].name, pb_type->name, is_secondary_model); + } + found = true; + } + model_port = model_port->next; + } + model_port = model_match_prim->outputs; + while (model_port && !found) { + if (strcmp(model_port->name, pb_type_ports[p].name) == 0) { + if (model_port->size < pb_type_ports[p].num_pins) { + model_port->size = pb_type_ports[p].num_pins; + } + if (model_port->min_size > pb_type_ports[p].num_pins + || model_port->min_size == -1) { + model_port->min_size = pb_type_ports[p].num_pins; + } + + pb_type_ports[p].model_port = model_port; + if (pb_type_ports[p].type != model_port->dir) { + archfpga_throw(get_arch_file_name(), 0, + "Direction for port '%s' on model does not match port direction in pb_type '%s', secondary: %d\n", + pb_type_ports[p].name, pb_type->name, is_secondary_model); + } + found = true; + } + model_port = model_port->next; + } + if (found != true) { + archfpga_throw(get_arch_file_name(), 0, + "No matching model port for port %s in pb_type %s, secondary: %d\n", + pb_type_ports[p].name, pb_type->name, is_secondary_model); + } + } +} + void SyncModelsPbTypes(t_arch* arch, const std::vector& Types) { for (auto& Type : Types) { @@ -1205,12 +1281,10 @@ void SyncModelsPbTypes(t_arch* arch, void SyncModelsPbTypes_rec(t_arch* arch, t_pb_type* pb_type) { - int i, j, p; + int i, j; t_model *model_match_prim, *cur_model; - t_model_ports* model_port; - vtr::t_linked_vptr* old; char* blif_model_name = nullptr; - + bool sync_secondary_model = false; bool found; if (pb_type->blif_model != nullptr) { @@ -1239,6 +1313,15 @@ void SyncModelsPbTypes_rec(t_arch* arch, while (cur_model && !found) { /* blif model always starts with .subckt so need to skip first 8 characters */ if (strcmp(blif_model_name, cur_model->name) == 0) { + if (strcmp(blif_model_name, MODEL_LATCH) == 0) { + /** + * Special case for .latch: this model exists in 2 variations which are + * defined one after another in linked list, make sure the second variant match + * and mark secondary model for sync. + */ + VTR_ASSERT(strcmp(blif_model_name, cur_model->next->name) == 0); + sync_secondary_model = true; + } found = true; model_match_prim = cur_model; } @@ -1249,67 +1332,11 @@ void SyncModelsPbTypes_rec(t_arch* arch, "No matching model for pb_type %s\n", pb_type->blif_model); } - pb_type->model = model_match_prim; - old = model_match_prim->pb_types; - model_match_prim->pb_types = (vtr::t_linked_vptr*)vtr::malloc(sizeof(vtr::t_linked_vptr)); - model_match_prim->pb_types->next = old; - model_match_prim->pb_types->data_vptr = pb_type; - - for (p = 0; p < pb_type->num_ports; p++) { - found = false; - /* TODO: Parse error checking - check if INPUT matches INPUT and OUTPUT matches OUTPUT (not yet done) */ - model_port = model_match_prim->inputs; - while (model_port && !found) { - if (strcmp(model_port->name, pb_type->ports[p].name) == 0) { - if (model_port->size < pb_type->ports[p].num_pins) { - model_port->size = pb_type->ports[p].num_pins; - } - if (model_port->min_size > pb_type->ports[p].num_pins - || model_port->min_size == -1) { - model_port->min_size = pb_type->ports[p].num_pins; - } - pb_type->ports[p].model_port = model_port; - if (pb_type->ports[p].type != model_port->dir) { - archfpga_throw(get_arch_file_name(), 0, - "Direction for port '%s' on model does not match port direction in pb_type '%s'\n", - pb_type->ports[p].name, pb_type->name); - } - if (pb_type->ports[p].is_clock != model_port->is_clock) { - archfpga_throw(get_arch_file_name(), 0, - "Port '%s' on model does not match is_clock in pb_type '%s'\n", - pb_type->ports[p].name, pb_type->name); - } - found = true; - } - model_port = model_port->next; - } - model_port = model_match_prim->outputs; - while (model_port && !found) { - if (strcmp(model_port->name, pb_type->ports[p].name) == 0) { - if (model_port->size < pb_type->ports[p].num_pins) { - model_port->size = pb_type->ports[p].num_pins; - } - if (model_port->min_size > pb_type->ports[p].num_pins - || model_port->min_size == -1) { - model_port->min_size = pb_type->ports[p].num_pins; - } + SyncModel(pb_type, model_match_prim, false); + // Synchronize secondary model + if (sync_secondary_model) + SyncModel(pb_type, model_match_prim->next, true); - pb_type->ports[p].model_port = model_port; - if (pb_type->ports[p].type != model_port->dir) { - archfpga_throw(get_arch_file_name(), 0, - "Direction for port '%s' on model does not match port direction in pb_type '%s'\n", - pb_type->ports[p].name, pb_type->name); - } - found = true; - } - model_port = model_port->next; - } - if (found != true) { - archfpga_throw(get_arch_file_name(), 0, - "No matching model port for port %s in pb_type %s\n", - pb_type->ports[p].name, pb_type->name); - } - } } else { for (i = 0; i < pb_type->num_modes; i++) { for (j = 0; j < pb_type->modes[i].num_pb_type_children; j++) { diff --git a/libs/libarchfpga/src/arch_util.h b/libs/libarchfpga/src/arch_util.h index 7d882450a5a..45d8133fc57 100644 --- a/libs/libarchfpga/src/arch_util.h +++ b/libs/libarchfpga/src/arch_util.h @@ -86,6 +86,10 @@ e_power_estimation_method power_method_inherited(e_power_estimation_method paren void CreateModelLibrary(t_arch* arch); +void SyncModel(t_pb_type* pb_type, + t_model* model_match_prim, + bool is_secondary_model); + void SyncModelsPbTypes(t_arch* arch, const std::vector& Types); From 9033994ea4b41543f69fb3a14156d09872e36079 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Wed, 7 Dec 2022 14:45:25 +0100 Subject: [PATCH 13/55] vpr: utils: use primary or secondary pins Signed-off-by: Pawel Czarnecki --- vpr/src/util/vpr_utils.cpp | 39 +++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/vpr/src/util/vpr_utils.cpp b/vpr/src/util/vpr_utils.cpp index 9efdab006b0..9e828dd5509 100644 --- a/vpr/src/util/vpr_utils.cpp +++ b/vpr/src/util/vpr_utils.cpp @@ -1021,20 +1021,32 @@ t_pb_graph_pin* get_pb_graph_node_pin_from_model_port_pin(const t_model_ports* m if (model_port->dir == IN_PORT) { if (model_port->is_clock == false) { + t_pb_graph_pin** input_pins; + if (model_port->trigg_edge == TriggeringEdge::FALLING_EDGE) + input_pins = pb_graph_node->input_pins_sec; + else + input_pins = pb_graph_node->input_pins; + for (i = 0; i < pb_graph_node->num_input_ports; i++) { - if (pb_graph_node->input_pins[i][0].port->model_port == model_port) { + if (input_pins[i][0].port->model_port == model_port) { if (pb_graph_node->num_input_pins[i] > model_pin) { - return &pb_graph_node->input_pins[i][model_pin]; + return &input_pins[i][model_pin]; } else { return nullptr; } } } } else { + t_pb_graph_pin** clock_pins; + if (model_port->trigg_edge == TriggeringEdge::FALLING_EDGE) + clock_pins = pb_graph_node->clock_pins_sec; + else + clock_pins = pb_graph_node->clock_pins; + for (i = 0; i < pb_graph_node->num_clock_ports; i++) { - if (pb_graph_node->clock_pins[i][0].port->model_port == model_port) { + if (clock_pins[i][0].port->model_port == model_port) { if (pb_graph_node->num_clock_pins[i] > model_pin) { - return &pb_graph_node->clock_pins[i][model_pin]; + return &clock_pins[i][model_pin]; } else { return nullptr; } @@ -1043,10 +1055,16 @@ t_pb_graph_pin* get_pb_graph_node_pin_from_model_port_pin(const t_model_ports* m } } else { VTR_ASSERT(model_port->dir == OUT_PORT); + t_pb_graph_pin** output_pins; + if (model_port->trigg_edge == TriggeringEdge::FALLING_EDGE) + output_pins = pb_graph_node->output_pins_sec; + else + output_pins = pb_graph_node->output_pins; + for (i = 0; i < pb_graph_node->num_output_ports; i++) { - if (pb_graph_node->output_pins[i][0].port->model_port == model_port) { + if (output_pins[i][0].port->model_port == model_port) { if (pb_graph_node->num_output_pins[i] > model_pin) { - return &pb_graph_node->output_pins[i][model_pin]; + return &output_pins[i][model_pin]; } else { return nullptr; } @@ -1096,7 +1114,14 @@ const t_pb_graph_pin* find_pb_graph_pin(const AtomNetlist& netlist, const AtomLo VTR_ASSERT(pb_gnode); //The graph node and pin/block should agree on the model they represent - VTR_ASSERT(netlist.block_model(blk_id) == pb_gnode->pb_type->model); + if (strcmp(netlist.block_model(blk_id)->name, MODEL_LATCH) == 0) { + if (netlist.block_model(blk_id)->inputs->trigg_edge == TriggeringEdge::FALLING_EDGE) + VTR_ASSERT(netlist.block_model(blk_id) == pb_gnode->pb_type->model_sec); + else + VTR_ASSERT(netlist.block_model(blk_id) == pb_gnode->pb_type->model); + } else { + VTR_ASSERT(netlist.block_model(blk_id) == pb_gnode->pb_type->model); + } //Get the pin index AtomPortId port_id = netlist.pin_port(pin_id); From c1004c1c2c35a9fdf80df9e0b4b3cd5d171a780f Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Wed, 7 Dec 2022 14:37:50 +0100 Subject: [PATCH 14/55] pack: pb_type_graph: use primary or secondary ports Signed-off-by: Pawel Czarnecki --- vpr/src/pack/pb_type_graph.cpp | 41 ++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/vpr/src/pack/pb_type_graph.cpp b/vpr/src/pack/pb_type_graph.cpp index 983d6efed68..c4c080b3e30 100644 --- a/vpr/src/pack/pb_type_graph.cpp +++ b/vpr/src/pack/pb_type_graph.cpp @@ -257,18 +257,25 @@ static void alloc_and_load_pb_graph(t_pb_graph_node* pb_graph_node, } i_input = i_output = i_clockport = 0; + t_port* pb_type_ports; for (i = 0; i < pb_type->num_ports; i++) { - if (pb_type->ports[i].model_port) { + if (pb_graph_node->has_secondary) { + pb_type_ports = pb_type->ports_sec; + } else { + pb_type_ports = pb_type->ports; + } + + if (pb_type_ports[i].model_port) { VTR_ASSERT(pb_type->num_modes == 0); } else { - VTR_ASSERT(pb_type->num_modes != 0 || pb_type->ports[i].is_clock); + VTR_ASSERT(pb_type->num_modes != 0 || pb_type_ports[i].is_clock); } - if (pb_type->ports[i].type == IN_PORT && !pb_type->ports[i].is_clock) { - pb_graph_node->input_pins[i_input] = new t_pb_graph_pin[pb_type->ports[i].num_pins]; - pb_graph_node->num_input_pins[i_input] = pb_type->ports[i].num_pins; - for (j = 0; j < pb_type->ports[i].num_pins; j++) { + if (pb_type_ports[i].type == IN_PORT && !pb_type_ports[i].is_clock) { + pb_graph_node->input_pins[i_input] = new t_pb_graph_pin[pb_type_ports[i].num_pins]; + pb_graph_node->num_input_pins[i_input] = pb_type_ports[i].num_pins; + for (j = 0; j < pb_type_ports[i].num_pins; j++) { pb_graph_node->input_pins[i_input][j].pin_number = j; - pb_graph_node->input_pins[i_input][j].port = &pb_type->ports[i]; + pb_graph_node->input_pins[i_input][j].port = &pb_type_ports[i]; pb_graph_node->input_pins[i_input][j].parent_node = pb_graph_node; pb_graph_node->input_pins[i_input][j].pin_count_in_cluster = pin_count_in_cluster; if (pb_graph_node->pb_type->blif_model != nullptr) { @@ -283,12 +290,12 @@ static void alloc_and_load_pb_graph(t_pb_graph_node* pb_graph_node, pin_count_in_cluster++; } i_input++; - } else if (pb_type->ports[i].type == OUT_PORT) { - pb_graph_node->output_pins[i_output] = new t_pb_graph_pin[pb_type->ports[i].num_pins]; - pb_graph_node->num_output_pins[i_output] = pb_type->ports[i].num_pins; - for (j = 0; j < pb_type->ports[i].num_pins; j++) { + } else if (pb_type_ports[i].type == OUT_PORT) { + pb_graph_node->output_pins[i_output] = new t_pb_graph_pin[pb_type_ports[i].num_pins]; + pb_graph_node->num_output_pins[i_output] = pb_type_ports[i].num_pins; + for (j = 0; j < pb_type_ports[i].num_pins; j++) { pb_graph_node->output_pins[i_output][j].pin_number = j; - pb_graph_node->output_pins[i_output][j].port = &pb_type->ports[i]; + pb_graph_node->output_pins[i_output][j].port = &pb_type_ports[i]; pb_graph_node->output_pins[i_output][j].parent_node = pb_graph_node; pb_graph_node->output_pins[i_output][j].pin_count_in_cluster = pin_count_in_cluster; if (pb_graph_node->pb_type->blif_model != nullptr) { @@ -304,12 +311,12 @@ static void alloc_and_load_pb_graph(t_pb_graph_node* pb_graph_node, } i_output++; } else { - VTR_ASSERT(pb_type->ports[i].is_clock && pb_type->ports[i].type == IN_PORT); - pb_graph_node->clock_pins[i_clockport] = new t_pb_graph_pin[pb_type->ports[i].num_pins]; - pb_graph_node->num_clock_pins[i_clockport] = pb_type->ports[i].num_pins; - for (j = 0; j < pb_type->ports[i].num_pins; j++) { + VTR_ASSERT(pb_type_ports[i].is_clock && pb_type_ports[i].type == IN_PORT); + pb_graph_node->clock_pins[i_clockport] = new t_pb_graph_pin[pb_type_ports[i].num_pins]; + pb_graph_node->num_clock_pins[i_clockport] = pb_type_ports[i].num_pins; + for (j = 0; j < pb_type_ports[i].num_pins; j++) { pb_graph_node->clock_pins[i_clockport][j].pin_number = j; - pb_graph_node->clock_pins[i_clockport][j].port = &pb_type->ports[i]; + pb_graph_node->clock_pins[i_clockport][j].port = &pb_type_ports[i]; pb_graph_node->clock_pins[i_clockport][j].parent_node = pb_graph_node; pb_graph_node->clock_pins[i_clockport][j].pin_count_in_cluster = pin_count_in_cluster; if (pb_graph_node->pb_type->blif_model != nullptr) { From 4df34e1f96488a75d7d447499a3a25ee9f6ba829 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Wed, 7 Dec 2022 14:32:58 +0100 Subject: [PATCH 15/55] base: read netlist: always assign primary pins Signed-off-by: Pawel Czarnecki --- vpr/src/base/read_netlist.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/vpr/src/base/read_netlist.cpp b/vpr/src/base/read_netlist.cpp index 9195721a012..29d9852aa83 100644 --- a/vpr/src/base/read_netlist.cpp +++ b/vpr/src/base/read_netlist.cpp @@ -1174,14 +1174,18 @@ static void load_atom_pin_mapping(const ClusteredNetlist& clb_nlist) { VTR_ASSERT_MSG(gnode->pb_type->model == atom_ctx.nlist.block_model(blk), "Atom block PB must match BLIF model"); + // Always assign primary pins + t_pb_graph_pin* pins; + for (int iport = 0; iport < gnode->num_input_ports; ++iport) { if (gnode->num_input_pins[iport] <= 0) continue; + pins = gnode->input_pins[iport]; - const AtomPortId port = atom_ctx.nlist.find_atom_port(blk, gnode->input_pins[iport][0].port->model_port); + const AtomPortId port = atom_ctx.nlist.find_atom_port(blk, pins[0].port->model_port); if (!port) continue; for (int ipin = 0; ipin < gnode->num_input_pins[iport]; ++ipin) { - const t_pb_graph_pin* gpin = &gnode->input_pins[iport][ipin]; + const t_pb_graph_pin* gpin = &pins[ipin]; VTR_ASSERT(gpin); set_atom_pin_mapping(clb_nlist, blk, port, gpin); @@ -1190,12 +1194,13 @@ static void load_atom_pin_mapping(const ClusteredNetlist& clb_nlist) { for (int iport = 0; iport < gnode->num_output_ports; ++iport) { if (gnode->num_output_pins[iport] <= 0) continue; + pins = gnode->output_pins[iport]; - const AtomPortId port = atom_ctx.nlist.find_atom_port(blk, gnode->output_pins[iport][0].port->model_port); + const AtomPortId port = atom_ctx.nlist.find_atom_port(blk, pins[0].port->model_port); if (!port) continue; for (int ipin = 0; ipin < gnode->num_output_pins[iport]; ++ipin) { - const t_pb_graph_pin* gpin = &gnode->output_pins[iport][ipin]; + const t_pb_graph_pin* gpin = &pins[ipin]; VTR_ASSERT(gpin); set_atom_pin_mapping(clb_nlist, blk, port, gpin); @@ -1204,12 +1209,13 @@ static void load_atom_pin_mapping(const ClusteredNetlist& clb_nlist) { for (int iport = 0; iport < gnode->num_clock_ports; ++iport) { if (gnode->num_clock_pins[iport] <= 0) continue; + pins = gnode->clock_pins[iport]; - const AtomPortId port = atom_ctx.nlist.find_atom_port(blk, gnode->clock_pins[iport][0].port->model_port); + const AtomPortId port = atom_ctx.nlist.find_atom_port(blk, pins[0].port->model_port); if (!port) continue; for (int ipin = 0; ipin < gnode->num_clock_pins[iport]; ++ipin) { - const t_pb_graph_pin* gpin = &gnode->clock_pins[iport][ipin]; + const t_pb_graph_pin* gpin = &pins[ipin]; VTR_ASSERT(gpin); set_atom_pin_mapping(clb_nlist, blk, port, gpin); From 55c6c47f3fe7821cdc4917facd23ecfe53f0f6fb Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Wed, 7 Dec 2022 14:34:11 +0100 Subject: [PATCH 16/55] base: read netlist: fixup asserts Signed-off-by: Pawel Czarnecki --- vpr/src/base/read_netlist.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/vpr/src/base/read_netlist.cpp b/vpr/src/base/read_netlist.cpp index 29d9852aa83..cfd148fd469 100644 --- a/vpr/src/base/read_netlist.cpp +++ b/vpr/src/base/read_netlist.cpp @@ -1171,8 +1171,18 @@ static void load_atom_pin_mapping(const ClusteredNetlist& clb_nlist) { VTR_ASSERT_MSG(pb, "Atom block must have a matching PB"); const t_pb_graph_node* gnode = pb->pb_graph_node; - VTR_ASSERT_MSG(gnode->pb_type->model == atom_ctx.nlist.block_model(blk), - "Atom block PB must match BLIF model"); + if (strcmp(atom_ctx.nlist.block_model(blk)->name, MODEL_LATCH) == 0) { + if (atom_ctx.nlist.block_model(blk)->inputs->trigg_edge == TriggeringEdge::FALLING_EDGE) { + VTR_ASSERT_MSG(gnode->pb_type->model_sec == atom_ctx.nlist.block_model(blk), + "Atom block PB must match BLIF model"); + } else { + VTR_ASSERT_MSG(gnode->pb_type->model == atom_ctx.nlist.block_model(blk), + "Atom block PB must match BLIF model"); + } + } else { + VTR_ASSERT_MSG(gnode->pb_type->model == atom_ctx.nlist.block_model(blk), + "Atom block PB must match BLIF model"); + } // Always assign primary pins t_pb_graph_pin* pins; From 04cb06cfca0cf3d4db81eced8dce4d10be54f197 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Wed, 23 Nov 2022 10:33:15 +0100 Subject: [PATCH 17/55] netlist writer: handle triggering clock edge in post-impl SDF writer Signed-off-by: Pawel Czarnecki --- vpr/src/base/netlist_writer.cpp | 37 ++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/vpr/src/base/netlist_writer.cpp b/vpr/src/base/netlist_writer.cpp index 60036425bbf..84e975ab5cd 100644 --- a/vpr/src/base/netlist_writer.cpp +++ b/vpr/src/base/netlist_writer.cpp @@ -431,6 +431,16 @@ class LatchInst : public Instance { return is; } + private: + std::string type_to_sdf_edge() { + if (type_ == Type::RISING_EDGE) + return "posedge"; + else if (type_ == Type::FALLING_EDGE) + return "negedge"; + else + VTR_ASSERT(false); + } + public: LatchInst(std::string inst_name, /// port_conns, ///inputs->next->trigg_edge == TriggeringEdge::FALLING_EDGE) { + type = LatchInst::Type::FALLING_EDGE; + } else { + type = LatchInst::Type::RISING_EDGE; + } + + //VPR currently doesn't store enough information to determine this attribute vtr::LogicValue init_value = vtr::LogicValue::FALSE; return std::make_shared(inst_name, port_conns, type, init_value, tcq, tsu); From 2653d831ba48daa9d8a220dbdfef0c0c49c422cf Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Wed, 23 Nov 2022 10:18:07 +0100 Subject: [PATCH 18/55] [TEST] EArch.xml: showcase 'edge' attribute in clock ports Signed-off-by: Pawel Czarnecki --- vtr_flow/arch/timing/EArch.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vtr_flow/arch/timing/EArch.xml b/vtr_flow/arch/timing/EArch.xml index 8585e14f6d4..48077ef35c5 100644 --- a/vtr_flow/arch/timing/EArch.xml +++ b/vtr_flow/arch/timing/EArch.xml @@ -104,7 +104,7 @@ - + @@ -126,7 +126,7 @@ - + From 76b92030e1f5730fdeaf5742fa26d7ad6a855722 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Wed, 23 Nov 2022 10:19:14 +0100 Subject: [PATCH 19/55] [TEST] multiclock.blif: set one FF as clocked on falling edge Signed-off-by: Pawel Czarnecki --- vtr_flow/benchmarks/blif/multiclock/multiclock.blif | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vtr_flow/benchmarks/blif/multiclock/multiclock.blif b/vtr_flow/benchmarks/blif/multiclock/multiclock.blif index 3dc5f636365..b147b62096b 100644 --- a/vtr_flow/benchmarks/blif/multiclock/multiclock.blif +++ b/vtr_flow/benchmarks/blif/multiclock/multiclock.blif @@ -3,7 +3,7 @@ .outputs out1 out2 out3 .latch to_FFA FFA re clk 0 -.latch to_FFC FFC re clk 0 +.latch to_FFC FFC fe clk 0 .latch to_FFD FFD re clk2 0 .latch to_FFB FFB re clk2 0 @@ -27,4 +27,4 @@ .names in3 out3 1 1 -.end \ No newline at end of file +.end From b63083b277ce9ecb8b7a7e3e242a246d40b26c1a Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Thu, 15 Dec 2022 15:50:01 +0100 Subject: [PATCH 20/55] add 180 deg shifted clocks derived from netlist clock in sdc file Signed-off-by: Pawel Czarnecki --- libs/EXTERNAL/libsdcparse/src/sdc_common.cpp | 13 +++ vpr/src/timing/read_sdc.cpp | 90 +++++++++++--------- 2 files changed, 62 insertions(+), 41 deletions(-) diff --git a/libs/EXTERNAL/libsdcparse/src/sdc_common.cpp b/libs/EXTERNAL/libsdcparse/src/sdc_common.cpp index 4080d4bd81c..32cc717012a 100644 --- a/libs/EXTERNAL/libsdcparse/src/sdc_common.cpp +++ b/libs/EXTERNAL/libsdcparse/src/sdc_common.cpp @@ -96,6 +96,19 @@ void add_sdc_create_clock(Callback& callback, const Lexer& lexer, CreateClock& s */ callback.create_clock(sdc_create_clock); + //Save clock targets + auto targets = sdc_create_clock.targets.strings; + //Clean targets + sdc_create_clock.targets = StringGroup(); + //Set 180 degrees phase shift and configure those clocks as virtual + sdc_create_clock.rise_edge = sdc_create_clock.fall_edge; + sdc_create_clock.fall_edge = sdc_create_clock.fall_edge * 2; + sdc_create_clock.is_virtual = true; + for (auto &str : targets) { + //Create new phase-shifted virtual clock per each target + sdc_create_clock.name = str + "_negedge"; + callback.create_clock(sdc_create_clock); + } } /* diff --git a/vpr/src/timing/read_sdc.cpp b/vpr/src/timing/read_sdc.cpp index 202a3cfe6e0..03c0304c941 100644 --- a/vpr/src/timing/read_sdc.cpp +++ b/vpr/src/timing/read_sdc.cpp @@ -119,12 +119,6 @@ class SdcParseCallback : public sdcparse::Callback { //Create netlist clock tatum::DomainId netlist_clk = tc_.create_clock_domain(clock_name); - if (sdc_clocks_.count(netlist_clk)) { - vpr_throw(VPR_ERROR_SDC, fname_.c_str(), lineno_, - "Found duplicate netlist clock definition for clock '%s' matching target pattern '%s'", - clock_name.c_str(), clock_name_glob_pattern.c_str()); - } - //Set the clock source AtomPinId clock_driver = netlist_.net_driver(clock_net); tatum::NodeId clock_source = lookup_.atom_pin_tnode(clock_driver); @@ -907,48 +901,62 @@ class SdcParseCallback : public sdcparse::Callback { "Expected clock names or collection via get_clocks"); } - for (const auto& clock_glob_pattern : clock_group.strings) { - std::regex clock_regex = glob_pattern_to_regex(clock_glob_pattern); - - bool found = false; - for (tatum::DomainId domain : tc_.clock_domains()) { - const auto& clock_name = tc_.clock_domain_name(domain); - - // Clock net aliases are built when reading the input circuit file. - // These aliases represent only real clock net names. - // - // If the SDC contains virtual clocks, the name of these does not - // appear in the net aliases data structure, therefore there is no - // need to iterate through the vector and a direct regex match can - // be applied. - // - // Furthermore, a virtual clock name would cause an error as there - // is no net associated with that when getting the net aliases from - // the netlist. - if (tc_.is_virtual_clock(domain)) { - if (std::regex_match(clock_name, clock_regex)) { - found = true; - - domains.insert(domain); - } - } else { - auto net_aliases = netlist_.net_aliases(clock_name); + for (int i = 0; i < 2; i++) { + for (const auto& clock_glob_pattern : clock_group.strings) { + std::string clk_gpattern; + switch (i) { + case 0: + clk_gpattern = clock_glob_pattern; + break; + case 1: + clk_gpattern = clock_glob_pattern + "_negedge"; + break; + default: + clk_gpattern = clock_glob_pattern; + break; + } + std::regex clock_regex = glob_pattern_to_regex(clk_gpattern); - for (const auto& alias : net_aliases) { - if (std::regex_match(alias, clock_regex)) { + bool found = false; + for (tatum::DomainId domain : tc_.clock_domains()) { + const auto& clock_name = tc_.clock_domain_name(domain); + + // Clock net aliases are built when reading the input circuit file. + // These aliases represent only real clock net names. + // + // If the SDC contains virtual clocks, the name of these does not + // appear in the net aliases data structure, therefore there is no + // need to iterate through the vector and a direct regex match can + // be applied. + // + // Furthermore, a virtual clock name would cause an error as there + // is no net associated with that when getting the net aliases from + // the netlist. + if (tc_.is_virtual_clock(domain)) { + if (std::regex_match(clock_name, clock_regex)) { found = true; domains.insert(domain); - // Exit the inner loop as the net is already being constrained - break; + } + } else { + auto net_aliases = netlist_.net_aliases(clock_name); + + for (const auto& alias : net_aliases) { + if (std::regex_match(alias, clock_regex)) { + found = true; + + domains.insert(domain); + // Exit the inner loop as the net is already being constrained + break; + } } } - } - if (!found) { - VTR_LOGF_WARN(fname_.c_str(), lineno_, - "get_clocks target name or pattern '%s' matched no clocks\n", - clock_glob_pattern.c_str()); + if (!found) { + VTR_LOGF_WARN(fname_.c_str(), lineno_, + "get_clocks target name or pattern '%s' matched no clocks\n", + clk_gpattern.c_str()); + } } } } From b26fbaa434a4bff4450323133aab7368741699e3 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Mon, 19 Dec 2022 13:52:59 +0100 Subject: [PATCH 21/55] libsdcparse: keep data on inverted clocks Signed-off-by: Pawel Czarnecki --- libs/EXTERNAL/libsdcparse/src/sdc_common.cpp | 1 + libs/EXTERNAL/libsdcparse/src/sdcparse.hpp | 1 + 2 files changed, 2 insertions(+) diff --git a/libs/EXTERNAL/libsdcparse/src/sdc_common.cpp b/libs/EXTERNAL/libsdcparse/src/sdc_common.cpp index 32cc717012a..b84c9c8fdcd 100644 --- a/libs/EXTERNAL/libsdcparse/src/sdc_common.cpp +++ b/libs/EXTERNAL/libsdcparse/src/sdc_common.cpp @@ -104,6 +104,7 @@ void add_sdc_create_clock(Callback& callback, const Lexer& lexer, CreateClock& s sdc_create_clock.rise_edge = sdc_create_clock.fall_edge; sdc_create_clock.fall_edge = sdc_create_clock.fall_edge * 2; sdc_create_clock.is_virtual = true; + sdc_create_clock.inverted = true; for (auto &str : targets) { //Create new phase-shifted virtual clock per each target sdc_create_clock.name = str + "_negedge"; diff --git a/libs/EXTERNAL/libsdcparse/src/sdcparse.hpp b/libs/EXTERNAL/libsdcparse/src/sdcparse.hpp index c9333241cd5..a7cb27f46de 100644 --- a/libs/EXTERNAL/libsdcparse/src/sdcparse.hpp +++ b/libs/EXTERNAL/libsdcparse/src/sdcparse.hpp @@ -208,6 +208,7 @@ struct CreateClock { StringGroup targets; //The set of strings indicating clock sources. // May be explicit strings or regexs. bool is_virtual = false; //Identifies this as a virtual (non-netlist) clock + bool inverted = false; //Identifies this as inverted version of netlist clock }; struct SetIoDelay { From 5e4a8f64b19415424acb044d07423407d11d48cf Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Mon, 19 Dec 2022 14:17:50 +0100 Subject: [PATCH 22/55] libtatum: skip incompatible constraints in timing tags propagation Signed-off-by: Pawel Czarnecki --- .../libtatum/tatum/TimingConstraints.cpp | 25 ++++++++++++++++++- .../libtatum/tatum/TimingConstraints.hpp | 4 +++ .../graph_visitors/CommonAnalysisVisitor.hpp | 11 +++++++- 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/libs/EXTERNAL/libtatum/libtatum/tatum/TimingConstraints.cpp b/libs/EXTERNAL/libtatum/libtatum/tatum/TimingConstraints.cpp index 510fadd9e51..3d7ee1a1589 100644 --- a/libs/EXTERNAL/libtatum/libtatum/tatum/TimingConstraints.cpp +++ b/libs/EXTERNAL/libtatum/libtatum/tatum/TimingConstraints.cpp @@ -20,6 +20,10 @@ std::string TimingConstraints::clock_domain_name(const DomainId id) const { return domain_names_[id]; } +bool TimingConstraints::clock_domain_inverted(const DomainId id) const { + return domain_inverted_[id]; +} + NodeId TimingConstraints::clock_domain_source_node(const DomainId id) const { return domain_sources_[id]; } @@ -292,7 +296,8 @@ DomainId TimingConstraints::create_clock_domain(const std::string name) { //Create it id = DomainId(domain_ids_.size()); domain_ids_.push_back(id); - + + domain_inverted_.push_back(false); domain_names_.push_back(name); domain_sources_.emplace_back(NodeId::INVALID()); @@ -303,6 +308,24 @@ DomainId TimingConstraints::create_clock_domain(const std::string name) { return id; } +DomainId TimingConstraints::create_clock_domain(const std::string name, bool inverted) { + DomainId id = find_clock_domain(name); + if(!id) { + //Create it + id = DomainId(domain_ids_.size()); + domain_ids_.push_back(id); + + domain_inverted_.push_back(inverted); + domain_names_.push_back(name); + domain_sources_.emplace_back(NodeId::INVALID()); + + TATUM_ASSERT(clock_domain_name(id) == name); + TATUM_ASSERT(find_clock_domain(name) == id); + } + + return id; +} + void TimingConstraints::set_setup_constraint(const DomainId src_domain, const DomainId sink_domain, const Time constraint) { set_setup_constraint(src_domain, sink_domain, NodeId::INVALID(), constraint); } diff --git a/libs/EXTERNAL/libtatum/libtatum/tatum/TimingConstraints.hpp b/libs/EXTERNAL/libtatum/libtatum/tatum/TimingConstraints.hpp index 07288ed08ba..927b8a3097a 100644 --- a/libs/EXTERNAL/libtatum/libtatum/tatum/TimingConstraints.hpp +++ b/libs/EXTERNAL/libtatum/libtatum/tatum/TimingConstraints.hpp @@ -42,6 +42,8 @@ class TimingConstraints { ///\returns The name of a clock domain std::string clock_domain_name(const DomainId id) const; + bool clock_domain_inverted(const DomainId id) const; + ///\returns The source NodeId of the specified domain NodeId clock_domain_source_node(const DomainId id) const; @@ -123,6 +125,7 @@ class TimingConstraints { public: //Mutators ///\returns The DomainId of the clock with the specified name (will be created if it doesn not exist) DomainId create_clock_domain(const std::string name); + DomainId create_clock_domain(const std::string name, bool inverted); ///Sets the setup constraint between src_domain and sink_domain with value constraint void set_setup_constraint(const DomainId src_domain, const DomainId sink_domain, const Time constraint); @@ -170,6 +173,7 @@ class TimingConstraints { private: //Data tatum::util::linear_map domain_ids_; tatum::util::linear_map domain_names_; + tatum::util::linear_map domain_inverted_; tatum::util::linear_map domain_sources_; std::unordered_set constant_generators_; diff --git a/libs/EXTERNAL/libtatum/libtatum/tatum/graph_visitors/CommonAnalysisVisitor.hpp b/libs/EXTERNAL/libtatum/libtatum/tatum/graph_visitors/CommonAnalysisVisitor.hpp index 6b901b21def..346f7b0a95e 100644 --- a/libs/EXTERNAL/libtatum/libtatum/tatum/graph_visitors/CommonAnalysisVisitor.hpp +++ b/libs/EXTERNAL/libtatum/libtatum/tatum/graph_visitors/CommonAnalysisVisitor.hpp @@ -294,6 +294,7 @@ bool CommonAnalysisVisitor::do_arrival_traverse_edge(const TimingGr //Pulling values from upstream source node NodeId src_node_id = tg.edge_src_node(edge_id); + NodeId sink_node_id = tg.edge_sink_node(edge_id); if(should_propagate_clocks(tg, tc, edge_id)) { /* @@ -311,7 +312,6 @@ bool CommonAnalysisVisitor::do_arrival_traverse_edge(const TimingGr for(const TimingTag& src_launch_clk_tag : src_launch_clk_tags) { //Standard propagation through the clock network - Time new_arr = src_launch_clk_tag.time() + clk_launch_edge_delay; timing_modified |= ops_.merge_arr_tags(node_id, new_arr, src_node_id, src_launch_clk_tag); @@ -328,6 +328,15 @@ bool CommonAnalysisVisitor::do_arrival_traverse_edge(const TimingGr for(const TimingTag& src_capture_clk_tag : src_capture_clk_tags) { //Standard propagation through the clock network + + //Skip propagation of timings derived from incompatible constraints + if ( tg.node_type(sink_node_id) == NodeType::CPIN ) { + if ((tg.trigg_edge(sink_node_id) == 1 && !tc.clock_domain_inverted(src_capture_clk_tag.launch_clock_domain())) || + (tg.trigg_edge(sink_node_id) == 0 && tc.clock_domain_inverted(src_capture_clk_tag.launch_clock_domain()))) { + continue; + } + } + timing_modified |= ops_.merge_arr_tags(node_id, src_capture_clk_tag.time() + clk_capture_edge_delay, src_node_id, src_capture_clk_tag); } } From c28d73b99943a4cfcb4acfaf4d007d42aeec3a6c Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Mon, 19 Dec 2022 14:19:20 +0100 Subject: [PATCH 23/55] vpr: timing: read_sdc: create clock domains with data on inverted clocks Signed-off-by: Pawel Czarnecki --- vpr/src/timing/read_sdc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vpr/src/timing/read_sdc.cpp b/vpr/src/timing/read_sdc.cpp index 03c0304c941..d8c813c4d40 100644 --- a/vpr/src/timing/read_sdc.cpp +++ b/vpr/src/timing/read_sdc.cpp @@ -81,7 +81,7 @@ class SdcParseCallback : public sdcparse::Callback { if (cmd.is_virtual) { //Create a virtual clock - tatum::DomainId virtual_clk = tc_.create_clock_domain(cmd.name); + tatum::DomainId virtual_clk = tc_.create_clock_domain(cmd.name, cmd.inverted); if (sdc_clocks_.count(virtual_clk)) { vpr_throw(VPR_ERROR_SDC, fname_.c_str(), lineno_, From 9e566eb6464bcca5a0a3265187eeb5faeeaf3075 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Tue, 20 Dec 2022 15:57:20 +0100 Subject: [PATCH 24/55] vpr: timing: read_sdc: add special case for inverted clocks Signed-off-by: Pawel Czarnecki --- vpr/src/timing/read_sdc.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/vpr/src/timing/read_sdc.cpp b/vpr/src/timing/read_sdc.cpp index d8c813c4d40..bec4716162a 100644 --- a/vpr/src/timing/read_sdc.cpp +++ b/vpr/src/timing/read_sdc.cpp @@ -741,6 +741,13 @@ class SdcParseCallback : public sdcparse::Callback { constraint = launch_clock.period; + } else if ((std::fabs(launch_clock.period - capture_clock.period) < EPSILON) && + (std::fabs((launch_clock.period / 2) - std::fabs(launch_clock.rise_edge - capture_clock.rise_edge)) < EPSILON) && + (std::fabs((launch_clock.period / 2) - std::fabs(launch_clock.fall_edge - capture_clock.fall_edge)) < EPSILON)) { + //The source and sink domains have the same period but are inverted, the constraint is half of the common clock period. + + constraint = (launch_clock.period / 2); + } else if (launch_clock.period < EPSILON || capture_clock.period < EPSILON) { //If either period is 0, the constraint is 0 constraint = 0.; From b0adc09110135f04b2c7c601b290f4b40c842c75 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Wed, 21 Dec 2022 10:10:50 +0100 Subject: [PATCH 25/55] invert rise- and fall-edge times for virtual inverted clocks Signed-off-by: Pawel Czarnecki --- libs/EXTERNAL/libsdcparse/src/sdc_common.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/EXTERNAL/libsdcparse/src/sdc_common.cpp b/libs/EXTERNAL/libsdcparse/src/sdc_common.cpp index b84c9c8fdcd..d4df8041000 100644 --- a/libs/EXTERNAL/libsdcparse/src/sdc_common.cpp +++ b/libs/EXTERNAL/libsdcparse/src/sdc_common.cpp @@ -101,8 +101,9 @@ void add_sdc_create_clock(Callback& callback, const Lexer& lexer, CreateClock& s //Clean targets sdc_create_clock.targets = StringGroup(); //Set 180 degrees phase shift and configure those clocks as virtual + double rise_edge = sdc_create_clock.rise_edge; sdc_create_clock.rise_edge = sdc_create_clock.fall_edge; - sdc_create_clock.fall_edge = sdc_create_clock.fall_edge * 2; + sdc_create_clock.fall_edge = rise_edge; sdc_create_clock.is_virtual = true; sdc_create_clock.inverted = true; for (auto &str : targets) { From b592f23e90d6ff9cd4830156a06e3c1613bd7f27 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Wed, 21 Dec 2022 10:17:02 +0100 Subject: [PATCH 26/55] add_sdc_create_clock: add comments Signed-off-by: Pawel Czarnecki --- libs/EXTERNAL/libsdcparse/src/sdc_common.cpp | 22 ++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/libs/EXTERNAL/libsdcparse/src/sdc_common.cpp b/libs/EXTERNAL/libsdcparse/src/sdc_common.cpp index d4df8041000..3cf8e1ac11b 100644 --- a/libs/EXTERNAL/libsdcparse/src/sdc_common.cpp +++ b/libs/EXTERNAL/libsdcparse/src/sdc_common.cpp @@ -96,18 +96,28 @@ void add_sdc_create_clock(Callback& callback, const Lexer& lexer, CreateClock& s */ callback.create_clock(sdc_create_clock); - //Save clock targets + //Prepare and create inverted version of the netlist clock. + //Use netlist clock from parsed SDC file (create_clock command) + //as a base for the inverted clock. It is created as virtual + //so that it won't interfere with existing netlist clock. + sdc_create_clock.is_virtual = true; + //Mark clock as inverted + sdc_create_clock.inverted = true; + + //Virtual clocks must have empty targets, overwrite those + //but first save the names of the targets auto targets = sdc_create_clock.targets.strings; - //Clean targets sdc_create_clock.targets = StringGroup(); - //Set 180 degrees phase shift and configure those clocks as virtual + + //180 degrees phase shift is done with inverting + //the rise- and fall-edge times of the original netlist clock double rise_edge = sdc_create_clock.rise_edge; sdc_create_clock.rise_edge = sdc_create_clock.fall_edge; sdc_create_clock.fall_edge = rise_edge; - sdc_create_clock.is_virtual = true; - sdc_create_clock.inverted = true; + + //Create new inverted virtual clock for each target from original netlist clock. for (auto &str : targets) { - //Create new phase-shifted virtual clock per each target + //Use saved names of the original netlist clock targets as inverted clock names sdc_create_clock.name = str + "_negedge"; callback.create_clock(sdc_create_clock); } From 5d297ece8ecb9c778ecbfd1f8aa90609075d77de Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Wed, 21 Dec 2022 10:23:06 +0100 Subject: [PATCH 27/55] domain_inverted: fix indent Signed-off-by: Pawel Czarnecki --- libs/EXTERNAL/libtatum/libtatum/tatum/TimingConstraints.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/EXTERNAL/libtatum/libtatum/tatum/TimingConstraints.cpp b/libs/EXTERNAL/libtatum/libtatum/tatum/TimingConstraints.cpp index 3d7ee1a1589..159de5d18da 100644 --- a/libs/EXTERNAL/libtatum/libtatum/tatum/TimingConstraints.cpp +++ b/libs/EXTERNAL/libtatum/libtatum/tatum/TimingConstraints.cpp @@ -315,7 +315,7 @@ DomainId TimingConstraints::create_clock_domain(const std::string name, bool inv id = DomainId(domain_ids_.size()); domain_ids_.push_back(id); - domain_inverted_.push_back(inverted); + domain_inverted_.push_back(inverted); domain_names_.push_back(name); domain_sources_.emplace_back(NodeId::INVALID()); From b177df7223e329de498df0a44a4a46054d08fb46 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Wed, 21 Dec 2022 10:33:00 +0100 Subject: [PATCH 28/55] libtatum: TimingConstraints: document clock_domain_inverted() Signed-off-by: Pawel Czarnecki --- libs/EXTERNAL/libtatum/libtatum/tatum/TimingConstraints.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libs/EXTERNAL/libtatum/libtatum/tatum/TimingConstraints.hpp b/libs/EXTERNAL/libtatum/libtatum/tatum/TimingConstraints.hpp index 927b8a3097a..134a53ef037 100644 --- a/libs/EXTERNAL/libtatum/libtatum/tatum/TimingConstraints.hpp +++ b/libs/EXTERNAL/libtatum/libtatum/tatum/TimingConstraints.hpp @@ -42,6 +42,9 @@ class TimingConstraints { ///\returns The name of a clock domain std::string clock_domain_name(const DomainId id) const; + ///Checks whether the clock domain was marked as inverted. Inverted clocks are virtual clocks created from netlist clocks with 180 degree phase shift applied + ///\param id The ID of the clock domain + ///\returns whether the clock domain with specified domain id was marked as inverted bool clock_domain_inverted(const DomainId id) const; ///\returns The source NodeId of the specified domain From c1b127c46e6b18a450acb5e5a073c1c0277f7ecf Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Wed, 21 Dec 2022 10:33:41 +0100 Subject: [PATCH 29/55] libtatum: TimingConstraints: fix typo Signed-off-by: Pawel Czarnecki --- libs/EXTERNAL/libtatum/libtatum/tatum/TimingConstraints.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/EXTERNAL/libtatum/libtatum/tatum/TimingConstraints.hpp b/libs/EXTERNAL/libtatum/libtatum/tatum/TimingConstraints.hpp index 134a53ef037..4db9d2f68bd 100644 --- a/libs/EXTERNAL/libtatum/libtatum/tatum/TimingConstraints.hpp +++ b/libs/EXTERNAL/libtatum/libtatum/tatum/TimingConstraints.hpp @@ -50,7 +50,7 @@ class TimingConstraints { ///\returns The source NodeId of the specified domain NodeId clock_domain_source_node(const DomainId id) const; - //\returns whether the specified domain id corresponds to a virtual lcock + //\returns whether the specified domain id corresponds to a virtual clock bool is_virtual_clock(const DomainId id) const; ///\returns The domain of the specified node id if it is a clock source From 9a0467fb0f724439e741790020e5ee35839be80e Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Wed, 21 Dec 2022 13:17:15 +0100 Subject: [PATCH 30/55] libtatum: use enum for triggering edges Signed-off-by: Pawel Czarnecki --- .../libtatum/libtatum/tatum/TimingGraph.cpp | 2 +- .../libtatum/libtatum/tatum/TimingGraph.hpp | 26 +++++++++++++------ .../graph_visitors/CommonAnalysisVisitor.hpp | 4 +-- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/libs/EXTERNAL/libtatum/libtatum/tatum/TimingGraph.cpp b/libs/EXTERNAL/libtatum/libtatum/tatum/TimingGraph.cpp index 57a7fd68eb3..435f41a2d77 100644 --- a/libs/EXTERNAL/libtatum/libtatum/tatum/TimingGraph.cpp +++ b/libs/EXTERNAL/libtatum/libtatum/tatum/TimingGraph.cpp @@ -198,7 +198,7 @@ NodeId TimingGraph::add_node(const NodeType type) { return node_id; } -NodeId TimingGraph::add_node(const NodeType type, int trigg_edge) { +NodeId TimingGraph::add_node(const NodeType type, TriggeringEdge trigg_edge) { //Invalidate the levelization is_levelized_ = false; diff --git a/libs/EXTERNAL/libtatum/libtatum/tatum/TimingGraph.hpp b/libs/EXTERNAL/libtatum/libtatum/tatum/TimingGraph.hpp index c46cfab8274..38887be28bb 100644 --- a/libs/EXTERNAL/libtatum/libtatum/tatum/TimingGraph.hpp +++ b/libs/EXTERNAL/libtatum/libtatum/tatum/TimingGraph.hpp @@ -63,6 +63,13 @@ namespace tatum { +enum TriggeringEdge { + RISING_EDGE, + FALLING_EDGE, + DONT_CARE, + ERROR_EDGE +}; + class TimingGraph { public: //Public types //Iterators @@ -84,16 +91,21 @@ class TimingGraph { ///\returns The type of the node NodeType node_type(const NodeId id) const { return node_types_[id]; } - int trigg_edge(const NodeId id) const { return trigg_edges_[id]; } + ///\param id The TimingGraph node ID + ///\returns TriggeringEdge enum describing the triggering edge of the TimingGraph node + TriggeringEdge trigg_edge(const NodeId id) const { return trigg_edges_[id]; } + + ///\param id The TimingGraph node ID + ///\returns String describing the triggering edge of the TimingGraph node std::string trigg_edge_str(const NodeId id) const { switch(trigg_edges_[id]) { - case 0: + case TriggeringEdge::RISING_EDGE: return "RISING"; break; - case 1: + case TriggeringEdge::FALLING_EDGE: return "FALLING"; break; - case 2: + case TriggeringEdge::DONT_CARE: return "DONT_CARE"; break; default: @@ -216,7 +228,7 @@ class TimingGraph { ///\param type The type of the node to be added ///\warning Graph will likely need to be re-levelized after modification NodeId add_node(const NodeType type); - NodeId add_node(const NodeType type, int trigg_edge); + NodeId add_node(const NodeType type, TriggeringEdge trigg_edge); ///Adds an edge to the timing graph ///\param type The edge's type @@ -301,7 +313,7 @@ class TimingGraph { //Node data tatum::util::linear_map node_ids_; //The node IDs in the graph tatum::util::linear_map node_types_; //Type of node - tatum::util::linear_map trigg_edges_; //Triggering edge of the clock + tatum::util::linear_map trigg_edges_; //Triggering edge of the clock tatum::util::linear_map> node_in_edges_; //Incomiing edge IDs for node tatum::util::linear_map> node_out_edges_; //Out going edge IDs for node tatum::util::linear_map node_levels_; //Out going edge IDs for node @@ -354,7 +366,5 @@ struct GraphIdMaps { tatum::util::linear_map edge_id_map; }; - - } //namepsace diff --git a/libs/EXTERNAL/libtatum/libtatum/tatum/graph_visitors/CommonAnalysisVisitor.hpp b/libs/EXTERNAL/libtatum/libtatum/tatum/graph_visitors/CommonAnalysisVisitor.hpp index 346f7b0a95e..8eba5c42821 100644 --- a/libs/EXTERNAL/libtatum/libtatum/tatum/graph_visitors/CommonAnalysisVisitor.hpp +++ b/libs/EXTERNAL/libtatum/libtatum/tatum/graph_visitors/CommonAnalysisVisitor.hpp @@ -331,8 +331,8 @@ bool CommonAnalysisVisitor::do_arrival_traverse_edge(const TimingGr //Skip propagation of timings derived from incompatible constraints if ( tg.node_type(sink_node_id) == NodeType::CPIN ) { - if ((tg.trigg_edge(sink_node_id) == 1 && !tc.clock_domain_inverted(src_capture_clk_tag.launch_clock_domain())) || - (tg.trigg_edge(sink_node_id) == 0 && tc.clock_domain_inverted(src_capture_clk_tag.launch_clock_domain()))) { + if ((tg.trigg_edge(sink_node_id) == TriggeringEdge::FALLING_EDGE && !tc.clock_domain_inverted(src_capture_clk_tag.launch_clock_domain())) || + (tg.trigg_edge(sink_node_id) == TriggeringEdge::RISING_EDGE && tc.clock_domain_inverted(src_capture_clk_tag.launch_clock_domain()))) { continue; } } From 5b47cebcc609ba6e35947e5d8472edb3d9c01454 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Wed, 21 Dec 2022 13:25:07 +0100 Subject: [PATCH 31/55] timing_graph_builder: convert enum types Signed-off-by: Pawel Czarnecki --- vpr/src/timing/timing_graph_builder.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/vpr/src/timing/timing_graph_builder.cpp b/vpr/src/timing/timing_graph_builder.cpp index ddba0d47fe3..56c8cd798e6 100644 --- a/vpr/src/timing/timing_graph_builder.cpp +++ b/vpr/src/timing/timing_graph_builder.cpp @@ -354,7 +354,7 @@ void TimingGraphBuilder::add_io_to_timing_graph(const AtomBlockId blk) { AtomPortId port = netlist_.pin_port(pin); const t_model_ports* model_port = netlist_.port_model(port); - NodeId tnode = tg_->add_node(node_type, model_port->trigg_edge); + NodeId tnode = tg_->add_node(node_type, (tatum::TriggeringEdge)model_port->trigg_edge); netlist_lookup_.set_atom_pin_tnode(pin, tnode, BlockTnode::EXTERNAL); } @@ -416,21 +416,21 @@ std::set TimingGraphBuilder::create_block_timing_nodes(const Atom VTR_ASSERT(!model_port->is_clock); if (model_port->clock.empty()) { //No clock => combinational input - tnode = tg_->add_node(NodeType::IPIN, model_port->trigg_edge); + tnode = tg_->add_node(NodeType::IPIN, (tatum::TriggeringEdge)model_port->trigg_edge); //A combinational pin is really both internal and external, mark it internal here //and external in the default case below netlist_lookup_.set_atom_pin_tnode(input_pin, tnode, BlockTnode::INTERNAL); } else { //This is a sequential data input (i.e. a sequential data capture point/timing path end-point) - tnode = tg_->add_node(NodeType::SINK, model_port->trigg_edge); + tnode = tg_->add_node(NodeType::SINK, (tatum::TriggeringEdge)model_port->trigg_edge); if (!model_port->combinational_sink_ports.empty()) { //There is an internal combinational connection starting at this sequential input //pin. This is a new timing path and hence we must create a new SOURCE node. //Create the internal source - NodeId internal_tnode = tg_->add_node(NodeType::SOURCE, model_port->trigg_edge); + NodeId internal_tnode = tg_->add_node(NodeType::SOURCE, (tatum::TriggeringEdge)model_port->trigg_edge); netlist_lookup_.set_atom_pin_tnode(input_pin, internal_tnode, BlockTnode::INTERNAL); } } @@ -455,7 +455,7 @@ std::set TimingGraphBuilder::create_block_timing_nodes(const Atom VTR_ASSERT(model_port->is_clock); VTR_ASSERT(model_port->clock.empty()); - NodeId tnode = tg_->add_node(NodeType::CPIN, model_port->trigg_edge); + NodeId tnode = tg_->add_node(NodeType::CPIN, (tatum::TriggeringEdge)model_port->trigg_edge); netlist_lookup_.set_atom_pin_tnode(clock_pin, tnode, BlockTnode::EXTERNAL); } @@ -471,7 +471,7 @@ std::set TimingGraphBuilder::create_block_timing_nodes(const Atom NodeId tnode; if (is_netlist_clock_source(output_pin)) { //A generated clock source - tnode = tg_->add_node(NodeType::SOURCE, model_port->trigg_edge); + tnode = tg_->add_node(NodeType::SOURCE, (tatum::TriggeringEdge)model_port->trigg_edge); clock_generator_tnodes.insert(tnode); @@ -491,7 +491,7 @@ std::set TimingGraphBuilder::create_block_timing_nodes(const Atom if (model_port->clock.empty()) { //No clock => combinational output - tnode = tg_->add_node(NodeType::OPIN, model_port->trigg_edge); + tnode = tg_->add_node(NodeType::OPIN, (tatum::TriggeringEdge)model_port->trigg_edge); //A combinational pin is really both internal and external, mark it internal here //and external in the default case below @@ -500,13 +500,13 @@ std::set TimingGraphBuilder::create_block_timing_nodes(const Atom } else { VTR_ASSERT(!model_port->clock.empty()); //Has an associated clock => sequential output - tnode = tg_->add_node(NodeType::SOURCE, model_port->trigg_edge); + tnode = tg_->add_node(NodeType::SOURCE, (tatum::TriggeringEdge)model_port->trigg_edge); if (output_ports_used_as_combinational_sinks.count(model_port->name)) { //There is a combinational path within the primitive terminating at this sequential output //Create the internal sink node - NodeId internal_tnode = tg_->add_node(NodeType::SINK, model_port->trigg_edge); + NodeId internal_tnode = tg_->add_node(NodeType::SINK, (tatum::TriggeringEdge)model_port->trigg_edge); netlist_lookup_.set_atom_pin_tnode(output_pin, internal_tnode, BlockTnode::INTERNAL); } } From 2a4f193f383f6aae0bd8c8eb6cb7fe0a84175db7 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Wed, 21 Dec 2022 16:38:15 +0100 Subject: [PATCH 32/55] libtatum: CommonAnalysisVisitor: comment the tag propagation mechanism Signed-off-by: Pawel Czarnecki --- .../graph_visitors/CommonAnalysisVisitor.hpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/libs/EXTERNAL/libtatum/libtatum/tatum/graph_visitors/CommonAnalysisVisitor.hpp b/libs/EXTERNAL/libtatum/libtatum/tatum/graph_visitors/CommonAnalysisVisitor.hpp index 8eba5c42821..dbf3b6ebc5f 100644 --- a/libs/EXTERNAL/libtatum/libtatum/tatum/graph_visitors/CommonAnalysisVisitor.hpp +++ b/libs/EXTERNAL/libtatum/libtatum/tatum/graph_visitors/CommonAnalysisVisitor.hpp @@ -329,10 +329,23 @@ bool CommonAnalysisVisitor::do_arrival_traverse_edge(const TimingGr for(const TimingTag& src_capture_clk_tag : src_capture_clk_tags) { //Standard propagation through the clock network - //Skip propagation of timings derived from incompatible constraints + /* + * Each source capture tag may be related to clock domain of one of the two types: + * 1. clock domain created for netlist clock, meant to be used with cells clocked at the rising edge + * 2. inverted virtual clock domain based on existing netlist clock. + * It is 180 degree phase shifted in relation to netlist clock + * and it is used in timing analysis for cells clocked at falling edge. + * + * The triggering edges of FFs should be taken into account when propagating tags + * to CPIN nodes. Tags of types which are incompatible with triggering edges + * of the FF clock inputs shouldn't be propagated because having those wouldn't allow + * timing analysis to calculate correct timings for transfers between cells + * clocked rising and falling edges of the same clock. + */ if ( tg.node_type(sink_node_id) == NodeType::CPIN ) { if ((tg.trigg_edge(sink_node_id) == TriggeringEdge::FALLING_EDGE && !tc.clock_domain_inverted(src_capture_clk_tag.launch_clock_domain())) || (tg.trigg_edge(sink_node_id) == TriggeringEdge::RISING_EDGE && tc.clock_domain_inverted(src_capture_clk_tag.launch_clock_domain()))) { + //Skip propagation of timings derived from incompatible constraints continue; } } From 079efe0fae1203cb88d972a403a444c18f919d4a Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Thu, 22 Dec 2022 09:28:36 +0100 Subject: [PATCH 33/55] libarchfpga: arch_util: remove magic number for internal library size Signed-off-by: Pawel Czarnecki --- libs/libarchfpga/src/arch_util.cpp | 4 ++-- libs/libarchfpga/src/arch_util.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libs/libarchfpga/src/arch_util.cpp b/libs/libarchfpga/src/arch_util.cpp index f9e9ac7c577..aab60b5c835 100644 --- a/libs/libarchfpga/src/arch_util.cpp +++ b/libs/libarchfpga/src/arch_util.cpp @@ -172,7 +172,7 @@ void free_arch(t_arch* arch) { vtr::free(arch->architecture_id); if (arch->model_library) { - for (int i = 0; i < 5; ++i) { + for (int i = 0; i < num_models_lib; ++i) { vtr::t_linked_vptr* vptr = arch->model_library[i].pb_types; while (vptr) { vtr::t_linked_vptr* vptr_prev = vptr; @@ -1057,7 +1057,7 @@ e_power_estimation_method power_method_inherited(e_power_estimation_method paren void CreateModelLibrary(t_arch* arch) { t_model* model_library; - model_library = new t_model[5]; + model_library = new t_model[num_models_lib]; //INPAD model_library[0].name = vtr::strdup(MODEL_INPUT); diff --git a/libs/libarchfpga/src/arch_util.h b/libs/libarchfpga/src/arch_util.h index 45d8133fc57..3b7ee8514bd 100644 --- a/libs/libarchfpga/src/arch_util.h +++ b/libs/libarchfpga/src/arch_util.h @@ -16,6 +16,7 @@ void set_arch_file_name(const char* arch); const char* get_arch_file_name(); constexpr const char* EMPTY_BLOCK_NAME = "EMPTY"; +constexpr const int num_models_lib = 5; class InstPort { public: From ab19fee1b3e801ca04f627ad2fc6571472279094 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Thu, 22 Dec 2022 10:09:51 +0100 Subject: [PATCH 34/55] libarchfpga: arch_util: change all free() to delete Signed-off-by: Pawel Czarnecki --- libs/libarchfpga/src/arch_util.cpp | 150 ++++++++++++++--------------- 1 file changed, 75 insertions(+), 75 deletions(-) diff --git a/libs/libarchfpga/src/arch_util.cpp b/libs/libarchfpga/src/arch_util.cpp index aab60b5c835..c1573f71dea 100644 --- a/libs/libarchfpga/src/arch_util.cpp +++ b/libs/libarchfpga/src/arch_util.cpp @@ -154,7 +154,7 @@ void free_arch(t_arch* arch) { for (int i = 0; i < arch->num_switches; ++i) { if (arch->Switches->name != nullptr) { - vtr::free(arch->Switches[i].name); + delete arch->Switches[i].name; } } delete[] arch->Switches; @@ -163,13 +163,13 @@ void free_arch(t_arch* arch) { free_arch_models(arch->models); for (int i = 0; i < arch->num_directs; ++i) { - vtr::free(arch->Directs[i].name); - vtr::free(arch->Directs[i].from_pin); - vtr::free(arch->Directs[i].to_pin); + delete arch->Directs[i].name; + delete arch->Directs[i].from_pin; + delete arch->Directs[i].to_pin; } - vtr::free(arch->Directs); + delete arch->Directs; - vtr::free(arch->architecture_id); + delete arch->architecture_id; if (arch->model_library) { for (int i = 0; i < num_models_lib; ++i) { @@ -177,38 +177,38 @@ void free_arch(t_arch* arch) { while (vptr) { vtr::t_linked_vptr* vptr_prev = vptr; vptr = vptr->next; - vtr::free(vptr_prev); + delete vptr_prev; } } - vtr::free(arch->model_library[0].name); - vtr::free(arch->model_library[0].outputs->name); + delete arch->model_library[0].name; + delete arch->model_library[0].outputs->name; delete[] arch->model_library[0].outputs; - vtr::free(arch->model_library[1].inputs->name); + delete arch->model_library[1].inputs->name; delete[] arch->model_library[1].inputs; - vtr::free(arch->model_library[1].name); - vtr::free(arch->model_library[2].name); - vtr::free(arch->model_library[2].inputs[0].name); - vtr::free(arch->model_library[2].inputs[1].name); + delete arch->model_library[1].name; + delete arch->model_library[2].name; + delete arch->model_library[2].inputs[0].name; + delete arch->model_library[2].inputs[1].name; delete[] arch->model_library[2].inputs; - vtr::free(arch->model_library[2].outputs->name); + delete arch->model_library[2].outputs->name; delete[] arch->model_library[2].outputs; - vtr::free(arch->model_library[3].name); - vtr::free(arch->model_library[3].inputs[0].name); - vtr::free(arch->model_library[3].inputs[1].name); + delete arch->model_library[3].name; + delete arch->model_library[3].inputs[0].name; + delete arch->model_library[3].inputs[1].name; delete[] arch->model_library[3].inputs; - vtr::free(arch->model_library[3].outputs->name); + delete arch->model_library[3].outputs->name; delete[] arch->model_library[3].outputs; - vtr::free(arch->model_library[4].name); - vtr::free(arch->model_library[4].inputs->name); + delete arch->model_library[4].name; + delete arch->model_library[4].inputs->name; delete[] arch->model_library[4].inputs; - vtr::free(arch->model_library[4].outputs->name); + delete arch->model_library[4].outputs->name; delete[] arch->model_library[4].outputs; delete[] arch->model_library; } if (arch->clocks) { - vtr::free(arch->clocks->clock_inf); + delete arch->clocks->clock_inf; } delete (arch->noc); @@ -235,12 +235,12 @@ t_model* free_arch_model(t_model* model) { while (vptr) { vtr::t_linked_vptr* vptr_prev = vptr; vptr = vptr->next; - vtr::free(vptr_prev); + delete vptr_prev; } if (model->instances) vtr::free(model->instances); - vtr::free(model->name); + delete model->name; delete model; return next_model; @@ -260,7 +260,7 @@ t_model_ports* free_arch_model_port(t_model_ports* model_port) { t_model_ports* next_port = model_port->next; - vtr::free(model_port->name); + delete model_port->name; delete model_port; return next_port; @@ -268,16 +268,16 @@ t_model_ports* free_arch_model_port(t_model_ports* model_port) { void free_type_descriptors(std::vector& type_descriptors) { for (auto& type : type_descriptors) { - vtr::free(type.name); + delete type.name; if (type.index == EMPTY_TYPE_INDEX) { continue; } for (auto& sub_tile : type.sub_tiles) { - vtr::free(sub_tile.name); + delete sub_tile.name; for (auto port : sub_tile.ports) { - vtr::free(port.name); + delete port.name; } } } @@ -288,7 +288,7 @@ void free_type_descriptors(std::vector& type_descriptors) free_all_pb_graph_nodes(type_descriptors); for (auto& type : type_descriptors) { - vtr::free(type.name); + delete type.name; if (type.index == EMPTY_TYPE_INDEX) { continue; } @@ -408,98 +408,98 @@ static void free_pb_graph(t_pb_graph_node* pb_graph_node) { for (k = 0; k < pb_type->modes[i].pb_type_children[j].num_pb; k++) { free_pb_graph(&pb_graph_node->child_pb_graph_nodes[i][j][k]); } - vtr::free(pb_graph_node->child_pb_graph_nodes[i][j]); + delete pb_graph_node->child_pb_graph_nodes[i][j]; } - vtr::free(pb_graph_node->child_pb_graph_nodes[i]); + delete pb_graph_node->child_pb_graph_nodes[i]; } - vtr::free(pb_graph_node->child_pb_graph_nodes); + delete pb_graph_node->child_pb_graph_nodes; } static void free_pb_type(t_pb_type* pb_type) { - vtr::free(pb_type->name); + delete pb_type->name; if (pb_type->blif_model) - vtr::free(pb_type->blif_model); + delete pb_type->blif_model; for (int i = 0; i < pb_type->num_modes; ++i) { for (int j = 0; j < pb_type->modes[i].num_pb_type_children; ++j) { free_pb_type(&pb_type->modes[i].pb_type_children[j]); } delete[] pb_type->modes[i].pb_type_children; - vtr::free(pb_type->modes[i].name); + delete pb_type->modes[i].name; for (int j = 0; j < pb_type->modes[i].num_interconnect; ++j) { - vtr::free(pb_type->modes[i].interconnect[j].input_string); - vtr::free(pb_type->modes[i].interconnect[j].output_string); - vtr::free(pb_type->modes[i].interconnect[j].name); + delete pb_type->modes[i].interconnect[j].input_string; + delete pb_type->modes[i].interconnect[j].output_string; + delete pb_type->modes[i].interconnect[j].name; for (int k = 0; k < pb_type->modes[i].interconnect[j].num_annotations; ++k) { if (pb_type->modes[i].interconnect[j].annotations[k].clock) - vtr::free(pb_type->modes[i].interconnect[j].annotations[k].clock); + delete pb_type->modes[i].interconnect[j].annotations[k].clock; if (pb_type->modes[i].interconnect[j].annotations[k].input_pins) { - vtr::free(pb_type->modes[i].interconnect[j].annotations[k].input_pins); + delete pb_type->modes[i].interconnect[j].annotations[k].input_pins; } if (pb_type->modes[i].interconnect[j].annotations[k].output_pins) { - vtr::free(pb_type->modes[i].interconnect[j].annotations[k].output_pins); + delete pb_type->modes[i].interconnect[j].annotations[k].output_pins; } for (int m = 0; m < pb_type->modes[i].interconnect[j].annotations[k].num_value_prop_pairs; ++m) { - vtr::free(pb_type->modes[i].interconnect[j].annotations[k].value[m]); + delete pb_type->modes[i].interconnect[j].annotations[k].value[m]; } - vtr::free(pb_type->modes[i].interconnect[j].annotations[k].prop); - vtr::free(pb_type->modes[i].interconnect[j].annotations[k].value); + delete pb_type->modes[i].interconnect[j].annotations[k].prop; + delete pb_type->modes[i].interconnect[j].annotations[k].value; } - vtr::free(pb_type->modes[i].interconnect[j].annotations); + delete pb_type->modes[i].interconnect[j].annotations; if (pb_type->modes[i].interconnect[j].interconnect_power) - vtr::free(pb_type->modes[i].interconnect[j].interconnect_power); + delete pb_type->modes[i].interconnect[j].interconnect_power; } if (pb_type->modes[i].interconnect) delete[] pb_type->modes[i].interconnect; if (pb_type->modes[i].mode_power) - vtr::free(pb_type->modes[i].mode_power); + delete pb_type->modes[i].mode_power; } if (pb_type->modes) delete[] pb_type->modes; for (int i = 0; i < pb_type->num_annotations; ++i) { for (int j = 0; j < pb_type->annotations[i].num_value_prop_pairs; ++j) { - vtr::free(pb_type->annotations[i].value[j]); + delete pb_type->annotations[i].value[j]; } - vtr::free(pb_type->annotations[i].value); - vtr::free(pb_type->annotations[i].prop); + delete pb_type->annotations[i].value; + delete pb_type->annotations[i].prop; if (pb_type->annotations[i].input_pins) { - vtr::free(pb_type->annotations[i].input_pins); + delete pb_type->annotations[i].input_pins; } if (pb_type->annotations[i].output_pins) { - vtr::free(pb_type->annotations[i].output_pins); + delete pb_type->annotations[i].output_pins; } if (pb_type->annotations[i].clock) { - vtr::free(pb_type->annotations[i].clock); + delete pb_type->annotations[i].clock; } } if (pb_type->num_annotations > 0) { - vtr::free(pb_type->annotations); + delete pb_type->annotations; } if (pb_type->pb_type_power) { - vtr::free(pb_type->pb_type_power); + delete pb_type->pb_type_power; } for (int i = 0; i < pb_type->num_ports; ++i) { - vtr::free(pb_type->ports[i].name); + delete pb_type->ports[i].name; if (pb_type->class_type == LATCH_CLASS) - vtr::free(pb_type->ports_sec[i].name); + delete pb_type->ports_sec[i].name; if (pb_type->ports[i].port_class) { - vtr::free(pb_type->ports[i].port_class); + delete pb_type->ports[i].port_class; if (pb_type->class_type == LATCH_CLASS) - vtr::free(pb_type->ports_sec[i].port_class); + delete pb_type->ports_sec[i].port_class; } if (pb_type->ports[i].port_power) { - vtr::free(pb_type->ports[i].port_power); + delete pb_type->ports[i].port_power; if (pb_type->class_type == LATCH_CLASS) - vtr::free(pb_type->ports_sec[i].port_power); + delete pb_type->ports_sec[i].port_power; } } - vtr::free(pb_type->ports); + delete pb_type->ports; if (pb_type->class_type == LATCH_CLASS) - vtr::free(pb_type->ports_sec); + delete pb_type->ports_sec; } t_port* findPortByName(const char* name, t_pb_type* pb_type, int* high_index, int* low_index) { @@ -796,22 +796,22 @@ void ProcessLutClass(t_pb_type* lut_pb_type) { /* moved annotations to child so delete old annotations */ for (i = 0; i < lut_pb_type->num_annotations; i++) { for (j = 0; j < lut_pb_type->annotations[i].num_value_prop_pairs; j++) { - free(lut_pb_type->annotations[i].value[j]); + delete lut_pb_type->annotations[i].value[j]; } - free(lut_pb_type->annotations[i].value); - free(lut_pb_type->annotations[i].prop); + delete lut_pb_type->annotations[i].value; + delete lut_pb_type->annotations[i].prop; if (lut_pb_type->annotations[i].input_pins) { - free(lut_pb_type->annotations[i].input_pins); + delete lut_pb_type->annotations[i].input_pins; } if (lut_pb_type->annotations[i].output_pins) { - free(lut_pb_type->annotations[i].output_pins); + delete lut_pb_type->annotations[i].output_pins; } if (lut_pb_type->annotations[i].clock) { - free(lut_pb_type->annotations[i].clock); + delete lut_pb_type->annotations[i].clock; } } lut_pb_type->num_annotations = 0; - free(lut_pb_type->annotations); + delete lut_pb_type->annotations; lut_pb_type->annotations = nullptr; lut_pb_type->modes[1].pb_type_children[0].depth = lut_pb_type->depth + 1; lut_pb_type->modes[1].pb_type_children[0].parent_mode = &lut_pb_type->modes[1]; @@ -860,9 +860,9 @@ void ProcessLutClass(t_pb_type* lut_pb_type) { lut_pb_type->modes[1].interconnect[1].parent_mode = &lut_pb_type->modes[1]; lut_pb_type->modes[1].interconnect[1].interconnect_power = (t_interconnect_power*)vtr::calloc(1, sizeof(t_interconnect_power)); - free(default_name); + delete default_name; - free(lut_pb_type->blif_model); + delete lut_pb_type->blif_model; lut_pb_type->blif_model = nullptr; lut_pb_type->model = nullptr; } @@ -911,7 +911,7 @@ void ProcessMemoryClass(t_pb_type* mem_pb_type) { mem_pb_type->num_modes = 1; - free(mem_pb_type->blif_model); + delete mem_pb_type->blif_model; mem_pb_type->blif_model = nullptr; mem_pb_type->model = nullptr; @@ -1030,7 +1030,7 @@ void ProcessMemoryClass(t_pb_type* mem_pb_type) { mem_pb_type->modes[0].num_interconnect = i_inter; - free(default_name); + delete default_name; } e_power_estimation_method power_method_inherited(e_power_estimation_method parent_power_method) { From 2353564add4ac1dc795dfe576d453f1db7a86302 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Thu, 22 Dec 2022 11:05:39 +0100 Subject: [PATCH 35/55] libarchfpga: change all .alloc() calls to 'new' Signed-off-by: Pawel Czarnecki --- libs/libarchfpga/src/arch_util.cpp | 121 +++++++++++------------------ 1 file changed, 46 insertions(+), 75 deletions(-) diff --git a/libs/libarchfpga/src/arch_util.cpp b/libs/libarchfpga/src/arch_util.cpp index c1573f71dea..e36c87af4c7 100644 --- a/libs/libarchfpga/src/arch_util.cpp +++ b/libs/libarchfpga/src/arch_util.cpp @@ -611,13 +611,12 @@ void alloc_and_load_default_child_for_pb_type(t_pb_type* pb_type, copy->num_pb = 1; /* Power */ - copy->pb_type_power = (t_pb_type_power*)vtr::calloc(1, - sizeof(t_pb_type_power)); + copy->pb_type_power = new t_pb_type_power[1](); copy->pb_type_power->estimation_method = power_method_inherited(pb_type->pb_type_power->estimation_method); /* Ports */ copy->num_ports = pb_type->num_ports; - copy->ports = (t_port*)vtr::calloc(pb_type->num_ports, sizeof(t_port)); + copy->ports = new t_port[pb_type->num_ports](); for (i = 0; i < pb_type->num_ports; i++) { copy->ports[i].is_clock = pb_type->ports[i].is_clock; copy->ports[i].model_port = pb_type->ports[i].model_port; @@ -630,8 +629,7 @@ void alloc_and_load_default_child_for_pb_type(t_pb_type* pb_type, copy->ports[i].index = pb_type->ports[i].index; copy->ports[i].absolute_first_pin_index = pb_type->ports[i].absolute_first_pin_index; - copy->ports[i].port_power = (t_port_power*)vtr::calloc(1, - sizeof(t_port_power)); + copy->ports[i].port_power = new t_port_power[1](); //Defaults if (copy->pb_type_power->estimation_method == POWER_METHOD_AUTO_SIZES) { copy->ports[i].port_power->wire_type = POWER_WIRE_TYPE_AUTO; @@ -645,7 +643,7 @@ void alloc_and_load_default_child_for_pb_type(t_pb_type* pb_type, // Special case for latch - fill secondary data fields if (pb_type->class_type == LATCH_CLASS) { copy->num_ports_sec = pb_type->num_ports; - copy->ports_sec = (t_port*)vtr::calloc(pb_type->num_ports, sizeof(t_port)); + copy->ports_sec = new t_port[pb_type->num_ports](); for (i = 0; i < pb_type->num_ports; i++) { copy->ports_sec[i].is_clock = pb_type->ports[i].is_clock; copy->ports_sec[i].model_port = pb_type->ports[i].model_port; @@ -658,8 +656,7 @@ void alloc_and_load_default_child_for_pb_type(t_pb_type* pb_type, copy->ports_sec[i].index = pb_type->ports[i].index; copy->ports_sec[i].absolute_first_pin_index = pb_type->ports[i].absolute_first_pin_index; - copy->ports_sec[i].port_power = (t_port_power*)vtr::calloc(1, - sizeof(t_port_power)); + copy->ports_sec[i].port_power = new t_port_power[1](); //Defaults if (copy->pb_type_power->estimation_method == POWER_METHOD_AUTO_SIZES) { copy->ports_sec[i].port_power->wire_type = POWER_WIRE_TYPE_AUTO; @@ -672,18 +669,18 @@ void alloc_and_load_default_child_for_pb_type(t_pb_type* pb_type, } } - copy->annotations = (t_pin_to_pin_annotation*)vtr::calloc(pb_type->num_annotations, sizeof(t_pin_to_pin_annotation)); + copy->annotations = new t_pin_to_pin_annotation[pb_type->num_annotations](); copy->num_annotations = pb_type->num_annotations; for (i = 0; i < copy->num_annotations; i++) { copy->annotations[i].clock = vtr::strdup(pb_type->annotations[i].clock); dot = strstr(pb_type->annotations[i].input_pins, "."); - copy->annotations[i].input_pins = (char*)vtr::malloc(sizeof(char) * (strlen(new_name) + strlen(dot) + 1)); + copy->annotations[i].input_pins = new char[strlen(new_name) + strlen(dot) + 1]; copy->annotations[i].input_pins[0] = '\0'; strcat(copy->annotations[i].input_pins, new_name); strcat(copy->annotations[i].input_pins, dot); if (pb_type->annotations[i].output_pins != nullptr) { dot = strstr(pb_type->annotations[i].output_pins, "."); - copy->annotations[i].output_pins = (char*)vtr::malloc(sizeof(char) * (strlen(new_name) + strlen(dot) + 1)); + copy->annotations[i].output_pins = new char[strlen(new_name) + strlen(dot) + 1]; copy->annotations[i].output_pins[0] = '\0'; strcat(copy->annotations[i].output_pins, new_name); strcat(copy->annotations[i].output_pins, dot); @@ -694,8 +691,8 @@ void alloc_and_load_default_child_for_pb_type(t_pb_type* pb_type, copy->annotations[i].format = pb_type->annotations[i].format; copy->annotations[i].type = pb_type->annotations[i].type; copy->annotations[i].num_value_prop_pairs = pb_type->annotations[i].num_value_prop_pairs; - copy->annotations[i].prop = (int*)vtr::malloc(sizeof(int) * pb_type->annotations[i].num_value_prop_pairs); - copy->annotations[i].value = (char**)vtr::malloc(sizeof(char*) * pb_type->annotations[i].num_value_prop_pairs); + copy->annotations[i].prop = new int[pb_type->annotations[i].num_value_prop_pairs]; + copy->annotations[i].value = new char*[pb_type->annotations[i].num_value_prop_pairs]; for (j = 0; j < pb_type->annotations[i].num_value_prop_pairs; j++) { copy->annotations[i].prop[j] = pb_type->annotations[i].prop[j]; copy->annotations[i].value[j] = vtr::strdup(pb_type->annotations[i].value[j]); @@ -725,8 +722,7 @@ void ProcessLutClass(t_pb_type* lut_pb_type) { lut_pb_type->modes[0].parent_pb_type = lut_pb_type; lut_pb_type->modes[0].index = 0; lut_pb_type->modes[0].num_pb_type_children = 0; - lut_pb_type->modes[0].mode_power = (t_mode_power*)vtr::calloc(1, - sizeof(t_mode_power)); + lut_pb_type->modes[0].mode_power = new t_mode_power[1](); /* Process interconnect */ /* TODO: add timing annotations to route-through */ @@ -743,25 +739,22 @@ void ProcessLutClass(t_pb_type* lut_pb_type) { } lut_pb_type->modes[0].num_interconnect = 1; lut_pb_type->modes[0].interconnect = new t_interconnect[1]; - lut_pb_type->modes[0].interconnect[0].name = (char*)vtr::calloc(strlen(lut_pb_type->name) + 10, sizeof(char)); + lut_pb_type->modes[0].interconnect[0].name = new char[strlen(lut_pb_type->name) + 10]; sprintf(lut_pb_type->modes[0].interconnect[0].name, "complete:%s", lut_pb_type->name); lut_pb_type->modes[0].interconnect[0].type = COMPLETE_INTERC; - lut_pb_type->modes[0].interconnect[0].input_string = (char*)vtr::calloc(strlen(lut_pb_type->name) + strlen(in_port->name) + 2, - sizeof(char)); + lut_pb_type->modes[0].interconnect[0].input_string = new char[strlen(lut_pb_type->name) + strlen(in_port->name) + 2]; sprintf(lut_pb_type->modes[0].interconnect[0].input_string, "%s.%s", lut_pb_type->name, in_port->name); - lut_pb_type->modes[0].interconnect[0].output_string = (char*)vtr::calloc(strlen(lut_pb_type->name) + strlen(out_port->name) + 2, - sizeof(char)); + lut_pb_type->modes[0].interconnect[0].output_string = new char[strlen(lut_pb_type->name) + strlen(out_port->name) + 2]; sprintf(lut_pb_type->modes[0].interconnect[0].output_string, "%s.%s", lut_pb_type->name, out_port->name); lut_pb_type->modes[0].interconnect[0].parent_mode_index = 0; lut_pb_type->modes[0].interconnect[0].parent_mode = &lut_pb_type->modes[0]; - lut_pb_type->modes[0].interconnect[0].interconnect_power = (t_interconnect_power*)vtr::calloc(1, sizeof(t_interconnect_power)); + lut_pb_type->modes[0].interconnect[0].interconnect_power = new t_interconnect_power[1](); - lut_pb_type->modes[0].interconnect[0].annotations = (t_pin_to_pin_annotation*)vtr::calloc(lut_pb_type->num_annotations, - sizeof(t_pin_to_pin_annotation)); + lut_pb_type->modes[0].interconnect[0].annotations = new t_pin_to_pin_annotation[lut_pb_type->num_annotations](); lut_pb_type->modes[0].interconnect[0].num_annotations = lut_pb_type->num_annotations; for (i = 0; i < lut_pb_type->modes[0].interconnect[0].num_annotations; i++) { @@ -772,10 +765,8 @@ void ProcessLutClass(t_pb_type* lut_pb_type) { lut_pb_type->modes[0].interconnect[0].annotations[i].format = lut_pb_type->annotations[i].format; lut_pb_type->modes[0].interconnect[0].annotations[i].type = lut_pb_type->annotations[i].type; lut_pb_type->modes[0].interconnect[0].annotations[i].num_value_prop_pairs = lut_pb_type->annotations[i].num_value_prop_pairs; - lut_pb_type->modes[0].interconnect[0].annotations[i].prop = (int*)vtr::malloc(sizeof(int) - * lut_pb_type->annotations[i].num_value_prop_pairs); - lut_pb_type->modes[0].interconnect[0].annotations[i].value = (char**)vtr::malloc(sizeof(char*) - * lut_pb_type->annotations[i].num_value_prop_pairs); + lut_pb_type->modes[0].interconnect[0].annotations[i].prop = new int[lut_pb_type->annotations[i].num_value_prop_pairs]; + lut_pb_type->modes[0].interconnect[0].annotations[i].value = new char*[lut_pb_type->annotations[i].num_value_prop_pairs]; for (j = 0; j < lut_pb_type->annotations[i].num_value_prop_pairs; j++) { lut_pb_type->modes[0].interconnect[0].annotations[i].prop[j] = lut_pb_type->annotations[i].prop[j]; lut_pb_type->modes[0].interconnect[0].annotations[i].value[j] = vtr::strdup(lut_pb_type->annotations[i].value[j]); @@ -788,8 +779,7 @@ void ProcessLutClass(t_pb_type* lut_pb_type) { lut_pb_type->modes[1].parent_pb_type = lut_pb_type; lut_pb_type->modes[1].index = 1; lut_pb_type->modes[1].num_pb_type_children = 1; - lut_pb_type->modes[1].mode_power = (t_mode_power*)vtr::calloc(1, - sizeof(t_mode_power)); + lut_pb_type->modes[1].mode_power = new t_mode_power[1](); lut_pb_type->modes[1].pb_type_children = new t_pb_type[1]; alloc_and_load_default_child_for_pb_type(lut_pb_type, default_name, lut_pb_type->modes[1].pb_type_children); @@ -824,41 +814,39 @@ void ProcessLutClass(t_pb_type* lut_pb_type) { /* Process interconnect */ lut_pb_type->modes[1].num_interconnect = 2; lut_pb_type->modes[1].interconnect = new t_interconnect[lut_pb_type->modes[1].num_interconnect]; - lut_pb_type->modes[1].interconnect[0].name = (char*)vtr::calloc(strlen(lut_pb_type->name) + 10, sizeof(char)); + lut_pb_type->modes[1].interconnect[0].name = new char[strlen(lut_pb_type->name) + 10]; sprintf(lut_pb_type->modes[1].interconnect[0].name, "direct:%s", lut_pb_type->name); lut_pb_type->modes[1].interconnect[0].type = DIRECT_INTERC; - lut_pb_type->modes[1].interconnect[0].input_string = (char*)vtr::calloc(strlen(lut_pb_type->name) + strlen(in_port->name) + 2, - sizeof(char)); + lut_pb_type->modes[1].interconnect[0].input_string = new char[strlen(lut_pb_type->name) + strlen(in_port->name) + 2]; sprintf(lut_pb_type->modes[1].interconnect[0].input_string, "%s.%s", lut_pb_type->name, in_port->name); - lut_pb_type->modes[1].interconnect[0].output_string = (char*)vtr::calloc(strlen(default_name) + strlen(in_port->name) + 2, sizeof(char)); + lut_pb_type->modes[1].interconnect[0].output_string = new char[strlen(default_name) + strlen(in_port->name) + 2]; sprintf(lut_pb_type->modes[1].interconnect[0].output_string, "%s.%s", default_name, in_port->name); lut_pb_type->modes[1].interconnect[0].infer_annotations = true; lut_pb_type->modes[1].interconnect[0].parent_mode_index = 1; lut_pb_type->modes[1].interconnect[0].parent_mode = &lut_pb_type->modes[1]; - lut_pb_type->modes[1].interconnect[0].interconnect_power = (t_interconnect_power*)vtr::calloc(1, sizeof(t_interconnect_power)); + lut_pb_type->modes[1].interconnect[0].interconnect_power = new t_interconnect_power[1](); - lut_pb_type->modes[1].interconnect[1].name = (char*)vtr::calloc(strlen(lut_pb_type->name) + 11, sizeof(char)); + lut_pb_type->modes[1].interconnect[1].name = new char[strlen(lut_pb_type->name) + 11]; sprintf(lut_pb_type->modes[1].interconnect[1].name, "direct:%s", lut_pb_type->name); lut_pb_type->modes[1].interconnect[1].type = DIRECT_INTERC; - lut_pb_type->modes[1].interconnect[1].input_string = (char*)vtr::calloc(strlen(default_name) + strlen(out_port->name) + 4, sizeof(char)); + lut_pb_type->modes[1].interconnect[1].input_string = new char[strlen(default_name) + strlen(out_port->name) + 4]; sprintf(lut_pb_type->modes[1].interconnect[1].input_string, "%s.%s", default_name, out_port->name); - lut_pb_type->modes[1].interconnect[1].output_string = (char*)vtr::calloc(strlen(lut_pb_type->name) + strlen(out_port->name) - + strlen(in_port->name) + 2, - sizeof(char)); + lut_pb_type->modes[1].interconnect[1].output_string = new char[strlen(lut_pb_type->name) + strlen(out_port->name) + + strlen(in_port->name) + 2]; sprintf(lut_pb_type->modes[1].interconnect[1].output_string, "%s.%s", lut_pb_type->name, out_port->name); lut_pb_type->modes[1].interconnect[1].infer_annotations = true; lut_pb_type->modes[1].interconnect[1].parent_mode_index = 1; lut_pb_type->modes[1].interconnect[1].parent_mode = &lut_pb_type->modes[1]; - lut_pb_type->modes[1].interconnect[1].interconnect_power = (t_interconnect_power*)vtr::calloc(1, sizeof(t_interconnect_power)); + lut_pb_type->modes[1].interconnect[1].interconnect_power = new t_interconnect_power[1](); delete default_name; @@ -883,8 +871,7 @@ void ProcessMemoryClass(t_pb_type* mem_pb_type) { mem_pb_type->modes[0].name = vtr::strdup(default_name); mem_pb_type->modes[0].parent_pb_type = mem_pb_type; mem_pb_type->modes[0].index = 0; - mem_pb_type->modes[0].mode_power = (t_mode_power*)vtr::calloc(1, - sizeof(t_mode_power)); + mem_pb_type->modes[0].mode_power = new t_mode_power[1](); num_pb = OPEN; for (i = 0; i < mem_pb_type->num_ports; i++) { if (mem_pb_type->ports[i].port_class != nullptr @@ -941,7 +928,7 @@ void ProcessMemoryClass(t_pb_type* mem_pb_type) { if (mem_pb_type->ports[i].port_class != nullptr && strstr(mem_pb_type->ports[i].port_class, "data") == mem_pb_type->ports[i].port_class) { - mem_pb_type->modes[0].interconnect[i_inter].name = (char*)vtr::calloc(i_inter / 10 + 8, sizeof(char)); + mem_pb_type->modes[0].interconnect[i_inter].name = new char[i_inter / 10 + 8]; sprintf(mem_pb_type->modes[0].interconnect[i_inter].name, "direct%d", i_inter); mem_pb_type->modes[0].interconnect[i_inter].infer_annotations = true; @@ -951,14 +938,11 @@ void ProcessMemoryClass(t_pb_type* mem_pb_type) { mem_pb_type->modes[0].pb_type_children[0].ports[i].num_pins = 1; mem_pb_type->modes[0].pb_type_children[0].num_input_pins -= (mem_pb_type->ports[i].num_pins - 1); - mem_pb_type->modes[0].interconnect[i_inter].input_string = (char*)vtr::calloc(strlen(input_name) + strlen(input_port_name) - + 2, - sizeof(char)); + mem_pb_type->modes[0].interconnect[i_inter].input_string = new char[strlen(input_name) + strlen(input_port_name) + 2]; sprintf(mem_pb_type->modes[0].interconnect[i_inter].input_string, "%s.%s", input_name, input_port_name); - mem_pb_type->modes[0].interconnect[i_inter].output_string = (char*)vtr::calloc(strlen(output_name) + strlen(output_port_name) - + 2 * (6 + num_pb / 10), - sizeof(char)); + mem_pb_type->modes[0].interconnect[i_inter].output_string = new char[strlen(output_name) + strlen(output_port_name) + + 2 * (6 + num_pb / 10)]; sprintf(mem_pb_type->modes[0].interconnect[i_inter].output_string, "%s[%d:0].%s", output_name, num_pb - 1, output_port_name); @@ -967,62 +951,49 @@ void ProcessMemoryClass(t_pb_type* mem_pb_type) { mem_pb_type->modes[0].pb_type_children[0].ports[i].num_pins = 1; mem_pb_type->modes[0].pb_type_children[0].num_output_pins -= (mem_pb_type->ports[i].num_pins - 1); - mem_pb_type->modes[0].interconnect[i_inter].input_string = (char*)vtr::calloc(strlen(input_name) + strlen(input_port_name) - + 2 * (6 + num_pb / 10), - sizeof(char)); + mem_pb_type->modes[0].interconnect[i_inter].input_string = new char[strlen(input_name) + strlen(input_port_name) + + 2 * (6 + num_pb / 10)]; sprintf(mem_pb_type->modes[0].interconnect[i_inter].input_string, "%s[%d:0].%s", input_name, num_pb - 1, input_port_name); - mem_pb_type->modes[0].interconnect[i_inter].output_string = (char*)vtr::calloc(strlen(output_name) + strlen(output_port_name) - + 2, - sizeof(char)); + mem_pb_type->modes[0].interconnect[i_inter].output_string = new char[strlen(output_name) + strlen(output_port_name) + + 2]; sprintf(mem_pb_type->modes[0].interconnect[i_inter].output_string, "%s.%s", output_name, output_port_name); } /* Allocate interconnect power structures */ - mem_pb_type->modes[0].interconnect[i_inter].interconnect_power = (t_interconnect_power*)vtr::calloc(1, - sizeof(t_interconnect_power)); + mem_pb_type->modes[0].interconnect[i_inter].interconnect_power = new t_interconnect_power[1](); i_inter++; } else { for (j = 0; j < num_pb; j++) { /* Anything that is not data must be an input */ - mem_pb_type->modes[0].interconnect[i_inter].name = (char*)vtr::calloc(i_inter / 10 + j / 10 + 10, - sizeof(char)); + mem_pb_type->modes[0].interconnect[i_inter].name = new char[i_inter / 10 + j / 10 + 10]; sprintf(mem_pb_type->modes[0].interconnect[i_inter].name, "direct%d_%d", i_inter, j); mem_pb_type->modes[0].interconnect[i_inter].infer_annotations = true; if (mem_pb_type->ports[i].type == IN_PORT) { mem_pb_type->modes[0].interconnect[i_inter].type = DIRECT_INTERC; - mem_pb_type->modes[0].interconnect[i_inter].input_string = (char*)vtr::calloc(strlen(input_name) + strlen(input_port_name) - + 2, - sizeof(char)); + mem_pb_type->modes[0].interconnect[i_inter].input_string = new char[strlen(input_name) + strlen(input_port_name) + 2]; sprintf(mem_pb_type->modes[0].interconnect[i_inter].input_string, "%s.%s", input_name, input_port_name); - mem_pb_type->modes[0].interconnect[i_inter].output_string = (char*)vtr::calloc(strlen(output_name) - + strlen(output_port_name) - + 2 * (6 + num_pb / 10), - sizeof(char)); + mem_pb_type->modes[0].interconnect[i_inter].output_string = new char[strlen(output_name) + strlen(output_port_name) + 2 * (6 + num_pb / 10)]; sprintf(mem_pb_type->modes[0].interconnect[i_inter].output_string, "%s[%d:%d].%s", output_name, j, j, output_port_name); } else { mem_pb_type->modes[0].interconnect[i_inter].type = DIRECT_INTERC; - mem_pb_type->modes[0].interconnect[i_inter].input_string = (char*)vtr::calloc(strlen(input_name) + strlen(input_port_name) - + 2 * (6 + num_pb / 10), - sizeof(char)); + mem_pb_type->modes[0].interconnect[i_inter].input_string = new char[strlen(input_name) + strlen(input_port_name) + + 2 * (6 + num_pb / 10)]; sprintf(mem_pb_type->modes[0].interconnect[i_inter].input_string, "%s[%d:%d].%s", input_name, j, j, input_port_name); - mem_pb_type->modes[0].interconnect[i_inter].output_string = (char*)vtr::calloc(strlen(output_name) - + strlen(output_port_name) + 2, - sizeof(char)); + mem_pb_type->modes[0].interconnect[i_inter].output_string = new char[strlen(output_name) + strlen(output_port_name) + 2]; sprintf(mem_pb_type->modes[0].interconnect[i_inter].output_string, "%s.%s", output_name, output_port_name); } /* Allocate interconnect power structures */ - mem_pb_type->modes[0].interconnect[i_inter].interconnect_power = (t_interconnect_power*)vtr::calloc(1, - sizeof(t_interconnect_power)); + mem_pb_type->modes[0].interconnect[i_inter].interconnect_power = new t_interconnect_power[1](); i_inter++; } } @@ -1210,7 +1181,7 @@ void SyncModel(t_pb_type* pb_type, t_model* model_match_prim, bool is_secondary_ } old = model_match_prim->pb_types; - model_match_prim->pb_types = (vtr::t_linked_vptr*)vtr::malloc(sizeof(vtr::t_linked_vptr)); + model_match_prim->pb_types = new vtr::t_linked_vptr(); model_match_prim->pb_types->next = old; model_match_prim->pb_types->data_vptr = pb_type; for (p = 0; p < pb_type->num_ports; p++) { From e0a3b9388807db76e2c35824c73a2ffcf6e26e2f Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Thu, 22 Dec 2022 12:05:57 +0100 Subject: [PATCH 36/55] libarchfpga: comments for freeing internal models lib Signed-off-by: Pawel Czarnecki --- libs/libarchfpga/src/arch_util.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/libs/libarchfpga/src/arch_util.cpp b/libs/libarchfpga/src/arch_util.cpp index e36c87af4c7..7e24b28714c 100644 --- a/libs/libarchfpga/src/arch_util.cpp +++ b/libs/libarchfpga/src/arch_util.cpp @@ -171,6 +171,7 @@ void free_arch(t_arch* arch) { delete arch->architecture_id; + //Free internal model library if (arch->model_library) { for (int i = 0; i < num_models_lib; ++i) { vtr::t_linked_vptr* vptr = arch->model_library[i].pb_types; @@ -181,29 +182,41 @@ void free_arch(t_arch* arch) { } } + //Each model has different number of inputs/outputs - delete each model separately + //Free INPAD delete arch->model_library[0].name; delete arch->model_library[0].outputs->name; delete[] arch->model_library[0].outputs; + + //Free OUTPAD + delete arch->model_library[1].name; delete arch->model_library[1].inputs->name; delete[] arch->model_library[1].inputs; - delete arch->model_library[1].name; + + //Free LATCH triggered at RISING EDGE delete arch->model_library[2].name; delete arch->model_library[2].inputs[0].name; delete arch->model_library[2].inputs[1].name; delete[] arch->model_library[2].inputs; delete arch->model_library[2].outputs->name; delete[] arch->model_library[2].outputs; + + //Free LATCH triggered at FALLING EDGE delete arch->model_library[3].name; delete arch->model_library[3].inputs[0].name; delete arch->model_library[3].inputs[1].name; delete[] arch->model_library[3].inputs; delete arch->model_library[3].outputs->name; delete[] arch->model_library[3].outputs; + + //Free NAMES delete arch->model_library[4].name; delete arch->model_library[4].inputs->name; delete[] arch->model_library[4].inputs; delete arch->model_library[4].outputs->name; delete[] arch->model_library[4].outputs; + + //Free the library array delete[] arch->model_library; } @@ -1031,6 +1044,10 @@ void CreateModelLibrary(t_arch* arch) { model_library = new t_model[num_models_lib]; //INPAD + //OUTPAD + //LATCH triggered at RISING EDGE + //LATCH triggered at FALLING EDGE + //NAMES model_library[0].name = vtr::strdup(MODEL_INPUT); model_library[0].index = 0; model_library[0].inputs = nullptr; From 362821ae61257014a8e0925029a84855a0df4f03 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Thu, 22 Dec 2022 14:48:09 +0100 Subject: [PATCH 37/55] arch_util: cleanup comments Signed-off-by: Pawel Czarnecki --- libs/libarchfpga/src/arch_util.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libs/libarchfpga/src/arch_util.cpp b/libs/libarchfpga/src/arch_util.cpp index 7e24b28714c..ab385ce5ebe 100644 --- a/libs/libarchfpga/src/arch_util.cpp +++ b/libs/libarchfpga/src/arch_util.cpp @@ -1044,10 +1044,6 @@ void CreateModelLibrary(t_arch* arch) { model_library = new t_model[num_models_lib]; //INPAD - //OUTPAD - //LATCH triggered at RISING EDGE - //LATCH triggered at FALLING EDGE - //NAMES model_library[0].name = vtr::strdup(MODEL_INPUT); model_library[0].index = 0; model_library[0].inputs = nullptr; From 0ce6545135ec2631dfc23b2fb2bc61e4f4efd190 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Thu, 22 Dec 2022 15:22:54 +0100 Subject: [PATCH 38/55] libarchfpga: add enum for internal models Signed-off-by: Pawel Czarnecki --- libs/libarchfpga/src/arch_util.cpp | 290 ++++++++++++++--------------- libs/libarchfpga/src/arch_util.h | 8 + 2 files changed, 153 insertions(+), 145 deletions(-) diff --git a/libs/libarchfpga/src/arch_util.cpp b/libs/libarchfpga/src/arch_util.cpp index ab385ce5ebe..24ffc050d63 100644 --- a/libs/libarchfpga/src/arch_util.cpp +++ b/libs/libarchfpga/src/arch_util.cpp @@ -184,37 +184,37 @@ void free_arch(t_arch* arch) { //Each model has different number of inputs/outputs - delete each model separately //Free INPAD - delete arch->model_library[0].name; - delete arch->model_library[0].outputs->name; - delete[] arch->model_library[0].outputs; + delete arch->model_library[LIB_INPUT].name; + delete arch->model_library[LIB_INPUT].outputs->name; + delete[] arch->model_library[LIB_INPUT].outputs; //Free OUTPAD - delete arch->model_library[1].name; - delete arch->model_library[1].inputs->name; - delete[] arch->model_library[1].inputs; + delete arch->model_library[LIB_OUTPUT].name; + delete arch->model_library[LIB_OUTPUT].inputs->name; + delete[] arch->model_library[LIB_OUTPUT].inputs; //Free LATCH triggered at RISING EDGE - delete arch->model_library[2].name; - delete arch->model_library[2].inputs[0].name; - delete arch->model_library[2].inputs[1].name; - delete[] arch->model_library[2].inputs; - delete arch->model_library[2].outputs->name; - delete[] arch->model_library[2].outputs; + delete arch->model_library[LIB_LATCH_RE].name; + delete arch->model_library[LIB_LATCH_RE].inputs[0].name; + delete arch->model_library[LIB_LATCH_RE].inputs[1].name; + delete[] arch->model_library[LIB_LATCH_RE].inputs; + delete arch->model_library[LIB_LATCH_RE].outputs->name; + delete[] arch->model_library[LIB_LATCH_RE].outputs; //Free LATCH triggered at FALLING EDGE - delete arch->model_library[3].name; - delete arch->model_library[3].inputs[0].name; - delete arch->model_library[3].inputs[1].name; - delete[] arch->model_library[3].inputs; - delete arch->model_library[3].outputs->name; - delete[] arch->model_library[3].outputs; + delete arch->model_library[LIB_LATCH_FE].name; + delete arch->model_library[LIB_LATCH_FE].inputs[0].name; + delete arch->model_library[LIB_LATCH_FE].inputs[1].name; + delete[] arch->model_library[LIB_LATCH_FE].inputs; + delete arch->model_library[LIB_LATCH_FE].outputs->name; + delete[] arch->model_library[LIB_LATCH_FE].outputs; //Free NAMES - delete arch->model_library[4].name; - delete arch->model_library[4].inputs->name; - delete[] arch->model_library[4].inputs; - delete arch->model_library[4].outputs->name; - delete[] arch->model_library[4].outputs; + delete arch->model_library[LIB_NAMES].name; + delete arch->model_library[LIB_NAMES].inputs->name; + delete[] arch->model_library[LIB_NAMES].inputs; + delete arch->model_library[LIB_NAMES].outputs->name; + delete[] arch->model_library[LIB_NAMES].outputs; //Free the library array delete[] arch->model_library; @@ -1044,136 +1044,136 @@ void CreateModelLibrary(t_arch* arch) { model_library = new t_model[num_models_lib]; //INPAD - model_library[0].name = vtr::strdup(MODEL_INPUT); - model_library[0].index = 0; - model_library[0].inputs = nullptr; - model_library[0].instances = nullptr; - model_library[0].next = &model_library[1]; - model_library[0].outputs = new t_model_ports[1]; - model_library[0].outputs->dir = OUT_PORT; - model_library[0].outputs->name = vtr::strdup("inpad"); - model_library[0].outputs->next = nullptr; - model_library[0].outputs->size = 1; - model_library[0].outputs->min_size = 1; - model_library[0].outputs->index = 0; - model_library[0].outputs->is_clock = false; + model_library[LIB_INPUT].name = vtr::strdup(MODEL_INPUT); + model_library[LIB_INPUT].index = LIB_INPUT; + model_library[LIB_INPUT].inputs = nullptr; + model_library[LIB_INPUT].instances = nullptr; + model_library[LIB_INPUT].next = &model_library[LIB_OUTPUT]; + model_library[LIB_INPUT].outputs = new t_model_ports[1]; + model_library[LIB_INPUT].outputs->dir = OUT_PORT; + model_library[LIB_INPUT].outputs->name = vtr::strdup("inpad"); + model_library[LIB_INPUT].outputs->next = nullptr; + model_library[LIB_INPUT].outputs->size = 1; + model_library[LIB_INPUT].outputs->min_size = 1; + model_library[LIB_INPUT].outputs->index = 0; + model_library[LIB_INPUT].outputs->is_clock = false; //OUTPAD - model_library[1].name = vtr::strdup(MODEL_OUTPUT); - model_library[1].index = 1; - model_library[1].inputs = new t_model_ports[1]; - model_library[1].inputs->dir = IN_PORT; - model_library[1].inputs->name = vtr::strdup("outpad"); - model_library[1].inputs->next = nullptr; - model_library[1].inputs->size = 1; - model_library[1].inputs->min_size = 1; - model_library[1].inputs->index = 0; - model_library[1].inputs->is_clock = false; - model_library[1].instances = nullptr; - model_library[1].next = &model_library[2]; - model_library[1].outputs = nullptr; + model_library[LIB_OUTPUT].name = vtr::strdup(MODEL_OUTPUT); + model_library[LIB_OUTPUT].index = LIB_OUTPUT; + model_library[LIB_OUTPUT].inputs = new t_model_ports[1]; + model_library[LIB_OUTPUT].inputs->dir = IN_PORT; + model_library[LIB_OUTPUT].inputs->name = vtr::strdup("outpad"); + model_library[LIB_OUTPUT].inputs->next = nullptr; + model_library[LIB_OUTPUT].inputs->size = 1; + model_library[LIB_OUTPUT].inputs->min_size = 1; + model_library[LIB_OUTPUT].inputs->index = 0; + model_library[LIB_OUTPUT].inputs->is_clock = false; + model_library[LIB_OUTPUT].instances = nullptr; + model_library[LIB_OUTPUT].next = &model_library[LIB_LATCH_RE]; + model_library[LIB_OUTPUT].outputs = nullptr; //LATCH triggered at RISING EDGE - model_library[2].name = vtr::strdup(MODEL_LATCH); - model_library[2].index = 2; - model_library[2].inputs = new t_model_ports[2]; - - model_library[2].inputs[0].dir = IN_PORT; - model_library[2].inputs[0].name = vtr::strdup("D"); - model_library[2].inputs[0].next = &model_library[2].inputs[1]; - model_library[2].inputs[0].size = 1; - model_library[2].inputs[0].min_size = 1; - model_library[2].inputs[0].index = 0; - model_library[2].inputs[0].is_clock = false; - model_library[2].inputs[0].clock = "clk"; - model_library[2].inputs[0].trigg_edge = TriggeringEdge::RISING_EDGE; - - model_library[2].inputs[1].dir = IN_PORT; - model_library[2].inputs[1].name = vtr::strdup("clk"); - model_library[2].inputs[1].next = nullptr; - model_library[2].inputs[1].size = 1; - model_library[2].inputs[1].min_size = 1; - model_library[2].inputs[1].index = 0; - model_library[2].inputs[1].is_clock = true; - model_library[2].inputs[1].trigg_edge = TriggeringEdge::RISING_EDGE; - - model_library[2].instances = nullptr; - model_library[2].next = &model_library[3]; - - model_library[2].outputs = new t_model_ports[1]; - model_library[2].outputs[0].dir = OUT_PORT; - model_library[2].outputs[0].name = vtr::strdup("Q"); - model_library[2].outputs[0].next = nullptr; - model_library[2].outputs[0].size = 1; - model_library[2].outputs[0].min_size = 1; - model_library[2].outputs[0].index = 0; - model_library[2].outputs[0].is_clock = false; - model_library[2].outputs[0].clock = "clk"; - model_library[2].outputs[0].trigg_edge = TriggeringEdge::RISING_EDGE; + model_library[LIB_LATCH_RE].name = vtr::strdup(MODEL_LATCH); + model_library[LIB_LATCH_RE].index = LIB_LATCH_RE; + model_library[LIB_LATCH_RE].inputs = new t_model_ports[2]; + + model_library[LIB_LATCH_RE].inputs[0].dir = IN_PORT; + model_library[LIB_LATCH_RE].inputs[0].name = vtr::strdup("D"); + model_library[LIB_LATCH_RE].inputs[0].next = &model_library[LIB_LATCH_RE].inputs[1]; + model_library[LIB_LATCH_RE].inputs[0].size = 1; + model_library[LIB_LATCH_RE].inputs[0].min_size = 1; + model_library[LIB_LATCH_RE].inputs[0].index = 0; + model_library[LIB_LATCH_RE].inputs[0].is_clock = false; + model_library[LIB_LATCH_RE].inputs[0].clock = "clk"; + model_library[LIB_LATCH_RE].inputs[0].trigg_edge = TriggeringEdge::RISING_EDGE; + + model_library[LIB_LATCH_RE].inputs[1].dir = IN_PORT; + model_library[LIB_LATCH_RE].inputs[1].name = vtr::strdup("clk"); + model_library[LIB_LATCH_RE].inputs[1].next = nullptr; + model_library[LIB_LATCH_RE].inputs[1].size = 1; + model_library[LIB_LATCH_RE].inputs[1].min_size = 1; + model_library[LIB_LATCH_RE].inputs[1].index = 0; + model_library[LIB_LATCH_RE].inputs[1].is_clock = true; + model_library[LIB_LATCH_RE].inputs[1].trigg_edge = TriggeringEdge::RISING_EDGE; + + model_library[LIB_LATCH_RE].instances = nullptr; + model_library[LIB_LATCH_RE].next = &model_library[LIB_LATCH_FE]; + + model_library[LIB_LATCH_RE].outputs = new t_model_ports[1]; + model_library[LIB_LATCH_RE].outputs[0].dir = OUT_PORT; + model_library[LIB_LATCH_RE].outputs[0].name = vtr::strdup("Q"); + model_library[LIB_LATCH_RE].outputs[0].next = nullptr; + model_library[LIB_LATCH_RE].outputs[0].size = 1; + model_library[LIB_LATCH_RE].outputs[0].min_size = 1; + model_library[LIB_LATCH_RE].outputs[0].index = 0; + model_library[LIB_LATCH_RE].outputs[0].is_clock = false; + model_library[LIB_LATCH_RE].outputs[0].clock = "clk"; + model_library[LIB_LATCH_RE].outputs[0].trigg_edge = TriggeringEdge::RISING_EDGE; //LATCH triggered at FALLING EDGE - model_library[3].name = vtr::strdup(MODEL_LATCH); - model_library[3].index = 3; - model_library[3].inputs = new t_model_ports[2]; - - model_library[3].inputs[0].dir = IN_PORT; - model_library[3].inputs[0].name = vtr::strdup("D"); - model_library[3].inputs[0].next = &model_library[3].inputs[1]; - model_library[3].inputs[0].size = 1; - model_library[3].inputs[0].min_size = 1; - model_library[3].inputs[0].index = 0; - model_library[3].inputs[0].is_clock = false; - model_library[3].inputs[0].clock = "clk"; - model_library[3].inputs[0].trigg_edge = TriggeringEdge::FALLING_EDGE; - - model_library[3].inputs[1].dir = IN_PORT; - model_library[3].inputs[1].name = vtr::strdup("clk"); - model_library[3].inputs[1].next = nullptr; - model_library[3].inputs[1].size = 1; - model_library[3].inputs[1].min_size = 1; - model_library[3].inputs[1].index = 0; - model_library[3].inputs[1].is_clock = true; - model_library[3].inputs[1].trigg_edge = TriggeringEdge::FALLING_EDGE; - - model_library[3].instances = nullptr; - model_library[3].next = &model_library[4]; - - model_library[3].outputs = new t_model_ports[1]; - model_library[3].outputs[0].dir = OUT_PORT; - model_library[3].outputs[0].name = vtr::strdup("Q"); - model_library[3].outputs[0].next = nullptr; - model_library[3].outputs[0].size = 1; - model_library[3].outputs[0].min_size = 1; - model_library[3].outputs[0].index = 0; - model_library[3].outputs[0].is_clock = false; - model_library[3].outputs[0].clock = "clk"; - model_library[3].outputs[0].trigg_edge = TriggeringEdge::FALLING_EDGE; + model_library[LIB_LATCH_FE].name = vtr::strdup(MODEL_LATCH); + model_library[LIB_LATCH_FE].index = LIB_LATCH_FE; + model_library[LIB_LATCH_FE].inputs = new t_model_ports[2]; + + model_library[LIB_LATCH_FE].inputs[0].dir = IN_PORT; + model_library[LIB_LATCH_FE].inputs[0].name = vtr::strdup("D"); + model_library[LIB_LATCH_FE].inputs[0].next = &model_library[LIB_LATCH_FE].inputs[1]; + model_library[LIB_LATCH_FE].inputs[0].size = 1; + model_library[LIB_LATCH_FE].inputs[0].min_size = 1; + model_library[LIB_LATCH_FE].inputs[0].index = 0; + model_library[LIB_LATCH_FE].inputs[0].is_clock = false; + model_library[LIB_LATCH_FE].inputs[0].clock = "clk"; + model_library[LIB_LATCH_FE].inputs[0].trigg_edge = TriggeringEdge::FALLING_EDGE; + + model_library[LIB_LATCH_FE].inputs[1].dir = IN_PORT; + model_library[LIB_LATCH_FE].inputs[1].name = vtr::strdup("clk"); + model_library[LIB_LATCH_FE].inputs[1].next = nullptr; + model_library[LIB_LATCH_FE].inputs[1].size = 1; + model_library[LIB_LATCH_FE].inputs[1].min_size = 1; + model_library[LIB_LATCH_FE].inputs[1].index = 0; + model_library[LIB_LATCH_FE].inputs[1].is_clock = true; + model_library[LIB_LATCH_FE].inputs[1].trigg_edge = TriggeringEdge::FALLING_EDGE; + + model_library[LIB_LATCH_FE].instances = nullptr; + model_library[LIB_LATCH_FE].next = &model_library[LIB_NAMES]; + + model_library[LIB_LATCH_FE].outputs = new t_model_ports[1]; + model_library[LIB_LATCH_FE].outputs[0].dir = OUT_PORT; + model_library[LIB_LATCH_FE].outputs[0].name = vtr::strdup("Q"); + model_library[LIB_LATCH_FE].outputs[0].next = nullptr; + model_library[LIB_LATCH_FE].outputs[0].size = 1; + model_library[LIB_LATCH_FE].outputs[0].min_size = 1; + model_library[LIB_LATCH_FE].outputs[0].index = 0; + model_library[LIB_LATCH_FE].outputs[0].is_clock = false; + model_library[LIB_LATCH_FE].outputs[0].clock = "clk"; + model_library[LIB_LATCH_FE].outputs[0].trigg_edge = TriggeringEdge::FALLING_EDGE; //NAMES - model_library[4].name = vtr::strdup(MODEL_NAMES); - model_library[4].index = 4; - - model_library[4].inputs = new t_model_ports[1]; - model_library[4].inputs[0].dir = IN_PORT; - model_library[4].inputs[0].name = vtr::strdup("in"); - model_library[4].inputs[0].next = nullptr; - model_library[4].inputs[0].size = 1; - model_library[4].inputs[0].min_size = 1; - model_library[4].inputs[0].index = 0; - model_library[4].inputs[0].is_clock = false; - model_library[4].inputs[0].combinational_sink_ports = {"out"}; - - model_library[4].instances = nullptr; - model_library[4].next = nullptr; - - model_library[4].outputs = new t_model_ports[1]; - model_library[4].outputs[0].dir = OUT_PORT; - model_library[4].outputs[0].name = vtr::strdup("out"); - model_library[4].outputs[0].next = nullptr; - model_library[4].outputs[0].size = 1; - model_library[4].outputs[0].min_size = 1; - model_library[4].outputs[0].index = 0; - model_library[4].outputs[0].is_clock = false; + model_library[LIB_NAMES].name = vtr::strdup(MODEL_NAMES); + model_library[LIB_NAMES].index = LIB_NAMES; + + model_library[LIB_NAMES].inputs = new t_model_ports[1]; + model_library[LIB_NAMES].inputs[0].dir = IN_PORT; + model_library[LIB_NAMES].inputs[0].name = vtr::strdup("in"); + model_library[LIB_NAMES].inputs[0].next = nullptr; + model_library[LIB_NAMES].inputs[0].size = 1; + model_library[LIB_NAMES].inputs[0].min_size = 1; + model_library[LIB_NAMES].inputs[0].index = 0; + model_library[LIB_NAMES].inputs[0].is_clock = false; + model_library[LIB_NAMES].inputs[0].combinational_sink_ports = {"out"}; + + model_library[LIB_NAMES].instances = nullptr; + model_library[LIB_NAMES].next = nullptr; + + model_library[LIB_NAMES].outputs = new t_model_ports[1]; + model_library[LIB_NAMES].outputs[0].dir = OUT_PORT; + model_library[LIB_NAMES].outputs[0].name = vtr::strdup("out"); + model_library[LIB_NAMES].outputs[0].next = nullptr; + model_library[LIB_NAMES].outputs[0].size = 1; + model_library[LIB_NAMES].outputs[0].min_size = 1; + model_library[LIB_NAMES].outputs[0].index = 0; + model_library[LIB_NAMES].outputs[0].is_clock = false; arch->model_library = model_library; } diff --git a/libs/libarchfpga/src/arch_util.h b/libs/libarchfpga/src/arch_util.h index 3b7ee8514bd..9834057ee35 100644 --- a/libs/libarchfpga/src/arch_util.h +++ b/libs/libarchfpga/src/arch_util.h @@ -18,6 +18,14 @@ const char* get_arch_file_name(); constexpr const char* EMPTY_BLOCK_NAME = "EMPTY"; constexpr const int num_models_lib = 5; +enum InternalModel { + LIB_INPUT, + LIB_OUTPUT, + LIB_LATCH_RE, + LIB_LATCH_FE, + LIB_NAMES +}; + class InstPort { public: static constexpr int UNSPECIFIED = -1; From 5c76fcb4fc6009a6e808a98592a1c974294266fc Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Thu, 22 Dec 2022 16:40:48 +0100 Subject: [PATCH 39/55] libarchfpga: comments for module library latch duplication Signed-off-by: Pawel Czarnecki --- libs/libarchfpga/src/arch_util.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/libs/libarchfpga/src/arch_util.cpp b/libs/libarchfpga/src/arch_util.cpp index 24ffc050d63..b73ef09e4ad 100644 --- a/libs/libarchfpga/src/arch_util.cpp +++ b/libs/libarchfpga/src/arch_util.cpp @@ -1111,6 +1111,25 @@ void CreateModelLibrary(t_arch* arch) { model_library[LIB_LATCH_RE].outputs[0].clock = "clk"; model_library[LIB_LATCH_RE].outputs[0].trigg_edge = TriggeringEdge::RISING_EDGE; + /* + * Duplicate LATCH model. + * Second separate model is required for falling edge support. + * It is a copy of LIB_LATCH_RE but with different trigg_edge configuration + * for inputs/outputs t_model_ports. It is used to represent FFs triggered at + * the falling edge of the clock, while LIB_LATCH_RE represents FFs triggered + * at the rising edge. + * + * VPR uses single model of each blif primitive type (e.g. '.latch', '.names') parsed from input blif file. + * That means models are used as configuration reference for parsed blif primitives when + * Latch instances are created in circuit evaluation, meaning: + * 1 unique blif primitive configuration (parsed from blif file) maps to + * 1 unique model (defined here, in VPR internal library) which represents configuration of + * multiple primitive instances (of given type and configuration) used in the circuit + * + * Models have to be duplicated because otherwise VPR will use the configuration + * of the last parsed '.latch' for each FF in the design + * + */ //LATCH triggered at FALLING EDGE model_library[LIB_LATCH_FE].name = vtr::strdup(MODEL_LATCH); model_library[LIB_LATCH_FE].index = LIB_LATCH_FE; From 7f9c9b0be0f67d019fde7da1b1c13d90ea5308b6 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Fri, 23 Dec 2022 10:45:22 +0100 Subject: [PATCH 40/55] libarchfpga: physical_types: comment logical models Signed-off-by: Pawel Czarnecki --- libs/libarchfpga/src/physical_types.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libs/libarchfpga/src/physical_types.h b/libs/libarchfpga/src/physical_types.h index d43bbe38909..cba89ff9896 100644 --- a/libs/libarchfpga/src/physical_types.h +++ b/libs/libarchfpga/src/physical_types.h @@ -910,8 +910,12 @@ struct t_logical_block_type { * name: name of the physical block type * num_pb: maximum number of instances of this physical block type sharing one parent * blif_model: the string in the blif circuit that corresponds with this pb type - * model: logical model - * model_sec: secondary logical model - used for pb_types matched to 2 available .latch models + * model: primary logical model - used for processing the majority of pb_types, + * including those matched to FFs triggered at the rising edge of the clock + * model_sec: secondary logical model - used for pb_types matched to .latch models + * representing FFs triggered at the falling edge of the clock. + * Required for asserting correct match between pb_type from pb_graph_node + * and netlist block in read_netlist.cpp and vpr_utils.cpp * class_type: Special library name * modes: Different modes accepted * ports: I/O and clock ports From d859ec32be08cad626e19b9cf10fa7c82eb6f6b4 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Fri, 23 Dec 2022 10:46:05 +0100 Subject: [PATCH 41/55] libarchfpga: physical_types: t_port: remove trigg_edge Signed-off-by: Pawel Czarnecki --- libs/libarchfpga/src/physical_types.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/libs/libarchfpga/src/physical_types.h b/libs/libarchfpga/src/physical_types.h index cba89ff9896..6bfe1ffa4ab 100644 --- a/libs/libarchfpga/src/physical_types.h +++ b/libs/libarchfpga/src/physical_types.h @@ -1047,7 +1047,6 @@ struct t_interconnect { * name: name of the port * model_port: associated model port * is_clock: whether or not this port is a clock - * trigg_edge: triggering edge of the clock port * is_non_clock_global: Applies to top level pb_type, this pin is not a clock but * is a global signal (useful for stuff like global reset signals, * perhaps useful for VCC and GND) @@ -1063,7 +1062,6 @@ struct t_port { t_model_ports* model_port; enum PORTS type; bool is_clock; - enum TriggeringEdge trigg_edge; bool is_non_clock_global; int num_pins; PortEquivalence equivalent; From de3857d18d7d25850910e0bf7da2183634777bc0 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Fri, 23 Dec 2022 11:15:55 +0100 Subject: [PATCH 42/55] libarchfpga: physical_types: comment ports Signed-off-by: Pawel Czarnecki --- libs/libarchfpga/src/physical_types.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libs/libarchfpga/src/physical_types.h b/libs/libarchfpga/src/physical_types.h index 6bfe1ffa4ab..083e6b68c8f 100644 --- a/libs/libarchfpga/src/physical_types.h +++ b/libs/libarchfpga/src/physical_types.h @@ -918,8 +918,11 @@ struct t_logical_block_type { * and netlist block in read_netlist.cpp and vpr_utils.cpp * class_type: Special library name * modes: Different modes accepted - * ports: I/O and clock ports - * ports_sec: secondary I/O and clock ports - used for pb_types matched to 2 available .latch models + * ports: primary I/O and clock ports - used for processing the majority of pb_types, + * including those matched to FFs triggered at the rising edge of the clock + * ports_sec: secondary I/O and clock ports - used for pb_types matched to .latch models + * representing FFs triggered at the falling edge of the clock. + * Required mainly for feasibility checks in clustering step * num_clock_pins: A count of the total number of clock pins * num_input_pins: A count of the total number of input pins * num_output_pins: A count of the total number of output pins From 977b9d666419844ddea98fa77ed108d13ee65c6a Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Fri, 23 Dec 2022 11:24:06 +0100 Subject: [PATCH 43/55] libarchfpga: t_pb_type: remove num_ports_sec Signed-off-by: Pawel Czarnecki --- libs/libarchfpga/src/arch_util.cpp | 1 - libs/libarchfpga/src/physical_types.h | 1 - 2 files changed, 2 deletions(-) diff --git a/libs/libarchfpga/src/arch_util.cpp b/libs/libarchfpga/src/arch_util.cpp index b73ef09e4ad..b7c84a174fd 100644 --- a/libs/libarchfpga/src/arch_util.cpp +++ b/libs/libarchfpga/src/arch_util.cpp @@ -655,7 +655,6 @@ void alloc_and_load_default_child_for_pb_type(t_pb_type* pb_type, } // Special case for latch - fill secondary data fields if (pb_type->class_type == LATCH_CLASS) { - copy->num_ports_sec = pb_type->num_ports; copy->ports_sec = new t_port[pb_type->num_ports](); for (i = 0; i < pb_type->num_ports; i++) { copy->ports_sec[i].is_clock = pb_type->ports[i].is_clock; diff --git a/libs/libarchfpga/src/physical_types.h b/libs/libarchfpga/src/physical_types.h index 083e6b68c8f..fd5df05bc54 100644 --- a/libs/libarchfpga/src/physical_types.h +++ b/libs/libarchfpga/src/physical_types.h @@ -945,7 +945,6 @@ struct t_pb_type { t_port* ports = nullptr; /* [0..num_ports] */ int num_ports = 0; t_port* ports_sec = nullptr; /* [0..num_ports] */ - int num_ports_sec = 0; int num_clock_pins = 0; int num_input_pins = 0; /* inputs not including clock pins */ From 3e4cd85ce81f113e0aedd3b0c534337de9a4f229 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Fri, 23 Dec 2022 12:05:47 +0100 Subject: [PATCH 44/55] libarchfpga: physical_types: comment update_pins Signed-off-by: Pawel Czarnecki --- libs/libarchfpga/src/physical_types.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/libs/libarchfpga/src/physical_types.h b/libs/libarchfpga/src/physical_types.h index fd5df05bc54..4aee269c679 100644 --- a/libs/libarchfpga/src/physical_types.h +++ b/libs/libarchfpga/src/physical_types.h @@ -922,7 +922,7 @@ struct t_logical_block_type { * including those matched to FFs triggered at the rising edge of the clock * ports_sec: secondary I/O and clock ports - used for pb_types matched to .latch models * representing FFs triggered at the falling edge of the clock. - * Required mainly for feasibility checks in clustering step + * Required for feasibility checks in clustering step. * num_clock_pins: A count of the total number of clock pins * num_input_pins: A count of the total number of input pins * num_output_pins: A count of the total number of output pins @@ -1249,6 +1249,14 @@ class t_pb_graph_node { // Ex: clb[0][default]/lab[0][default]/fle[3][n1_lut6]/ble6[0][default]/lut6[0] std::string hierarchical_type_name() const; + /** Fill secondary pin structs with data + * + * When pb_graph_node for falling edge clocked FF is processed, + * secondary structures for input, output and clock pins have to be + * filled with data. + * Do that by copying data from primary pin structures and replacing + * references to primary t_ports with references to secondary t_ports. + */ void update_pins(); }; From 91369c9b48da93c9e57fbab402c5445633e2e1b6 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Fri, 23 Dec 2022 12:06:24 +0100 Subject: [PATCH 45/55] vpr_utils: comment primitive_type_feasible Signed-off-by: Pawel Czarnecki --- vpr/src/util/vpr_utils.cpp | 14 ++++++++------ vpr/src/util/vpr_utils.h | 4 ++++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/vpr/src/util/vpr_utils.cpp b/vpr/src/util/vpr_utils.cpp index 9e828dd5509..5fbb3c36576 100644 --- a/vpr/src/util/vpr_utils.cpp +++ b/vpr/src/util/vpr_utils.cpp @@ -905,6 +905,7 @@ bool primitive_type_feasible(const AtomBlockId blk_id, const t_pb_type* cur_pb_t //Feasible return true; } + bool primitive_type_feasible(const AtomBlockId blk_id, t_pb_graph_node* curr_pb_graph_node) { t_pb_type* cur_pb_type = curr_pb_graph_node->pb_type; @@ -913,15 +914,16 @@ bool primitive_type_feasible(const AtomBlockId blk_id, t_pb_graph_node* curr_pb_ } auto& atom_ctx = g_vpr_ctx.atom(); + //Model does not match if (cur_pb_type->model != atom_ctx.nlist.block_model(blk_id)) { + //Check if the AtomBlock is related to FF (LATCH model) if ((strcmp(atom_ctx.nlist.block_model(blk_id)->name, MODEL_LATCH) == 0) && (strcmp(atom_ctx.nlist.block_model(blk_id)->name, cur_pb_type->model->name) == 0)) { - /** - * Special case for .latch: this model exists in 2 variations which are - * defined one after another in linked list, check if the second variant match - */ - + //Special case for .latch: this model exists in 2 variations which are + //defined one after another in linked list, check if the second variant match if (cur_pb_type->model->next == atom_ctx.nlist.block_model(blk_id) && atom_ctx.nlist.block_model(blk_id)->inputs[1].trigg_edge == TriggeringEdge::FALLING_EDGE) { - //Next primitive match atom - add secondary references + // Next primitive matched AtomBlock + // VPR will need data in secondary pin structs in curr_pb_graph_node + // Fill those if they are empty if (!curr_pb_graph_node->has_secondary) curr_pb_graph_node->update_pins(); } else { diff --git a/vpr/src/util/vpr_utils.h b/vpr/src/util/vpr_utils.h index 924abbdd2ef..7f64ffd797f 100644 --- a/vpr/src/util/vpr_utils.h +++ b/vpr/src/util/vpr_utils.h @@ -108,7 +108,11 @@ t_logical_block_type_ptr infer_logic_block_type(const DeviceGrid& grid); int get_max_primitives_in_pb_type(t_pb_type* pb_type); int get_max_depth_of_pb_type(t_pb_type* pb_type); int get_max_nets_in_pb_type(const t_pb_type* pb_type); + +//Check whether given pb_type is feasible for use with given atom block bool primitive_type_feasible(AtomBlockId blk_id, const t_pb_type* cur_pb_type); +//Perform the same check whether given pb_type is feasible for use with given atom block +//but also take into account the special case for atom blocks related to FFs clocked at falling edge bool primitive_type_feasible(AtomBlockId blk_id, t_pb_graph_node* curr_pb_graph_node); t_pb_graph_pin* get_pb_graph_node_pin_from_model_port_pin(const t_model_ports* model_port, const int model_pin, const t_pb_graph_node* pb_graph_node); const t_pb_graph_pin* find_pb_graph_pin(const AtomNetlist& netlist, const AtomLookup& netlist_lookup, const AtomPinId pin_id); From ebfaea83690765aa842e22a153bb7b0936a06dc6 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Fri, 23 Dec 2022 12:35:25 +0100 Subject: [PATCH 46/55] libarchfpga: read xml: comments on processing secondary pb_type ports Signed-off-by: Pawel Czarnecki --- libs/libarchfpga/src/read_xml_arch_file.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libs/libarchfpga/src/read_xml_arch_file.cpp b/libs/libarchfpga/src/read_xml_arch_file.cpp index e1852ae5d54..585d13c0b9e 100644 --- a/libs/libarchfpga/src/read_xml_arch_file.cpp +++ b/libs/libarchfpga/src/read_xml_arch_file.cpp @@ -1240,6 +1240,10 @@ static void ProcessPb_Type(vtr::string_internment* strings, pugi::xml_node Paren pb_type_ports[j].absolute_first_pin_index = absolute_port_first_pin_index; absolute_port_first_pin_index += pb_type_ports[j].num_pins; + //If the processed pb_type is of LATCH class, + //then process additional secondary set of pb_type_ports + //which is required for falling edge support in FFs due to + //2 possible internal models (t_model) for latches and their ports pb_type_ports = pb_type->ports_sec; l++; } while ((pb_type->class_type == LATCH_CLASS) && (l <= 1)); @@ -1278,6 +1282,9 @@ static void ProcessPb_Type(vtr::string_internment* strings, pugi::xml_node Paren pb_type->num_clock_pins += pb_type_ports[i].num_pins; } } + //If the processed pb_type is of LATCH class, then also count + //the numbers of secondary pin sets because of 2 possible + //internal models (t_model) for latches and their ports pb_type_ports = pb_type->ports_sec; l++; } while ((pb_type->class_type == LATCH_CLASS) && (l <= 1)); From 4649f0f0160b8c6502c1d8e7887788f39cd41492 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Fri, 23 Dec 2022 12:51:38 +0100 Subject: [PATCH 47/55] vpr: atom_netlist_utils: fixup latch handling in printing netlist Signed-off-by: Pawel Czarnecki --- vpr/src/base/atom_netlist_utils.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/vpr/src/base/atom_netlist_utils.cpp b/vpr/src/base/atom_netlist_utils.cpp index 807bea63474..5e80ac79c8a 100644 --- a/vpr/src/base/atom_netlist_utils.cpp +++ b/vpr/src/base/atom_netlist_utils.cpp @@ -190,12 +190,13 @@ void print_netlist_as_blif(FILE* f, const AtomNetlist& netlist) { } //Latch type - auto type = "xy"; + auto type = "invalid"; if ((blk_model->name == std::string(MODEL_LATCH)) && (blk_model->inputs[1].is_clock)) { if (blk_model->inputs[1].trigg_edge == TriggeringEdge::FALLING_EDGE) { type = "fe"; } else { - //Always assume rising edge + //Otherwise always assume rising edge (.latch could be also configured as: + //'active high', 'active low', 'asynchronous') type = "re"; } } From cb46900cd1316f5bde306844d1e8d98c98491a0d Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Fri, 23 Dec 2022 13:37:51 +0100 Subject: [PATCH 48/55] libarchfpga: models library: add constant for the ID of latch clock input Signed-off-by: Pawel Czarnecki --- libs/libarchfpga/src/arch_util.h | 1 + vpr/src/base/atom_netlist_utils.cpp | 4 ++-- vpr/src/base/read_blif.cpp | 2 +- vpr/src/util/vpr_utils.cpp | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/libs/libarchfpga/src/arch_util.h b/libs/libarchfpga/src/arch_util.h index 9834057ee35..1ad777aac7e 100644 --- a/libs/libarchfpga/src/arch_util.h +++ b/libs/libarchfpga/src/arch_util.h @@ -17,6 +17,7 @@ const char* get_arch_file_name(); constexpr const char* EMPTY_BLOCK_NAME = "EMPTY"; constexpr const int num_models_lib = 5; +constexpr const int LATCH_CLOCK_INPUT_ID = 1; enum InternalModel { LIB_INPUT, diff --git a/vpr/src/base/atom_netlist_utils.cpp b/vpr/src/base/atom_netlist_utils.cpp index 5e80ac79c8a..d7758f14dd4 100644 --- a/vpr/src/base/atom_netlist_utils.cpp +++ b/vpr/src/base/atom_netlist_utils.cpp @@ -191,8 +191,8 @@ void print_netlist_as_blif(FILE* f, const AtomNetlist& netlist) { //Latch type auto type = "invalid"; - if ((blk_model->name == std::string(MODEL_LATCH)) && (blk_model->inputs[1].is_clock)) { - if (blk_model->inputs[1].trigg_edge == TriggeringEdge::FALLING_EDGE) { + if ((blk_model->name == std::string(MODEL_LATCH)) && (blk_model->inputs[LATCH_CLOCK_INPUT_ID].is_clock)) { + if (blk_model->inputs[LATCH_CLOCK_INPUT_ID].trigg_edge == TriggeringEdge::FALLING_EDGE) { type = "fe"; } else { //Otherwise always assume rising edge (.latch could be also configured as: diff --git a/vpr/src/base/read_blif.cpp b/vpr/src/base/read_blif.cpp index e921d8deeaa..776a439d49f 100644 --- a/vpr/src/base/read_blif.cpp +++ b/vpr/src/base/read_blif.cpp @@ -477,7 +477,7 @@ struct BlifAllocCallback : public blifparse::Callback { arch_model = arch_models; while (arch_model) { if (strcmp(MODEL_LATCH, arch_model->name) == 0) { - if (t_edge == arch_model->inputs[1].trigg_edge) { + if (t_edge == arch_model->inputs[LATCH_CLOCK_INPUT_ID].trigg_edge) { //Found it break; } diff --git a/vpr/src/util/vpr_utils.cpp b/vpr/src/util/vpr_utils.cpp index 5fbb3c36576..8a2dcc1a425 100644 --- a/vpr/src/util/vpr_utils.cpp +++ b/vpr/src/util/vpr_utils.cpp @@ -920,7 +920,7 @@ bool primitive_type_feasible(const AtomBlockId blk_id, t_pb_graph_node* curr_pb_ if ((strcmp(atom_ctx.nlist.block_model(blk_id)->name, MODEL_LATCH) == 0) && (strcmp(atom_ctx.nlist.block_model(blk_id)->name, cur_pb_type->model->name) == 0)) { //Special case for .latch: this model exists in 2 variations which are //defined one after another in linked list, check if the second variant match - if (cur_pb_type->model->next == atom_ctx.nlist.block_model(blk_id) && atom_ctx.nlist.block_model(blk_id)->inputs[1].trigg_edge == TriggeringEdge::FALLING_EDGE) { + if (cur_pb_type->model->next == atom_ctx.nlist.block_model(blk_id) && atom_ctx.nlist.block_model(blk_id)->inputs[LATCH_CLOCK_INPUT_ID].trigg_edge == TriggeringEdge::FALLING_EDGE) { // Next primitive matched AtomBlock // VPR will need data in secondary pin structs in curr_pb_graph_node // Fill those if they are empty From 50fe438f5eb8d81e43aae0aed0e6fb1c8e60fb63 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Fri, 23 Dec 2022 13:53:40 +0100 Subject: [PATCH 49/55] vpr: pack: pb_type_graph: explain has_secondary usage Signed-off-by: Pawel Czarnecki --- vpr/src/pack/pb_type_graph.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vpr/src/pack/pb_type_graph.cpp b/vpr/src/pack/pb_type_graph.cpp index c4c080b3e30..07d280f3a6e 100644 --- a/vpr/src/pack/pb_type_graph.cpp +++ b/vpr/src/pack/pb_type_graph.cpp @@ -259,6 +259,9 @@ static void alloc_and_load_pb_graph(t_pb_graph_node* pb_graph_node, i_input = i_output = i_clockport = 0; t_port* pb_type_ports; for (i = 0; i < pb_type->num_ports; i++) { + //Decide which ports should be referenced in pins of pb_graph_nodes + //If this pb_graph_node was marked with has_secondary, it means that + //it references FF clocked at falling edge so the secondary ports should be used. if (pb_graph_node->has_secondary) { pb_type_ports = pb_type->ports_sec; } else { From 9996637c8ca95c477bd4b2ea30ca654f1cfd3375 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Fri, 23 Dec 2022 14:03:57 +0100 Subject: [PATCH 50/55] vpr: timing: read_sdc: comment get_clocks Signed-off-by: Pawel Czarnecki --- vpr/src/timing/read_sdc.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/vpr/src/timing/read_sdc.cpp b/vpr/src/timing/read_sdc.cpp index bec4716162a..64f932c124c 100644 --- a/vpr/src/timing/read_sdc.cpp +++ b/vpr/src/timing/read_sdc.cpp @@ -908,10 +908,15 @@ class SdcParseCallback : public sdcparse::Callback { "Expected clock names or collection via get_clocks"); } - for (int i = 0; i < 2; i++) { + //There are 2 clock variants: + // * regular - derived from netlist clocks specified in SDC file + // * inverted - copy of regular clock, created as virtual clock + // with 180 degree phase shift and name suffixed with '_negedge' + // Look for both variants + for (int clk_variant = 0; clk_variant < 2; clk_variant++) { for (const auto& clock_glob_pattern : clock_group.strings) { std::string clk_gpattern; - switch (i) { + switch (clk_variant) { case 0: clk_gpattern = clock_glob_pattern; break; From f6e7fea76677dadca08689b0d9bebf8323f967cd Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Fri, 23 Dec 2022 14:11:10 +0100 Subject: [PATCH 51/55] vpr_utils: explain TriggeringEdge usage in pb_graph_pin matching Signed-off-by: Pawel Czarnecki --- vpr/src/util/vpr_utils.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vpr/src/util/vpr_utils.cpp b/vpr/src/util/vpr_utils.cpp index 8a2dcc1a425..4046694ba9b 100644 --- a/vpr/src/util/vpr_utils.cpp +++ b/vpr/src/util/vpr_utils.cpp @@ -1016,6 +1016,8 @@ AtomBlockId find_memory_sibling(const t_pb* pb) { /** * Return pb_graph_node pin from model port and pin + * Decide pins of which set (primary or secondary) should be used + * based on triggering edge of t_model_ports (defaults to primary pins) * NULL if not found */ t_pb_graph_pin* get_pb_graph_node_pin_from_model_port_pin(const t_model_ports* model_port, const int model_pin, const t_pb_graph_node* pb_graph_node) { From e94702659248930f2e65e01956cbb82f46c48180 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Fri, 23 Dec 2022 14:43:40 +0100 Subject: [PATCH 52/55] libarchfpga: physical_types: link to t_pb_types definition Signed-off-by: Pawel Czarnecki --- libs/libarchfpga/src/arch_util.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/libarchfpga/src/arch_util.cpp b/libs/libarchfpga/src/arch_util.cpp index b7c84a174fd..b2f9605734e 100644 --- a/libs/libarchfpga/src/arch_util.cpp +++ b/libs/libarchfpga/src/arch_util.cpp @@ -654,6 +654,7 @@ void alloc_and_load_default_child_for_pb_type(t_pb_type* pb_type, } } // Special case for latch - fill secondary data fields + // For more information on secondary fields please refer to t_pb_type definition in physical_types.h if (pb_type->class_type == LATCH_CLASS) { copy->ports_sec = new t_port[pb_type->num_ports](); for (i = 0; i < pb_type->num_ports; i++) { From 4ed6e5ab9d850cc800fe2241ca865df3ac7c7efb Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Fri, 23 Dec 2022 15:02:22 +0100 Subject: [PATCH 53/55] formatting fixes Signed-off-by: Pawel Czarnecki --- libs/libarchfpga/src/arch_util.cpp | 56 ++++++++++++++--------------- libs/libarchfpga/src/arch_util.h | 10 +++--- vpr/src/base/atom_netlist_utils.cpp | 2 +- vpr/src/timing/read_sdc.cpp | 4 +-- vpr/src/util/vpr_utils.cpp | 4 +-- 5 files changed, 37 insertions(+), 39 deletions(-) diff --git a/libs/libarchfpga/src/arch_util.cpp b/libs/libarchfpga/src/arch_util.cpp index b2f9605734e..606406f07ff 100644 --- a/libs/libarchfpga/src/arch_util.cpp +++ b/libs/libarchfpga/src/arch_util.cpp @@ -171,7 +171,7 @@ void free_arch(t_arch* arch) { delete arch->architecture_id; - //Free internal model library + //Free internal model library if (arch->model_library) { for (int i = 0; i < num_models_lib; ++i) { vtr::t_linked_vptr* vptr = arch->model_library[i].pb_types; @@ -183,7 +183,7 @@ void free_arch(t_arch* arch) { } //Each model has different number of inputs/outputs - delete each model separately - //Free INPAD + //Free INPAD delete arch->model_library[LIB_INPUT].name; delete arch->model_library[LIB_INPUT].outputs->name; delete[] arch->model_library[LIB_INPUT].outputs; @@ -216,7 +216,7 @@ void free_arch(t_arch* arch) { delete arch->model_library[LIB_NAMES].outputs->name; delete[] arch->model_library[LIB_NAMES].outputs; - //Free the library array + //Free the library array delete[] arch->model_library; } @@ -687,7 +687,7 @@ void alloc_and_load_default_child_for_pb_type(t_pb_type* pb_type, for (i = 0; i < copy->num_annotations; i++) { copy->annotations[i].clock = vtr::strdup(pb_type->annotations[i].clock); dot = strstr(pb_type->annotations[i].input_pins, "."); - copy->annotations[i].input_pins = new char[strlen(new_name) + strlen(dot) + 1]; + copy->annotations[i].input_pins = new char[strlen(new_name) + strlen(dot) + 1]; copy->annotations[i].input_pins[0] = '\0'; strcat(copy->annotations[i].input_pins, new_name); strcat(copy->annotations[i].input_pins, dot); @@ -852,7 +852,7 @@ void ProcessLutClass(t_pb_type* lut_pb_type) { sprintf(lut_pb_type->modes[1].interconnect[1].input_string, "%s.%s", default_name, out_port->name); lut_pb_type->modes[1].interconnect[1].output_string = new char[strlen(lut_pb_type->name) + strlen(out_port->name) - + strlen(in_port->name) + 2]; + + strlen(in_port->name) + 2]; sprintf(lut_pb_type->modes[1].interconnect[1].output_string, "%s.%s", lut_pb_type->name, out_port->name); lut_pb_type->modes[1].interconnect[1].infer_annotations = true; @@ -955,7 +955,7 @@ void ProcessMemoryClass(t_pb_type* mem_pb_type) { sprintf(mem_pb_type->modes[0].interconnect[i_inter].input_string, "%s.%s", input_name, input_port_name); mem_pb_type->modes[0].interconnect[i_inter].output_string = new char[strlen(output_name) + strlen(output_port_name) - + 2 * (6 + num_pb / 10)]; + + 2 * (6 + num_pb / 10)]; sprintf(mem_pb_type->modes[0].interconnect[i_inter].output_string, "%s[%d:0].%s", output_name, num_pb - 1, output_port_name); @@ -965,11 +965,11 @@ void ProcessMemoryClass(t_pb_type* mem_pb_type) { mem_pb_type->modes[0].pb_type_children[0].num_output_pins -= (mem_pb_type->ports[i].num_pins - 1); mem_pb_type->modes[0].interconnect[i_inter].input_string = new char[strlen(input_name) + strlen(input_port_name) - + 2 * (6 + num_pb / 10)]; + + 2 * (6 + num_pb / 10)]; sprintf(mem_pb_type->modes[0].interconnect[i_inter].input_string, "%s[%d:0].%s", input_name, num_pb - 1, input_port_name); mem_pb_type->modes[0].interconnect[i_inter].output_string = new char[strlen(output_name) + strlen(output_port_name) - + 2]; + + 2]; sprintf(mem_pb_type->modes[0].interconnect[i_inter].output_string, "%s.%s", output_name, output_port_name); } @@ -997,7 +997,7 @@ void ProcessMemoryClass(t_pb_type* mem_pb_type) { } else { mem_pb_type->modes[0].interconnect[i_inter].type = DIRECT_INTERC; mem_pb_type->modes[0].interconnect[i_inter].input_string = new char[strlen(input_name) + strlen(input_port_name) - + 2 * (6 + num_pb / 10)]; + + 2 * (6 + num_pb / 10)]; sprintf(mem_pb_type->modes[0].interconnect[i_inter].input_string, "%s[%d:%d].%s", input_name, j, j, input_port_name); mem_pb_type->modes[0].interconnect[i_inter].output_string = new char[strlen(output_name) + strlen(output_port_name) + 2]; @@ -1111,25 +1111,25 @@ void CreateModelLibrary(t_arch* arch) { model_library[LIB_LATCH_RE].outputs[0].clock = "clk"; model_library[LIB_LATCH_RE].outputs[0].trigg_edge = TriggeringEdge::RISING_EDGE; - /* - * Duplicate LATCH model. - * Second separate model is required for falling edge support. - * It is a copy of LIB_LATCH_RE but with different trigg_edge configuration - * for inputs/outputs t_model_ports. It is used to represent FFs triggered at - * the falling edge of the clock, while LIB_LATCH_RE represents FFs triggered - * at the rising edge. - * - * VPR uses single model of each blif primitive type (e.g. '.latch', '.names') parsed from input blif file. - * That means models are used as configuration reference for parsed blif primitives when - * Latch instances are created in circuit evaluation, meaning: - * 1 unique blif primitive configuration (parsed from blif file) maps to - * 1 unique model (defined here, in VPR internal library) which represents configuration of - * multiple primitive instances (of given type and configuration) used in the circuit - * - * Models have to be duplicated because otherwise VPR will use the configuration - * of the last parsed '.latch' for each FF in the design - * - */ + /* + * Duplicate LATCH model. + * Second separate model is required for falling edge support. + * It is a copy of LIB_LATCH_RE but with different trigg_edge configuration + * for inputs/outputs t_model_ports. It is used to represent FFs triggered at + * the falling edge of the clock, while LIB_LATCH_RE represents FFs triggered + * at the rising edge. + * + * VPR uses single model of each blif primitive type (e.g. '.latch', '.names') parsed from input blif file. + * That means models are used as configuration reference for parsed blif primitives when + * Latch instances are created in circuit evaluation, meaning: + * 1 unique blif primitive configuration (parsed from blif file) maps to + * 1 unique model (defined here, in VPR internal library) which represents configuration of + * multiple primitive instances (of given type and configuration) used in the circuit + * + * Models have to be duplicated because otherwise VPR will use the configuration + * of the last parsed '.latch' for each FF in the design + * + */ //LATCH triggered at FALLING EDGE model_library[LIB_LATCH_FE].name = vtr::strdup(MODEL_LATCH); model_library[LIB_LATCH_FE].index = LIB_LATCH_FE; diff --git a/libs/libarchfpga/src/arch_util.h b/libs/libarchfpga/src/arch_util.h index 1ad777aac7e..9701adc948d 100644 --- a/libs/libarchfpga/src/arch_util.h +++ b/libs/libarchfpga/src/arch_util.h @@ -20,11 +20,11 @@ constexpr const int num_models_lib = 5; constexpr const int LATCH_CLOCK_INPUT_ID = 1; enum InternalModel { - LIB_INPUT, - LIB_OUTPUT, - LIB_LATCH_RE, - LIB_LATCH_FE, - LIB_NAMES + LIB_INPUT, + LIB_OUTPUT, + LIB_LATCH_RE, + LIB_LATCH_FE, + LIB_NAMES }; class InstPort { diff --git a/vpr/src/base/atom_netlist_utils.cpp b/vpr/src/base/atom_netlist_utils.cpp index d7758f14dd4..95117d24a57 100644 --- a/vpr/src/base/atom_netlist_utils.cpp +++ b/vpr/src/base/atom_netlist_utils.cpp @@ -196,7 +196,7 @@ void print_netlist_as_blif(FILE* f, const AtomNetlist& netlist) { type = "fe"; } else { //Otherwise always assume rising edge (.latch could be also configured as: - //'active high', 'active low', 'asynchronous') + //'active high', 'active low', 'asynchronous') type = "re"; } } diff --git a/vpr/src/timing/read_sdc.cpp b/vpr/src/timing/read_sdc.cpp index 64f932c124c..460867a4d10 100644 --- a/vpr/src/timing/read_sdc.cpp +++ b/vpr/src/timing/read_sdc.cpp @@ -741,9 +741,7 @@ class SdcParseCallback : public sdcparse::Callback { constraint = launch_clock.period; - } else if ((std::fabs(launch_clock.period - capture_clock.period) < EPSILON) && - (std::fabs((launch_clock.period / 2) - std::fabs(launch_clock.rise_edge - capture_clock.rise_edge)) < EPSILON) && - (std::fabs((launch_clock.period / 2) - std::fabs(launch_clock.fall_edge - capture_clock.fall_edge)) < EPSILON)) { + } else if ((std::fabs(launch_clock.period - capture_clock.period) < EPSILON) && (std::fabs((launch_clock.period / 2) - std::fabs(launch_clock.rise_edge - capture_clock.rise_edge)) < EPSILON) && (std::fabs((launch_clock.period / 2) - std::fabs(launch_clock.fall_edge - capture_clock.fall_edge)) < EPSILON)) { //The source and sink domains have the same period but are inverted, the constraint is half of the common clock period. constraint = (launch_clock.period / 2); diff --git a/vpr/src/util/vpr_utils.cpp b/vpr/src/util/vpr_utils.cpp index 4046694ba9b..88e2228fef8 100644 --- a/vpr/src/util/vpr_utils.cpp +++ b/vpr/src/util/vpr_utils.cpp @@ -918,8 +918,8 @@ bool primitive_type_feasible(const AtomBlockId blk_id, t_pb_graph_node* curr_pb_ if (cur_pb_type->model != atom_ctx.nlist.block_model(blk_id)) { //Check if the AtomBlock is related to FF (LATCH model) if ((strcmp(atom_ctx.nlist.block_model(blk_id)->name, MODEL_LATCH) == 0) && (strcmp(atom_ctx.nlist.block_model(blk_id)->name, cur_pb_type->model->name) == 0)) { - //Special case for .latch: this model exists in 2 variations which are - //defined one after another in linked list, check if the second variant match + //Special case for .latch: this model exists in 2 variations which are + //defined one after another in linked list, check if the second variant match if (cur_pb_type->model->next == atom_ctx.nlist.block_model(blk_id) && atom_ctx.nlist.block_model(blk_id)->inputs[LATCH_CLOCK_INPUT_ID].trigg_edge == TriggeringEdge::FALLING_EDGE) { // Next primitive matched AtomBlock // VPR will need data in secondary pin structs in curr_pb_graph_node From aa0561b2ffabf4c9dfc0554d74eaf7fcf6220c63 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Fri, 23 Dec 2022 19:33:38 +0100 Subject: [PATCH 54/55] Revert "libarchfpga: change all .alloc() calls to 'new'" This reverts commit 2353564add4ac1dc795dfe576d453f1db7a86302. --- libs/libarchfpga/src/arch_util.cpp | 121 ++++++++++++++++++----------- 1 file changed, 75 insertions(+), 46 deletions(-) diff --git a/libs/libarchfpga/src/arch_util.cpp b/libs/libarchfpga/src/arch_util.cpp index 606406f07ff..59189e0093d 100644 --- a/libs/libarchfpga/src/arch_util.cpp +++ b/libs/libarchfpga/src/arch_util.cpp @@ -624,12 +624,13 @@ void alloc_and_load_default_child_for_pb_type(t_pb_type* pb_type, copy->num_pb = 1; /* Power */ - copy->pb_type_power = new t_pb_type_power[1](); + copy->pb_type_power = (t_pb_type_power*)vtr::calloc(1, + sizeof(t_pb_type_power)); copy->pb_type_power->estimation_method = power_method_inherited(pb_type->pb_type_power->estimation_method); /* Ports */ copy->num_ports = pb_type->num_ports; - copy->ports = new t_port[pb_type->num_ports](); + copy->ports = (t_port*)vtr::calloc(pb_type->num_ports, sizeof(t_port)); for (i = 0; i < pb_type->num_ports; i++) { copy->ports[i].is_clock = pb_type->ports[i].is_clock; copy->ports[i].model_port = pb_type->ports[i].model_port; @@ -642,7 +643,8 @@ void alloc_and_load_default_child_for_pb_type(t_pb_type* pb_type, copy->ports[i].index = pb_type->ports[i].index; copy->ports[i].absolute_first_pin_index = pb_type->ports[i].absolute_first_pin_index; - copy->ports[i].port_power = new t_port_power[1](); + copy->ports[i].port_power = (t_port_power*)vtr::calloc(1, + sizeof(t_port_power)); //Defaults if (copy->pb_type_power->estimation_method == POWER_METHOD_AUTO_SIZES) { copy->ports[i].port_power->wire_type = POWER_WIRE_TYPE_AUTO; @@ -656,7 +658,7 @@ void alloc_and_load_default_child_for_pb_type(t_pb_type* pb_type, // Special case for latch - fill secondary data fields // For more information on secondary fields please refer to t_pb_type definition in physical_types.h if (pb_type->class_type == LATCH_CLASS) { - copy->ports_sec = new t_port[pb_type->num_ports](); + copy->ports_sec = (t_port*)vtr::calloc(pb_type->num_ports, sizeof(t_port)); for (i = 0; i < pb_type->num_ports; i++) { copy->ports_sec[i].is_clock = pb_type->ports[i].is_clock; copy->ports_sec[i].model_port = pb_type->ports[i].model_port; @@ -669,7 +671,8 @@ void alloc_and_load_default_child_for_pb_type(t_pb_type* pb_type, copy->ports_sec[i].index = pb_type->ports[i].index; copy->ports_sec[i].absolute_first_pin_index = pb_type->ports[i].absolute_first_pin_index; - copy->ports_sec[i].port_power = new t_port_power[1](); + copy->ports_sec[i].port_power = (t_port_power*)vtr::calloc(1, + sizeof(t_port_power)); //Defaults if (copy->pb_type_power->estimation_method == POWER_METHOD_AUTO_SIZES) { copy->ports_sec[i].port_power->wire_type = POWER_WIRE_TYPE_AUTO; @@ -682,18 +685,18 @@ void alloc_and_load_default_child_for_pb_type(t_pb_type* pb_type, } } - copy->annotations = new t_pin_to_pin_annotation[pb_type->num_annotations](); + copy->annotations = (t_pin_to_pin_annotation*)vtr::calloc(pb_type->num_annotations, sizeof(t_pin_to_pin_annotation)); copy->num_annotations = pb_type->num_annotations; for (i = 0; i < copy->num_annotations; i++) { copy->annotations[i].clock = vtr::strdup(pb_type->annotations[i].clock); dot = strstr(pb_type->annotations[i].input_pins, "."); - copy->annotations[i].input_pins = new char[strlen(new_name) + strlen(dot) + 1]; + copy->annotations[i].input_pins = (char*)vtr::malloc(sizeof(char) * (strlen(new_name) + strlen(dot) + 1)); copy->annotations[i].input_pins[0] = '\0'; strcat(copy->annotations[i].input_pins, new_name); strcat(copy->annotations[i].input_pins, dot); if (pb_type->annotations[i].output_pins != nullptr) { dot = strstr(pb_type->annotations[i].output_pins, "."); - copy->annotations[i].output_pins = new char[strlen(new_name) + strlen(dot) + 1]; + copy->annotations[i].output_pins = (char*)vtr::malloc(sizeof(char) * (strlen(new_name) + strlen(dot) + 1)); copy->annotations[i].output_pins[0] = '\0'; strcat(copy->annotations[i].output_pins, new_name); strcat(copy->annotations[i].output_pins, dot); @@ -704,8 +707,8 @@ void alloc_and_load_default_child_for_pb_type(t_pb_type* pb_type, copy->annotations[i].format = pb_type->annotations[i].format; copy->annotations[i].type = pb_type->annotations[i].type; copy->annotations[i].num_value_prop_pairs = pb_type->annotations[i].num_value_prop_pairs; - copy->annotations[i].prop = new int[pb_type->annotations[i].num_value_prop_pairs]; - copy->annotations[i].value = new char*[pb_type->annotations[i].num_value_prop_pairs]; + copy->annotations[i].prop = (int*)vtr::malloc(sizeof(int) * pb_type->annotations[i].num_value_prop_pairs); + copy->annotations[i].value = (char**)vtr::malloc(sizeof(char*) * pb_type->annotations[i].num_value_prop_pairs); for (j = 0; j < pb_type->annotations[i].num_value_prop_pairs; j++) { copy->annotations[i].prop[j] = pb_type->annotations[i].prop[j]; copy->annotations[i].value[j] = vtr::strdup(pb_type->annotations[i].value[j]); @@ -735,7 +738,8 @@ void ProcessLutClass(t_pb_type* lut_pb_type) { lut_pb_type->modes[0].parent_pb_type = lut_pb_type; lut_pb_type->modes[0].index = 0; lut_pb_type->modes[0].num_pb_type_children = 0; - lut_pb_type->modes[0].mode_power = new t_mode_power[1](); + lut_pb_type->modes[0].mode_power = (t_mode_power*)vtr::calloc(1, + sizeof(t_mode_power)); /* Process interconnect */ /* TODO: add timing annotations to route-through */ @@ -752,22 +756,25 @@ void ProcessLutClass(t_pb_type* lut_pb_type) { } lut_pb_type->modes[0].num_interconnect = 1; lut_pb_type->modes[0].interconnect = new t_interconnect[1]; - lut_pb_type->modes[0].interconnect[0].name = new char[strlen(lut_pb_type->name) + 10]; + lut_pb_type->modes[0].interconnect[0].name = (char*)vtr::calloc(strlen(lut_pb_type->name) + 10, sizeof(char)); sprintf(lut_pb_type->modes[0].interconnect[0].name, "complete:%s", lut_pb_type->name); lut_pb_type->modes[0].interconnect[0].type = COMPLETE_INTERC; - lut_pb_type->modes[0].interconnect[0].input_string = new char[strlen(lut_pb_type->name) + strlen(in_port->name) + 2]; + lut_pb_type->modes[0].interconnect[0].input_string = (char*)vtr::calloc(strlen(lut_pb_type->name) + strlen(in_port->name) + 2, + sizeof(char)); sprintf(lut_pb_type->modes[0].interconnect[0].input_string, "%s.%s", lut_pb_type->name, in_port->name); - lut_pb_type->modes[0].interconnect[0].output_string = new char[strlen(lut_pb_type->name) + strlen(out_port->name) + 2]; + lut_pb_type->modes[0].interconnect[0].output_string = (char*)vtr::calloc(strlen(lut_pb_type->name) + strlen(out_port->name) + 2, + sizeof(char)); sprintf(lut_pb_type->modes[0].interconnect[0].output_string, "%s.%s", lut_pb_type->name, out_port->name); lut_pb_type->modes[0].interconnect[0].parent_mode_index = 0; lut_pb_type->modes[0].interconnect[0].parent_mode = &lut_pb_type->modes[0]; - lut_pb_type->modes[0].interconnect[0].interconnect_power = new t_interconnect_power[1](); + lut_pb_type->modes[0].interconnect[0].interconnect_power = (t_interconnect_power*)vtr::calloc(1, sizeof(t_interconnect_power)); - lut_pb_type->modes[0].interconnect[0].annotations = new t_pin_to_pin_annotation[lut_pb_type->num_annotations](); + lut_pb_type->modes[0].interconnect[0].annotations = (t_pin_to_pin_annotation*)vtr::calloc(lut_pb_type->num_annotations, + sizeof(t_pin_to_pin_annotation)); lut_pb_type->modes[0].interconnect[0].num_annotations = lut_pb_type->num_annotations; for (i = 0; i < lut_pb_type->modes[0].interconnect[0].num_annotations; i++) { @@ -778,8 +785,10 @@ void ProcessLutClass(t_pb_type* lut_pb_type) { lut_pb_type->modes[0].interconnect[0].annotations[i].format = lut_pb_type->annotations[i].format; lut_pb_type->modes[0].interconnect[0].annotations[i].type = lut_pb_type->annotations[i].type; lut_pb_type->modes[0].interconnect[0].annotations[i].num_value_prop_pairs = lut_pb_type->annotations[i].num_value_prop_pairs; - lut_pb_type->modes[0].interconnect[0].annotations[i].prop = new int[lut_pb_type->annotations[i].num_value_prop_pairs]; - lut_pb_type->modes[0].interconnect[0].annotations[i].value = new char*[lut_pb_type->annotations[i].num_value_prop_pairs]; + lut_pb_type->modes[0].interconnect[0].annotations[i].prop = (int*)vtr::malloc(sizeof(int) + * lut_pb_type->annotations[i].num_value_prop_pairs); + lut_pb_type->modes[0].interconnect[0].annotations[i].value = (char**)vtr::malloc(sizeof(char*) + * lut_pb_type->annotations[i].num_value_prop_pairs); for (j = 0; j < lut_pb_type->annotations[i].num_value_prop_pairs; j++) { lut_pb_type->modes[0].interconnect[0].annotations[i].prop[j] = lut_pb_type->annotations[i].prop[j]; lut_pb_type->modes[0].interconnect[0].annotations[i].value[j] = vtr::strdup(lut_pb_type->annotations[i].value[j]); @@ -792,7 +801,8 @@ void ProcessLutClass(t_pb_type* lut_pb_type) { lut_pb_type->modes[1].parent_pb_type = lut_pb_type; lut_pb_type->modes[1].index = 1; lut_pb_type->modes[1].num_pb_type_children = 1; - lut_pb_type->modes[1].mode_power = new t_mode_power[1](); + lut_pb_type->modes[1].mode_power = (t_mode_power*)vtr::calloc(1, + sizeof(t_mode_power)); lut_pb_type->modes[1].pb_type_children = new t_pb_type[1]; alloc_and_load_default_child_for_pb_type(lut_pb_type, default_name, lut_pb_type->modes[1].pb_type_children); @@ -827,39 +837,41 @@ void ProcessLutClass(t_pb_type* lut_pb_type) { /* Process interconnect */ lut_pb_type->modes[1].num_interconnect = 2; lut_pb_type->modes[1].interconnect = new t_interconnect[lut_pb_type->modes[1].num_interconnect]; - lut_pb_type->modes[1].interconnect[0].name = new char[strlen(lut_pb_type->name) + 10]; + lut_pb_type->modes[1].interconnect[0].name = (char*)vtr::calloc(strlen(lut_pb_type->name) + 10, sizeof(char)); sprintf(lut_pb_type->modes[1].interconnect[0].name, "direct:%s", lut_pb_type->name); lut_pb_type->modes[1].interconnect[0].type = DIRECT_INTERC; - lut_pb_type->modes[1].interconnect[0].input_string = new char[strlen(lut_pb_type->name) + strlen(in_port->name) + 2]; + lut_pb_type->modes[1].interconnect[0].input_string = (char*)vtr::calloc(strlen(lut_pb_type->name) + strlen(in_port->name) + 2, + sizeof(char)); sprintf(lut_pb_type->modes[1].interconnect[0].input_string, "%s.%s", lut_pb_type->name, in_port->name); - lut_pb_type->modes[1].interconnect[0].output_string = new char[strlen(default_name) + strlen(in_port->name) + 2]; + lut_pb_type->modes[1].interconnect[0].output_string = (char*)vtr::calloc(strlen(default_name) + strlen(in_port->name) + 2, sizeof(char)); sprintf(lut_pb_type->modes[1].interconnect[0].output_string, "%s.%s", default_name, in_port->name); lut_pb_type->modes[1].interconnect[0].infer_annotations = true; lut_pb_type->modes[1].interconnect[0].parent_mode_index = 1; lut_pb_type->modes[1].interconnect[0].parent_mode = &lut_pb_type->modes[1]; - lut_pb_type->modes[1].interconnect[0].interconnect_power = new t_interconnect_power[1](); + lut_pb_type->modes[1].interconnect[0].interconnect_power = (t_interconnect_power*)vtr::calloc(1, sizeof(t_interconnect_power)); - lut_pb_type->modes[1].interconnect[1].name = new char[strlen(lut_pb_type->name) + 11]; + lut_pb_type->modes[1].interconnect[1].name = (char*)vtr::calloc(strlen(lut_pb_type->name) + 11, sizeof(char)); sprintf(lut_pb_type->modes[1].interconnect[1].name, "direct:%s", lut_pb_type->name); lut_pb_type->modes[1].interconnect[1].type = DIRECT_INTERC; - lut_pb_type->modes[1].interconnect[1].input_string = new char[strlen(default_name) + strlen(out_port->name) + 4]; + lut_pb_type->modes[1].interconnect[1].input_string = (char*)vtr::calloc(strlen(default_name) + strlen(out_port->name) + 4, sizeof(char)); sprintf(lut_pb_type->modes[1].interconnect[1].input_string, "%s.%s", default_name, out_port->name); - lut_pb_type->modes[1].interconnect[1].output_string = new char[strlen(lut_pb_type->name) + strlen(out_port->name) - + strlen(in_port->name) + 2]; + lut_pb_type->modes[1].interconnect[1].output_string = (char*)vtr::calloc(strlen(lut_pb_type->name) + strlen(out_port->name) + + strlen(in_port->name) + 2, + sizeof(char)); sprintf(lut_pb_type->modes[1].interconnect[1].output_string, "%s.%s", lut_pb_type->name, out_port->name); lut_pb_type->modes[1].interconnect[1].infer_annotations = true; lut_pb_type->modes[1].interconnect[1].parent_mode_index = 1; lut_pb_type->modes[1].interconnect[1].parent_mode = &lut_pb_type->modes[1]; - lut_pb_type->modes[1].interconnect[1].interconnect_power = new t_interconnect_power[1](); + lut_pb_type->modes[1].interconnect[1].interconnect_power = (t_interconnect_power*)vtr::calloc(1, sizeof(t_interconnect_power)); delete default_name; @@ -884,7 +896,8 @@ void ProcessMemoryClass(t_pb_type* mem_pb_type) { mem_pb_type->modes[0].name = vtr::strdup(default_name); mem_pb_type->modes[0].parent_pb_type = mem_pb_type; mem_pb_type->modes[0].index = 0; - mem_pb_type->modes[0].mode_power = new t_mode_power[1](); + mem_pb_type->modes[0].mode_power = (t_mode_power*)vtr::calloc(1, + sizeof(t_mode_power)); num_pb = OPEN; for (i = 0; i < mem_pb_type->num_ports; i++) { if (mem_pb_type->ports[i].port_class != nullptr @@ -941,7 +954,7 @@ void ProcessMemoryClass(t_pb_type* mem_pb_type) { if (mem_pb_type->ports[i].port_class != nullptr && strstr(mem_pb_type->ports[i].port_class, "data") == mem_pb_type->ports[i].port_class) { - mem_pb_type->modes[0].interconnect[i_inter].name = new char[i_inter / 10 + 8]; + mem_pb_type->modes[0].interconnect[i_inter].name = (char*)vtr::calloc(i_inter / 10 + 8, sizeof(char)); sprintf(mem_pb_type->modes[0].interconnect[i_inter].name, "direct%d", i_inter); mem_pb_type->modes[0].interconnect[i_inter].infer_annotations = true; @@ -951,11 +964,14 @@ void ProcessMemoryClass(t_pb_type* mem_pb_type) { mem_pb_type->modes[0].pb_type_children[0].ports[i].num_pins = 1; mem_pb_type->modes[0].pb_type_children[0].num_input_pins -= (mem_pb_type->ports[i].num_pins - 1); - mem_pb_type->modes[0].interconnect[i_inter].input_string = new char[strlen(input_name) + strlen(input_port_name) + 2]; + mem_pb_type->modes[0].interconnect[i_inter].input_string = (char*)vtr::calloc(strlen(input_name) + strlen(input_port_name) + + 2, + sizeof(char)); sprintf(mem_pb_type->modes[0].interconnect[i_inter].input_string, "%s.%s", input_name, input_port_name); - mem_pb_type->modes[0].interconnect[i_inter].output_string = new char[strlen(output_name) + strlen(output_port_name) - + 2 * (6 + num_pb / 10)]; + mem_pb_type->modes[0].interconnect[i_inter].output_string = (char*)vtr::calloc(strlen(output_name) + strlen(output_port_name) + + 2 * (6 + num_pb / 10), + sizeof(char)); sprintf(mem_pb_type->modes[0].interconnect[i_inter].output_string, "%s[%d:0].%s", output_name, num_pb - 1, output_port_name); @@ -964,49 +980,62 @@ void ProcessMemoryClass(t_pb_type* mem_pb_type) { mem_pb_type->modes[0].pb_type_children[0].ports[i].num_pins = 1; mem_pb_type->modes[0].pb_type_children[0].num_output_pins -= (mem_pb_type->ports[i].num_pins - 1); - mem_pb_type->modes[0].interconnect[i_inter].input_string = new char[strlen(input_name) + strlen(input_port_name) - + 2 * (6 + num_pb / 10)]; + mem_pb_type->modes[0].interconnect[i_inter].input_string = (char*)vtr::calloc(strlen(input_name) + strlen(input_port_name) + + 2 * (6 + num_pb / 10), + sizeof(char)); sprintf(mem_pb_type->modes[0].interconnect[i_inter].input_string, "%s[%d:0].%s", input_name, num_pb - 1, input_port_name); - mem_pb_type->modes[0].interconnect[i_inter].output_string = new char[strlen(output_name) + strlen(output_port_name) - + 2]; + mem_pb_type->modes[0].interconnect[i_inter].output_string = (char*)vtr::calloc(strlen(output_name) + strlen(output_port_name) + + 2, + sizeof(char)); sprintf(mem_pb_type->modes[0].interconnect[i_inter].output_string, "%s.%s", output_name, output_port_name); } /* Allocate interconnect power structures */ - mem_pb_type->modes[0].interconnect[i_inter].interconnect_power = new t_interconnect_power[1](); + mem_pb_type->modes[0].interconnect[i_inter].interconnect_power = (t_interconnect_power*)vtr::calloc(1, + sizeof(t_interconnect_power)); i_inter++; } else { for (j = 0; j < num_pb; j++) { /* Anything that is not data must be an input */ - mem_pb_type->modes[0].interconnect[i_inter].name = new char[i_inter / 10 + j / 10 + 10]; + mem_pb_type->modes[0].interconnect[i_inter].name = (char*)vtr::calloc(i_inter / 10 + j / 10 + 10, + sizeof(char)); sprintf(mem_pb_type->modes[0].interconnect[i_inter].name, "direct%d_%d", i_inter, j); mem_pb_type->modes[0].interconnect[i_inter].infer_annotations = true; if (mem_pb_type->ports[i].type == IN_PORT) { mem_pb_type->modes[0].interconnect[i_inter].type = DIRECT_INTERC; - mem_pb_type->modes[0].interconnect[i_inter].input_string = new char[strlen(input_name) + strlen(input_port_name) + 2]; + mem_pb_type->modes[0].interconnect[i_inter].input_string = (char*)vtr::calloc(strlen(input_name) + strlen(input_port_name) + + 2, + sizeof(char)); sprintf(mem_pb_type->modes[0].interconnect[i_inter].input_string, "%s.%s", input_name, input_port_name); - mem_pb_type->modes[0].interconnect[i_inter].output_string = new char[strlen(output_name) + strlen(output_port_name) + 2 * (6 + num_pb / 10)]; + mem_pb_type->modes[0].interconnect[i_inter].output_string = (char*)vtr::calloc(strlen(output_name) + + strlen(output_port_name) + + 2 * (6 + num_pb / 10), + sizeof(char)); sprintf(mem_pb_type->modes[0].interconnect[i_inter].output_string, "%s[%d:%d].%s", output_name, j, j, output_port_name); } else { mem_pb_type->modes[0].interconnect[i_inter].type = DIRECT_INTERC; - mem_pb_type->modes[0].interconnect[i_inter].input_string = new char[strlen(input_name) + strlen(input_port_name) - + 2 * (6 + num_pb / 10)]; + mem_pb_type->modes[0].interconnect[i_inter].input_string = (char*)vtr::calloc(strlen(input_name) + strlen(input_port_name) + + 2 * (6 + num_pb / 10), + sizeof(char)); sprintf(mem_pb_type->modes[0].interconnect[i_inter].input_string, "%s[%d:%d].%s", input_name, j, j, input_port_name); - mem_pb_type->modes[0].interconnect[i_inter].output_string = new char[strlen(output_name) + strlen(output_port_name) + 2]; + mem_pb_type->modes[0].interconnect[i_inter].output_string = (char*)vtr::calloc(strlen(output_name) + + strlen(output_port_name) + 2, + sizeof(char)); sprintf(mem_pb_type->modes[0].interconnect[i_inter].output_string, "%s.%s", output_name, output_port_name); } /* Allocate interconnect power structures */ - mem_pb_type->modes[0].interconnect[i_inter].interconnect_power = new t_interconnect_power[1](); + mem_pb_type->modes[0].interconnect[i_inter].interconnect_power = (t_interconnect_power*)vtr::calloc(1, + sizeof(t_interconnect_power)); i_inter++; } } @@ -1213,7 +1242,7 @@ void SyncModel(t_pb_type* pb_type, t_model* model_match_prim, bool is_secondary_ } old = model_match_prim->pb_types; - model_match_prim->pb_types = new vtr::t_linked_vptr(); + model_match_prim->pb_types = (vtr::t_linked_vptr*)vtr::malloc(sizeof(vtr::t_linked_vptr)); model_match_prim->pb_types->next = old; model_match_prim->pb_types->data_vptr = pb_type; for (p = 0; p < pb_type->num_ports; p++) { From c59f504d9fdc65840e366eac8c0c599789b677da Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Fri, 23 Dec 2022 19:47:12 +0100 Subject: [PATCH 55/55] Revert "libarchfpga: arch_util: change all free() to delete" This reverts commit ab19fee1b3e801ca04f627ad2fc6571472279094. --- libs/libarchfpga/src/arch_util.cpp | 150 ++++++++++++++--------------- 1 file changed, 75 insertions(+), 75 deletions(-) diff --git a/libs/libarchfpga/src/arch_util.cpp b/libs/libarchfpga/src/arch_util.cpp index 59189e0093d..0fbe31278cd 100644 --- a/libs/libarchfpga/src/arch_util.cpp +++ b/libs/libarchfpga/src/arch_util.cpp @@ -154,7 +154,7 @@ void free_arch(t_arch* arch) { for (int i = 0; i < arch->num_switches; ++i) { if (arch->Switches->name != nullptr) { - delete arch->Switches[i].name; + vtr::free(arch->Switches[i].name); } } delete[] arch->Switches; @@ -163,13 +163,13 @@ void free_arch(t_arch* arch) { free_arch_models(arch->models); for (int i = 0; i < arch->num_directs; ++i) { - delete arch->Directs[i].name; - delete arch->Directs[i].from_pin; - delete arch->Directs[i].to_pin; + vtr::free(arch->Directs[i].name); + vtr::free(arch->Directs[i].from_pin); + vtr::free(arch->Directs[i].to_pin); } - delete arch->Directs; + vtr::free(arch->Directs); - delete arch->architecture_id; + vtr::free(arch->architecture_id); //Free internal model library if (arch->model_library) { @@ -178,42 +178,42 @@ void free_arch(t_arch* arch) { while (vptr) { vtr::t_linked_vptr* vptr_prev = vptr; vptr = vptr->next; - delete vptr_prev; + vtr::free(vptr_prev); } } //Each model has different number of inputs/outputs - delete each model separately //Free INPAD - delete arch->model_library[LIB_INPUT].name; - delete arch->model_library[LIB_INPUT].outputs->name; + vtr::free(arch->model_library[LIB_INPUT].name); + vtr::free(arch->model_library[LIB_INPUT].outputs->name); delete[] arch->model_library[LIB_INPUT].outputs; //Free OUTPAD - delete arch->model_library[LIB_OUTPUT].name; - delete arch->model_library[LIB_OUTPUT].inputs->name; + vtr::free(arch->model_library[LIB_OUTPUT].name); + vtr::free(arch->model_library[LIB_OUTPUT].inputs->name); delete[] arch->model_library[LIB_OUTPUT].inputs; //Free LATCH triggered at RISING EDGE - delete arch->model_library[LIB_LATCH_RE].name; - delete arch->model_library[LIB_LATCH_RE].inputs[0].name; - delete arch->model_library[LIB_LATCH_RE].inputs[1].name; + vtr::free(arch->model_library[LIB_LATCH_RE].name); + vtr::free(arch->model_library[LIB_LATCH_RE].inputs[0].name); + vtr::free(arch->model_library[LIB_LATCH_RE].inputs[1].name); delete[] arch->model_library[LIB_LATCH_RE].inputs; - delete arch->model_library[LIB_LATCH_RE].outputs->name; + vtr::free(arch->model_library[LIB_LATCH_RE].outputs->name); delete[] arch->model_library[LIB_LATCH_RE].outputs; //Free LATCH triggered at FALLING EDGE - delete arch->model_library[LIB_LATCH_FE].name; - delete arch->model_library[LIB_LATCH_FE].inputs[0].name; - delete arch->model_library[LIB_LATCH_FE].inputs[1].name; + vtr::free(arch->model_library[LIB_LATCH_FE].name); + vtr::free(arch->model_library[LIB_LATCH_FE].inputs[0].name); + vtr::free(arch->model_library[LIB_LATCH_FE].inputs[1].name); delete[] arch->model_library[LIB_LATCH_FE].inputs; - delete arch->model_library[LIB_LATCH_FE].outputs->name; + vtr::free(arch->model_library[LIB_LATCH_FE].outputs->name); delete[] arch->model_library[LIB_LATCH_FE].outputs; //Free NAMES - delete arch->model_library[LIB_NAMES].name; - delete arch->model_library[LIB_NAMES].inputs->name; + vtr::free(arch->model_library[LIB_NAMES].name); + vtr::free(arch->model_library[LIB_NAMES].inputs->name); delete[] arch->model_library[LIB_NAMES].inputs; - delete arch->model_library[LIB_NAMES].outputs->name; + vtr::free(arch->model_library[LIB_NAMES].outputs->name); delete[] arch->model_library[LIB_NAMES].outputs; //Free the library array @@ -221,7 +221,7 @@ void free_arch(t_arch* arch) { } if (arch->clocks) { - delete arch->clocks->clock_inf; + vtr::free(arch->clocks->clock_inf); } delete (arch->noc); @@ -248,12 +248,12 @@ t_model* free_arch_model(t_model* model) { while (vptr) { vtr::t_linked_vptr* vptr_prev = vptr; vptr = vptr->next; - delete vptr_prev; + vtr::free(vptr_prev); } if (model->instances) vtr::free(model->instances); - delete model->name; + vtr::free(model->name); delete model; return next_model; @@ -273,7 +273,7 @@ t_model_ports* free_arch_model_port(t_model_ports* model_port) { t_model_ports* next_port = model_port->next; - delete model_port->name; + vtr::free(model_port->name); delete model_port; return next_port; @@ -281,16 +281,16 @@ t_model_ports* free_arch_model_port(t_model_ports* model_port) { void free_type_descriptors(std::vector& type_descriptors) { for (auto& type : type_descriptors) { - delete type.name; + vtr::free(type.name); if (type.index == EMPTY_TYPE_INDEX) { continue; } for (auto& sub_tile : type.sub_tiles) { - delete sub_tile.name; + vtr::free(sub_tile.name); for (auto port : sub_tile.ports) { - delete port.name; + vtr::free(port.name); } } } @@ -301,7 +301,7 @@ void free_type_descriptors(std::vector& type_descriptors) free_all_pb_graph_nodes(type_descriptors); for (auto& type : type_descriptors) { - delete type.name; + vtr::free(type.name); if (type.index == EMPTY_TYPE_INDEX) { continue; } @@ -421,98 +421,98 @@ static void free_pb_graph(t_pb_graph_node* pb_graph_node) { for (k = 0; k < pb_type->modes[i].pb_type_children[j].num_pb; k++) { free_pb_graph(&pb_graph_node->child_pb_graph_nodes[i][j][k]); } - delete pb_graph_node->child_pb_graph_nodes[i][j]; + vtr::free(pb_graph_node->child_pb_graph_nodes[i][j]); } - delete pb_graph_node->child_pb_graph_nodes[i]; + vtr::free(pb_graph_node->child_pb_graph_nodes[i]); } - delete pb_graph_node->child_pb_graph_nodes; + vtr::free(pb_graph_node->child_pb_graph_nodes); } static void free_pb_type(t_pb_type* pb_type) { - delete pb_type->name; + vtr::free(pb_type->name); if (pb_type->blif_model) - delete pb_type->blif_model; + vtr::free(pb_type->blif_model); for (int i = 0; i < pb_type->num_modes; ++i) { for (int j = 0; j < pb_type->modes[i].num_pb_type_children; ++j) { free_pb_type(&pb_type->modes[i].pb_type_children[j]); } delete[] pb_type->modes[i].pb_type_children; - delete pb_type->modes[i].name; + vtr::free(pb_type->modes[i].name); for (int j = 0; j < pb_type->modes[i].num_interconnect; ++j) { - delete pb_type->modes[i].interconnect[j].input_string; - delete pb_type->modes[i].interconnect[j].output_string; - delete pb_type->modes[i].interconnect[j].name; + vtr::free(pb_type->modes[i].interconnect[j].input_string); + vtr::free(pb_type->modes[i].interconnect[j].output_string); + vtr::free(pb_type->modes[i].interconnect[j].name); for (int k = 0; k < pb_type->modes[i].interconnect[j].num_annotations; ++k) { if (pb_type->modes[i].interconnect[j].annotations[k].clock) - delete pb_type->modes[i].interconnect[j].annotations[k].clock; + vtr::free(pb_type->modes[i].interconnect[j].annotations[k].clock); if (pb_type->modes[i].interconnect[j].annotations[k].input_pins) { - delete pb_type->modes[i].interconnect[j].annotations[k].input_pins; + vtr::free(pb_type->modes[i].interconnect[j].annotations[k].input_pins); } if (pb_type->modes[i].interconnect[j].annotations[k].output_pins) { - delete pb_type->modes[i].interconnect[j].annotations[k].output_pins; + vtr::free(pb_type->modes[i].interconnect[j].annotations[k].output_pins); } for (int m = 0; m < pb_type->modes[i].interconnect[j].annotations[k].num_value_prop_pairs; ++m) { - delete pb_type->modes[i].interconnect[j].annotations[k].value[m]; + vtr::free(pb_type->modes[i].interconnect[j].annotations[k].value[m]); } - delete pb_type->modes[i].interconnect[j].annotations[k].prop; - delete pb_type->modes[i].interconnect[j].annotations[k].value; + vtr::free(pb_type->modes[i].interconnect[j].annotations[k].prop); + vtr::free(pb_type->modes[i].interconnect[j].annotations[k].value); } - delete pb_type->modes[i].interconnect[j].annotations; + vtr::free(pb_type->modes[i].interconnect[j].annotations); if (pb_type->modes[i].interconnect[j].interconnect_power) - delete pb_type->modes[i].interconnect[j].interconnect_power; + vtr::free(pb_type->modes[i].interconnect[j].interconnect_power); } if (pb_type->modes[i].interconnect) delete[] pb_type->modes[i].interconnect; if (pb_type->modes[i].mode_power) - delete pb_type->modes[i].mode_power; + vtr::free(pb_type->modes[i].mode_power); } if (pb_type->modes) delete[] pb_type->modes; for (int i = 0; i < pb_type->num_annotations; ++i) { for (int j = 0; j < pb_type->annotations[i].num_value_prop_pairs; ++j) { - delete pb_type->annotations[i].value[j]; + vtr::free(pb_type->annotations[i].value[j]); } - delete pb_type->annotations[i].value; - delete pb_type->annotations[i].prop; + vtr::free(pb_type->annotations[i].value); + vtr::free(pb_type->annotations[i].prop); if (pb_type->annotations[i].input_pins) { - delete pb_type->annotations[i].input_pins; + vtr::free(pb_type->annotations[i].input_pins); } if (pb_type->annotations[i].output_pins) { - delete pb_type->annotations[i].output_pins; + vtr::free(pb_type->annotations[i].output_pins); } if (pb_type->annotations[i].clock) { - delete pb_type->annotations[i].clock; + vtr::free(pb_type->annotations[i].clock); } } if (pb_type->num_annotations > 0) { - delete pb_type->annotations; + vtr::free(pb_type->annotations); } if (pb_type->pb_type_power) { - delete pb_type->pb_type_power; + vtr::free(pb_type->pb_type_power); } for (int i = 0; i < pb_type->num_ports; ++i) { - delete pb_type->ports[i].name; + vtr::free(pb_type->ports[i].name); if (pb_type->class_type == LATCH_CLASS) - delete pb_type->ports_sec[i].name; + vtr::free(pb_type->ports_sec[i].name); if (pb_type->ports[i].port_class) { - delete pb_type->ports[i].port_class; + vtr::free(pb_type->ports[i].port_class); if (pb_type->class_type == LATCH_CLASS) - delete pb_type->ports_sec[i].port_class; + vtr::free(pb_type->ports_sec[i].port_class); } if (pb_type->ports[i].port_power) { - delete pb_type->ports[i].port_power; + vtr::free(pb_type->ports[i].port_power); if (pb_type->class_type == LATCH_CLASS) - delete pb_type->ports_sec[i].port_power; + vtr::free(pb_type->ports_sec[i].port_power); } } - delete pb_type->ports; + vtr::free(pb_type->ports); if (pb_type->class_type == LATCH_CLASS) - delete pb_type->ports_sec; + vtr::free(pb_type->ports_sec); } t_port* findPortByName(const char* name, t_pb_type* pb_type, int* high_index, int* low_index) { @@ -809,22 +809,22 @@ void ProcessLutClass(t_pb_type* lut_pb_type) { /* moved annotations to child so delete old annotations */ for (i = 0; i < lut_pb_type->num_annotations; i++) { for (j = 0; j < lut_pb_type->annotations[i].num_value_prop_pairs; j++) { - delete lut_pb_type->annotations[i].value[j]; + free(lut_pb_type->annotations[i].value[j]); } - delete lut_pb_type->annotations[i].value; - delete lut_pb_type->annotations[i].prop; + free(lut_pb_type->annotations[i].value); + free(lut_pb_type->annotations[i].prop); if (lut_pb_type->annotations[i].input_pins) { - delete lut_pb_type->annotations[i].input_pins; + free(lut_pb_type->annotations[i].input_pins); } if (lut_pb_type->annotations[i].output_pins) { - delete lut_pb_type->annotations[i].output_pins; + free(lut_pb_type->annotations[i].output_pins); } if (lut_pb_type->annotations[i].clock) { - delete lut_pb_type->annotations[i].clock; + free(lut_pb_type->annotations[i].clock); } } lut_pb_type->num_annotations = 0; - delete lut_pb_type->annotations; + free(lut_pb_type->annotations); lut_pb_type->annotations = nullptr; lut_pb_type->modes[1].pb_type_children[0].depth = lut_pb_type->depth + 1; lut_pb_type->modes[1].pb_type_children[0].parent_mode = &lut_pb_type->modes[1]; @@ -873,9 +873,9 @@ void ProcessLutClass(t_pb_type* lut_pb_type) { lut_pb_type->modes[1].interconnect[1].parent_mode = &lut_pb_type->modes[1]; lut_pb_type->modes[1].interconnect[1].interconnect_power = (t_interconnect_power*)vtr::calloc(1, sizeof(t_interconnect_power)); - delete default_name; + free(default_name); - delete lut_pb_type->blif_model; + free(lut_pb_type->blif_model); lut_pb_type->blif_model = nullptr; lut_pb_type->model = nullptr; } @@ -924,7 +924,7 @@ void ProcessMemoryClass(t_pb_type* mem_pb_type) { mem_pb_type->num_modes = 1; - delete mem_pb_type->blif_model; + free(mem_pb_type->blif_model); mem_pb_type->blif_model = nullptr; mem_pb_type->model = nullptr; @@ -1043,7 +1043,7 @@ void ProcessMemoryClass(t_pb_type* mem_pb_type) { mem_pb_type->modes[0].num_interconnect = i_inter; - delete default_name; + free(default_name); } e_power_estimation_method power_method_inherited(e_power_estimation_method parent_power_method) {