From ccf8c1a3d1aa36507033197953a7c0bacdc3d4bc Mon Sep 17 00:00:00 2001 From: AlexandreSinger Date: Thu, 24 Apr 2025 12:57:12 -0400 Subject: [PATCH] [LibArchFPGA] Updating Model Data Structures The logical models (the technology-mapped logical blocks) for an architecture were stored using two independent linked lists. One for the library models (the models that all architectures have, such as luts and ffs) and one of the user models. This linked lists were hard to traverse and were injecting pointers all across VPR. Created a new class to store and manage the logical models. This class maintains a unique ID for each logical model (similar to the netlist data structures in VPR). It also contains helper methods to make working with the logical models easier. --- libs/libarchfpga/src/arch_check.cpp | 95 +- libs/libarchfpga/src/arch_check.h | 6 +- libs/libarchfpga/src/arch_types.h | 9 - libs/libarchfpga/src/arch_util.cpp | 252 +--- libs/libarchfpga/src/arch_util.h | 8 - libs/libarchfpga/src/echo_arch.cpp | 97 +- libs/libarchfpga/src/logic_types.cpp | 171 +++ libs/libarchfpga/src/logic_types.h | 233 +++- libs/libarchfpga/src/physical_types.h | 5 +- .../src/read_fpga_interchange_arch.cpp | 116 +- libs/libarchfpga/src/read_xml_arch_file.cpp | 62 +- libs/libarchfpga/src/write_models_bb.cpp | 60 +- odin_ii/src/core/adders.cpp | 8 +- odin_ii/src/core/hard_blocks.cpp | 26 +- odin_ii/src/core/multipliers.cpp | 8 +- odin_ii/src/verilog/verilog_writer.cpp | 8 +- parmys/parmys-plugin/core/adder.cc | 10 +- parmys/parmys-plugin/core/hard_block.cc | 40 +- parmys/parmys-plugin/core/multiplier.cc | 8 +- parmys/parmys-plugin/parmys.cc | 5 +- parmys/parmys-plugin/parmys_arch.cc | 12 +- utils/fasm/src/fasm.cpp | 6 +- utils/vqm2blif/src/base/hard_block_recog.cpp | 19 +- utils/vqm2blif/src/base/preprocess.cpp | 41 +- utils/vqm2blif/src/base/vqm2blif.h | 3 +- utils/vqm2blif/src/base/vqm2blif_util.cpp | 60 +- utils/vqm2blif/src/base/vqm2blif_util.h | 18 +- utils/vqm2blif/src/main.cpp | 284 ++-- .../carpat/carpat_stratixiv_arch_timing.blif | 1190 ++++++++--------- .../murax/murax_stratixiv_arch_timing.blif | 104 +- ...csb_152_tap_fir_stratixiv_arch_timing.blif | 38 +- vpr/src/analysis/timing_reports.cpp | 8 +- .../analytical_placement_flow.cpp | 2 +- .../flat_placement_mass_calculator.cpp | 55 +- vpr/src/analytical_place/full_legalizer.cpp | 13 +- vpr/src/analytical_place/model_grouper.cpp | 77 +- vpr/src/analytical_place/model_grouper.h | 17 +- .../analytical_place/partial_legalizer.cpp | 112 +- vpr/src/analytical_place/partial_legalizer.h | 14 +- vpr/src/base/SetupVPR.cpp | 9 +- vpr/src/base/SetupVPR.h | 3 - vpr/src/base/atom_netlist.cpp | 28 +- vpr/src/base/atom_netlist.h | 12 +- vpr/src/base/atom_netlist_utils.cpp | 181 ++- vpr/src/base/atom_netlist_utils.h | 27 +- vpr/src/base/check_netlist.cpp | 6 +- vpr/src/base/clustered_netlist.cpp | 11 +- vpr/src/base/clustered_netlist.h | 4 +- vpr/src/base/netlist_writer.cpp | 69 +- vpr/src/base/netlist_writer.h | 6 +- vpr/src/base/read_blif.cpp | 151 +-- vpr/src/base/read_blif.h | 8 +- vpr/src/base/read_circuit.cpp | 33 +- vpr/src/base/read_circuit.h | 6 +- vpr/src/base/read_interchange_netlist.cpp | 72 +- vpr/src/base/read_interchange_netlist.h | 5 +- vpr/src/base/read_netlist.cpp | 4 +- vpr/src/base/vpr_api.cpp | 20 +- vpr/src/base/vpr_api.h | 2 - vpr/src/base/vpr_types.cpp | 9 +- vpr/src/base/vpr_types.h | 4 +- vpr/src/draw/intra_logic_block.cpp | 5 +- vpr/src/pack/cluster_legalizer.cpp | 15 +- vpr/src/pack/cluster_legalizer.h | 3 + vpr/src/pack/cluster_util.cpp | 35 +- vpr/src/pack/cluster_util.h | 6 +- vpr/src/pack/greedy_candidate_selector.cpp | 21 +- vpr/src/pack/greedy_candidate_selector.h | 11 +- vpr/src/pack/greedy_clusterer.cpp | 26 +- vpr/src/pack/greedy_clusterer.h | 4 +- vpr/src/pack/greedy_seed_selector.cpp | 31 +- vpr/src/pack/greedy_seed_selector.h | 2 + vpr/src/pack/noc_aware_cluster_util.cpp | 9 +- vpr/src/pack/noc_aware_cluster_util.h | 3 +- vpr/src/pack/pack.cpp | 1 + vpr/src/pack/pb_type_graph.cpp | 5 +- vpr/src/pack/prepack.cpp | 45 +- vpr/src/pack/prepack.h | 13 +- vpr/src/place/placement_log_printer.cpp | 3 +- vpr/src/power/power.cpp | 4 +- vpr/src/power/power_sizing.cpp | 5 +- vpr/src/route/route_common.cpp | 8 +- vpr/src/route/route_utils.cpp | 3 +- vpr/src/server/pathhelper.cpp | 3 +- vpr/src/timing/PreClusterDelayCalculator.h | 10 +- .../timing/PreClusterTimingGraphResolver.cpp | 6 +- .../timing/PreClusterTimingGraphResolver.h | 4 + vpr/src/timing/PreClusterTimingManager.cpp | 2 + vpr/src/timing/VprTimingGraphResolver.cpp | 7 +- vpr/src/timing/VprTimingGraphResolver.h | 3 + vpr/src/timing/read_sdc.cpp | 18 +- vpr/src/timing/read_sdc.h | 3 + vpr/src/timing/timing_graph_builder.cpp | 8 +- vpr/src/timing/timing_graph_builder.h | 5 +- vpr/src/util/vpr_utils.cpp | 36 +- vpr/src/util/vpr_utils.h | 3 - vpr/test/test_interchange_device.cpp | 24 +- vpr/test/test_interchange_netlist.cpp | 7 +- 98 files changed, 2192 insertions(+), 2175 deletions(-) create mode 100644 libs/libarchfpga/src/logic_types.cpp diff --git a/libs/libarchfpga/src/arch_check.cpp b/libs/libarchfpga/src/arch_check.cpp index 5360d6e4c02..75c96aa3cfb 100644 --- a/libs/libarchfpga/src/arch_check.cpp +++ b/libs/libarchfpga/src/arch_check.cpp @@ -1,14 +1,14 @@ #include -#include +#include "logic_types.h" #include "vtr_log.h" #include "arch_error.h" #include "arch_check.h" -bool check_model_clocks(t_model* model, const char* file, uint32_t line) { +bool check_model_clocks(const t_model& model, const char* file, uint32_t line) { //Collect the ports identified as clocks std::set clocks; - for (t_model_ports* ports : {model->inputs, model->outputs}) { + for (t_model_ports* ports : {model.inputs, model.outputs}) { for (t_model_ports* port = ports; port != nullptr; port = port->next) { if (port->is_clock) { clocks.insert(port->name); @@ -17,41 +17,41 @@ bool check_model_clocks(t_model* model, const char* file, uint32_t line) { } //Check that any clock references on the ports are to identified clock ports - for (t_model_ports* ports : {model->inputs, model->outputs}) { + for (t_model_ports* ports : {model.inputs, model.outputs}) { for (t_model_ports* port = ports; port != nullptr; port = port->next) { if (!port->clock.empty() && !clocks.count(port->clock)) { archfpga_throw(file, line, "No matching clock port '%s' on model '%s', required for port '%s'", - port->clock.c_str(), model->name, port->name); + port->clock.c_str(), model.name, port->name); } } } return true; } -bool check_model_combinational_sinks(const t_model* model, const char* file, uint32_t line) { +bool check_model_combinational_sinks(const t_model& model, const char* file, uint32_t line) { //Outputs should have no combinational sinks - for (t_model_ports* port = model->outputs; port != nullptr; port = port->next) { + for (t_model_ports* port = model.outputs; port != nullptr; port = port->next) { if (!port->combinational_sink_ports.empty()) { archfpga_throw(file, line, "Model '%s' output port '%s' can not have combinational sink ports", - model->name, port->name); + model.name, port->name); } } //Record the output ports std::map output_ports; - for (t_model_ports* port = model->outputs; port != nullptr; port = port->next) { + for (t_model_ports* port = model.outputs; port != nullptr; port = port->next) { output_ports.insert({port->name, port}); } - for (t_model_ports* port = model->inputs; port != nullptr; port = port->next) { + for (t_model_ports* port = model.inputs; port != nullptr; port = port->next) { for (const std::string& sink_port_name : port->combinational_sink_ports) { //Check that the input port combinational sinks are all outputs if (!output_ports.count(sink_port_name)) { archfpga_throw(file, line, "Model '%s' input port '%s' can not be combinationally connected to '%s' (not an output port of the model)", - model->name, port->name, sink_port_name.c_str()); + model.name, port->name, sink_port_name.c_str()); } //Check that any output combinational sinks are not clocks @@ -61,7 +61,7 @@ bool check_model_combinational_sinks(const t_model* model, const char* file, uin archfpga_throw(file, line, "Model '%s' output port '%s' can not be both: a clock source (is_clock=\"%d\")," " and combinationally connected to input port '%s' (acting as a clock buffer).", - model->name, sink_port->name, sink_port->is_clock, port->name); + model.name, sink_port->name, sink_port->is_clock, port->name); } } } @@ -69,28 +69,28 @@ bool check_model_combinational_sinks(const t_model* model, const char* file, uin return true; } -void warn_model_missing_timing(const t_model* model, const char* file, uint32_t line) { +void warn_model_missing_timing(const t_model& model, const char* file, uint32_t line) { //Check whether there are missing edges and warn the user std::set comb_connected_outputs; - for (t_model_ports* port = model->inputs; port != nullptr; port = port->next) { + for (t_model_ports* port = model.inputs; port != nullptr; port = port->next) { if (port->clock.empty() //Not sequential && port->combinational_sink_ports.empty() //Doesn't drive any combinational outputs && !port->is_clock //Not an input clock ) { VTR_LOGF_WARN(file, line, - "Model '%s' input port '%s' has no timing specification (no clock specified to create a sequential input port, not combinationally connected to any outputs, not a clock input)\n", model->name, port->name); + "Model '%s' input port '%s' has no timing specification (no clock specified to create a sequential input port, not combinationally connected to any outputs, not a clock input)\n", model.name, port->name); } comb_connected_outputs.insert(port->combinational_sink_ports.begin(), port->combinational_sink_ports.end()); } - for (t_model_ports* port = model->outputs; port != nullptr; port = port->next) { + for (t_model_ports* port = model.outputs; port != nullptr; port = port->next) { if (port->clock.empty() //Not sequential && !comb_connected_outputs.count(port->name) //Not combinationally driven && !port->is_clock //Not an output clock ) { VTR_LOGF_WARN(file, line, - "Model '%s' output port '%s' has no timing specification (no clock specified to create a sequential output port, not combinationally connected to any inputs, not a clock output)\n", model->name, port->name); + "Model '%s' output port '%s' has no timing specification (no clock specified to create a sequential output port, not combinationally connected to any inputs, not a clock output)\n", model.name, port->name); } } } @@ -144,23 +144,13 @@ bool check_leaf_pb_model_timing_consistency(const t_pb_type* pb_type, const t_ar } //Find the matching model - const t_model* model = nullptr; - - for (const t_model* models : {arch.models, arch.model_library}) { - for (model = models; model != nullptr; model = model->next) { - if (std::string(model->name) == blif_model) { - break; - } - } - if (model != nullptr) { - break; - } - } - if (model == nullptr) { + LogicalModelId blif_model_id = arch.models.get_model_by_name(blif_model); + if (!blif_model_id.is_valid()) { archfpga_throw(get_arch_file_name(), -1, "Unable to find model for blif_model '%s' found on pb_type '%s'", blif_model.c_str(), pb_type->name); } + const t_model& model = arch.models.get_model(blif_model_id); //Now that we have the model we can compare the timing annotations @@ -185,7 +175,7 @@ bool check_leaf_pb_model_timing_consistency(const t_pb_type* pb_type, const t_ar //Find the model port const t_model_ports* model_port = nullptr; - for (const t_model_ports* ports : {model->inputs, model->outputs}) { + for (const t_model_ports* ports : {model.inputs, model.outputs}) { for (const t_model_ports* port = ports; port != nullptr; port = port->next) { if (port->name == annot_port.port_name()) { model_port = port; @@ -206,13 +196,13 @@ bool check_leaf_pb_model_timing_consistency(const t_pb_type* pb_type, const t_ar archfpga_throw(get_arch_file_name(), annot->line_num, " timing-annotation/ mismatch on port '%s' of model '%s', model specifies" " no clock but timing annotation specifies '%s'", - annot_port.port_name().c_str(), model->name, annot_clock.port_name().c_str()); + annot_port.port_name().c_str(), model.name, annot_clock.port_name().c_str()); } if (model_port->clock != annot_clock.port_name()) { archfpga_throw(get_arch_file_name(), annot->line_num, " timing-annotation/ mismatch on port '%s' of model '%s', model specifies" " clock as '%s' but timing annotation specifies '%s'", - annot_port.port_name().c_str(), model->name, model_clock.c_str(), annot_clock.port_name().c_str()); + annot_port.port_name().c_str(), model.name, model_clock.c_str(), annot_clock.port_name().c_str()); } } } @@ -227,7 +217,7 @@ bool check_leaf_pb_model_timing_consistency(const t_pb_type* pb_type, const t_ar //Find the input model port const t_model_ports* model_port = nullptr; - for (const t_model_ports* port = model->inputs; port != nullptr; port = port->next) { + for (const t_model_ports* port = model.inputs; port != nullptr; port = port->next) { if (port->name == annot_in.port_name()) { model_port = port; break; @@ -248,7 +238,7 @@ bool check_leaf_pb_model_timing_consistency(const t_pb_type* pb_type, const t_ar archfpga_throw(get_arch_file_name(), annot->line_num, " timing-annotation/ mismatch on port '%s' of model '%s', timing annotation" " specifies combinational connection to port '%s' but the connection does not exist in the model", - model_port->name, model->name, annot_out.port_name().c_str()); + model_port->name, model.name, annot_out.port_name().c_str()); } } } @@ -260,7 +250,7 @@ bool check_leaf_pb_model_timing_consistency(const t_pb_type* pb_type, const t_ar //Build a list of combinationally connected sinks std::set comb_connected_outputs; - for (t_model_ports* model_ports : {model->inputs, model->outputs}) { + for (t_model_ports* model_ports : {model.inputs, model.outputs}) { for (t_model_ports* model_port = model_ports; model_port != nullptr; model_port = model_port->next) { comb_connected_outputs.insert(model_port->combinational_sink_ports.begin(), model_port->combinational_sink_ports.end()); } @@ -270,7 +260,7 @@ bool check_leaf_pb_model_timing_consistency(const t_pb_type* pb_type, const t_ar // // This ensures that the pb_type has annotations for all delays/values // required by the model - for (t_model_ports* model_ports : {model->inputs, model->outputs}) { + for (t_model_ports* model_ports : {model.inputs, model.outputs}) { for (t_model_ports* model_port = model_ports; model_port != nullptr; model_port = model_port->next) { //If the model port has no timing specification don't check anything (e.g. architectures with no timing info) if (model_port->clock.empty() @@ -288,10 +278,10 @@ bool check_leaf_pb_model_timing_consistency(const t_pb_type* pb_type, const t_ar && find_sequential_annotation(pb_type, model_port, E_ANNOT_PIN_TO_PIN_DELAY_THOLD) == nullptr) { std::stringstream msg; msg << " '" << pb_type->name << "' timing-annotation/ mismatch on"; - msg << " port '" << model_port->name << "' of model '" << model->name << "',"; + msg << " port '" << model_port->name << "' of model '" << model.name << "',"; msg << " port is a sequential input but has neither T_setup nor T_hold specified"; - if (is_library_model(model)) { + if (arch.models.is_library_model(blif_model_id)) { //Only warn if timing info is missing from a library model (e.g. .names/.latch on a non-timing architecture) VTR_LOGF_WARN(get_arch_file_name(), -1, "%s\n", msg.str().c_str()); } else { @@ -305,11 +295,11 @@ bool check_leaf_pb_model_timing_consistency(const t_pb_type* pb_type, const t_ar && find_sequential_annotation(pb_type, model_port, E_ANNOT_PIN_TO_PIN_DELAY_CLOCK_TO_Q_MIN) == nullptr) { std::stringstream msg; msg << " '" << pb_type->name << "' timing-annotation/ mismatch on"; - msg << " port '" << model_port->name << "' of model '" << model->name << "',"; + msg << " port '" << model_port->name << "' of model '" << model.name << "',"; msg << " port is a sequential input with internal combinational connects but has neither"; msg << " min nor max T_clock_to_Q specified"; - if (is_library_model(model)) { + if (arch.models.is_library_model(blif_model_id)) { //Only warn if timing info is missing from a library model (e.g. .names/.latch on a non-timing architecture) VTR_LOGF_WARN(get_arch_file_name(), -1, "%s\n", msg.str().c_str()); } else { @@ -325,10 +315,10 @@ bool check_leaf_pb_model_timing_consistency(const t_pb_type* pb_type, const t_ar && find_sequential_annotation(pb_type, model_port, E_ANNOT_PIN_TO_PIN_DELAY_CLOCK_TO_Q_MIN) == nullptr) { std::stringstream msg; msg << " '" << pb_type->name << "' timing-annotation/ mismatch on"; - msg << " port '" << model_port->name << "' of model '" << model->name << "',"; + msg << " port '" << model_port->name << "' of model '" << model.name << "',"; msg << " port is a sequential output but has neither min nor max T_clock_to_Q specified"; - if (is_library_model(model)) { + if (arch.models.is_library_model(blif_model_id)) { //Only warn if timing info is missing from a library model (e.g. .names/.latch on a non-timing architecture) VTR_LOGF_WARN(get_arch_file_name(), -1, "%s\n", msg.str().c_str()); } else { @@ -342,11 +332,11 @@ bool check_leaf_pb_model_timing_consistency(const t_pb_type* pb_type, const t_ar && find_sequential_annotation(pb_type, model_port, E_ANNOT_PIN_TO_PIN_DELAY_THOLD) == nullptr) { std::stringstream msg; msg << " '" << pb_type->name << "' timing-annotation/ mismatch on"; - msg << " port '" << model_port->name << "' of model '" << model->name << "',"; + msg << " port '" << model_port->name << "' of model '" << model.name << "',"; msg << " port is a sequential output with internal combinational connections but has"; msg << " neither T_setup nor T_hold specified"; - if (is_library_model(model)) { + if (arch.models.is_library_model(blif_model_id)) { //Only warn if timing info is missing from a library model (e.g. .names/.latch on a non-timing architecture) VTR_LOGF_WARN(get_arch_file_name(), -1, "%s\n", msg.str().c_str()); } else { @@ -363,11 +353,11 @@ bool check_leaf_pb_model_timing_consistency(const t_pb_type* pb_type, const t_ar if (find_combinational_annotation(pb_type, model_port->name, sink_port) == nullptr) { std::stringstream msg; msg << " '" << pb_type->name << "' timing-annotation/ mismatch on"; - msg << " port '" << model_port->name << "' of model '" << model->name << "',"; + msg << " port '" << model_port->name << "' of model '" << model.name << "',"; msg << " input port '" << model_port->name << "' has combinational connections to"; msg << " port '" << sink_port.c_str() << "'; specified in model, but no combinational delays found on pb_type"; - if (is_library_model(model)) { + if (arch.models.is_library_model(blif_model_id)) { //Only warn if timing info is missing from a library model (e.g. .names/.latch on a non-timing architecture) VTR_LOGF_WARN(get_arch_file_name(), -1, "%s\n", msg.str().c_str()); } else { @@ -383,15 +373,16 @@ bool check_leaf_pb_model_timing_consistency(const t_pb_type* pb_type, const t_ar } void check_models(t_arch* arch) { - for (t_model* model = arch->models; model != nullptr; model = model->next) { - if (model->pb_types == nullptr) { + for (LogicalModelId model_id : arch->models.user_models()) { + const t_model& model = arch->models.get_model(model_id); + if (model.pb_types == nullptr) { archfpga_throw(get_arch_file_name(), 0, - "No pb_type found for model %s\n", model->name); + "No pb_type found for model %s\n", model.name); } int clk_count, input_count, output_count; clk_count = input_count = output_count = 0; - for (auto ports : {model->inputs, model->outputs}) { + for (auto ports : {model.inputs, model.outputs}) { for (auto port = ports; port != nullptr; port = port->next) { int index; switch (port->dir) { @@ -403,7 +394,7 @@ void check_models(t_arch* arch) { break; default: archfpga_throw(get_arch_file_name(), 0, - "Port %s of model %s, has an unrecognized type %s\n", port->name, model->name); + "Port %s of model %s, has an unrecognized type %s\n", port->name, model.name); } port->index = index; diff --git a/libs/libarchfpga/src/arch_check.h b/libs/libarchfpga/src/arch_check.h index 20b3ad30d4b..b057cbde347 100644 --- a/libs/libarchfpga/src/arch_check.h +++ b/libs/libarchfpga/src/arch_check.h @@ -26,7 +26,7 @@ extern "C" { * @param file architecture file * @param line line in the architecture file that generates the failure */ -bool check_model_clocks(t_model* model, const char* file, uint32_t line); +bool check_model_clocks(const t_model& model, const char* file, uint32_t line); /** * @brief Checks the correctness of the combinational sinks in the model inputs to outputs connections @@ -35,7 +35,7 @@ bool check_model_clocks(t_model* model, const char* file, uint32_t line); * @param file architecture file * @param line line in the architecture file that generates the failure */ -bool check_model_combinational_sinks(const t_model* model, const char* file, uint32_t line); +bool check_model_combinational_sinks(const t_model& model, const char* file, uint32_t line); /** * @brief Checks whether the I/O ports can have timing specifications based on their connectivity. @@ -47,7 +47,7 @@ bool check_model_combinational_sinks(const t_model* model, const char* file, uin * @param file architecture file * @param line line in the architecture file that generates the failure */ -void warn_model_missing_timing(const t_model* model, const char* file, uint32_t line); +void warn_model_missing_timing(const t_model& model, const char* file, uint32_t line); /** * @brief Checks the consistency of the mappings between a logical block and the corresponding physical tile. diff --git a/libs/libarchfpga/src/arch_types.h b/libs/libarchfpga/src/arch_types.h index 69ac28ae479..8ea9c44b67f 100644 --- a/libs/libarchfpga/src/arch_types.h +++ b/libs/libarchfpga/src/arch_types.h @@ -18,18 +18,9 @@ /* Value for UNDEFINED data */ constexpr int UNDEFINED = -1; -/** The total number of predefined blif models */ -constexpr int NUM_MODELS_IN_LIBRARY = 4; - /* Maximum value for minimum channel width to avoid overflows of short data type. */ constexpr int MAX_CHANNEL_WIDTH = 8000; -/* Built-in library models */ -constexpr const char* MODEL_NAMES = ".names"; -constexpr const char* MODEL_LATCH = ".latch"; -constexpr const char* MODEL_INPUT = ".input"; -constexpr const char* MODEL_OUTPUT = ".output"; - enum class e_arch_format { VTR, /// #include +#include +#include "logic_types.h" #include "vtr_assert.h" +#include "vtr_list.h" #include "vtr_memory.h" #include "vtr_util.h" @@ -10,7 +13,6 @@ #include "arch_error.h" #include "read_xml_arch_file.h" -#include "read_xml_util.h" /******************** Subroutine declarations ********************************/ @@ -152,7 +154,7 @@ void free_arch(t_arch* arch) { return; } - free_arch_models(arch->models); + arch->models.clear_models(); vtr::release_memory(arch->switches); @@ -160,36 +162,6 @@ void free_arch(t_arch* arch) { vtr::free(arch->architecture_id); - if (arch->model_library) { - for (int i = 0; i < 4; ++i) { - vtr::t_linked_vptr* vptr = arch->model_library[i].pb_types; - while (vptr) { - vtr::t_linked_vptr* vptr_prev = vptr; - vptr = vptr->next; - vtr::free(vptr_prev); - } - } - - vtr::free(arch->model_library[0].name); - vtr::free(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; - 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[2].inputs; - 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); - delete[] arch->model_library[3].inputs; - vtr::free(arch->model_library[3].outputs->name); - delete[] arch->model_library[3].outputs; - delete[] arch->model_library; - } - if (arch->clocks) { vtr::free(arch->clocks->clock_inf); } @@ -197,58 +169,6 @@ void free_arch(t_arch* arch) { delete (arch->noc); } -//Frees all models in the linked list -void free_arch_models(t_model* models) { - t_model* model = models; - while (model) { - model = free_arch_model(model); - } -} - -//Frees the specified model, and returns the next model (if any) in the linked list -t_model* free_arch_model(t_model* model) { - if (!model) return nullptr; - - t_model* next_model = model->next; - - free_arch_model_ports(model->inputs); - free_arch_model_ports(model->outputs); - - vtr::t_linked_vptr* vptr = model->pb_types; - while (vptr) { - vtr::t_linked_vptr* vptr_prev = vptr; - vptr = vptr->next; - vtr::free(vptr_prev); - } - - if (model->instances) - vtr::free(model->instances); - vtr::free(model->name); - delete model; - - return next_model; -} - -//Frees all the model ports in a linked list -void free_arch_model_ports(t_model_ports* model_ports) { - t_model_ports* model_port = model_ports; - while (model_port) { - model_port = free_arch_model_port(model_port); - } -} - -//Frees the specified model_port, and returns the next model_port (if any) in the linked list -t_model_ports* free_arch_model_port(t_model_ports* model_port) { - if (!model_port) return nullptr; - - t_model_ports* next_port = model_port->next; - - vtr::free(model_port->name); - delete model_port; - - return next_port; -} - void free_type_descriptors(std::vector& type_descriptors) { for (t_physical_tile_type& type : type_descriptors) { vtr::release_memory(type.name); @@ -565,7 +485,7 @@ void alloc_and_load_default_child_for_pb_type(t_pb_type* pb_type, copy->blif_model = vtr::strdup(pb_type->blif_model); copy->class_type = pb_type->class_type; copy->depth = pb_type->depth; - copy->model = pb_type->model; + copy->model_id = pb_type->model_id; copy->modes = nullptr; copy->num_modes = 0; copy->num_clock_pins = pb_type->num_clock_pins; @@ -799,7 +719,7 @@ void ProcessLutClass(t_pb_type* lut_pb_type) { free(lut_pb_type->blif_model); lut_pb_type->blif_model = nullptr; - lut_pb_type->model = nullptr; + lut_pb_type->model_id = LogicalModelId::INVALID(); } /* populate special memory class */ @@ -848,7 +768,7 @@ void ProcessMemoryClass(t_pb_type* mem_pb_type) { free(mem_pb_type->blif_model); mem_pb_type->blif_model = nullptr; - mem_pb_type->model = nullptr; + mem_pb_type->model_id = LogicalModelId::INVALID(); mem_pb_type->modes[0].num_interconnect = mem_pb_type->num_ports * num_pb; mem_pb_type->modes[0].interconnect = new t_interconnect[mem_pb_type->modes[0].num_interconnect]; @@ -989,105 +909,6 @@ 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]; - - //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; - - //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; - - //LATCH - 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[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].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"; - - //NAMES - model_library[3].name = vtr::strdup(MODEL_NAMES); - model_library[3].index = 3; - - 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].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].instances = nullptr; - model_library[3].next = nullptr; - - 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].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; - - arch->model_library = model_library; -} - void SyncModelsPbTypes(t_arch* arch, const std::vector& Types) { for (auto& Type : Types) { @@ -1099,16 +920,10 @@ void SyncModelsPbTypes(t_arch* arch, void SyncModelsPbTypes_rec(t_arch* arch, t_pb_type* pb_type) { - t_model *model_match_prim, *cur_model; - t_model_ports* model_port; - vtr::t_linked_vptr* old; - char* blif_model_name = nullptr; - - bool found; if (pb_type->blif_model != nullptr) { /* get actual name of subckt */ - blif_model_name = pb_type->blif_model; + char* blif_model_name = pb_type->blif_model; if (strstr(blif_model_name, ".subckt ") == blif_model_name) { blif_model_name = strchr(blif_model_name, ' '); ++blif_model_name; //Advance past space @@ -1119,39 +934,24 @@ void SyncModelsPbTypes_rec(t_arch* arch, pb_type->blif_model, pb_type->name); } - /* There are two sets of models to consider, the standard library of models and the user defined models */ - if (is_library_model(blif_model_name)) { - cur_model = arch->model_library; - } else { - cur_model = arch->models; - } - /* Determine the logical model to use */ - found = false; - model_match_prim = nullptr; - 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) { - found = true; - model_match_prim = cur_model; - } - cur_model = cur_model->next; - } - if (!found) { + LogicalModelId model_match_prim_id = arch->models.get_model_by_name(blif_model_name); + if (!model_match_prim_id.is_valid()) { archfpga_throw(get_arch_file_name(), 0, "No matching model for pb_type %s\n", pb_type->blif_model); } + t_model& model_match_prim = arch->models.get_model(model_match_prim_id); - 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; + pb_type->model_id = model_match_prim_id; + vtr::t_linked_vptr* 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 (int p = 0; p < pb_type->num_ports; p++) { - found = false; + bool found = false; /* TODO: Parse error checking - check if INPUT matches INPUT and OUTPUT matches OUTPUT (not yet done) */ - model_port = model_match_prim->inputs; + t_model_ports* 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) { @@ -1176,7 +976,7 @@ void SyncModelsPbTypes_rec(t_arch* arch, } model_port = model_port->next; } - model_port = model_match_prim->outputs; + 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) { @@ -1260,20 +1060,6 @@ bool segment_exists(const t_arch* arch, std::string_view name) { return find_segment(arch, name) != nullptr; } -bool is_library_model(const char* model_name) { - if (model_name == std::string(MODEL_NAMES) - || model_name == std::string(MODEL_LATCH) - || model_name == std::string(MODEL_INPUT) - || model_name == std::string(MODEL_OUTPUT)) { - return true; - } - return false; -} - -bool is_library_model(const t_model* model) { - return is_library_model(model->name); -} - //Returns true if the specified block type contains the specified blif model name // // TODO: Remove block_type_contains_blif_model / pb_type_contains_blif_model diff --git a/libs/libarchfpga/src/arch_util.h b/libs/libarchfpga/src/arch_util.h index fb251bffe10..fb87262878c 100644 --- a/libs/libarchfpga/src/arch_util.h +++ b/libs/libarchfpga/src/arch_util.h @@ -52,10 +52,6 @@ class InstPort { }; void free_arch(t_arch* arch); -void free_arch_models(t_model* models); -t_model* free_arch_model(t_model* model); -void free_arch_model_ports(t_model_ports* model_ports); -t_model_ports* free_arch_model_port(t_model_ports* model_port); void free_type_descriptors(std::vector& type_descriptors); void free_type_descriptors(std::vector& type_descriptors); @@ -84,8 +80,6 @@ void ProcessMemoryClass(t_pb_type* mem_pb_type); e_power_estimation_method power_method_inherited(e_power_estimation_method parent_power_method); -void CreateModelLibrary(t_arch* arch); - void SyncModelsPbTypes(t_arch* arch, const std::vector& Types); @@ -97,8 +91,6 @@ void primitives_annotation_clock_match(t_pin_to_pin_annotation* annotation, bool segment_exists(const t_arch* arch, std::string_view name); const t_segment_inf* find_segment(const t_arch* arch, std::string_view name); -bool is_library_model(const char* model_name); -bool is_library_model(const t_model* model); //Returns true if the specified block type contains the specified blif model name bool block_type_contains_blif_model(t_logical_block_type_ptr type, const std::string& blif_model_name); diff --git a/libs/libarchfpga/src/echo_arch.cpp b/libs/libarchfpga/src/echo_arch.cpp index edceeb748fb..2e08c196946 100644 --- a/libs/libarchfpga/src/echo_arch.cpp +++ b/libs/libarchfpga/src/echo_arch.cpp @@ -1,24 +1,22 @@ #include #include #include -#include #include "echo_arch.h" -#include "arch_types.h" #include "arch_util.h" +#include "logic_types.h" #include "vtr_list.h" #include "vtr_util.h" #include "vtr_memory.h" #include "vtr_assert.h" -using vtr::t_linked_vptr; - /// @brief indices to lookup IPIN connection block switch name constexpr int ipin_cblock_switch_index_within_die = 0; constexpr int ipin_cblock_switch_index_between_dice = 1; void PrintArchInfo(FILE* Echo, const t_arch* arch); -static void PrintPb_types_rec(FILE* Echo, const t_pb_type* pb_type, int level); +static void print_model(FILE* echo, const t_model& model); +static void PrintPb_types_rec(FILE* Echo, const t_pb_type* pb_type, int level, const LogicalModels& models); static void PrintPb_types_recPower(FILE* Echo, const t_pb_type* pb_type, const char* tabs); @@ -29,55 +27,21 @@ void EchoArch(const char* EchoFile, const std::vector& PhysicalTileTypes, const std::vector& LogicalBlockTypes, const t_arch* arch) { - int i, j; - FILE* Echo; - t_model* cur_model; - t_model_ports* model_port; - t_linked_vptr* cur_vptr; - Echo = vtr::fopen(EchoFile, "w"); - cur_model = nullptr; + FILE* Echo = vtr::fopen(EchoFile, "w"); //Print all layout device switch/segment list info first PrintArchInfo(Echo, arch); //Models fprintf(Echo, "*************************************************\n"); - for (j = 0; j < 2; j++) { - if (j == 0) { - fprintf(Echo, "Printing user models \n"); - cur_model = arch->models; - } else if (j == 1) { - fprintf(Echo, "Printing library models \n"); - cur_model = arch->model_library; - } - while (cur_model) { - fprintf(Echo, "Model: \"%s\"\n", cur_model->name); - model_port = cur_model->inputs; - while (model_port) { - fprintf(Echo, "\tInput Ports: \"%s\" \"%d\" min_size=\"%d\"\n", - model_port->name, model_port->size, - model_port->min_size); - model_port = model_port->next; - } - model_port = cur_model->outputs; - while (model_port) { - fprintf(Echo, "\tOutput Ports: \"%s\" \"%d\" min_size=\"%d\"\n", - model_port->name, model_port->size, - model_port->min_size); - model_port = model_port->next; - } - cur_vptr = cur_model->pb_types; - i = 0; - while (cur_vptr != nullptr) { - fprintf(Echo, "\tpb_type %d: \"%s\"\n", i, - ((t_pb_type*)cur_vptr->data_vptr)->name); - cur_vptr = cur_vptr->next; - i++; - } - - cur_model = cur_model->next; - } + fprintf(Echo, "Printing library models \n"); + for (LogicalModelId model_id : arch->models.library_models()) { + print_model(Echo, arch->models.get_model(model_id)); + } + fprintf(Echo, "Printing user models \n"); + for (LogicalModelId model_id : arch->models.user_models()) { + print_model(Echo, arch->models.get_model(model_id)); } fprintf(Echo, "*************************************************\n\n"); fprintf(Echo, "*************************************************\n"); @@ -122,7 +86,7 @@ void EchoArch(const char* EchoFile, for (auto& LogicalBlock : LogicalBlockTypes) { if (LogicalBlock.pb_type) { - PrintPb_types_rec(Echo, LogicalBlock.pb_type, 2); + PrintPb_types_rec(Echo, LogicalBlock.pb_type, 2, arch->models); } fprintf(Echo, "\n"); } @@ -390,7 +354,33 @@ void PrintArchInfo(FILE* Echo, const t_arch* arch) { fprintf(Echo, "*************************************************\n\n"); } -static void PrintPb_types_rec(FILE* Echo, const t_pb_type* pb_type, int level) { +static void print_model(FILE* echo, const t_model& model) { + fprintf(echo, "Model: \"%s\"\n", model.name); + t_model_ports* input_model_port = model.inputs; + while (input_model_port) { + fprintf(echo, "\tInput Ports: \"%s\" \"%d\" min_size=\"%d\"\n", + input_model_port->name, input_model_port->size, + input_model_port->min_size); + input_model_port = input_model_port->next; + } + t_model_ports* output_model_port = model.outputs; + while (output_model_port) { + fprintf(echo, "\tOutput Ports: \"%s\" \"%d\" min_size=\"%d\"\n", + output_model_port->name, output_model_port->size, + output_model_port->min_size); + output_model_port = output_model_port->next; + } + vtr::t_linked_vptr* cur_vptr = model.pb_types; + int i = 0; + while (cur_vptr != nullptr) { + fprintf(echo, "\tpb_type %d: \"%s\"\n", i, + ((t_pb_type*)cur_vptr->data_vptr)->name); + cur_vptr = cur_vptr->next; + i++; + } +} + +static void PrintPb_types_rec(FILE* Echo, const t_pb_type* pb_type, int level, const LogicalModels& models) { char* tabs; tabs = (char*)vtr::malloc((level + 1) * sizeof(char)); @@ -415,7 +405,7 @@ static void PrintPb_types_rec(FILE* Echo, const t_pb_type* pb_type, int level) { fprintf(Echo, "%s\tmode %s:\n", tabs, pb_type->modes[i].name); for (int j = 0; j < pb_type->modes[i].num_pb_type_children; j++) { PrintPb_types_rec(Echo, &pb_type->modes[i].pb_type_children[j], - level + 2); + level + 2, models); } for (int j = 0; j < pb_type->modes[i].num_interconnect; j++) { fprintf(Echo, "%s\t\tinterconnect %d %s %s\n", tabs, @@ -447,9 +437,10 @@ static void PrintPb_types_rec(FILE* Echo, const t_pb_type* pb_type, int level) { * I/O has no annotations to be displayed * All other library or user models may have delays specificied, e.g. Tsetup and Tcq * Display the additional information*/ - if (strcmp(pb_type->model->name, MODEL_NAMES) - && strcmp(pb_type->model->name, MODEL_INPUT) - && strcmp(pb_type->model->name, MODEL_OUTPUT)) { + std::string pb_type_model_name = models.get_model(pb_type->model_id).name; + if (pb_type_model_name != LogicalModels::MODEL_NAMES + && pb_type_model_name != LogicalModels::MODEL_INPUT + && pb_type_model_name != LogicalModels::MODEL_OUTPUT) { for (int k = 0; k < pb_type->num_annotations; k++) { fprintf(Echo, "%s\t\t\tannotation %s %s %s %d: %s\n", tabs, pb_type->annotations[k].clock, diff --git a/libs/libarchfpga/src/logic_types.cpp b/libs/libarchfpga/src/logic_types.cpp new file mode 100644 index 00000000000..dc4801d3347 --- /dev/null +++ b/libs/libarchfpga/src/logic_types.cpp @@ -0,0 +1,171 @@ +/** + * @file + * @author Alex Singer + * @date April 2025 + * @brief Implementation of the LogicalModels data structure. + */ + +#include "logic_types.h" +#include "vtr_assert.h" +#include "vtr_util.h" + +/** + * @brief Frees all the model ports in a linked list + */ +static void free_arch_model_ports(t_model_ports* model_ports); + +/** + * @brief Frees the specified model_port, and returns the next model_port (if + * any) in the linked list + */ +static t_model_ports* free_arch_model_port(t_model_ports* model_port); + +LogicalModels::LogicalModels() { + // Create the logical models. These must be created first and stored at the + // start of the list of models. + VTR_ASSERT_MSG(all_models().size() == 0, + "The first models created must be the library models"); + //INPAD + { + LogicalModelId inpad_model_id = create_logical_model(MODEL_INPUT); + t_model& inpad_model = get_model(inpad_model_id); + + inpad_model.inputs = nullptr; + + inpad_model.instances = nullptr; + + inpad_model.outputs = new t_model_ports; + inpad_model.outputs->dir = OUT_PORT; + inpad_model.outputs->name = vtr::strdup("inpad"); + inpad_model.outputs->next = nullptr; + inpad_model.outputs->size = 1; + inpad_model.outputs->min_size = 1; + inpad_model.outputs->index = 0; + inpad_model.outputs->is_clock = false; + } + + //OUTPAD + { + LogicalModelId outpad_model_id = create_logical_model(MODEL_OUTPUT); + t_model& outpad_model = get_model(outpad_model_id); + + outpad_model.inputs = new t_model_ports; + outpad_model.inputs->dir = IN_PORT; + outpad_model.inputs->name = vtr::strdup("outpad"); + outpad_model.inputs->next = nullptr; + outpad_model.inputs->size = 1; + outpad_model.inputs->min_size = 1; + outpad_model.inputs->index = 0; + outpad_model.inputs->is_clock = false; + + outpad_model.instances = nullptr; + + outpad_model.outputs = nullptr; + } + + //LATCH + { + LogicalModelId latch_model_id = create_logical_model(MODEL_LATCH); + t_model& latch_model = get_model(latch_model_id); + t_model_ports* latch_model_input_port_1 = new t_model_ports; + t_model_ports* latch_model_input_port_2 = new t_model_ports; + + latch_model.inputs = latch_model_input_port_1; + latch_model_input_port_1->dir = IN_PORT; + latch_model_input_port_1->name = vtr::strdup("D"); + latch_model_input_port_1->next = latch_model_input_port_2; + latch_model_input_port_1->size = 1; + latch_model_input_port_1->min_size = 1; + latch_model_input_port_1->index = 0; + latch_model_input_port_1->is_clock = false; + latch_model_input_port_1->clock = "clk"; + + latch_model_input_port_2->dir = IN_PORT; + latch_model_input_port_2->name = vtr::strdup("clk"); + latch_model_input_port_2->next = nullptr; + latch_model_input_port_2->size = 1; + latch_model_input_port_2->min_size = 1; + latch_model_input_port_2->index = 0; + latch_model_input_port_2->is_clock = true; + + latch_model.instances = nullptr; + + latch_model.outputs = new t_model_ports; + latch_model.outputs->dir = OUT_PORT; + latch_model.outputs->name = vtr::strdup("Q"); + latch_model.outputs->next = nullptr; + latch_model.outputs->size = 1; + latch_model.outputs->min_size = 1; + latch_model.outputs->index = 0; + latch_model.outputs->is_clock = false; + latch_model.outputs->clock = "clk"; + } + + //NAMES + { + LogicalModelId names_model_id = create_logical_model(MODEL_NAMES); + t_model& names_model = get_model(names_model_id); + + names_model.inputs = new t_model_ports; + names_model.inputs->dir = IN_PORT; + names_model.inputs->name = vtr::strdup("in"); + names_model.inputs->next = nullptr; + names_model.inputs->size = 1; + names_model.inputs->min_size = 1; + names_model.inputs->index = 0; + names_model.inputs->is_clock = false; + names_model.inputs->combinational_sink_ports = {"out"}; + + names_model.instances = nullptr; + + names_model.outputs = new t_model_ports; + names_model.outputs->dir = OUT_PORT; + names_model.outputs->name = vtr::strdup("out"); + names_model.outputs->next = nullptr; + names_model.outputs->size = 1; + names_model.outputs->min_size = 1; + names_model.outputs->index = 0; + names_model.outputs->is_clock = false; + } + + // Checks to ensure that all library models have been successfully created + // and the number of library models matches the NUM_MODELS_IN_LIBRARY variable. + VTR_ASSERT_MSG(all_models().size() == library_models().size(), + "The only models that have been created should be the library models"); + VTR_ASSERT_MSG(library_models().size() == NUM_MODELS_IN_LIBRARY, + "The number of models in the library must be the expected number"); +} + +void LogicalModels::free_model_data(t_model& model) { + free_arch_model_ports(model.inputs); + free_arch_model_ports(model.outputs); + + vtr::t_linked_vptr* vptr = model.pb_types; + while (vptr) { + vtr::t_linked_vptr* vptr_prev = vptr; + vptr = vptr->next; + vtr::free(vptr_prev); + } + + if (model.instances) + vtr::free(model.instances); + vtr::free(model.name); +} + +static void free_arch_model_ports(t_model_ports* model_ports) { + t_model_ports* model_port = model_ports; + while (model_port) { + model_port = free_arch_model_port(model_port); + } +} + +static t_model_ports* free_arch_model_port(t_model_ports* model_port) { + if (!model_port) return nullptr; + + t_model_ports* next_port = model_port->next; + + vtr::free(model_port->name); + delete model_port; + + return next_port; +} diff --git a/libs/libarchfpga/src/logic_types.h b/libs/libarchfpga/src/logic_types.h index 4427b85016f..0a23b23d8e9 100644 --- a/libs/libarchfpga/src/logic_types.h +++ b/libs/libarchfpga/src/logic_types.h @@ -5,12 +5,22 @@ * * Date: February 19, 2009 * Authors: Jason Luu and Kenneth Kent + * + * Updated with the LogicalModels data structure by Alex Singer + * Date: April, 2025 */ #ifndef LOGIC_TYPES_H #define LOGIC_TYPES_H +#include "vtr_assert.h" #include "vtr_list.h" +#include "vtr_memory.h" +#include "vtr_range.h" +#include "vtr_strong_id.h" +#include "vtr_util.h" +#include "vtr_vector_map.h" +#include #include #include @@ -40,18 +50,223 @@ struct t_model_ports { int index = -1; /* indexing for array look-up */ }; +/** + * @brief Struct containing the information stored for a logical model in the + * LogicalModels storage class below. + */ struct t_model { - char* name = nullptr; /* name of this logic model */ - t_model_ports* inputs = nullptr; /* linked list of input/clock ports */ - t_model_ports* outputs = nullptr; /* linked list of output ports */ - void* instances = nullptr; - int used = 0; - vtr::t_linked_vptr* pb_types = nullptr; /* Physical block types that implement this model */ - t_model* next = nullptr; /* next model (linked list) */ + char* name = nullptr; ///< name of this logic model + t_model_ports* inputs = nullptr; ///< linked list of input/clock ports + t_model_ports* outputs = nullptr; ///< linked list of output ports + void* instances = nullptr; ///< TODO: Remove this. This is only used in the Parmys plugin and should be moved into there. + int used = 0; ///< TODO: Remove this. This is only used in the Parmys plugin and should be moved into there. + vtr::t_linked_vptr* pb_types = nullptr; ///< Physical block types that implement this model + bool never_prune = false; ///< Don't remove from the netlist even if a block of this type has no output ports used and, therefore, unconnected to the rest of the netlist +}; + +// Tag for the logical model ID +struct logical_model_id_tag; +// A unique ID that represents a logical model in the architecture. +typedef vtr::StrongId LogicalModelId; + +/** + * @brief A storage class containing all of the logical models in an FPGA + * architecture. + * + * This class manages creating, storing, and destroying logical models. It also + * contains helper methods to parse the logical models. + * + * A logical model is the definition of a type of primitive block that can occur + * in the atom netlist for a given FPGA architecture; it stores data that all + * block instances of that type share. + * + * There are two types of logical models: + * 1) Library Models: These are models that all architectures share. These are + * created in the construtor of this class. + * 2) User Models: These are models defined by the user and are created outside + * of this class (usually by parsing an architecture file). + */ +class LogicalModels { + public: + // The total number of predefined blif models. + static constexpr size_t NUM_MODELS_IN_LIBRARY = 4; + + // Built-in library model names. + static constexpr const char* MODEL_NAMES = ".names"; + static constexpr const char* MODEL_LATCH = ".latch"; + static constexpr const char* MODEL_INPUT = ".input"; + static constexpr const char* MODEL_OUTPUT = ".output"; + + // Iterator for the logical model IDs array. + typedef typename vtr::vector_map::const_iterator model_iterator; + + // A range of model IDs within the logical model IDs array. + typedef typename vtr::Range model_range; + + public: + // Since this class maintaines pointers and these pointers are freed upon + // destruction, this class cannot (and should not) be copied. + LogicalModels(const LogicalModels&) = delete; + LogicalModels& operator=(const LogicalModels&) = delete; + + /** + * @brief The constructor of the LogicalModels class. + * + * This populates the library models. + */ + LogicalModels(); + + ~LogicalModels() { + // Free the data of all models. + clear_models(); + } + + /** + * @brief Returns a range of logical model IDs representing all models in + * the architecture (both library and user models). + */ + inline model_range all_models() const { + return vtr::make_range(logical_model_ids_.begin(), logical_model_ids_.end()); + } + + /** + * @brief Returns a range of logical model IDs representing all library + * models in the architecture. + */ + inline model_range library_models() const { + VTR_ASSERT_SAFE_MSG(logical_model_ids_.size() >= NUM_MODELS_IN_LIBRARY, + "Library models missing"); + // The library models are created in the constructor, thus they must be + // the first L models in the IDs (where L is the number of library models). + return vtr::make_range(logical_model_ids_.begin(), + logical_model_ids_.begin() + NUM_MODELS_IN_LIBRARY); + } + + /** + * @brief Returns a range of logical model IDs representing all user models + * in the architecture. + */ + inline model_range user_models() const { + VTR_ASSERT_SAFE_MSG(logical_model_ids_.size() >= NUM_MODELS_IN_LIBRARY, + "Library models missing"); + + // The user models will always be located after the library models since + // the library models were added in the constructor. + return vtr::make_range(logical_model_ids_.begin() + NUM_MODELS_IN_LIBRARY, + logical_model_ids_.end()); + } + + /** + * @brief Returns true if the given model ID represents a library model. + */ + inline bool is_library_model(LogicalModelId model_id) const { + VTR_ASSERT_SAFE_MSG(model_id.is_valid(), + "Invalid model ID"); + // The first L model IDs must be the library models. Where L is the + // number of models in the library + if ((size_t)model_id < NUM_MODELS_IN_LIBRARY) + return true; + + return false; + } + + /** + * @brief Create a logical model with the given name. + * + * This method will construct a t_model object with the given name. This + * object can be accessed and modified using the get_model method. + * + * @return The ID of the newly created model. + */ + inline LogicalModelId create_logical_model(const std::string& model_name) { + VTR_ASSERT_MSG(model_name_to_logical_model_id_.count(model_name) == 0, + "A model with the given name already exists"); + // Create the new model. + t_model new_model; + new_model.name = vtr::strdup(model_name.c_str()); + + // Create the new model's ID + LogicalModelId new_model_id = LogicalModelId(logical_model_ids_.size()); + + // Update the internal state. + logical_models_.push_back(std::move(new_model)); + logical_model_ids_.push_back(new_model_id); + model_name_to_logical_model_id_[model_name] = new_model_id; + + return new_model_id; + } + + /** + * @brief Immutable accessor to the underlying model data structure for the + * given model ID. + */ + inline const t_model& get_model(LogicalModelId model_id) const { + VTR_ASSERT_SAFE_MSG(model_id.is_valid(), + "Cannot get model of invalid model ID"); + return logical_models_[model_id]; + } + + /** + * @brief Mutable accessor to the underlying model data structure for the + * given model ID. + */ + inline t_model& get_model(LogicalModelId model_id) { + VTR_ASSERT_SAFE_MSG(model_id.is_valid(), + "Cannot get model of invalid model ID"); + return logical_models_[model_id]; + } + + /** + * @brief Returns the name of the given model. + */ + inline std::string model_name(LogicalModelId model_id) const { + VTR_ASSERT_SAFE_MSG(model_id.is_valid(), + "Cannot get name of invalid model ID"); + return logical_models_[model_id].name; + } + + /** + * @brief Returns the ID of the model with the given name. If no model has + * the given name, the invalid model ID will be returned. + * + * This method has O(1) time complexity. + */ + inline LogicalModelId get_model_by_name(std::string model_name) const { + auto itr = model_name_to_logical_model_id_.find(model_name); + if (itr == model_name_to_logical_model_id_.end()) + return LogicalModelId::INVALID(); + return itr->second; + } + + /** + * @brief Destroys all of the models. This frees all internal model data. + */ + void clear_models() { + // Free the model data of all models. + for (LogicalModelId model_id : all_models()) { + free_model_data(logical_models_[model_id]); + } + // Clear all data structures. + logical_model_ids_.clear(); + logical_models_.clear(); + model_name_to_logical_model_id_.clear(); + } + + private: + /** + * @brief Helper method for freeing the internal data of the given model. + */ + void free_model_data(t_model& model); + + private: + /// @brief A list of all logical model IDs. + vtr::vector_map logical_model_ids_; - bool never_prune = false; /* Don't remove from the netlist even if a block of this type has no output ports used and, therefore, unconnected to the rest of the netlist */ + /// @brief A list of a logical models. + vtr::vector_map logical_models_; - int index = -1; + /// @brief A lookup between the name of a logical model and its ID. + std::unordered_map model_name_to_logical_model_id_; }; #endif diff --git a/libs/libarchfpga/src/physical_types.h b/libs/libarchfpga/src/physical_types.h index b3550e83d01..ace0f5be509 100644 --- a/libs/libarchfpga/src/physical_types.h +++ b/libs/libarchfpga/src/physical_types.h @@ -1042,7 +1042,7 @@ struct t_pb_type { char* name = nullptr; int num_pb = 0; char* blif_model = nullptr; - t_model* model = nullptr; + LogicalModelId model_id; enum e_pb_type_class class_type = UNKNOWN_CLASS; t_mode* modes = nullptr; /* [0..num_modes-1] */ @@ -2180,8 +2180,7 @@ struct t_arch { /// Contains information about all direct chain connections in the architecture std::vector directs; - t_model* models = nullptr; - t_model* model_library = nullptr; + LogicalModels models; t_power_arch* power = nullptr; t_clock_arch* clocks = nullptr; diff --git a/libs/libarchfpga/src/read_fpga_interchange_arch.cpp b/libs/libarchfpga/src/read_fpga_interchange_arch.cpp index 50840cbb948..265991c23f2 100644 --- a/libs/libarchfpga/src/read_fpga_interchange_arch.cpp +++ b/libs/libarchfpga/src/read_fpga_interchange_arch.cpp @@ -1,7 +1,7 @@ #include "read_fpga_interchange_arch.h" -#include "vtr_error.h" +#include "logic_types.h" #ifdef VTR_ENABLE_CAPNPROTO @@ -19,14 +19,12 @@ #include "vtr_assert.h" #include "vtr_digest.h" -#include "vtr_log.h" #include "vtr_memory.h" #include "vtr_util.h" #include "arch_check.h" #include "arch_error.h" #include "arch_util.h" -#include "arch_types.h" /* * FPGA Interchange Device frontend @@ -161,32 +159,28 @@ static float get_corner_value(Device::CornerModel::Reader model, const char* spe } /** @brief Returns the port corresponding to the given model in the architecture */ -static t_model_ports* get_model_port(t_arch* arch, std::string model, std::string port, bool fail = true) { - for (t_model* m : {arch->models, arch->model_library}) { - for (; m != nullptr; m = m->next) { - if (std::string(m->name) != model) - continue; - - for (t_model_ports* p : {m->inputs, m->outputs}) - for (; p != nullptr; p = p->next) - if (std::string(p->name) == port) - return p; - } +static t_model_ports* get_model_port(t_arch* arch, std::string model_name, std::string port, bool fail = true) { + LogicalModelId model_id = arch->models.get_model_by_name(model_name); + if (model_id.is_valid()) { + const t_model& model = arch->models.get_model(model_id); + for (t_model_ports* p : {model.inputs, model.outputs}) + for (; p != nullptr; p = p->next) + if (std::string(p->name) == port) + return p; } if (fail) archfpga_throw(__FILE__, __LINE__, - "Could not find model port: %s (%s)\n", port.c_str(), model.c_str()); + "Could not find model port: %s (%s)\n", port.c_str(), model_name.c_str()); return nullptr; } /** @brief Returns the specified architecture model */ -static t_model* get_model(t_arch* arch, std::string model) { - for (t_model* m : {arch->models, arch->model_library}) - for (; m != nullptr; m = m->next) - if (std::string(m->name) == model) - return m; +static LogicalModelId get_model(t_arch* arch, std::string model) { + LogicalModelId model_id = arch->models.get_model_by_name(model); + if (model_id.is_valid()) + return model_id; archfpga_throw(__FILE__, __LINE__, "Could not find model: %s\n", model.c_str()); @@ -914,16 +908,9 @@ struct ArchReader { // Model processing void process_models() { - // Populate the common library, namely .inputs, .outputs, .names, .latches - CreateModelLibrary(arch_); - - t_model* temp = nullptr; std::map model_name_map; std::pair::iterator, bool> ret_map_name; - int model_index = NUM_MODELS_IN_LIBRARY; - arch_->models = nullptr; - auto primLib = ar_.getPrimLibs(); for (auto primitive : primLib.getCellDecls()) { if (str(primitive.getLib()) == std::string("primitives")) { @@ -951,38 +938,31 @@ struct ArchReader { continue; try { - temp = new t_model; - temp->index = model_index++; - - temp->never_prune = true; - temp->name = vtr::strdup(prim_name.c_str()); - - ret_map_name = model_name_map.insert(std::pair(temp->name, 0)); + ret_map_name = model_name_map.insert(std::pair(prim_name, 0)); if (!ret_map_name.second) { archfpga_throw(arch_file_, __LINE__, - "Duplicate model name: '%s'.\n", temp->name); + "Duplicate model name: '%s'.\n", prim_name.c_str()); } - if (!process_model_ports(temp, primitive)) { - free_arch_model(temp); + LogicalModelId new_model_id = arch_->models.create_logical_model(prim_name); + t_model& new_model = arch_->models.get_model(new_model_id); + new_model.never_prune = true; + + if (!process_model_ports(new_model, primitive)) { continue; } - check_model_clocks(temp, arch_file_, __LINE__); - check_model_combinational_sinks(temp, arch_file_, __LINE__); - warn_model_missing_timing(temp, arch_file_, __LINE__); - + check_model_clocks(new_model, arch_file_, __LINE__); + check_model_combinational_sinks(new_model, arch_file_, __LINE__); + warn_model_missing_timing(new_model, arch_file_, __LINE__); } catch (ArchFpgaError& e) { - free_arch_model(temp); throw; } - temp->next = arch_->models; - arch_->models = temp; } } } - bool process_model_ports(t_model* model, Netlist::CellDeclaration::Reader primitive) { + bool process_model_ports(t_model& model, Netlist::CellDeclaration::Reader primitive) { auto primLib = ar_.getPrimLibs(); auto portList = primLib.getPortList(); @@ -1040,12 +1020,12 @@ struct ArchReader { port_names.insert(std::pair(model_port->name, dir)); //Add the port if (dir == IN_PORT) { - model_port->next = model->inputs; - model->inputs = model_port; + model_port->next = model.inputs; + model.inputs = model_port; } else if (dir == OUT_PORT) { - model_port->next = model->outputs; - model->outputs = model_port; + model_port->next = model.outputs; + model.outputs = model_port; } } @@ -1309,13 +1289,13 @@ struct ArchReader { lut->num_pb = 1; lut->parent_mode = mode; - lut->blif_model = vtr::strdup(MODEL_NAMES); - lut->model = get_model(arch_, std::string(MODEL_NAMES)); + lut->blif_model = vtr::strdup(LogicalModels::MODEL_NAMES); + lut->model_id = get_model(arch_, LogicalModels::MODEL_NAMES); lut->num_ports = 2; lut->ports = (t_port*)vtr::calloc(lut->num_ports, sizeof(t_port)); - lut->ports[0] = get_generic_port(arch_, lut, IN_PORT, "in", MODEL_NAMES, width); - lut->ports[1] = get_generic_port(arch_, lut, OUT_PORT, "out", MODEL_NAMES); + lut->ports[0] = get_generic_port(arch_, lut, IN_PORT, "in", LogicalModels::MODEL_NAMES, width); + lut->ports[1] = get_generic_port(arch_, lut, OUT_PORT, "out", LogicalModels::MODEL_NAMES); lut->ports[0].equivalent = PortEquivalence::FULL; @@ -1416,10 +1396,10 @@ struct ArchReader { num_ports = 1; opad->num_ports = num_ports; opad->ports = (t_port*)vtr::calloc(num_ports, sizeof(t_port)); - opad->blif_model = vtr::strdup(MODEL_OUTPUT); - opad->model = get_model(arch_, std::string(MODEL_OUTPUT)); + opad->blif_model = vtr::strdup(LogicalModels::MODEL_OUTPUT); + opad->model_id = get_model(arch_, LogicalModels::MODEL_OUTPUT); - opad->ports[0] = get_generic_port(arch_, opad, IN_PORT, "outpad", MODEL_OUTPUT); + opad->ports[0] = get_generic_port(arch_, opad, IN_PORT, "outpad", LogicalModels::MODEL_OUTPUT); omode->pb_type_children[0] = *opad; // IPAD mode @@ -1438,10 +1418,10 @@ struct ArchReader { num_ports = 1; ipad->num_ports = num_ports; ipad->ports = (t_port*)vtr::calloc(num_ports, sizeof(t_port)); - ipad->blif_model = vtr::strdup(MODEL_INPUT); - ipad->model = get_model(arch_, std::string(MODEL_INPUT)); + ipad->blif_model = vtr::strdup(LogicalModels::MODEL_INPUT); + ipad->model_id = get_model(arch_, LogicalModels::MODEL_INPUT); - ipad->ports[0] = get_generic_port(arch_, ipad, OUT_PORT, "inpad", MODEL_INPUT); + ipad->ports[0] = get_generic_port(arch_, ipad, OUT_PORT, "inpad", LogicalModels::MODEL_INPUT); imode->pb_type_children[0] = *ipad; // Handle interconnects @@ -1566,7 +1546,7 @@ struct ArchReader { leaf->num_ports = num_ports; leaf->ports = (t_port*)vtr::calloc(num_ports, sizeof(t_port)); leaf->blif_model = vtr::strdup((std::string(".subckt ") + name).c_str()); - leaf->model = get_model(arch_, name); + leaf->model_id = get_model(arch_, name); mode->num_interconnect = num_ports; mode->interconnect = new t_interconnect[num_ports]; @@ -2140,7 +2120,7 @@ struct ArchReader { leaf_pb_type->num_ports = num_ports; leaf_pb_type->ports = (t_port*)vtr::calloc(num_ports, sizeof(t_port)); leaf_pb_type->blif_model = vtr::strdup(const_cell.first.c_str()); - leaf_pb_type->model = get_model(arch_, const_cell.first); + leaf_pb_type->model_id = get_model(arch_, const_cell.first); leaf_pb_type->ports[0] = get_generic_port(arch_, leaf_pb_type, OUT_PORT, const_cell.second, const_cell.first); pb_type->ports[count] = get_generic_port(arch_, leaf_pb_type, OUT_PORT, const_cell.first + "_" + const_cell.second); @@ -2170,11 +2150,10 @@ struct ArchReader { // Create constant models for (auto const_cell : const_cells) { - t_model* model = new t_model; - model->index = arch_->models->index + 1; + LogicalModelId new_model_id = arch_->models.create_logical_model(const_cell.first); + t_model& new_model = arch_->models.get_model(new_model_id); - model->never_prune = true; - model->name = vtr::strdup(const_cell.first.c_str()); + new_model.never_prune = true; t_model_ports* model_port = new t_model_ports; model_port->dir = OUT_PORT; @@ -2182,11 +2161,8 @@ struct ArchReader { model_port->min_size = 1; model_port->size = 1; - model_port->next = model->outputs; - model->outputs = model_port; - - model->next = arch_->models; - arch_->models = model; + model_port->next = new_model.outputs; + new_model.outputs = model_port; } } diff --git a/libs/libarchfpga/src/read_xml_arch_file.cpp b/libs/libarchfpga/src/read_xml_arch_file.cpp index 5ac6acf6b9a..9d54b9e2a41 100644 --- a/libs/libarchfpga/src/read_xml_arch_file.cpp +++ b/libs/libarchfpga/src/read_xml_arch_file.cpp @@ -43,6 +43,7 @@ #include #include +#include "logic_types.h" #include "pugixml.hpp" #include "pugixml_util.hpp" @@ -295,7 +296,7 @@ static void ProcessChanWidthDistr(pugi::xml_node Node, const pugiutil::loc_data& loc_data); static void ProcessChanWidthDistrDir(pugi::xml_node Node, t_chan* chan, const pugiutil::loc_data& loc_data); static void ProcessModels(pugi::xml_node Node, t_arch* arch, const pugiutil::loc_data& loc_data); -static void ProcessModelPorts(pugi::xml_node port_group, t_model* model, std::set& port_names, const pugiutil::loc_data& loc_data); +static void ProcessModelPorts(pugi::xml_node port_group, t_model& model, std::set& port_names, const pugiutil::loc_data& loc_data); static void ProcessLayout(pugi::xml_node Node, t_arch* arch, const pugiutil::loc_data& loc_data, int& num_of_avail_layer); static t_grid_def ProcessGridLayout(vtr::string_internment& strings, pugi::xml_node layout_type_tag, const pugiutil::loc_data& loc_data, t_arch* arch, int& num_of_avail_layer); static void ProcessBlockTypeLocs(t_grid_def& grid_def, int die_number, vtr::string_internment& strings, pugi::xml_node layout_block_type_tag, const pugiutil::loc_data& loc_data); @@ -434,7 +435,6 @@ void XmlReadArch(const char* ArchFile, /* Process models */ Next = get_single_child(architecture, "models", loc_data); ProcessModels(Next, arch, loc_data); - CreateModelLibrary(arch); /* Process layout */ int num_of_avail_layers = 0; @@ -2245,15 +2245,9 @@ static void ProcessSwitchblockLocations(pugi::xml_node switchblock_locations, * child type objects. */ static void ProcessModels(pugi::xml_node Node, t_arch* arch, const pugiutil::loc_data& loc_data) { pugi::xml_node p; - t_model* temp = nullptr; - int L_index; /* std::maps for checking duplicates */ std::map model_name_map; - std::pair::iterator, bool> ret_map_name; - L_index = NUM_MODELS_IN_LIBRARY; - - arch->models = nullptr; for (pugi::xml_node model : Node.children()) { //Process each model if (model.name() != std::string("model")) { @@ -2261,27 +2255,25 @@ static void ProcessModels(pugi::xml_node Node, t_arch* arch, const pugiutil::loc } try { - temp = new t_model; - temp->index = L_index; - L_index++; - //Process the tag attributes + bool new_model_never_prune = false; + std::string new_model_name; for (pugi::xml_attribute attr : model.attributes()) { if (attr.name() == std::string("never_prune")) { auto model_type_str = vtr::strdup(attr.value()); if (std::strcmp(model_type_str, "true") == 0) { - temp->never_prune = true; + new_model_never_prune = true; } else if (std::strcmp(model_type_str, "false") == 0) { - temp->never_prune = false; + new_model_never_prune = false; } else { archfpga_throw(loc_data.filename_c_str(), loc_data.line(model), "Unsupported never prune attribute value."); } } else if (attr.name() == std::string("name")) { - if (!temp->name) { + if (new_model_name.empty()) { //First name attr. seen - temp->name = vtr::strdup(attr.value()); + new_model_name = attr.value(); } else { //Duplicate name archfpga_throw(loc_data.filename_c_str(), loc_data.line(model), @@ -2293,41 +2285,41 @@ static void ProcessModels(pugi::xml_node Node, t_arch* arch, const pugiutil::loc } /* Try insert new model, check if already exist at the same time */ - ret_map_name = model_name_map.insert(std::pair(temp->name, 0)); + auto ret_map_name = model_name_map.insert(std::pair(new_model_name, 0)); if (!ret_map_name.second) { archfpga_throw(loc_data.filename_c_str(), loc_data.line(model), - "Duplicate model name: '%s'.\n", temp->name); + "Duplicate model name: '%s'.\n", new_model_name.c_str()); } + // Create the model in the model storage class + LogicalModelId new_model_id = arch->models.create_logical_model(new_model_name); + t_model& new_model = arch->models.get_model(new_model_id); + new_model.never_prune = new_model_never_prune; + //Process the ports std::set port_names; for (pugi::xml_node port_group : model.children()) { if (port_group.name() == std::string("input_ports")) { - ProcessModelPorts(port_group, temp, port_names, loc_data); + ProcessModelPorts(port_group, new_model, port_names, loc_data); } else if (port_group.name() == std::string("output_ports")) { - ProcessModelPorts(port_group, temp, port_names, loc_data); + ProcessModelPorts(port_group, new_model, port_names, loc_data); } else { bad_tag(port_group, loc_data, model, {"input_ports", "output_ports"}); } } //Sanity check the model - check_model_clocks(temp, loc_data.filename_c_str(), loc_data.line(model)); - check_model_combinational_sinks(temp, loc_data.filename_c_str(), loc_data.line(model)); - warn_model_missing_timing(temp, loc_data.filename_c_str(), loc_data.line(model)); + check_model_clocks(new_model, loc_data.filename_c_str(), loc_data.line(model)); + check_model_combinational_sinks(new_model, loc_data.filename_c_str(), loc_data.line(model)); + warn_model_missing_timing(new_model, loc_data.filename_c_str(), loc_data.line(model)); } catch (ArchFpgaError& e) { - free_arch_model(temp); throw; } - - //Add the model - temp->next = arch->models; - arch->models = temp; } return; } -static void ProcessModelPorts(pugi::xml_node port_group, t_model* model, std::set& port_names, const pugiutil::loc_data& loc_data) { +static void ProcessModelPorts(pugi::xml_node port_group, t_model& model, std::set& port_names, const pugiutil::loc_data& loc_data) { for (pugi::xml_attribute attr : port_group.attributes()) { bad_attribute(attr, port_group, loc_data); } @@ -2401,14 +2393,14 @@ static void ProcessModelPorts(pugi::xml_node port_group, t_model* model, std::se //Add the port if (dir == IN_PORT) { - model_port->next = model->inputs; - model->inputs = model_port; + model_port->next = model.inputs; + model.inputs = model_port; } else { VTR_ASSERT(dir == OUT_PORT); - model_port->next = model->outputs; - model->outputs = model_port; + model_port->next = model.outputs; + model.outputs = model_port; } } } @@ -2975,14 +2967,14 @@ static void MarkIoTypes(std::vector& PhysicalTileTypes) { auto equivalent_sites = get_equivalent_sites_set(&type); for (const auto& equivalent_site : equivalent_sites) { - if (block_type_contains_blif_model(equivalent_site, MODEL_INPUT)) { + if (block_type_contains_blif_model(equivalent_site, LogicalModels::MODEL_INPUT)) { type.is_input_type = true; break; } } for (const auto& equivalent_site : equivalent_sites) { - if (block_type_contains_blif_model(equivalent_site, MODEL_OUTPUT)) { + if (block_type_contains_blif_model(equivalent_site, LogicalModels::MODEL_OUTPUT)) { type.is_output_type = true; break; } diff --git a/libs/libarchfpga/src/write_models_bb.cpp b/libs/libarchfpga/src/write_models_bb.cpp index a48c0b1ab9f..0ea43f3ebc5 100644 --- a/libs/libarchfpga/src/write_models_bb.cpp +++ b/libs/libarchfpga/src/write_models_bb.cpp @@ -1,12 +1,12 @@ -#include // std::all_of +#include +#include +#include "logic_types.h" #include "vtr_util.h" // vtr::fopen #include "vtr_assert.h" // VTR ASSERT #include "write_models_bb.h" -using vtr::t_linked_vptr; - /* the output file description */ #define OUTPUT_HEADER_COMMENT(Echo, ArchFile) \ { \ @@ -26,20 +26,9 @@ using vtr::t_linked_vptr; /* a comment for the body of black box modules */ const char* HARD_BLOCK_COMMENT = "/* the body of the complex block module is empty since it should be seen as a black box */"; -/* list of vtr primitives blocks */ -static constexpr short num_vtr_primitives = 8; -static constexpr const char* vtr_primitives[num_vtr_primitives] = { - "LUT_K", - "DFF", - "fpga_interconnect", - "mux", - "adder", - "multiply", - "single_port_ram", - "dual_port_ram"}; /* declarations */ -void DeclareModel_bb(FILE* Echo, const t_model* model); +void DeclareModel_bb(FILE* Echo, const t_model& model); /** * (function: WriteModels_bb) @@ -58,21 +47,35 @@ void WriteModels_bb(const char* ArchFile, VTR_ASSERT(arch); FILE* Echo = vtr::fopen(VEchoFile, "w"); - t_model* cur_model = arch->models; /* the output file description */ OUTPUT_HEADER_COMMENT(Echo, ArchFile) + // Collect the model IDs of all the vtr primitives. + std::set vtr_primitives; + std::vector vtr_primitive_names = { + "LUT_K", + "DFF", + "fpga_interconnect", + "mux", + "adder", + "multiply", + "single_port_ram", + "dual_port_ram"}; + for (const std::string& primitive_name : vtr_primitive_names) { + LogicalModelId primitive_model_id = arch->models.get_model_by_name(primitive_name); + if (!primitive_model_id.is_valid()) + continue; + vtr_primitives.insert(primitive_model_id); + } + // iterate over models - while (cur_model) { + for (LogicalModelId model_id : arch->models.all_models()) { // avoid printing vtr primitives - if (std::all_of(vtr_primitives, - vtr_primitives + num_vtr_primitives, - [&](const auto& e) { return strcmp(e, cur_model->name); })) - DeclareModel_bb(Echo, cur_model); + if (vtr_primitives.count(model_id) != 0) + continue; - // moving forward with the next complex block - cur_model = cur_model->next; + DeclareModel_bb(Echo, arch->models.get_model(model_id)); } // CLEAN UP @@ -88,22 +91,19 @@ void WriteModels_bb(const char* ArchFile, * @param Echo pointer output file * @param model pointer to the complex block t_model */ -void DeclareModel_bb(FILE* Echo, const t_model* model) { - // validate the blackbox name - VTR_ASSERT(model); - +void DeclareModel_bb(FILE* Echo, const t_model& model) { // module - fprintf(Echo, "module %s(\n", model->name); + fprintf(Echo, "module %s(\n", model.name); // input/output ports - t_model_ports* input_port = model->inputs; + t_model_ports* input_port = model.inputs; while (input_port) { fprintf(Echo, "\tinput\t[%d:0]\t%s,\n", input_port->size - 1, input_port->name); // move forward until the end of input ports' list input_port = input_port->next; } - t_model_ports* output_port = model->outputs; + t_model_ports* output_port = model.outputs; while (output_port) { fprintf(Echo, "\toutput\t[%d:0]\t%s,\n", output_port->size - 1, output_port->name); // move forward until the end of output ports' list diff --git a/odin_ii/src/core/adders.cpp b/odin_ii/src/core/adders.cpp index ed6ecdb3f1c..4dce94d3758 100644 --- a/odin_ii/src/core/adders.cpp +++ b/odin_ii/src/core/adders.cpp @@ -26,6 +26,7 @@ #include #include +#include "logic_types.h" #include "odin_types.h" #include "odin_util.h" #include "node_creation_library.h" @@ -107,17 +108,18 @@ void report_add_distribution() { * (function: find_hard_adders) *-------------------------------------------------------------------------*/ void find_hard_adders() { - hard_adders = Arch.models; //Disable the size in configuration file.(The threshold for the extra bits). //min_add = configuration.min_hard_adder; min_threshold_adder = configuration.min_threshold_adder; - while (hard_adders != NULL) { + hard_adders = NULL; + for (LogicalModelId model_id : Arch.models.user_models()) { + hard_adders = &Arch.models.get_model(model_id); if (strcmp(hard_adders->name, "adder") == 0) { init_add_distribution(); return; } else { - hard_adders = hard_adders->next; + hard_adders = NULL; } } diff --git a/odin_ii/src/core/hard_blocks.cpp b/odin_ii/src/core/hard_blocks.cpp index ebdd39e4401..e920d54fead 100644 --- a/odin_ii/src/core/hard_blocks.cpp +++ b/odin_ii/src/core/hard_blocks.cpp @@ -26,6 +26,7 @@ #include #include +#include "logic_types.h" #include "odin_types.h" #include "odin_util.h" #include "odin_globals.h" @@ -55,14 +56,11 @@ t_model_ports* get_model_port(t_model_ports* ports, const char* name) { } void cache_hard_block_names() { - t_model* hard_blocks = NULL; - - hard_blocks = Arch.models; hard_block_names = sc_new_string_cache(); - while (hard_blocks) { + for (LogicalModelId model_id : Arch.models.user_models()) { + t_model* hard_blocks = &Arch.models.get_model(model_id); int sc_spot = sc_add_string(hard_block_names, hard_blocks->name); hard_block_names->data[sc_spot] = (void*)hard_blocks; - hard_blocks = hard_blocks->next; } } @@ -112,14 +110,9 @@ void deregister_hard_blocks() { } t_model* find_hard_block(const char* name) { - t_model* hard_blocks; - - hard_blocks = Arch.models; - while (hard_blocks) - if (!strcmp(hard_blocks->name, name)) - return hard_blocks; - else - hard_blocks = hard_blocks->next; + LogicalModelId hard_block_model_id = Arch.models.get_model_by_name(name); + if (hard_block_model_id.is_valid()) + return &Arch.models.get_model(hard_block_model_id); return NULL; } @@ -208,19 +201,17 @@ void define_hard_block(nnode_t* node, FILE* out) { void output_hard_blocks(FILE* out) { t_model_ports* hb_ports; - t_model* hard_blocks; char buffer[MAX_BUF]; int count; int i; oassert(out != NULL); - hard_blocks = Arch.models; - while (hard_blocks != NULL) { + for (LogicalModelId model_id : Arch.models.user_models()) { + t_model* hard_blocks = &Arch.models.get_model(model_id); if (hard_blocks->used == 1) /* Hard Block is utilized */ { //IF the hard_blocks is an adder or a multiplier, we ignore it.(Already print out in add_the_blackbox_for_adds and add_the_blackbox_for_mults) if (strcmp(hard_blocks->name, "adder") == 0 || strcmp(hard_blocks->name, "multiply") == 0) { - hard_blocks = hard_blocks->next; break; } @@ -261,7 +252,6 @@ void output_hard_blocks(FILE* out) { fprintf(out, "\n.blackbox\n.end\n\n"); } - hard_blocks = hard_blocks->next; } return; diff --git a/odin_ii/src/core/multipliers.cpp b/odin_ii/src/core/multipliers.cpp index a14eaa86781..6b62c93e751 100644 --- a/odin_ii/src/core/multipliers.cpp +++ b/odin_ii/src/core/multipliers.cpp @@ -29,6 +29,7 @@ #include #include +#include "logic_types.h" #include "odin_types.h" #include "odin_util.h" #include "node_creation_library.h" @@ -297,14 +298,15 @@ void report_mult_distribution() { * (function: find_hard_multipliers) *-------------------------------------------------------------------------*/ void find_hard_multipliers() { - hard_multipliers = Arch.models; + hard_multipliers = NULL; min_mult = configuration.min_hard_multiplier; - while (hard_multipliers != NULL) { + for (LogicalModelId model_id : Arch.models.user_models()) { + hard_multipliers = &Arch.models.get_model(model_id); if (strcmp(hard_multipliers->name, "multiply") == 0) { init_mult_distribution(); return; } else { - hard_multipliers = hard_multipliers->next; + hard_multipliers = NULL; } } diff --git a/odin_ii/src/verilog/verilog_writer.cpp b/odin_ii/src/verilog/verilog_writer.cpp index 623f16de861..51499a20c56 100644 --- a/odin_ii/src/verilog/verilog_writer.cpp +++ b/odin_ii/src/verilog/verilog_writer.cpp @@ -25,6 +25,7 @@ #include //std::stringstream +#include "logic_types.h" #include "verilog.h" #include "odin_globals.h" #include "hard_blocks.h" @@ -59,15 +60,12 @@ void verilog::writer::_write(const netlist_t* netlist) { } // print out the rest od models, including DSPs in the target architecture - t_model* model = Arch.models; - - while (model) { + for (LogicalModelId model_id : Arch.models.user_models()) { int sc_spot; - if ((sc_spot = sc_lookup_string(this->models_declaration, model->name)) != -1) { + if ((sc_spot = sc_lookup_string(this->models_declaration, Arch.models.model_name(model_id).c_str())) != -1) { fprintf(this->output_file, "%s", (char*)this->models_declaration->data[sc_spot]); fflush(this->output_file); } - model = model->next; } } diff --git a/parmys/parmys-plugin/core/adder.cc b/parmys/parmys-plugin/core/adder.cc index fa184b34c54..ae5cc6ef26d 100644 --- a/parmys/parmys-plugin/core/adder.cc +++ b/parmys/parmys-plugin/core/adder.cc @@ -16,6 +16,7 @@ * SPDX-License-Identifier: Apache-2.0 */ #include "adder.h" +#include "logic_types.h" #include "multiplier.h" #include "netlist_utils.h" #include "node_utils.h" @@ -96,17 +97,18 @@ void report_add_distribution() *-------------------------------------------------------------------------*/ void find_hard_adders() { - hard_adders = Arch.models; // Disable the size in configuration file.(The threshold for the extra bits). // min_add = configuration.min_hard_adder; min_threshold_adder = configuration.min_threshold_adder; - while (hard_adders != NULL) { + hard_adders = NULL; + for (LogicalModelId model_id : Arch.models.user_models()) { + hard_adders = &Arch.models.get_model(model_id); if (strcmp(hard_adders->name, "adder") == 0) { init_add_distribution(); return; } else { - hard_adders = hard_adders->next; + hard_adders = NULL; } } @@ -1405,4 +1407,4 @@ nnode_t *check_missing_ports(nnode_t *node, uintptr_t traverse_mark_number, netl } return new_node; -} \ No newline at end of file +} diff --git a/parmys/parmys-plugin/core/hard_block.cc b/parmys/parmys-plugin/core/hard_block.cc index a7437518f78..cfadd5b0dac 100644 --- a/parmys/parmys-plugin/core/hard_block.cc +++ b/parmys/parmys-plugin/core/hard_block.cc @@ -15,9 +15,11 @@ * * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include "hard_block.h" +#include "logic_types.h" #include "memory.h" #include "netlist_utils.h" #include "odin_globals.h" @@ -53,14 +55,17 @@ t_model_ports *get_model_port(t_model_ports *ports, const char *name) void cache_hard_block_names() { - t_model *hard_blocks = NULL; - - hard_blocks = Arch.models; hard_block_names = sc_new_string_cache(); - while (hard_blocks) { + // After a change to the construction of the user models, the order was + // reversed, which slightly changed the results. Reversing them back to + // attain the same results, simplifying my testing. + // TODO: Regenerate the golden solutions to use the new model order. + std::vector user_models(Arch.models.user_models().begin(), Arch.models.user_models().end()); + std::reverse(user_models.begin(), user_models.end()); + for (LogicalModelId model_id : user_models) { + t_model* hard_blocks = &Arch.models.get_model(model_id); int sc_spot = sc_add_string(hard_block_names, hard_blocks->name); hard_block_names->data[sc_spot] = (void *)hard_blocks; - hard_blocks = hard_blocks->next; } } @@ -98,14 +103,9 @@ void register_hard_blocks() t_model *find_hard_block(const char *name) { - t_model *hard_blocks; - - hard_blocks = Arch.models; - while (hard_blocks) - if (!strcmp(hard_blocks->name, name)) - return hard_blocks; - else - hard_blocks = hard_blocks->next; + LogicalModelId hard_block_model_id = Arch.models.get_model_by_name(name); + if (hard_block_model_id.is_valid()) + return &Arch.models.get_model(hard_block_model_id); return NULL; } @@ -201,16 +201,20 @@ void cell_hard_block(nnode_t *node, Yosys::Module *module, netlist_t *netlist, Y void output_hard_blocks_yosys(Yosys::Design *design) { t_model_ports *hb_ports; - t_model *hard_blocks; - hard_blocks = Arch.models; - while (hard_blocks != NULL) { + // After a change to the construction of the user models, the order was + // reversed, which slightly changed the results. Reversing them back to + // attain the same results, simplifying my testing. + // TODO: Regenerate the golden solutions to use the new model order. + std::vector user_models(Arch.models.user_models().begin(), Arch.models.user_models().end()); + std::reverse(user_models.begin(), user_models.end()); + for (LogicalModelId model_id : user_models) { + t_model* hard_blocks = &Arch.models.get_model(model_id); if (hard_blocks->used == 1) /* Hard Block is utilized */ { // IF the hard_blocks is an adder or a multiplier, we ignore it.(Already print out in add_the_blackbox_for_adds and // add_the_blackbox_for_mults) if (strcmp(hard_blocks->name, "adder") == 0 || strcmp(hard_blocks->name, "multiply") == 0) { - hard_blocks = hard_blocks->next; break; } @@ -277,8 +281,6 @@ void output_hard_blocks_yosys(Yosys::Design *design) module->attributes[Yosys::ID::blackbox] = Yosys::RTLIL::Const(1); } - - hard_blocks = hard_blocks->next; } return; diff --git a/parmys/parmys-plugin/core/multiplier.cc b/parmys/parmys-plugin/core/multiplier.cc index befb0b337bd..3a411217f25 100644 --- a/parmys/parmys-plugin/core/multiplier.cc +++ b/parmys/parmys-plugin/core/multiplier.cc @@ -16,6 +16,7 @@ * SPDX-License-Identifier: Apache-2.0 */ #include "multiplier.h" +#include "logic_types.h" #include "netlist_utils.h" #include "node_utils.h" #include "odin_globals.h" @@ -544,14 +545,15 @@ void report_mult_distribution() *-------------------------------------------------------------------------*/ void find_hard_multipliers() { - hard_multipliers = Arch.models; + hard_multipliers = NULL; min_mult = configuration.min_hard_multiplier; - while (hard_multipliers != NULL) { + for (LogicalModelId model_id : Arch.models.user_models()) { + hard_multipliers = &Arch.models.get_model(model_id); if (strcmp(hard_multipliers->name, "multiply") == 0) { init_mult_distribution(); return; } else { - hard_multipliers = hard_multipliers->next; + hard_multipliers = NULL; } } diff --git a/parmys/parmys-plugin/parmys.cc b/parmys/parmys-plugin/parmys.cc index 910f7711dee..158db0253b8 100644 --- a/parmys/parmys-plugin/parmys.cc +++ b/parmys/parmys-plugin/parmys.cc @@ -1159,9 +1159,8 @@ struct ParMYSPass : public Pass { free_netlist(transformed); - if (Arch.models) { + if (!Arch.models.all_models().empty()) { free_arch(&Arch); - Arch.models = nullptr; } free_type_descriptors(logical_block_types); @@ -1183,4 +1182,4 @@ struct ParMYSPass : public Pass { } } ParMYSPass; -PRIVATE_NAMESPACE_END \ No newline at end of file +PRIVATE_NAMESPACE_END diff --git a/parmys/parmys-plugin/parmys_arch.cc b/parmys/parmys-plugin/parmys_arch.cc index 97a8591ab60..995c9356264 100644 --- a/parmys/parmys-plugin/parmys_arch.cc +++ b/parmys/parmys-plugin/parmys_arch.cc @@ -120,15 +120,19 @@ struct ParmysArchPass : public Pass { const char *arch_info_file = "arch.info"; EchoArch(arch_info_file, physical_tile_types, logical_block_types, &arch); - t_model *hb = arch.models; - while (hb) { + // After a change to the construction of the user models, the order was + // reversed, which slightly changed the results. Reversing them back to + // attain the same results. + // TODO: Regenerate the golden solutions to use the new model order. + std::vector user_models(arch.models.user_models().begin(), arch.models.user_models().end()); + std::reverse(user_models.begin(), user_models.end()); + for (LogicalModelId model_id : user_models) { + t_model* hb = &arch.models.get_model(model_id); if (strcmp(hb->name, SINGLE_PORT_RAM_string) && strcmp(hb->name, DUAL_PORT_RAM_string) && strcmp(hb->name, "multiply") && strcmp(hb->name, "adder")) { add_hb_to_design(hb, design); log("Hard block added to the Design ---> `%s`\n", hb->name); } - - hb = hb->next; } // CLEAN UP diff --git a/utils/fasm/src/fasm.cpp b/utils/fasm/src/fasm.cpp index 2785c1149e8..9a10808cdb1 100644 --- a/utils/fasm/src/fasm.cpp +++ b/utils/fasm/src/fasm.cpp @@ -591,14 +591,16 @@ void FasmWriterVisitor::check_for_param(const t_pb *atom) { void FasmWriterVisitor::check_for_lut(const t_pb* atom) { auto& atom_ctx = g_vpr_ctx.atom(); + const LogicalModels& models = g_vpr_ctx.device().arch->models; auto atom_blk_id = atom_ctx.lookup().atom_pb_bimap().pb_atom(atom); if (atom_blk_id == AtomBlockId::INVALID()) { return; } - const t_model* model = atom_ctx.netlist().block_model(atom_blk_id); - if (model->name == std::string(MODEL_NAMES)) { + LogicalModelId names_model_id = models.get_model_by_name(LogicalModels::MODEL_NAMES); + LogicalModelId model_id = atom_ctx.netlist().block_model(atom_blk_id); + if (model_id == names_model_id) { VTR_ASSERT(atom->pb_graph_node != nullptr); const auto *lut_definition = find_lut(atom->pb_graph_node); VTR_ASSERT(lut_definition->num_inputs == *atom->pb_graph_node->num_input_pins); diff --git a/utils/vqm2blif/src/base/hard_block_recog.cpp b/utils/vqm2blif/src/base/hard_block_recog.cpp index 60be10d9457..f16f8ebfa3d 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.cpp +++ b/utils/vqm2blif/src/base/hard_block_recog.cpp @@ -124,6 +124,7 @@ #include "hard_block_recog.h" +#include "logic_types.h" //============================================================================================ // INTERNAL FUNCTION DECLARATIONS @@ -133,7 +134,7 @@ static void initialize_hard_block_models(t_arch* main_arch, std::vector* hard_block_type_name_list, t_hard_block_recog* module_hard_block_node_refs_and_info); -static bool create_and_initialize_all_hard_block_ports(t_model* hard_block_arch_model, t_hard_block_recog* storage_of_hard_block_info); +static bool create_and_initialize_all_hard_block_ports(const t_model& hard_block_arch_model, t_hard_block_recog* storage_of_hard_block_info); static void create_hard_block_port_info_structure(t_hard_block_recog* storage_of_hard_block_info, std::string hard_block_type_name); @@ -323,7 +324,6 @@ void add_hard_blocks_to_netlist(t_module* main_module, t_arch* main_arch, std::v */ static void initialize_hard_block_models(t_arch* main_arch, std::vector* hard_block_type_names, t_hard_block_recog* storage_of_hard_block_info) { - t_model* hard_block_model = NULL; std::vector::iterator hard_block_type_name_traverser; bool single_hard_block_init_result = false; @@ -331,15 +331,16 @@ static void initialize_hard_block_models(t_arch* main_arch, std::vectorbegin(); hard_block_type_name_traverser != hard_block_type_names->end(); hard_block_type_name_traverser++) { // get the corresponding model for each hard block name - hard_block_model = find_arch_model_by_name(*hard_block_type_name_traverser, main_arch->models); + LogicalModelId hard_block_model_id = main_arch->models.get_model_by_name(*hard_block_type_name_traverser); // a check to see if the model was found within the FPGA architecture - if (hard_block_model == NULL) + if (!hard_block_model_id.is_valid()) { throw vtr::VtrError("The provided hard block model: '" + *hard_block_type_name_traverser + "' was not found within the corresponding FPGA architecture."); } else - { + { + const t_model& hard_block_model = main_arch->models.get_model(hard_block_model_id); // store the port information for the current hard block model single_hard_block_init_result = create_and_initialize_all_hard_block_ports(hard_block_model, storage_of_hard_block_info); @@ -478,15 +479,15 @@ static void process_module_nodes_and_create_hard_blocks(t_module* main_module, s * the FPGA had any ports. * */ -static bool create_and_initialize_all_hard_block_ports(t_model* hard_block_arch_model, t_hard_block_recog* storage_of_hard_block_info) +static bool create_and_initialize_all_hard_block_ports(const t_model& hard_block_arch_model, t_hard_block_recog* storage_of_hard_block_info) { int hard_block_port_index = 0; - std::string hard_block_arch_model_name = hard_block_arch_model->name; + std::string hard_block_arch_model_name = hard_block_arch_model.name; bool result = true; // get the hard block ports - t_model_ports* input_ports = hard_block_arch_model->inputs; - t_model_ports* output_ports = hard_block_arch_model->outputs; + t_model_ports* input_ports = hard_block_arch_model.inputs; + t_model_ports* output_ports = hard_block_arch_model.outputs; //initialize a hard block node port array create_hard_block_port_info_structure(storage_of_hard_block_info,hard_block_arch_model_name); diff --git a/utils/vqm2blif/src/base/preprocess.cpp b/utils/vqm2blif/src/base/preprocess.cpp index 8ae41297d23..092d8a67180 100644 --- a/utils/vqm2blif/src/base/preprocess.cpp +++ b/utils/vqm2blif/src/base/preprocess.cpp @@ -2,6 +2,7 @@ // INCLUDES //============================================================================================ #include "preprocess.h" +#include "logic_types.h" #include "vqm_common.h" #include "lut_stats.h" #include "vtr_memory.h" @@ -9,7 +10,6 @@ #include "vtr_assert.h" #include "vqm2blif_util.h" #include "physical_types.h" -#include //============================================================================================ @@ -19,9 +19,9 @@ //Functions to identify and decompose inout pins void decompose_inout_pins(t_module* module, t_arch* arch, string device); -t_model* find_model_in_architecture(t_model* arch_models, t_node* node, string device); +LogicalModelId find_model_in_architecture(const LogicalModels& arch_models, t_node* node, string device); -t_model_ports* find_port_in_architecture_model(t_model* arch_model, t_node_port_association* node_port); +t_model_ports* find_port_in_architecture_model(const t_model& arch_model, t_node_port_association* node_port); char* prefix_string(const char* prefix, const char* base); @@ -314,11 +314,11 @@ void decompose_inout_pins(t_module* module, t_arch* arch, string device){ */ //Architecture pointers - t_model* arch_model; t_model_ports* arch_model_port; //Find the model - arch_model = find_model_in_architecture(arch->models, node, device); + LogicalModelId arch_model_id = find_model_in_architecture(arch->models, node, device); + const t_model& arch_model = arch->models.get_model(arch_model_id); //Find the architecure model port arch_model_port = find_port_in_architecture_model(arch_model, node_port); @@ -372,7 +372,7 @@ void decompose_inout_pins(t_module* module, t_arch* arch, string device){ cout << "\t>> Decomposed " << number_of_inout_pins_found << " 'inout' pin(s), moving " << number_of_nets_moved << " net(s)" << endl; } -t_model* find_model_in_architecture(t_model* arch_models, t_node* node, string device) { +LogicalModelId find_model_in_architecture(const LogicalModels& arch_models, t_node* node, string device) { /* * Finds the archtecture module corresponding to the node type * @@ -387,20 +387,15 @@ t_model* find_model_in_architecture(t_model* arch_models, t_node* node, string d string elaborated_name = generate_opname(node, arch_models, device); //Find the correct model, by name matching - t_model* arch_model = arch_models; - while((arch_model) && (strcmp(elaborated_name.c_str(), arch_model->name) != 0)) { - //Move to the next model - arch_model = arch_model->next; - } + LogicalModelId arch_model_id = arch_models.get_model_by_name(elaborated_name); //The model must be in the arch file - if (arch_model == NULL) { + if (!arch_model_id.is_valid()) { cout << "Error: could not find model in architecture file for '" << node->type << "'\n"; exit(1); } - VTR_ASSERT(arch_model != NULL); - return arch_model; + return arch_model_id; } char* prefix_string(const char* prefix, const char* base) { @@ -416,7 +411,7 @@ char* prefix_string(const char* prefix, const char* base) { return new_string; } -t_model_ports* find_port_in_architecture_model(t_model* arch_model, t_node_port_association* node_port) { +t_model_ports* find_port_in_architecture_model(const t_model& arch_model, t_node_port_association* node_port) { /* * Finds the module port corresponding to the port name * @@ -435,7 +430,7 @@ t_model_ports* find_port_in_architecture_model(t_model* arch_model, t_node_port_ //Check inputs //Find the correct port, by name matching - t_model_ports* arch_model_port = arch_model->inputs; + t_model_ports* arch_model_port = arch_model.inputs; //Until NULL or a matching port name while ((arch_model_port) && (strcmp(arch_model_port->name, node_port->port_name) != 0)) { @@ -451,7 +446,7 @@ t_model_ports* find_port_in_architecture_model(t_model* arch_model, t_node_port_ //Not an input should be an output //Check outputs - arch_model_port = arch_model->outputs; + arch_model_port = arch_model.outputs; //Until NULL or a matching port name while ((arch_model_port) && (strcmp(arch_model_port->name, node_port->port_name) != 0)) { @@ -465,7 +460,7 @@ t_model_ports* find_port_in_architecture_model(t_model* arch_model, t_node_port_ //arch_model_port must be either an input or an output, // hence it should never be NULL at this point if (arch_model_port == NULL) { - cout << "Error: could not find port '" << node_port->port_name << "' on model '" << arch_model->name << "' in architecture file\n"; + cout << "Error: could not find port '" << node_port->port_name << "' on model '" << arch_model.name << "' in architecture file\n"; exit(1); } } @@ -1496,7 +1491,8 @@ void check_and_fix_clock_to_normal_port_connections(t_module* module, t_arch* ar //check whether it is the driver //Find the model - t_model* arch_model = find_model_in_architecture(arch->models, node, device); + LogicalModelId arch_model_id = find_model_in_architecture(arch->models, node, device); + const t_model& arch_model = arch->models.get_model(arch_model_id); //Look-up the arch model port t_model_ports* arch_model_port = find_port_in_architecture_model(arch_model, node_port); @@ -1618,7 +1614,8 @@ void check_and_fix_clock_to_normal_port_connections(t_module* module, t_arch* ar t_node_port_association* node_port = node->array_of_ports[j]; //Find the model - t_model* arch_model = find_model_in_architecture(arch->models, node, device); + LogicalModelId arch_model_id = find_model_in_architecture(arch->models, node, device); + const t_model& arch_model = arch->models.get_model(arch_model_id); //Look-up the arch model port t_model_ports* arch_model_port = find_port_in_architecture_model(arch_model, node_port); @@ -2516,11 +2513,11 @@ t_net_driver_map identify_net_drivers(t_module* module, t_arch* arch, t_global_p */ //Architecture pointers - t_model* arch_model; t_model_ports* arch_model_port; //Find the model - arch_model = find_model_in_architecture(arch->models, node, device); + LogicalModelId arch_model_id = find_model_in_architecture(arch->models, node, device); + const t_model& arch_model = arch->models.get_model(arch_model_id); //Find the architecure model port arch_model_port = find_port_in_architecture_model(arch_model, node_port); diff --git a/utils/vqm2blif/src/base/vqm2blif.h b/utils/vqm2blif/src/base/vqm2blif.h index e206ba11d7c..c855dc7b200 100644 --- a/utils/vqm2blif/src/base/vqm2blif.h +++ b/utils/vqm2blif/src/base/vqm2blif.h @@ -56,6 +56,7 @@ // INCLUDES //============================================================================================ +#include "logic_types.h" #include "vqm2blif_util.h" #include "lutmask.h" #include "cleanup.h" @@ -74,7 +75,7 @@ struct t_subckt_param_attr { typedef struct s_blif_subckt{ string inst_name; - t_model* model_type; + LogicalModelId model_type; portmap input_cnxns; diff --git a/utils/vqm2blif/src/base/vqm2blif_util.cpp b/utils/vqm2blif/src/base/vqm2blif_util.cpp index dbee284a5f7..d2bd322c5a2 100644 --- a/utils/vqm2blif/src/base/vqm2blif_util.cpp +++ b/utils/vqm2blif/src/base/vqm2blif_util.cpp @@ -1,6 +1,6 @@ #include "vqm2blif_util.h" +#include "logic_types.h" #include "vtr_util.h" -#include "vtr_memory.h" #include "vtr_assert.h" #define dsp_clock_count 15 @@ -215,7 +215,7 @@ string get_wire_name(t_pin_def* net, int index){ //============================================================================================ //============================================================================================ -string generate_opname (t_node* vqm_node, t_model* arch_models, string device){ +string generate_opname (t_node* vqm_node, const LogicalModels& arch_models, string device){ //Add support for different architectures here. // Currently only support Stratix IV and Stratix 10 string mode_hash; @@ -225,7 +225,8 @@ string generate_opname (t_node* vqm_node, t_model* arch_models, string device){ mode_hash = generate_opname_stratixiv(vqm_node, arch_models); //Final sanity check - if (NULL == find_arch_model_by_name(mode_hash, arch_models)){ + LogicalModelId arch_model_id = arch_models.get_model_by_name(mode_hash); + if (!arch_model_id.is_valid()) { cout << "Error: could not find primitive '" << mode_hash << "' in architecture file" << endl; exit(1); } @@ -234,7 +235,7 @@ string generate_opname (t_node* vqm_node, t_model* arch_models, string device){ } -string generate_opname_stratixiv (t_node* vqm_node, t_model* arch_models){ +string generate_opname_stratixiv (t_node* vqm_node, const LogicalModels& arch_models){ /* Generates a mode-hash string based on a node's name and parameter set * * ARGUMENTS @@ -281,16 +282,14 @@ string generate_opname_stratixiv (t_node* vqm_node, t_model* arch_models){ * DSP Block Multipliers */ if(strcmp(vqm_node->type, "stratixiv_mac_mult") == 0) { - generate_opname_stratixiv_dsp_mult(vqm_node, arch_models, mode_hash); - + generate_opname_stratixiv_dsp_mult(vqm_node, mode_hash); } /* * DSP Block Output (MAC) */ if(strcmp(vqm_node->type, "stratixiv_mac_out") == 0) { - generate_opname_stratixiv_dsp_out(vqm_node, arch_models, mode_hash); - + generate_opname_stratixiv_dsp_out(vqm_node, mode_hash); } /* @@ -303,7 +302,7 @@ string generate_opname_stratixiv (t_node* vqm_node, t_model* arch_models){ return mode_hash; } -void generate_opname_stratixiv_dsp_mult (t_node* vqm_node, t_model* /*arch_models*/, string& mode_hash) { +void generate_opname_stratixiv_dsp_mult (t_node* vqm_node, string& mode_hash) { //We check for all mac_mult's input ports to see if any use a clock // if so, we set ALL input ports to be registered. While this is an approximation, // it would be very unusually to have only some of the ports registered. @@ -413,7 +412,7 @@ void generate_opname_stratixiv_dsp_mult (t_node* vqm_node, t_model* /*arch_model } } -void generate_opname_stratixiv_dsp_out (t_node* vqm_node, t_model* /*arch_models*/, string& mode_hash) { +void generate_opname_stratixiv_dsp_out (t_node* vqm_node, string& mode_hash) { //It is not practical to model all of the internal registers of the mac_out block, as this // would significantly increase the size of the architecture description. As a result, we // only identify whether the input or output registers are used. @@ -525,7 +524,7 @@ void generate_opname_stratixiv_dsp_out (t_node* vqm_node, t_model* /*arch_models } -void generate_opname_ram (t_node* vqm_node, t_model* arch_models, string& mode_hash, string device) { +void generate_opname_ram (t_node* vqm_node, const LogicalModels& arch_models, string& mode_hash, string device) { if(device == "stratixiv") VTR_ASSERT(strcmp(vqm_node->type, "stratixiv_ram_block") == 0); @@ -607,7 +606,8 @@ void generate_opname_ram (t_node* vqm_node, t_model* arch_models, string& mode_h //Only print the address width, the data widths are handled by the VPR memory class mode_hash.append(".port_a_address_width{" + std::to_string(ram_info.port_a_addr_width) + "}"); - if (find_arch_model_by_name(mode_hash, arch_models) == NULL){ + LogicalModelId arch_model_id = arch_models.get_model_by_name(mode_hash); + if (!arch_model_id.is_valid()) { cout << "Error: could not find single port memory primitive '" << mode_hash << "' in architecture file" << endl; exit(1); } @@ -623,7 +623,8 @@ void generate_opname_ram (t_node* vqm_node, t_model* arch_models, string& mode_h mode_hash.append(".port_a_address_width{" + std::to_string(ram_info.port_a_addr_width) + "}"); mode_hash.append(".port_b_address_width{" + std::to_string(ram_info.port_b_addr_width) + "}"); - if (find_arch_model_by_name(mode_hash, arch_models) == NULL){ + LogicalModelId arch_model_id = arch_models.get_model_by_name(mode_hash); + if (!arch_model_id.is_valid()) { cout << "Error: could not find dual port (non-mixed_width) memory primitive '" << mode_hash << "' in architecture file"; exit(1); } @@ -644,7 +645,8 @@ void generate_opname_ram (t_node* vqm_node, t_model* arch_models, string& mode_h tmp_mode_hash.append(".port_a_data_width{" + std::to_string(ram_info.port_a_data_width) + "}"); tmp_mode_hash.append(".port_b_data_width{" + std::to_string(ram_info.port_b_data_width) + "}"); - if (find_arch_model_by_name(tmp_mode_hash, arch_models) == NULL){ + LogicalModelId arch_model_id = arch_models.get_model_by_name(tmp_mode_hash); + if (!arch_model_id.is_valid()) { //3a) Not found, use the default name (no specific address/data widths) ; // do nothing } else { @@ -655,7 +657,7 @@ void generate_opname_ram (t_node* vqm_node, t_model* arch_models, string& mode_h } } -string generate_opname_stratix10 (t_node* vqm_node, t_model* arch_models){ +string generate_opname_stratix10 (t_node* vqm_node, const LogicalModels& arch_models){ /* Generates a mode-hash string based on a node's name and parameter set * * ARGUMENTS @@ -707,7 +709,7 @@ string generate_opname_stratix10 (t_node* vqm_node, t_model* arch_models){ * DSP Block - fixed point */ if(strcmp(vqm_node->type, "fourteennm_mac") == 0) { - generate_opname_stratix10_dsp(vqm_node, arch_models, mode_hash, 0); + generate_opname_stratix10_dsp(vqm_node, mode_hash, 0); } @@ -715,7 +717,7 @@ string generate_opname_stratix10 (t_node* vqm_node, t_model* arch_models){ * DSP Block - floating point */ if(strcmp(vqm_node->type, "fourteennm_fp_mac") == 0) { - generate_opname_stratix10_dsp(vqm_node, arch_models, mode_hash, 1); + generate_opname_stratix10_dsp(vqm_node, mode_hash, 1); } @@ -729,7 +731,7 @@ string generate_opname_stratix10 (t_node* vqm_node, t_model* arch_models){ return mode_hash; } -void generate_opname_stratix10_dsp (t_node* vqm_node, t_model* /*arch_models*/, string& mode_hash, bool dsp_mode) { +void generate_opname_stratix10_dsp (t_node* vqm_node, string& mode_hash, bool dsp_mode) { // // It is not practical to model all of the internal registers of the mac block, as this // would significantly increase the size of the architecture description. As a result, we @@ -904,28 +906,6 @@ void clean_name(char* name) { } } -//============================================================================================ -//============================================================================================ -t_model* find_arch_model_by_name(string model_name, t_model* arch_models) { - /* - * Finds the archtecture module corresponding to the model_name string - * - * model_name : the model name to match - * arch_models: the head of the linked list of architecture models - * - * Returns: A pointer to the corresponding model (or NULL if not found) - */ - - //Find the correct model, by name matching - t_model* arch_model = arch_models; - while((arch_model) && (strcmp(model_name.c_str(), arch_model->name) != 0)) { - //Move to the next model - arch_model = arch_model->next; - } - - return arch_model; -} - //============================================================================================ //============================================================================================ diff --git a/utils/vqm2blif/src/base/vqm2blif_util.h b/utils/vqm2blif/src/base/vqm2blif_util.h index 314724e6226..45cc5adedf4 100644 --- a/utils/vqm2blif/src/base/vqm2blif_util.h +++ b/utils/vqm2blif/src/base/vqm2blif_util.h @@ -13,6 +13,7 @@ //these assignments are not observed. Buses in a VQM File are flattened into 1-bit wide assigns. //NOTE: The functionality of this option is untested. +#include "logic_types.h" #define MAX_LEN 350 //maximum length of a port/net name #define MAX_PPL 10 //maximum number of ports that can be put into one line of a BLIF @@ -175,22 +176,19 @@ void construct_filename (char* filename, const char* path, const char* ext); //c //Naming Conventions -string generate_opname (t_node* vqm_node, t_model* arch_models, string device); //generates a mode-hashed name for a subcircuit instance +string generate_opname (t_node* vqm_node, const LogicalModels& arch_models, string device); //generates a mode-hashed name for a subcircuit instance -void generate_opname_ram (t_node* vqm_node, t_model* arch_models, string& mode_hash, string device); //mode-hash for RAM blocks +void generate_opname_ram (t_node* vqm_node, const LogicalModels& arch_models, string& mode_hash, string device); //mode-hash for RAM blocks -string generate_opname_stratixiv (t_node* vqm_node, t_model* arch_models); //mode-hash for Stratix IV -void generate_opname_stratixiv_dsp_mult (t_node* vqm_node, t_model* arch_models, string& mode_hash); //mode-hash for Stratix IV DSP Multiplers -void generate_opname_stratixiv_dsp_out (t_node* vqm_node, t_model* arch_models, string& mode_hash); //mode-hash for Stratix IV DSP Output (MAC) +string generate_opname_stratixiv (t_node* vqm_node, const LogicalModels& arch_models); //mode-hash for Stratix IV +void generate_opname_stratixiv_dsp_mult (t_node* vqm_node, string& mode_hash); //mode-hash for Stratix IV DSP Multiplers +void generate_opname_stratixiv_dsp_out (t_node* vqm_node, string& mode_hash); //mode-hash for Stratix IV DSP Output (MAC) -string generate_opname_stratix10 (t_node* vqm_node, t_model* arch_models); //mode-hash for Stratix 10 -void generate_opname_stratix10_ram (t_node* vqm_node, t_model* arch_models, string& mode_hash); //mode-hash for Stratix 10 RAM blocks -void generate_opname_stratix10_dsp (t_node* vqm_node, t_model* arch_models, string& mode_hash, bool dsp_mode); //mode-hash for Stratix 10 DSP fixed point Multiplers +string generate_opname_stratix10 (t_node* vqm_node, const LogicalModels& arch_models); //mode-hash for Stratix 10 +void generate_opname_stratix10_dsp (t_node* vqm_node, string& mode_hash, bool dsp_mode); //mode-hash for Stratix 10 DSP fixed point Multiplers void generate_opname_stratix10_lut (t_node* vqm_node, string& mode_hash); //mode-hash for Stratix 10 LUTs void remap_lut_ports(t_node* vqm_node); // remaps the input ports of the LUT atom to the ports [dataa-datae] -t_model* find_arch_model_by_name(string model_name, t_model* arch_models); //returns the pointer to a module from the arch file, searches by name - string get_wire_name(t_pin_def* net, int index); //returns a string with the appropriate wire name string append_index_to_str (string busname, int index); //appends an integer index to the end of a string diff --git a/utils/vqm2blif/src/main.cpp b/utils/vqm2blif/src/main.cpp index 36c30b57e07..20e82c0ac2f 100644 --- a/utils/vqm2blif/src/main.cpp +++ b/utils/vqm2blif/src/main.cpp @@ -77,11 +77,13 @@ * For more, see "logic_types.h", "read_xml_arch_file.h" and "read_xml_arch_file.c" in libvpr *********************************************************************************************/ +#include "logic_types.h" #include "vqm2blif.h" #include "lut_stats.h" #include "vtr_error.h" #include "physical_types.h" #include "hard_block_recog.h" +#include "vtr_vector.h" #include @@ -97,8 +99,8 @@ lut_support_map supported_luts; //map structure for verifying a VQM primitive ag //LUT configurations (see lut_regoc.h & lut_recog.cpp) -int* model_count; //array of flags indicating whether a model read from - //the architecture was instantiated in the .vqm file. +vtr::vector model_count; //array of flags indicating whether a model read from + //the architecture was instantiated in the .vqm file. t_boolean debug_mode; //user-set flag causing the creation of intermediate files //with debug information. @@ -157,19 +159,19 @@ void cmd_line_parse (int argc, char** argv, string* sourcefile, string* archfile //Execution Functions void init_blif_models(t_blif_model* my_model, t_module* my_module, t_arch* arch, string device); - void subckt_prep(t_model* cur_model); + void subckt_prep(const LogicalModels& models); void init_blif_subckts (t_node **vqm_nodes, int number_of_vqm_nodes, - t_model *arch_models, t_blif_model* my_model, string device); + const LogicalModels& models, t_blif_model* my_model, string device); //1-to-1 Subcircuit Function //Translates one VQM Node into one BLIF Subcircuit, appends a mode-hash based on //parameters if elab_mode is MODES or MODES_TIMING. - void push_node_1_to_1 (t_node* vqm_node, t_model* arch_models, scktvec* blif_subckts, string device); + void push_node_1_to_1 (t_node* vqm_node, const LogicalModels& models, scktvec* blif_subckts, string device); //Atomize Subcircuit Function //Uses select parameters and a dictionary to atomize each block and //name it as the dictionary says. - void push_node_atomize (t_node* vqm_node, t_model* arch_models, scktvec* blif_subckts); + void push_node_atomize (t_node* vqm_node, const LogicalModels& models, scktvec* blif_subckts); //General Subcircuit Initialization //No matter the translation, models from the architecture get turned into @@ -187,7 +189,7 @@ void init_blif_models(t_blif_model* my_model, t_module* my_module, t_arch* arch, void dump_blif (char* blif_file, t_blif_model* main_model, t_arch* arch, t_boolean print_unused_subckt_pins); -void dump_main_model(t_blif_model* model, ofstream& outfile, t_boolean print_unused_subckt_pins, t_boolean eblif_format, t_boolean debug); +void dump_main_model(t_blif_model* model, ofstream& outfile, const LogicalModels& models, t_boolean print_unused_subckt_pins, t_boolean eblif_format, t_boolean debug); void dump_portlist (ofstream& outfile, pinvec ports, t_boolean debug); void dump_assignments(ofstream& outfile, t_blif_model* model, t_boolean eblif_format, t_boolean debug); @@ -208,7 +210,7 @@ void dump_wire_assign(ofstream& outfile, string target_name, void dump_luts (ofstream& outfile, lutvec* blif_luts, t_boolean eblif_format, t_boolean debug); -void dump_subckts(ofstream& outfile, scktvec* subckts, t_boolean print_unused_pins, t_boolean eblif_format, t_boolean debug); +void dump_subckts(ofstream& outfile, scktvec* subckts, const LogicalModels& models, t_boolean print_unused_pins, t_boolean eblif_format, t_boolean debug); void dump_subckt_map (ofstream& outfile, portmap* map, t_model_ports* temp_port, const char* inst_name, const char* maptype, int s_index, t_boolean print_unused_pins, t_boolean debug, bool last); @@ -216,7 +218,7 @@ size_t count_print_pins(t_model_ports* temp_port, portmap* map, t_boolean print_ void dump_subckt_portlist(ofstream& outfile, t_model_ports* port, string indent, t_boolean debug); -void dump_subckt_models(t_model* temp_model, ofstream& outfile, t_boolean debug); +void dump_subckt_models(const LogicalModels& models, ofstream& outfile, t_boolean debug); //Debug functions void echo_module (char* echo_file, const char* vqm_filename, t_module* my_module); @@ -224,7 +226,7 @@ void echo_module_pins (ofstream& outfile, t_module* module); void echo_module_assigns (ofstream& outfile, t_module* module); void echo_module_nodes (ofstream& outfile, t_module* module); void echo_blif_model (char* echo_file, const char* vqm_filename, - t_blif_model* my_model, t_model* temp_model); + t_blif_model* my_model, const LogicalModels& models); //Other Functions @@ -335,7 +337,7 @@ int main(int argc, char* argv[]) numTypes = logical_block_types.size(); VTR_ASSERT((types) && (numTypes > 0)); - VTR_ASSERT(arch.models != NULL); + VTR_ASSERT(!arch.models.user_models().empty()); //Pre-process the netlist // Currently this just 'cleans up' bi-directional inout pins @@ -858,7 +860,7 @@ void init_blif_models(t_blif_model* my_model, t_module* my_module, t_arch* arch, //============================================================================================ void init_blif_subckts ( t_node **vqm_nodes, int number_of_vqm_nodes, - t_model *arch_models, + const LogicalModels& models, t_blif_model* my_model, string device){ /* Initializes the subcircuits vector within a t_blif_model based on a t_node array. * @@ -876,8 +878,7 @@ void init_blif_subckts ( t_node **vqm_nodes, t_node* temp_node; //from vqm_dll.h //Preparations before the subcircuits can be assigned. - VTR_ASSERT(arch_models != NULL); - subckt_prep(arch_models); + subckt_prep(models); VTR_ASSERT((vqm_nodes != NULL)&&(vqm_nodes[0] != NULL)&&(number_of_vqm_nodes >= 0)); @@ -896,9 +897,9 @@ void init_blif_subckts ( t_node **vqm_nodes, if ((lut_mode == BLIF)&&(is_lut(temp_node))){ push_lut ( temp_node, &(my_model->luts) ); } else if ((elab_mode == NONE)||(elab_mode == MODES)||(elab_mode == MODES_TIMING)){ - push_node_1_to_1 (temp_node, arch_models, &(my_model->subckts), device); + push_node_1_to_1 (temp_node, models, &(my_model->subckts), device); } else if (elab_mode == ATOMS){ - push_node_atomize (temp_node, arch_models, &(my_model->subckts)); + push_node_atomize (temp_node, models, &(my_model->subckts)); } else { //Should never get here; a bad elab_mode should be rejected at parse-time cout << "\nERROR: Corrupted Elaboration Mode.\n" ; @@ -910,7 +911,7 @@ void init_blif_subckts ( t_node **vqm_nodes, //============================================================================================ //============================================================================================ -void subckt_prep(t_model* cur_model){ +void subckt_prep(const LogicalModels& models){ /* Accomplishes preparatory tasks before the subcircuits of a blif_model can be initialized. * * ARGUMENTS @@ -918,24 +919,10 @@ void subckt_prep(t_model* cur_model){ * Linked list containing all model information from the Architecture file. */ -//TASK 1: Find the maximum index among the models in the Architecture. - int max_model_index; - max_model_index = cur_model->index; - while(cur_model){ - //Cycle through the list, save the highest index. - if (cur_model->index > max_model_index){ - max_model_index = cur_model->index; - } - cur_model = cur_model->next; - } +//TASK 1: Allocate and initialize the model_count array (global). + model_count = vtr::vector(models.all_models().size(), 0); -//TASK 2: Allocate and initialize the model_count array (global). - model_count = (int*)malloc((max_model_index + 1)*sizeof(int)); - for (int i = 0; i <= max_model_index; i++){ - model_count[i] = 0; - } - -//TASK 3: Initialize the unconn and open_port structures. +//TASK 2: Initialize the unconn and open_port structures. unconn.name = strdup("unconn"); unconn.indexed = T_FALSE; unconn.type = PIN_WIRE; @@ -951,7 +938,7 @@ void subckt_prep(t_model* cur_model){ //============================================================================================ //============================================================================================ -void push_node_1_to_1 (t_node* vqm_node, t_model* arch_models, scktvec* blif_subckts, string device){ +void push_node_1_to_1 (t_node* vqm_node, const LogicalModels& models, scktvec* blif_subckts, string device){ /* Interprets each VQM block as a single instance of a BLIF subcircuit. Depending on * the global elab_mode, the Architecture will be searched either for the VQM block name as-is * or a name appended with a special mode-hash, generated from parameters of the VQM block. @@ -967,16 +954,12 @@ void push_node_1_to_1 (t_node* vqm_node, t_model* arch_models, scktvec* blif_sub //temporary process variables t_blif_subckt temp_subckt; //from vqm2blif.h - t_model* cur_model; //from physical_types.h boolvec vqm_ports_found; //verification flags indicating that all ports //found in the VQM were mapped. string search; //temporary variable to construct a desired block name within. - cur_model = arch_models; //search for the corresponding model in the list from the architecture. - VTR_ASSERT(cur_model != NULL); - temp_subckt.inst_name = (string)vqm_node->name; //copy the instance name VTR_ASSERT( !temp_subckt.inst_name.empty() ); @@ -987,7 +970,7 @@ void push_node_1_to_1 (t_node* vqm_node, t_model* arch_models, scktvec* blif_sub } else if (elab_mode == MODES || elab_mode == MODES_TIMING){ //search for an Architecture model based on the block name and the parameters - search = generate_opname(vqm_node, arch_models, device); //generate the simple mode-hashed name based on parameters. + search = generate_opname(vqm_node, models, device); //generate the simple mode-hashed name based on parameters. } else { //should never get here, based on condition in init_blif_subckts() @@ -1008,100 +991,100 @@ void push_node_1_to_1 (t_node* vqm_node, t_model* arch_models, scktvec* blif_sub cout << "\n\t\t>> Blackbox Identified." ; cout << "\n\t\t>> Searching Architecture for Model Data \""<< search << "\"" ; } - while ((cur_model)&&(strcmp(cur_model->name, search.c_str()) != 0)){ - cur_model = cur_model->next; - } + LogicalModelId model_id = models.get_model_by_name(search); //cur_model now points to either NULL or the appropriate Architecture model. - if (!cur_model){ + if (!model_id.is_valid()){ //cur_model == NULL if the end of the model list was reached without success. cout << "\n\nERROR: Model name " << search << " was not found in the architecture.\n" ; exit(1); - } else { - if (verbose_mode){ - cout << "\n\t\t>> Model " << search << " identified.\n" ; - } - temp_subckt.model_type = cur_model; //initialize model_type - model_count[cur_model->index]++; //increment the instance count of the model - temp_subckt.input_cnxns.clear(); //reset the input and output maps - temp_subckt.output_cnxns.clear(); - - //map the input ports of the model read from the architecture - //to the corresponding external pin as per the vqm - init_subckt_map( &(temp_subckt.input_cnxns), - temp_subckt.model_type->inputs, - vqm_node, &vqm_ports_found); - //vqm_ports_found entries are set as ports are mapped - - VTR_ASSERT(!temp_subckt.input_cnxns.empty()); //all blocks must have an input - - //now map the output ports - init_subckt_map( &(temp_subckt.output_cnxns), - temp_subckt.model_type->outputs, - vqm_node, &vqm_ports_found); - //vqm_ports_found entries are set as ports are mapped - - VTR_ASSERT(!temp_subckt.output_cnxns.empty()); //all blocks must have an output - - //Pass through parameters - for (int iparam = 0; iparam < vqm_node->number_of_params; ++iparam) { - t_subckt_param_attr param; - t_node_parameter* vqm_param = vqm_node->array_of_params[iparam]; - param.name = vqm_param->name; - - if (vqm_param->type == NODE_PARAMETER_STRING) { - param.value = vqm_param->value.string_value; - } else { - VTR_ASSERT(vqm_param->type == NODE_PARAMETER_INTEGER); - param.value = std::to_string(vqm_param->value.integer_value); - } - temp_subckt.params.push_back(param); + } + + if (verbose_mode){ + cout << "\n\t\t>> Model " << search << " identified.\n" ; + } + temp_subckt.model_type = model_id; //initialize model_type + model_count[model_id]++; //increment the instance count of the model + temp_subckt.input_cnxns.clear(); //reset the input and output maps + temp_subckt.output_cnxns.clear(); + + const t_model& model = models.get_model(model_id); + + //map the input ports of the model read from the architecture + //to the corresponding external pin as per the vqm + init_subckt_map( &(temp_subckt.input_cnxns), + model.inputs, + vqm_node, &vqm_ports_found); + //vqm_ports_found entries are set as ports are mapped + + VTR_ASSERT(!temp_subckt.input_cnxns.empty()); //all blocks must have an input + + //now map the output ports + init_subckt_map( &(temp_subckt.output_cnxns), + model.outputs, + vqm_node, &vqm_ports_found); + //vqm_ports_found entries are set as ports are mapped + + VTR_ASSERT(!temp_subckt.output_cnxns.empty()); //all blocks must have an output + + //Pass through parameters + for (int iparam = 0; iparam < vqm_node->number_of_params; ++iparam) { + t_subckt_param_attr param; + t_node_parameter* vqm_param = vqm_node->array_of_params[iparam]; + param.name = vqm_param->name; + + if (vqm_param->type == NODE_PARAMETER_STRING) { + param.value = vqm_param->value.string_value; + } else { + VTR_ASSERT(vqm_param->type == NODE_PARAMETER_INTEGER); + param.value = std::to_string(vqm_param->value.integer_value); } + temp_subckt.params.push_back(param); + } - //Verify that all ports specified in the VQM node were successfully mapped before - //committing the subcircuit to the BLIF structure. + //Verify that all ports specified in the VQM node were successfully mapped before + //committing the subcircuit to the BLIF structure. + if (verbose_mode){ + cout << "\t\tVQM Port Verification:\n" ; + } + for (int i = 0; i < vqm_node->number_of_ports; i++){ + /* The mapping process maps all ports of the architecture either to the open port or + * a port in the VQM. If a port appeared in the VQM and not in the + * architecture, the association's corresponding entry in vqm_ports_found would + * remain T_FALSE through the mapping process. + */ if (verbose_mode){ - cout << "\t\tVQM Port Verification:\n" ; - } - for (int i = 0; i < vqm_node->number_of_ports; i++){ - /* The mapping process maps all ports of the architecture either to the open port or - * a port in the VQM. If a port appeared in the VQM and not in the - * architecture, the association's corresponding entry in vqm_ports_found would - * remain T_FALSE through the mapping process. - */ - if (verbose_mode){ - //Print whether the port was mapped explicitly - //Prints "Port (port)[index] = [ mapped | unmapped ]" - cout << "\t\t\tPort " << vqm_node->array_of_ports[i]->port_name ; - - if (vqm_node->array_of_ports[i]->port_index >= 0){ - cout << "[" << vqm_node->array_of_ports[i]->port_index << "]" ; - } + //Print whether the port was mapped explicitly + //Prints "Port (port)[index] = [ mapped | unmapped ]" + cout << "\t\t\tPort " << vqm_node->array_of_ports[i]->port_name ; - cout <<"= " << ((vqm_ports_found[i])? "mapped":"unmapped") << endl; + if (vqm_node->array_of_ports[i]->port_index >= 0){ + cout << "[" << vqm_node->array_of_ports[i]->port_index << "]" ; } - if (vqm_ports_found[i] == T_FALSE){ - cout << "\n\nERROR: Port " << vqm_node->array_of_ports[i]->port_name ; - if (vqm_node->array_of_ports[i]->port_index >= 0){ - cout << "[" << vqm_node->array_of_ports[i]->port_index << "]" ; - } - cout << " not found in architecture for " << search << endl ; - exit(1); - } + cout <<"= " << ((vqm_ports_found[i])? "mapped":"unmapped") << endl; } - if (verbose_mode){ - cout << endl ; + + if (vqm_ports_found[i] == T_FALSE){ + cout << "\n\nERROR: Port " << vqm_node->array_of_ports[i]->port_name ; + if (vqm_node->array_of_ports[i]->port_index >= 0){ + cout << "[" << vqm_node->array_of_ports[i]->port_index << "]" ; + } + cout << " not found in architecture for " << search << endl ; + exit(1); } - //push the temp_subckt into the subckt vector - blif_subckts->push_back(temp_subckt); } + if (verbose_mode){ + cout << endl ; + } + //push the temp_subckt into the subckt vector + blif_subckts->push_back(temp_subckt); } //============================================================================================ //============================================================================================ -void push_node_atomize (t_node* /*vqm_node*/, t_model* /*arch_models*/, scktvec* /*blif_subckts*/ /*, FILE* dict*/){ +void push_node_atomize (t_node* /*vqm_node*/, const LogicalModels& /*models*/, scktvec* /*blif_subckts*/ /*, FILE* dict*/){ /* Interprets each VQM block and its parameter set, then expands that block into its smaller * atomic constituents based on a "Dictionary" document. * @@ -1336,7 +1319,7 @@ void dump_blif (char* blif_file, t_blif_model* main_model, t_arch* arch, t_boole blif_out << "\n#MAIN MODEL\n" ; //completely dump the top-level model - dump_main_model(main_model, blif_out, print_unused_subckt_pins_local, eblif_format, T_FALSE); + dump_main_model(main_model, blif_out, arch->models, print_unused_subckt_pins_local, eblif_format, T_FALSE); //now dump the subckt models from the architecture //that were used in the vqm @@ -1352,7 +1335,7 @@ void dump_blif (char* blif_file, t_blif_model* main_model, t_arch* arch, t_boole //============================================================================================ //============================================================================================ -void dump_main_model(t_blif_model* model, ofstream& outfile, t_boolean print_unused_subckt_pins_local, t_boolean eblif_format_local, t_boolean debug){ +void dump_main_model(t_blif_model* model, ofstream& outfile, const LogicalModels& models, t_boolean print_unused_subckt_pins_local, t_boolean eblif_format_local, t_boolean debug){ /* Dumps information stored in a model structure in proper BLIF syntax. * * ARGUMENTS @@ -1408,7 +1391,7 @@ void dump_main_model(t_blif_model* model, ofstream& outfile, t_boolean print_unu //Print Subcircuit Variable information if (model->subckts.size() > 0){ - dump_subckts(outfile, &(model->subckts), print_unused_subckt_pins_local, eblif_format_local, debug); + dump_subckts(outfile, &(model->subckts), models, print_unused_subckt_pins_local, eblif_format_local, debug); } //Printing the model data is complete. @@ -1718,7 +1701,7 @@ void dump_luts (ofstream& outfile, lutvec* blif_luts, t_boolean eblif_format_loc //============================================================================================ //============================================================================================ -void dump_subckts(ofstream& outfile, scktvec* subckts, t_boolean print_unused_pins, t_boolean eblif_format_local, t_boolean debug){ +void dump_subckts(ofstream& outfile, scktvec* subckts, const LogicalModels& models, t_boolean print_unused_pins, t_boolean eblif_format_local, t_boolean debug){ /* Traverse the subcircuit vector, printing the names and connections * of each instantiated subcircuit in the main model. * @@ -1738,15 +1721,16 @@ void dump_subckts(ofstream& outfile, scktvec* subckts, t_boolean print_unused_pi for(int i = 0; i < limit; i++){ //print each subcircuit's name, port, and connectivity information temp_subckt = &(subckts->at(i)); + const t_model& model_type = models.get_model(temp_subckt->model_type); if (debug){ outfile << "\nSubcircuit Number: " << i << endl; outfile << "Instance Name: " << temp_subckt->inst_name << endl; - outfile << "Type: " << temp_subckt->model_type->name << endl ; + outfile << "Type: " << model_type.name << endl ; } else { if (!eblif_format_local) { outfile << "\n# Subckt " << i << ": " << temp_subckt->inst_name << " \n"; } - outfile << ".subckt " << temp_subckt->model_type->name << " \\\n" ; + outfile << ".subckt " << model_type.name << " \\\n" ; } @@ -1754,13 +1738,13 @@ void dump_subckts(ofstream& outfile, scktvec* subckts, t_boolean print_unused_pi outfile << "Input Map:\n" ; } - size_t num_print_output_pins = count_print_pins(temp_subckt->model_type->outputs, &(temp_subckt->output_cnxns), print_unused_pins); + size_t num_print_output_pins = count_print_pins(model_type.outputs, &(temp_subckt->output_cnxns), print_unused_pins); //dump the input map containing connectivity data bool last = (num_print_output_pins == 0); dump_subckt_map(outfile, &(temp_subckt->input_cnxns), - temp_subckt->model_type->inputs, + model_type.inputs, temp_subckt->inst_name.c_str(), "input", i, print_unused_pins, @@ -1775,7 +1759,7 @@ void dump_subckts(ofstream& outfile, scktvec* subckts, t_boolean print_unused_pi last = true; dump_subckt_map(outfile, &(temp_subckt->output_cnxns), - temp_subckt->model_type->outputs, + model_type.outputs, temp_subckt->inst_name.c_str(), "output", i, print_unused_pins, @@ -1925,7 +1909,7 @@ size_t count_print_pins(t_model_ports* temp_port, portmap* map, t_boolean print_ //============================================================================================ //============================================================================================ -void dump_subckt_models(t_model* temp_model, ofstream& outfile, t_boolean debug){ +void dump_subckt_models(const LogicalModels& models, ofstream& outfile, t_boolean debug){ /* Cycles through all models declared in the architecture * and dumps the ones used by the VQM as blackbox models * at the end of the .blif file @@ -1938,27 +1922,29 @@ void dump_subckt_models(t_model* temp_model, ofstream& outfile, t_boolean debug) * flag to indicate whether to print in DEBUG or BLIF format. */ unsigned long total_block_count = 0; - while(temp_model){ - if (model_count[temp_model->index] > 0){ - //Count the number of blocks - total_block_count += model_count[temp_model->index]; - - //dump all .subckt models declared in the architecture - //Use the model_count array to only output the models that were used. - if (!debug){ - cout << "\t>> Introduced " << model_count[temp_model->index] << " instances of blackbox " << temp_model->name << endl; - } - outfile << ((debug)? "\n Model: " : "\n.model ") << temp_model->name << endl ; - - outfile << ((debug)? "Inputs:\n" : ".inputs \\\n") ; //cycle through all inputs - dump_subckt_portlist(outfile, temp_model->inputs, " ", debug); + for (LogicalModelId model_id : models.user_models()) { + if (model_count[model_id] == 0) + continue; + + //Count the number of blocks + total_block_count += model_count[model_id]; + + const t_model& model = models.get_model(model_id); - outfile << ((debug)? "Outputs:\n" : ".outputs \\\n") ; //cycle through all outputs - dump_subckt_portlist(outfile, temp_model->outputs, " ", debug); + //dump all .subckt models declared in the architecture + //Use the model_count array to only output the models that were used. + if (!debug){ + cout << "\t>> Introduced " << model_count[model_id] << " instances of blackbox " << model.name << endl; + } + outfile << ((debug)? "\n Model: " : "\n.model ") << model.name << endl ; + + outfile << ((debug)? "Inputs:\n" : ".inputs \\\n") ; //cycle through all inputs + dump_subckt_portlist(outfile, model.inputs, " ", debug); + + outfile << ((debug)? "Outputs:\n" : ".outputs \\\n") ; //cycle through all outputs + dump_subckt_portlist(outfile, model.outputs, " ", debug); - outfile << ((debug)? "\nEND MODEL\n" : ".blackbox\n.end\n") ; - } - temp_model = temp_model->next; + outfile << ((debug)? "\nEND MODEL\n" : ".blackbox\n.end\n") ; } cout << "\t>> Total Block Count: " << total_block_count; } @@ -2013,8 +1999,8 @@ void all_data_cleanup(){ */ vqm_data_cleanup();//found in ../LIB/vqm_dll.h, frees parser-allocated memory - free(model_count); - + model_count.clear(); + return; } @@ -2253,7 +2239,7 @@ void echo_module_nodes (ofstream& outfile, t_module* module){ //============================================================================================ void echo_blif_model (char* echo_file, const char* vqm_filename, - t_blif_model* my_model, t_model* temp_model) { + t_blif_model* my_model, const LogicalModels& models) { /* Prints all model data into a .txt for debugging * Used to ensure correct population of the parser data into the model. * @@ -2278,14 +2264,14 @@ void echo_blif_model (char* echo_file, const char* vqm_filename, model_out << "\n\tMAIN MODEL\n" ; //completely dump the top-level model in DEBUG format - dump_main_model(my_model, model_out, T_TRUE, T_TRUE, T_TRUE); + dump_main_model(my_model, model_out, models, T_TRUE, T_TRUE, T_TRUE); model_out << "\n\tSUBCKT MODELS\n"; //now dump the subckt models from the architecture //that were used in the VQM file, in DEBUG format. if (my_model->subckts.size() > 0){ - dump_subckt_models(temp_model, model_out, T_TRUE); + dump_subckt_models(models, model_out, T_TRUE); } // Close file. diff --git a/utils/vqm2blif/test/netlists/carpat/carpat_stratixiv_arch_timing.blif b/utils/vqm2blif/test/netlists/carpat/carpat_stratixiv_arch_timing.blif index 90a7e92bcfa..190d8cf395b 100644 --- a/utils/vqm2blif/test/netlists/carpat/carpat_stratixiv_arch_timing.blif +++ b/utils/vqm2blif/test/netlists/carpat/carpat_stratixiv_arch_timing.blif @@ -1,4 +1,4 @@ -#BLIF OUTPUT: titan_release_dev/benchmarks/other_benchmarks/carpat/netlists/carpat_stratixiv_arch_timing.blif +#BLIF OUTPUT: ./utils/vqm2blif/test/scripts/../netlists/carpat/carpat_stratixiv.golden.blif #MAIN MODEL @@ -264730,87 +264730,497 @@ #SUBCKT MODELS -.model stratixiv_pll.opmode{normal} +.model stratixiv_lcell_comb .inputs \ - scandata \ - scanclkena \ - scanclk \ - phaseupdown \ - phasestep \ - phasecounterselect[0] \ - phasecounterselect[1] \ - phasecounterselect[2] \ - phasecounterselect[3] \ - pfdena \ - inclk \ - fbin \ - configupdate \ - clkswitch \ - areset + sharein \ + cin \ + datag \ + dataf \ + datae \ + datad \ + datac \ + datab \ + dataa .outputs \ - vcounderrange \ - vcooverrange \ - scandone \ - scandataout \ - phasedone \ - locked \ - fbout \ - clkbad[0] \ - clkbad[1] \ - clk[0] \ - clk[1] \ - clk[2] \ - clk[3] \ - clk[4] \ - clk[5] \ - clk[6] \ - clk[7] \ - clk[8] \ - clk[9] \ - activeclock + shareout \ + cout \ + sumout \ + combout .blackbox .end -.model stratixiv_io_obuf +.model dffeas .inputs \ - parallelterminationcontrol[0] \ - parallelterminationcontrol[1] \ - parallelterminationcontrol[2] \ - parallelterminationcontrol[3] \ - parallelterminationcontrol[4] \ - parallelterminationcontrol[5] \ - parallelterminationcontrol[6] \ - parallelterminationcontrol[7] \ - parallelterminationcontrol[8] \ - parallelterminationcontrol[9] \ - parallelterminationcontrol[10] \ - parallelterminationcontrol[11] \ - parallelterminationcontrol[12] \ - parallelterminationcontrol[13] \ - seriesterminationcontrol[0] \ - seriesterminationcontrol[1] \ - seriesterminationcontrol[2] \ - seriesterminationcontrol[3] \ - seriesterminationcontrol[4] \ - seriesterminationcontrol[5] \ - seriesterminationcontrol[6] \ - seriesterminationcontrol[7] \ - seriesterminationcontrol[8] \ - seriesterminationcontrol[9] \ - seriesterminationcontrol[10] \ - seriesterminationcontrol[11] \ - seriesterminationcontrol[12] \ - seriesterminationcontrol[13] \ - dynamicterminationcontrol \ - oe \ - i + devpor \ + devclrn \ + d \ + sclr \ + sload \ + aload \ + asdata \ + clrn \ + prn \ + ena \ + clk .outputs \ - obar \ - o + q .blackbox .end -.model stratixiv_mac_out.opmode{double}.input_type{reg}.output_type{comb} +.model stratixiv_ram_block.opmode{dual_port}.output_type{reg}.port_a_address_width{9}.port_b_address_width{9} +.inputs \ + portbaddr[0] \ + portbaddr[1] \ + portbaddr[2] \ + portbaddr[3] \ + portbaddr[4] \ + portbaddr[5] \ + portbaddr[6] \ + portbaddr[7] \ + portbaddr[8] \ + portbaddrstall \ + portawe \ + clk_portbout \ + portbre \ + portaaddr[0] \ + portaaddr[1] \ + portaaddr[2] \ + portaaddr[3] \ + portaaddr[4] \ + portaaddr[5] \ + portaaddr[6] \ + portaaddr[7] \ + portaaddr[8] \ + portaaddrstall \ + clk_portaout \ + ena1 \ + ena0 \ + ena3 \ + ena2 \ + clk_portain \ + portabyteenamasks[0] \ + portabyteenamasks[1] \ + portabyteenamasks[2] \ + portabyteenamasks[3] \ + portabyteenamasks[4] \ + portabyteenamasks[5] \ + portabyteenamasks[6] \ + portabyteenamasks[7] \ + clk_portbin \ + clr0 \ + clr1 \ + portadatain +.outputs \ + eccstatus[0] \ + eccstatus[1] \ + eccstatus[2] \ + portbdataout +.blackbox +.end + +.model stratixiv_ram_block.opmode{dual_port}.output_type{reg}.port_a_address_width{6}.port_b_address_width{6} +.inputs \ + portbaddr[0] \ + portbaddr[1] \ + portbaddr[2] \ + portbaddr[3] \ + portbaddr[4] \ + portbaddr[5] \ + portbaddrstall \ + portawe \ + clk_portbout \ + portbre \ + portaaddr[0] \ + portaaddr[1] \ + portaaddr[2] \ + portaaddr[3] \ + portaaddr[4] \ + portaaddr[5] \ + portaaddrstall \ + clk_portaout \ + ena1 \ + ena0 \ + ena3 \ + ena2 \ + clk_portain \ + portabyteenamasks[0] \ + portabyteenamasks[1] \ + portabyteenamasks[2] \ + portabyteenamasks[3] \ + portabyteenamasks[4] \ + portabyteenamasks[5] \ + portabyteenamasks[6] \ + portabyteenamasks[7] \ + clk_portbin \ + clr0 \ + clr1 \ + portadatain +.outputs \ + eccstatus[0] \ + eccstatus[1] \ + eccstatus[2] \ + portbdataout +.blackbox +.end + +.model stratixiv_ram_block.opmode{dual_port}.output_type{reg}.port_a_address_width{5}.port_b_address_width{5} +.inputs \ + portbaddr[0] \ + portbaddr[1] \ + portbaddr[2] \ + portbaddr[3] \ + portbaddr[4] \ + portbaddrstall \ + portawe \ + clk_portbout \ + portbre \ + portaaddr[0] \ + portaaddr[1] \ + portaaddr[2] \ + portaaddr[3] \ + portaaddr[4] \ + portaaddrstall \ + clk_portaout \ + ena1 \ + ena0 \ + ena3 \ + ena2 \ + clk_portain \ + portabyteenamasks[0] \ + portabyteenamasks[1] \ + portabyteenamasks[2] \ + portabyteenamasks[3] \ + portabyteenamasks[4] \ + portabyteenamasks[5] \ + portabyteenamasks[6] \ + portabyteenamasks[7] \ + clk_portbin \ + clr0 \ + clr1 \ + portadatain +.outputs \ + eccstatus[0] \ + eccstatus[1] \ + eccstatus[2] \ + portbdataout +.blackbox +.end + +.model stratixiv_ram_block.opmode{dual_port}.output_type{reg}.port_a_address_width{4}.port_b_address_width{4} +.inputs \ + portbaddr[0] \ + portbaddr[1] \ + portbaddr[2] \ + portbaddr[3] \ + portbaddrstall \ + portawe \ + clk_portbout \ + portbre \ + portaaddr[0] \ + portaaddr[1] \ + portaaddr[2] \ + portaaddr[3] \ + portaaddrstall \ + clk_portaout \ + ena1 \ + ena0 \ + ena3 \ + ena2 \ + clk_portain \ + portabyteenamasks[0] \ + portabyteenamasks[1] \ + portabyteenamasks[2] \ + portabyteenamasks[3] \ + portabyteenamasks[4] \ + portabyteenamasks[5] \ + portabyteenamasks[6] \ + portabyteenamasks[7] \ + clk_portbin \ + clr0 \ + clr1 \ + portadatain +.outputs \ + eccstatus[0] \ + eccstatus[1] \ + eccstatus[2] \ + portbdataout +.blackbox +.end + +.model stratixiv_ram_block.opmode{dual_port}.output_type{reg}.port_a_address_width{3}.port_b_address_width{3} +.inputs \ + portbaddr[0] \ + portbaddr[1] \ + portbaddr[2] \ + portbaddrstall \ + portawe \ + clk_portbout \ + portbre \ + portaaddr[0] \ + portaaddr[1] \ + portaaddr[2] \ + portaaddrstall \ + clk_portaout \ + ena1 \ + ena0 \ + ena3 \ + ena2 \ + clk_portain \ + portabyteenamasks[0] \ + portabyteenamasks[1] \ + portabyteenamasks[2] \ + portabyteenamasks[3] \ + portabyteenamasks[4] \ + portabyteenamasks[5] \ + portabyteenamasks[6] \ + portabyteenamasks[7] \ + clk_portbin \ + clr0 \ + clr1 \ + portadatain +.outputs \ + eccstatus[0] \ + eccstatus[1] \ + eccstatus[2] \ + portbdataout +.blackbox +.end + +.model stratixiv_ram_block.opmode{dual_port}.output_type{reg}.port_a_address_width{2}.port_b_address_width{2} +.inputs \ + portbaddr[0] \ + portbaddr[1] \ + portbaddrstall \ + portawe \ + clk_portbout \ + portbre \ + portaaddr[0] \ + portaaddr[1] \ + portaaddrstall \ + clk_portaout \ + ena1 \ + ena0 \ + ena3 \ + ena2 \ + clk_portain \ + portabyteenamasks[0] \ + portabyteenamasks[1] \ + portabyteenamasks[2] \ + portabyteenamasks[3] \ + portabyteenamasks[4] \ + portabyteenamasks[5] \ + portabyteenamasks[6] \ + portabyteenamasks[7] \ + clk_portbin \ + clr0 \ + clr1 \ + portadatain +.outputs \ + eccstatus[0] \ + eccstatus[1] \ + eccstatus[2] \ + portbdataout +.blackbox +.end + +.model stratixiv_ram_block.opmode{rom}.output_type{reg}.port_a_address_width{10} +.inputs \ + clk_portaout \ + clk_portain \ + portaaddr[0] \ + portaaddr[1] \ + portaaddr[2] \ + portaaddr[3] \ + portaaddr[4] \ + portaaddr[5] \ + portaaddr[6] \ + portaaddr[7] \ + portaaddr[8] \ + portaaddr[9] \ + portaaddrstall \ + ena1 \ + ena0 \ + ena3 \ + ena2 \ + portare \ + clr0 \ + clr1 +.outputs \ + portadataout +.blackbox +.end + +.model stratixiv_ram_block.opmode{rom}.output_type{reg}.port_a_address_width{9} +.inputs \ + clk_portaout \ + clk_portain \ + portaaddr[0] \ + portaaddr[1] \ + portaaddr[2] \ + portaaddr[3] \ + portaaddr[4] \ + portaaddr[5] \ + portaaddr[6] \ + portaaddr[7] \ + portaaddr[8] \ + portaaddrstall \ + ena1 \ + ena0 \ + ena3 \ + ena2 \ + portare \ + clr0 \ + clr1 +.outputs \ + portadataout +.blackbox +.end + +.model stratixiv_ram_block.opmode{rom}.output_type{reg}.port_a_address_width{1} +.inputs \ + clk_portaout \ + clk_portain \ + portaaddr \ + portaaddrstall \ + ena1 \ + ena0 \ + ena3 \ + ena2 \ + portare \ + clr0 \ + clr1 +.outputs \ + portadataout +.blackbox +.end + +.model stratixiv_ram_block.opmode{rom}.output_type{reg}.port_a_address_width{0} +.inputs \ + clk_portaout \ + clk_portain \ + portaaddr \ + portaaddrstall \ + ena1 \ + ena0 \ + ena3 \ + ena2 \ + portare \ + clr0 \ + clr1 +.outputs \ + portadataout +.blackbox +.end + +.model stratixiv_mac_mult.input_type{comb} +.inputs \ + devpor \ + devclrn \ + aclr[0] \ + aclr[1] \ + aclr[2] \ + aclr[3] \ + ena[0] \ + ena[1] \ + ena[2] \ + ena[3] \ + signb \ + signa \ + datab[0] \ + datab[1] \ + datab[2] \ + datab[3] \ + datab[4] \ + datab[5] \ + datab[6] \ + datab[7] \ + datab[8] \ + datab[9] \ + datab[10] \ + datab[11] \ + datab[12] \ + datab[13] \ + datab[14] \ + datab[15] \ + datab[16] \ + datab[17] \ + dataa[0] \ + dataa[1] \ + dataa[2] \ + dataa[3] \ + dataa[4] \ + dataa[5] \ + dataa[6] \ + dataa[7] \ + dataa[8] \ + dataa[9] \ + dataa[10] \ + dataa[11] \ + dataa[12] \ + dataa[13] \ + dataa[14] \ + dataa[15] \ + dataa[16] \ + dataa[17] +.outputs \ + dataout[0] \ + dataout[1] \ + dataout[2] \ + dataout[3] \ + dataout[4] \ + dataout[5] \ + dataout[6] \ + dataout[7] \ + dataout[8] \ + dataout[9] \ + dataout[10] \ + dataout[11] \ + dataout[12] \ + dataout[13] \ + dataout[14] \ + dataout[15] \ + dataout[16] \ + dataout[17] \ + dataout[18] \ + dataout[19] \ + dataout[20] \ + dataout[21] \ + dataout[22] \ + dataout[23] \ + dataout[24] \ + dataout[25] \ + dataout[26] \ + dataout[27] \ + dataout[28] \ + dataout[29] \ + dataout[30] \ + dataout[31] \ + dataout[32] \ + dataout[33] \ + dataout[34] \ + dataout[35] \ + scanouta[0] \ + scanouta[1] \ + scanouta[2] \ + scanouta[3] \ + scanouta[4] \ + scanouta[5] \ + scanouta[6] \ + scanouta[7] \ + scanouta[8] \ + scanouta[9] \ + scanouta[10] \ + scanouta[11] \ + scanouta[12] \ + scanouta[13] \ + scanouta[14] \ + scanouta[15] \ + scanouta[16] \ + scanouta[17] +.blackbox +.end + +.model stratixiv_mac_out.opmode{36_bit_multiply}.input_type{comb}.output_type{comb} .inputs \ devpor \ devclrn \ @@ -264818,7 +265228,6 @@ aclr[1] \ aclr[2] \ aclr[3] \ - clk \ ena[0] \ ena[1] \ ena[2] \ @@ -265025,11 +265434,28 @@ dataout[51] \ dataout[52] \ dataout[53] \ - dataout[54] + dataout[54] \ + dataout[55] \ + dataout[56] \ + dataout[57] \ + dataout[58] \ + dataout[59] \ + dataout[60] \ + dataout[61] \ + dataout[62] \ + dataout[63] \ + dataout[64] \ + dataout[65] \ + dataout[66] \ + dataout[67] \ + dataout[68] \ + dataout[69] \ + dataout[70] \ + dataout[71] .blackbox .end -.model stratixiv_mac_out.opmode{double}.input_type{comb}.output_type{comb} +.model stratixiv_mac_out.opmode{36_bit_multiply}.input_type{comb}.output_type{reg} .inputs \ devpor \ devclrn \ @@ -265037,6 +265463,7 @@ aclr[1] \ aclr[2] \ aclr[3] \ + clk \ ena[0] \ ena[1] \ ena[2] \ @@ -265243,11 +265670,28 @@ dataout[51] \ dataout[52] \ dataout[53] \ - dataout[54] + dataout[54] \ + dataout[55] \ + dataout[56] \ + dataout[57] \ + dataout[58] \ + dataout[59] \ + dataout[60] \ + dataout[61] \ + dataout[62] \ + dataout[63] \ + dataout[64] \ + dataout[65] \ + dataout[66] \ + dataout[67] \ + dataout[68] \ + dataout[69] \ + dataout[70] \ + dataout[71] .blackbox .end -.model stratixiv_mac_out.opmode{36_bit_multiply}.input_type{comb}.output_type{reg} +.model stratixiv_mac_out.opmode{double}.input_type{comb}.output_type{comb} .inputs \ devpor \ devclrn \ @@ -265255,7 +265699,6 @@ aclr[1] \ aclr[2] \ aclr[3] \ - clk \ ena[0] \ ena[1] \ ena[2] \ @@ -265462,28 +265905,11 @@ dataout[51] \ dataout[52] \ dataout[53] \ - dataout[54] \ - dataout[55] \ - dataout[56] \ - dataout[57] \ - dataout[58] \ - dataout[59] \ - dataout[60] \ - dataout[61] \ - dataout[62] \ - dataout[63] \ - dataout[64] \ - dataout[65] \ - dataout[66] \ - dataout[67] \ - dataout[68] \ - dataout[69] \ - dataout[70] \ - dataout[71] + dataout[54] .blackbox .end -.model stratixiv_mac_out.opmode{36_bit_multiply}.input_type{comb}.output_type{comb} +.model stratixiv_mac_out.opmode{double}.input_type{reg}.output_type{comb} .inputs \ devpor \ devclrn \ @@ -265491,6 +265917,7 @@ aclr[1] \ aclr[2] \ aclr[3] \ + clk \ ena[0] \ ena[1] \ ena[2] \ @@ -265697,513 +266124,86 @@ dataout[51] \ dataout[52] \ dataout[53] \ - dataout[54] \ - dataout[55] \ - dataout[56] \ - dataout[57] \ - dataout[58] \ - dataout[59] \ - dataout[60] \ - dataout[61] \ - dataout[62] \ - dataout[63] \ - dataout[64] \ - dataout[65] \ - dataout[66] \ - dataout[67] \ - dataout[68] \ - dataout[69] \ - dataout[70] \ - dataout[71] -.blackbox -.end - -.model stratixiv_mac_mult.input_type{comb} -.inputs \ - devpor \ - devclrn \ - aclr[0] \ - aclr[1] \ - aclr[2] \ - aclr[3] \ - ena[0] \ - ena[1] \ - ena[2] \ - ena[3] \ - signb \ - signa \ - datab[0] \ - datab[1] \ - datab[2] \ - datab[3] \ - datab[4] \ - datab[5] \ - datab[6] \ - datab[7] \ - datab[8] \ - datab[9] \ - datab[10] \ - datab[11] \ - datab[12] \ - datab[13] \ - datab[14] \ - datab[15] \ - datab[16] \ - datab[17] \ - dataa[0] \ - dataa[1] \ - dataa[2] \ - dataa[3] \ - dataa[4] \ - dataa[5] \ - dataa[6] \ - dataa[7] \ - dataa[8] \ - dataa[9] \ - dataa[10] \ - dataa[11] \ - dataa[12] \ - dataa[13] \ - dataa[14] \ - dataa[15] \ - dataa[16] \ - dataa[17] -.outputs \ - dataout[0] \ - dataout[1] \ - dataout[2] \ - dataout[3] \ - dataout[4] \ - dataout[5] \ - dataout[6] \ - dataout[7] \ - dataout[8] \ - dataout[9] \ - dataout[10] \ - dataout[11] \ - dataout[12] \ - dataout[13] \ - dataout[14] \ - dataout[15] \ - dataout[16] \ - dataout[17] \ - dataout[18] \ - dataout[19] \ - dataout[20] \ - dataout[21] \ - dataout[22] \ - dataout[23] \ - dataout[24] \ - dataout[25] \ - dataout[26] \ - dataout[27] \ - dataout[28] \ - dataout[29] \ - dataout[30] \ - dataout[31] \ - dataout[32] \ - dataout[33] \ - dataout[34] \ - dataout[35] \ - scanouta[0] \ - scanouta[1] \ - scanouta[2] \ - scanouta[3] \ - scanouta[4] \ - scanouta[5] \ - scanouta[6] \ - scanouta[7] \ - scanouta[8] \ - scanouta[9] \ - scanouta[10] \ - scanouta[11] \ - scanouta[12] \ - scanouta[13] \ - scanouta[14] \ - scanouta[15] \ - scanouta[16] \ - scanouta[17] -.blackbox -.end - -.model stratixiv_ram_block.opmode{rom}.output_type{reg}.port_a_address_width{0} -.inputs \ - clk_portaout \ - clk_portain \ - portaaddr \ - portaaddrstall \ - ena1 \ - ena0 \ - ena3 \ - ena2 \ - portare \ - clr0 \ - clr1 -.outputs \ - portadataout -.blackbox -.end - -.model stratixiv_ram_block.opmode{rom}.output_type{reg}.port_a_address_width{1} -.inputs \ - clk_portaout \ - clk_portain \ - portaaddr \ - portaaddrstall \ - ena1 \ - ena0 \ - ena3 \ - ena2 \ - portare \ - clr0 \ - clr1 -.outputs \ - portadataout -.blackbox -.end - -.model stratixiv_ram_block.opmode{rom}.output_type{reg}.port_a_address_width{9} -.inputs \ - clk_portaout \ - clk_portain \ - portaaddr[0] \ - portaaddr[1] \ - portaaddr[2] \ - portaaddr[3] \ - portaaddr[4] \ - portaaddr[5] \ - portaaddr[6] \ - portaaddr[7] \ - portaaddr[8] \ - portaaddrstall \ - ena1 \ - ena0 \ - ena3 \ - ena2 \ - portare \ - clr0 \ - clr1 -.outputs \ - portadataout -.blackbox -.end - -.model stratixiv_ram_block.opmode{rom}.output_type{reg}.port_a_address_width{10} -.inputs \ - clk_portaout \ - clk_portain \ - portaaddr[0] \ - portaaddr[1] \ - portaaddr[2] \ - portaaddr[3] \ - portaaddr[4] \ - portaaddr[5] \ - portaaddr[6] \ - portaaddr[7] \ - portaaddr[8] \ - portaaddr[9] \ - portaaddrstall \ - ena1 \ - ena0 \ - ena3 \ - ena2 \ - portare \ - clr0 \ - clr1 -.outputs \ - portadataout -.blackbox -.end - -.model stratixiv_ram_block.opmode{dual_port}.output_type{reg}.port_a_address_width{2}.port_b_address_width{2} -.inputs \ - portbaddr[0] \ - portbaddr[1] \ - portbaddrstall \ - portawe \ - clk_portbout \ - portbre \ - portaaddr[0] \ - portaaddr[1] \ - portaaddrstall \ - clk_portaout \ - ena1 \ - ena0 \ - ena3 \ - ena2 \ - clk_portain \ - portabyteenamasks[0] \ - portabyteenamasks[1] \ - portabyteenamasks[2] \ - portabyteenamasks[3] \ - portabyteenamasks[4] \ - portabyteenamasks[5] \ - portabyteenamasks[6] \ - portabyteenamasks[7] \ - clk_portbin \ - clr0 \ - clr1 \ - portadatain -.outputs \ - eccstatus[0] \ - eccstatus[1] \ - eccstatus[2] \ - portbdataout -.blackbox -.end - -.model stratixiv_ram_block.opmode{dual_port}.output_type{reg}.port_a_address_width{3}.port_b_address_width{3} -.inputs \ - portbaddr[0] \ - portbaddr[1] \ - portbaddr[2] \ - portbaddrstall \ - portawe \ - clk_portbout \ - portbre \ - portaaddr[0] \ - portaaddr[1] \ - portaaddr[2] \ - portaaddrstall \ - clk_portaout \ - ena1 \ - ena0 \ - ena3 \ - ena2 \ - clk_portain \ - portabyteenamasks[0] \ - portabyteenamasks[1] \ - portabyteenamasks[2] \ - portabyteenamasks[3] \ - portabyteenamasks[4] \ - portabyteenamasks[5] \ - portabyteenamasks[6] \ - portabyteenamasks[7] \ - clk_portbin \ - clr0 \ - clr1 \ - portadatain -.outputs \ - eccstatus[0] \ - eccstatus[1] \ - eccstatus[2] \ - portbdataout -.blackbox -.end - -.model stratixiv_ram_block.opmode{dual_port}.output_type{reg}.port_a_address_width{4}.port_b_address_width{4} -.inputs \ - portbaddr[0] \ - portbaddr[1] \ - portbaddr[2] \ - portbaddr[3] \ - portbaddrstall \ - portawe \ - clk_portbout \ - portbre \ - portaaddr[0] \ - portaaddr[1] \ - portaaddr[2] \ - portaaddr[3] \ - portaaddrstall \ - clk_portaout \ - ena1 \ - ena0 \ - ena3 \ - ena2 \ - clk_portain \ - portabyteenamasks[0] \ - portabyteenamasks[1] \ - portabyteenamasks[2] \ - portabyteenamasks[3] \ - portabyteenamasks[4] \ - portabyteenamasks[5] \ - portabyteenamasks[6] \ - portabyteenamasks[7] \ - clk_portbin \ - clr0 \ - clr1 \ - portadatain -.outputs \ - eccstatus[0] \ - eccstatus[1] \ - eccstatus[2] \ - portbdataout -.blackbox -.end - -.model stratixiv_ram_block.opmode{dual_port}.output_type{reg}.port_a_address_width{5}.port_b_address_width{5} -.inputs \ - portbaddr[0] \ - portbaddr[1] \ - portbaddr[2] \ - portbaddr[3] \ - portbaddr[4] \ - portbaddrstall \ - portawe \ - clk_portbout \ - portbre \ - portaaddr[0] \ - portaaddr[1] \ - portaaddr[2] \ - portaaddr[3] \ - portaaddr[4] \ - portaaddrstall \ - clk_portaout \ - ena1 \ - ena0 \ - ena3 \ - ena2 \ - clk_portain \ - portabyteenamasks[0] \ - portabyteenamasks[1] \ - portabyteenamasks[2] \ - portabyteenamasks[3] \ - portabyteenamasks[4] \ - portabyteenamasks[5] \ - portabyteenamasks[6] \ - portabyteenamasks[7] \ - clk_portbin \ - clr0 \ - clr1 \ - portadatain -.outputs \ - eccstatus[0] \ - eccstatus[1] \ - eccstatus[2] \ - portbdataout -.blackbox -.end - -.model stratixiv_ram_block.opmode{dual_port}.output_type{reg}.port_a_address_width{6}.port_b_address_width{6} -.inputs \ - portbaddr[0] \ - portbaddr[1] \ - portbaddr[2] \ - portbaddr[3] \ - portbaddr[4] \ - portbaddr[5] \ - portbaddrstall \ - portawe \ - clk_portbout \ - portbre \ - portaaddr[0] \ - portaaddr[1] \ - portaaddr[2] \ - portaaddr[3] \ - portaaddr[4] \ - portaaddr[5] \ - portaaddrstall \ - clk_portaout \ - ena1 \ - ena0 \ - ena3 \ - ena2 \ - clk_portain \ - portabyteenamasks[0] \ - portabyteenamasks[1] \ - portabyteenamasks[2] \ - portabyteenamasks[3] \ - portabyteenamasks[4] \ - portabyteenamasks[5] \ - portabyteenamasks[6] \ - portabyteenamasks[7] \ - clk_portbin \ - clr0 \ - clr1 \ - portadatain -.outputs \ - eccstatus[0] \ - eccstatus[1] \ - eccstatus[2] \ - portbdataout -.blackbox -.end - -.model stratixiv_ram_block.opmode{dual_port}.output_type{reg}.port_a_address_width{9}.port_b_address_width{9} -.inputs \ - portbaddr[0] \ - portbaddr[1] \ - portbaddr[2] \ - portbaddr[3] \ - portbaddr[4] \ - portbaddr[5] \ - portbaddr[6] \ - portbaddr[7] \ - portbaddr[8] \ - portbaddrstall \ - portawe \ - clk_portbout \ - portbre \ - portaaddr[0] \ - portaaddr[1] \ - portaaddr[2] \ - portaaddr[3] \ - portaaddr[4] \ - portaaddr[5] \ - portaaddr[6] \ - portaaddr[7] \ - portaaddr[8] \ - portaaddrstall \ - clk_portaout \ - ena1 \ - ena0 \ - ena3 \ - ena2 \ - clk_portain \ - portabyteenamasks[0] \ - portabyteenamasks[1] \ - portabyteenamasks[2] \ - portabyteenamasks[3] \ - portabyteenamasks[4] \ - portabyteenamasks[5] \ - portabyteenamasks[6] \ - portabyteenamasks[7] \ - clk_portbin \ - clr0 \ - clr1 \ - portadatain -.outputs \ - eccstatus[0] \ - eccstatus[1] \ - eccstatus[2] \ - portbdataout + dataout[54] .blackbox .end -.model dffeas +.model stratixiv_io_obuf .inputs \ - devpor \ - devclrn \ - d \ - sclr \ - sload \ - aload \ - asdata \ - clrn \ - prn \ - ena \ - clk + parallelterminationcontrol[0] \ + parallelterminationcontrol[1] \ + parallelterminationcontrol[2] \ + parallelterminationcontrol[3] \ + parallelterminationcontrol[4] \ + parallelterminationcontrol[5] \ + parallelterminationcontrol[6] \ + parallelterminationcontrol[7] \ + parallelterminationcontrol[8] \ + parallelterminationcontrol[9] \ + parallelterminationcontrol[10] \ + parallelterminationcontrol[11] \ + parallelterminationcontrol[12] \ + parallelterminationcontrol[13] \ + seriesterminationcontrol[0] \ + seriesterminationcontrol[1] \ + seriesterminationcontrol[2] \ + seriesterminationcontrol[3] \ + seriesterminationcontrol[4] \ + seriesterminationcontrol[5] \ + seriesterminationcontrol[6] \ + seriesterminationcontrol[7] \ + seriesterminationcontrol[8] \ + seriesterminationcontrol[9] \ + seriesterminationcontrol[10] \ + seriesterminationcontrol[11] \ + seriesterminationcontrol[12] \ + seriesterminationcontrol[13] \ + dynamicterminationcontrol \ + oe \ + i .outputs \ - q + obar \ + o .blackbox .end -.model stratixiv_lcell_comb +.model stratixiv_pll.opmode{normal} .inputs \ - sharein \ - cin \ - datag \ - dataf \ - datae \ - datad \ - datac \ - datab \ - dataa + scandata \ + scanclkena \ + scanclk \ + phaseupdown \ + phasestep \ + phasecounterselect[0] \ + phasecounterselect[1] \ + phasecounterselect[2] \ + phasecounterselect[3] \ + pfdena \ + inclk \ + fbin \ + configupdate \ + clkswitch \ + areset .outputs \ - shareout \ - cout \ - sumout \ - combout + vcounderrange \ + vcooverrange \ + scandone \ + scandataout \ + phasedone \ + locked \ + fbout \ + clkbad[0] \ + clkbad[1] \ + clk[0] \ + clk[1] \ + clk[2] \ + clk[3] \ + clk[4] \ + clk[5] \ + clk[6] \ + clk[7] \ + clk[8] \ + clk[9] \ + activeclock .blackbox .end diff --git a/utils/vqm2blif/test/netlists/murax/murax_stratixiv_arch_timing.blif b/utils/vqm2blif/test/netlists/murax/murax_stratixiv_arch_timing.blif index 8ae3d5e3def..5d4fad42dde 100644 --- a/utils/vqm2blif/test/netlists/murax/murax_stratixiv_arch_timing.blif +++ b/utils/vqm2blif/test/netlists/murax/murax_stratixiv_arch_timing.blif @@ -1,4 +1,4 @@ -#BLIF OUTPUT: titan_release_dev/benchmarks/other_benchmarks/murax/netlists/murax_stratixiv_arch_timing.blif +#BLIF OUTPUT: ./utils/vqm2blif/test/scripts/../netlists/murax/murax_stratixiv.golden.blif #MAIN MODEL @@ -18187,12 +18187,55 @@ #SUBCKT MODELS -.model stratixiv_ram_block.opmode{dual_port}.output_type{comb}.port_a_address_width{4}.port_b_address_width{4} +.model stratixiv_lcell_comb +.inputs \ + sharein \ + cin \ + datag \ + dataf \ + datae \ + datad \ + datac \ + datab \ + dataa +.outputs \ + shareout \ + cout \ + sumout \ + combout +.blackbox +.end + +.model dffeas +.inputs \ + devpor \ + devclrn \ + d \ + sclr \ + sload \ + aload \ + asdata \ + clrn \ + prn \ + ena \ + clk +.outputs \ + q +.blackbox +.end + +.model stratixiv_ram_block.opmode{dual_port}.output_type{comb}.port_a_address_width{10}.port_b_address_width{10} .inputs \ portbaddr[0] \ portbaddr[1] \ portbaddr[2] \ portbaddr[3] \ + portbaddr[4] \ + portbaddr[5] \ + portbaddr[6] \ + portbaddr[7] \ + portbaddr[8] \ + portbaddr[9] \ portbaddrstall \ portawe \ clk_portbout \ @@ -18201,6 +18244,12 @@ portaaddr[1] \ portaaddr[2] \ portaaddr[3] \ + portaaddr[4] \ + portaaddr[5] \ + portaaddr[6] \ + portaaddr[7] \ + portaaddr[8] \ + portaaddr[9] \ portaaddrstall \ clk_portaout \ ena1 \ @@ -18271,18 +18320,12 @@ .blackbox .end -.model stratixiv_ram_block.opmode{dual_port}.output_type{comb}.port_a_address_width{10}.port_b_address_width{10} +.model stratixiv_ram_block.opmode{dual_port}.output_type{comb}.port_a_address_width{4}.port_b_address_width{4} .inputs \ portbaddr[0] \ portbaddr[1] \ portbaddr[2] \ portbaddr[3] \ - portbaddr[4] \ - portbaddr[5] \ - portbaddr[6] \ - portbaddr[7] \ - portbaddr[8] \ - portbaddr[9] \ portbaddrstall \ portawe \ clk_portbout \ @@ -18291,12 +18334,6 @@ portaaddr[1] \ portaaddr[2] \ portaaddr[3] \ - portaaddr[4] \ - portaaddr[5] \ - portaaddr[6] \ - portaaddr[7] \ - portaaddr[8] \ - portaaddr[9] \ portaaddrstall \ clk_portaout \ ena1 \ @@ -18323,40 +18360,3 @@ portbdataout .blackbox .end - -.model dffeas -.inputs \ - devpor \ - devclrn \ - d \ - sclr \ - sload \ - aload \ - asdata \ - clrn \ - prn \ - ena \ - clk -.outputs \ - q -.blackbox -.end - -.model stratixiv_lcell_comb -.inputs \ - sharein \ - cin \ - datag \ - dataf \ - datae \ - datad \ - datac \ - datab \ - dataa -.outputs \ - shareout \ - cout \ - sumout \ - combout -.blackbox -.end diff --git a/utils/vqm2blif/test/netlists/ucsb_152_tap_fir/ucsb_152_tap_fir_stratixiv_arch_timing.blif b/utils/vqm2blif/test/netlists/ucsb_152_tap_fir/ucsb_152_tap_fir_stratixiv_arch_timing.blif index a7ed3f84596..cab3e1222dc 100644 --- a/utils/vqm2blif/test/netlists/ucsb_152_tap_fir/ucsb_152_tap_fir_stratixiv_arch_timing.blif +++ b/utils/vqm2blif/test/netlists/ucsb_152_tap_fir/ucsb_152_tap_fir_stratixiv_arch_timing.blif @@ -1,4 +1,4 @@ -#BLIF OUTPUT: titan_release_dev/benchmarks/other_benchmarks/ucsb_152_tap_fir/netlists/ucsb_152_tap_fir_stratixiv_arch_timing.blif +#BLIF OUTPUT: ./utils/vqm2blif/test/scripts/../netlists/ucsb_152_tap_fir/ucsb_152_tap_fir_stratixiv.golden.blif #MAIN MODEL @@ -132420,24 +132420,6 @@ #SUBCKT MODELS -.model dffeas -.inputs \ - devpor \ - devclrn \ - d \ - sclr \ - sload \ - aload \ - asdata \ - clrn \ - prn \ - ena \ - clk -.outputs \ - q -.blackbox -.end - .model stratixiv_lcell_comb .inputs \ sharein \ @@ -132456,3 +132438,21 @@ combout .blackbox .end + +.model dffeas +.inputs \ + devpor \ + devclrn \ + d \ + sclr \ + sload \ + aload \ + asdata \ + clrn \ + prn \ + ena \ + clk +.outputs \ + q +.blackbox +.end diff --git a/vpr/src/analysis/timing_reports.cpp b/vpr/src/analysis/timing_reports.cpp index 542269395c5..281a40b67a0 100644 --- a/vpr/src/analysis/timing_reports.cpp +++ b/vpr/src/analysis/timing_reports.cpp @@ -1,7 +1,5 @@ #include "timing_reports.h" -#include "vtr_log.h" - #include "tatum/TimingReporter.hpp" #include "vpr_types.h" @@ -20,10 +18,11 @@ void generate_setup_timing_stats(const std::string& prefix, const BlkLocRegistry& blk_loc_registry) { auto& timing_ctx = g_vpr_ctx.timing(); auto& atom_ctx = g_vpr_ctx.atom(); + const LogicalModels& models = g_vpr_ctx.device().arch->models; print_setup_timing_summary(*timing_ctx.constraints, *timing_info.setup_analyzer(), "Final ", analysis_opts.write_timing_summary); - VprTimingGraphResolver resolver(atom_ctx.netlist(), atom_ctx.lookup(), *timing_ctx.graph, delay_calc, is_flat, blk_loc_registry); + VprTimingGraphResolver resolver(atom_ctx.netlist(), atom_ctx.lookup(), models, *timing_ctx.graph, delay_calc, is_flat, blk_loc_registry); resolver.set_detail_level(analysis_opts.timing_report_detail); tatum::TimingReporter timing_reporter(resolver, *timing_ctx.graph, *timing_ctx.constraints); @@ -45,10 +44,11 @@ void generate_hold_timing_stats(const std::string& prefix, const BlkLocRegistry& blk_loc_registry) { auto& timing_ctx = g_vpr_ctx.timing(); auto& atom_ctx = g_vpr_ctx.atom(); + const LogicalModels& models = g_vpr_ctx.device().arch->models; print_hold_timing_summary(*timing_ctx.constraints, *timing_info.hold_analyzer(), "Final "); - VprTimingGraphResolver resolver(atom_ctx.netlist(), atom_ctx.lookup(), *timing_ctx.graph, delay_calc, is_flat, blk_loc_registry); + VprTimingGraphResolver resolver(atom_ctx.netlist(), atom_ctx.lookup(), models, *timing_ctx.graph, delay_calc, is_flat, blk_loc_registry); resolver.set_detail_level(analysis_opts.timing_report_detail); tatum::TimingReporter timing_reporter(resolver, *timing_ctx.graph, *timing_ctx.constraints); diff --git a/vpr/src/analytical_place/analytical_placement_flow.cpp b/vpr/src/analytical_place/analytical_placement_flow.cpp index 853f4cb2f02..1b0f3885559 100644 --- a/vpr/src/analytical_place/analytical_placement_flow.cpp +++ b/vpr/src/analytical_place/analytical_placement_flow.cpp @@ -159,7 +159,7 @@ void run_analytical_placement_flow(t_vpr_setup& vpr_setup) { const UserPlaceConstraints& constraints = g_vpr_ctx.floorplanning().constraints; // Run the prepacker - const Prepacker prepacker(atom_nlist, device_ctx.logical_block_types); + const Prepacker prepacker(atom_nlist, device_ctx.arch->models, device_ctx.logical_block_types); // Create the ap netlist from the atom netlist using the result from the // prepacker. diff --git a/vpr/src/analytical_place/flat_placement_mass_calculator.cpp b/vpr/src/analytical_place/flat_placement_mass_calculator.cpp index c99aaf29339..d9978cdad82 100644 --- a/vpr/src/analytical_place/flat_placement_mass_calculator.cpp +++ b/vpr/src/analytical_place/flat_placement_mass_calculator.cpp @@ -25,9 +25,9 @@ * TODO: This will be made more complicated later. Models may be weighted based * on some factors. */ -static float get_model_mass(const t_model* model) { +static float get_model_mass(LogicalModelId model_id) { // Currently, all models have a mass of one. - (void)model; + (void)model_id; return 1.f; } @@ -69,10 +69,9 @@ static PrimitiveVector calc_pb_type_capacity(const t_pb_type* pb_type) { PrimitiveVector capacity; // If this is a leaf / primitive, create the base PrimitiveVector capacity. if (pb_type->num_modes == 0) { - const t_model* model = pb_type->model; - VTR_ASSERT(model != nullptr); - VTR_ASSERT_DEBUG(model->index >= 0); - capacity.add_val_to_dim(get_model_mass(model), model->index); + LogicalModelId model_id = pb_type->model_id; + VTR_ASSERT(model_id.is_valid()); + capacity.add_val_to_dim(get_model_mass(model_id), (size_t)model_id); return capacity; } // For now, we simply mix the capacities of modes by taking the max of each @@ -167,9 +166,9 @@ static PrimitiveVector calc_block_mass(APBlockId blk_id, // safely be ignored. if (!atom_blk_id.is_valid()) continue; - const t_model* model = atom_netlist.block_model(atom_blk_id); - VTR_ASSERT_DEBUG(model->index >= 0); - mass.add_val_to_dim(get_model_mass(model), model->index); + LogicalModelId model_id = atom_netlist.block_model(atom_blk_id); + VTR_ASSERT(model_id.is_valid()); + mass.add_val_to_dim(get_model_mass(model_id), (size_t)model_id); } return mass; } @@ -182,38 +181,22 @@ static void print_capacities(const std::vector& logical_block_t const std::vector& physical_tile_type_capacities, const std::vector& logical_block_types, const std::vector& physical_tile_types) { - // Get a linear list of all models. - // TODO: I do not like using the global context here, but these models - // should be stable in VTR. If they were stored better, we may be - // able to pass them in. - std::vector all_models; - t_model* curr_model = g_vpr_ctx.device().arch->models; - while (curr_model != nullptr) { - if (curr_model->index >= (int)all_models.size()) - all_models.resize(curr_model->index + 1); - all_models[curr_model->index] = curr_model; - curr_model = curr_model->next; - } - curr_model = g_vpr_ctx.device().arch->model_library; - while (curr_model != nullptr) { - if (curr_model->index >= (int)all_models.size()) - all_models.resize(curr_model->index + 1); - all_models[curr_model->index] = curr_model; - curr_model = curr_model->next; - } + // TODO: Pass these into this function. + const LogicalModels& models = g_vpr_ctx.device().arch->models; + // Print the capacities. VTR_LOG("Logical Block Type Capacities:\n"); VTR_LOG("------------------------------\n"); VTR_LOG("name\t"); - for (t_model* model : all_models) { - VTR_LOG("%s\t", model->name); + for (LogicalModelId model_id : models.all_models()) { + VTR_LOG("%s\t", models.get_model(model_id).name); } VTR_LOG("\n"); for (const t_logical_block_type& block_type : logical_block_types) { const PrimitiveVector& capacity = logical_block_type_capacities[block_type.index]; VTR_LOG("%s\t", block_type.name.c_str()); - for (t_model* model : all_models) { - VTR_LOG("%.2f\t", capacity.get_dim_val(model->index)); + for (LogicalModelId model_id : models.all_models()) { + VTR_LOG("%.2f\t", capacity.get_dim_val((size_t)model_id)); } VTR_LOG("\n"); } @@ -221,15 +204,15 @@ static void print_capacities(const std::vector& logical_block_t VTR_LOG("Physical Tile Type Capacities:\n"); VTR_LOG("------------------------------\n"); VTR_LOG("name\t"); - for (t_model* model : all_models) { - VTR_LOG("%s\t", model->name); + for (LogicalModelId model_id : models.all_models()) { + VTR_LOG("%s\t", models.get_model(model_id).name); } VTR_LOG("\n"); for (const t_physical_tile_type& tile_type : physical_tile_types) { const PrimitiveVector& capacity = physical_tile_type_capacities[tile_type.index]; VTR_LOG("%s\t", tile_type.name.c_str()); - for (t_model* model : all_models) { - VTR_LOG("%.2f\t", capacity.get_dim_val(model->index)); + for (LogicalModelId model_id : models.all_models()) { + VTR_LOG("%.2f\t", capacity.get_dim_val((size_t)model_id)); } VTR_LOG("\n"); } diff --git a/vpr/src/analytical_place/full_legalizer.cpp b/vpr/src/analytical_place/full_legalizer.cpp index 767ac67e3d9..7b7cc9cfb39 100644 --- a/vpr/src/analytical_place/full_legalizer.cpp +++ b/vpr/src/analytical_place/full_legalizer.cpp @@ -249,7 +249,7 @@ class APClusterPlacer { static LegalizationClusterId create_new_cluster(PackMoleculeId seed_molecule_id, const Prepacker& prepacker, ClusterLegalizer& cluster_legalizer, - const std::map>& primitive_candidate_block_types) { + const vtr::vector>& primitive_candidate_block_types) { const AtomContext& atom_ctx = g_vpr_ctx.atom(); // This was stolen from pack/cluster_util.cpp:start_new_cluster // It tries to find a block type and mode for the given molecule. @@ -260,11 +260,11 @@ static LegalizationClusterId create_new_cluster(PackMoleculeId seed_molecule_id, VTR_ASSERT(seed_molecule_id.is_valid()); const t_pack_molecule& seed_molecule = prepacker.get_molecule(seed_molecule_id); AtomBlockId root_atom = seed_molecule.atom_block_ids[seed_molecule.root]; - const t_model* root_model = atom_ctx.netlist().block_model(root_atom); + LogicalModelId root_model_id = atom_ctx.netlist().block_model(root_atom); - auto itr = primitive_candidate_block_types.find(root_model); - VTR_ASSERT(itr != primitive_candidate_block_types.end()); - const std::vector& candidate_types = itr->second; + VTR_ASSERT(root_model_id.is_valid()); + VTR_ASSERT(!primitive_candidate_block_types[root_model_id].empty()); + const std::vector& candidate_types = primitive_candidate_block_types[root_model_id]; for (t_logical_block_type_ptr type : candidate_types) { int num_modes = type->pb_graph_head->pb_type->num_modes; @@ -295,6 +295,7 @@ void NaiveFullLegalizer::create_clusters(const PartialPlacement& p_placement) { high_fanout_thresholds, ClusterLegalizationStrategy::FULL, vpr_setup_.PackerOpts.enable_pin_feasibility_filter, + arch_.models, vpr_setup_.PackerOpts.pack_verbosity); // Create clusters for each tile. // Start by giving each root tile a unique ID. @@ -328,7 +329,7 @@ void NaiveFullLegalizer::create_clusters(const PartialPlacement& p_placement) { blocks_in_tiles[tile_id].push_back(ap_blk_id); } // Create the legalized clusters per tile. - std::map> + vtr::vector> primitive_candidate_block_types = identify_primitive_candidate_block_types(); for (size_t tile_id_idx = 0; tile_id_idx < num_device_tiles; tile_id_idx++) { DeviceTileId tile_id = DeviceTileId(tile_id_idx); diff --git a/vpr/src/analytical_place/model_grouper.cpp b/vpr/src/analytical_place/model_grouper.cpp index 0aca963c96a..1c74c7cdac3 100644 --- a/vpr/src/analytical_place/model_grouper.cpp +++ b/vpr/src/analytical_place/model_grouper.cpp @@ -8,7 +8,6 @@ #include "model_grouper.h" #include -#include #include #include #include "cad_types.h" @@ -16,6 +15,7 @@ #include "prepack.h" #include "vtr_assert.h" #include "vtr_log.h" +#include "vtr_vector.h" /** * @brief Recursive helper function which gets the models in the given pattern @@ -30,7 +30,7 @@ * been visited. */ static void get_pattern_models_recurr(t_pack_pattern_block* pattern_block, - std::unordered_set& models, + std::unordered_set& models, std::vector& block_visited) { // If the pattern block is invalid or this block has been visited, return. if (pattern_block == nullptr || block_visited[pattern_block->block_id]) { @@ -39,7 +39,7 @@ static void get_pattern_models_recurr(t_pack_pattern_block* pattern_block, // Mark this block as visited and insert its model into the models vector. block_visited[pattern_block->block_id] = true; - models.insert(pattern_block->pb_type->model->index); + models.insert(pattern_block->pb_type->model_id); // Go through this block's connections and get their pattern models. t_pack_pattern_connections* connection = pattern_block->connections; @@ -54,8 +54,8 @@ static void get_pattern_models_recurr(t_pack_pattern_block* pattern_block, * @brief Entry point into the recursive function above. Gets the models in * the given pack pattern. */ -static std::unordered_set get_pattern_models(const t_pack_patterns& pack_pattern) { - std::unordered_set models_in_pattern; +static std::unordered_set get_pattern_models(const t_pack_patterns& pack_pattern) { + std::unordered_set models_in_pattern; // Initialize the visited flags for each block to false. std::vector block_visited(pack_pattern.num_blocks, false); @@ -66,8 +66,7 @@ static std::unordered_set get_pattern_models(const t_pack_patterns& pack_pa } ModelGrouper::ModelGrouper(const Prepacker& prepacker, - t_model* user_models, - t_model* library_models, + const LogicalModels& models, int log_verbosity) { /** * Group the models together based on their pack patterns. If model A and @@ -80,26 +79,10 @@ ModelGrouper::ModelGrouper(const Prepacker& prepacker, * the connected sub-graphs which will be the groups. */ - // Get the number of models - // TODO: Clean up the models vectors in VTR. - std::unordered_map model_name; - unsigned num_models = 0; - t_model* model = library_models; - while (model != nullptr) { - model_name[model->index] = model->name; - num_models++; - model = model->next; - } - model = user_models; - while (model != nullptr) { - model_name[model->index] = model->name; - num_models++; - model = model->next; - } - // Create an adjacency list for the edges. An edge is formed where two // models share a pack pattern together. - std::vector> adj_list(num_models); + size_t num_models = models.all_models().size(); + vtr::vector> adj_list(num_models); for (const t_pack_patterns& pack_pattern : prepacker.get_all_pack_patterns()) { // Get the models within this pattern. auto models_in_pattern = get_pattern_models(pack_pattern); @@ -108,8 +91,8 @@ ModelGrouper::ModelGrouper(const Prepacker& prepacker, // Debug print the models within the pattern. if (log_verbosity >= 20) { VTR_LOG("Pattern: %s\n\t", pack_pattern.name); - for (int model_idx : models_in_pattern) { - VTR_LOG("%s ", model_name[model_idx]); + for (LogicalModelId model_id : models_in_pattern) { + VTR_LOG("%s ", models.model_name(model_id).c_str()); } VTR_LOG("\n"); } @@ -117,8 +100,8 @@ ModelGrouper::ModelGrouper(const Prepacker& prepacker, // Connect each of the models to the first model in the pattern. Since // we only care if there exist a path from each model to another, we do // not need to connect the models in a clique. - int first_model_idx = *models_in_pattern.begin(); - for (int model_idx : models_in_pattern) { + LogicalModelId first_model_idx = *models_in_pattern.begin(); + for (LogicalModelId model_idx : models_in_pattern) { adj_list[model_idx].insert(first_model_idx); adj_list[first_model_idx].insert(model_idx); } @@ -127,57 +110,57 @@ ModelGrouper::ModelGrouper(const Prepacker& prepacker, // Perform BFS to group the models. VTR_LOGV(log_verbosity >= 20, "Finding model groups...\n"); - std::queue node_queue; + std::queue node_queue; model_group_id_.resize(num_models, ModelGroupId::INVALID()); - for (int model_idx = 0; model_idx < (int)num_models; model_idx++) { + for (LogicalModelId model_id : models.all_models()) { // If this model is already in a group, skip it. - if (model_group_id_[model_idx].is_valid()) { + if (model_group_id_[model_id].is_valid()) { VTR_LOGV(log_verbosity >= 20, - "\t(%d -> %d)\n", model_idx, model_group_id_[model_idx]); + "\t(%zu -> %zu)\n", model_id, model_group_id_[model_id]); continue; } ModelGroupId group_id = ModelGroupId(group_ids_.size()); // Put the model in this group and push to the queue. - model_group_id_[model_idx] = group_id; - node_queue.push(model_idx); + model_group_id_[model_id] = group_id; + node_queue.push(model_id); while (!node_queue.empty()) { // Pop a node from the queue, and explore its neighbors. - int node_model_idx = node_queue.front(); + LogicalModelId node_model_id = node_queue.front(); node_queue.pop(); - for (int neighbor_model_idx : adj_list[node_model_idx]) { + for (LogicalModelId neighbor_model_id : adj_list[node_model_id]) { // If this neighbor is already in this group, skip it. - if (model_group_id_[neighbor_model_idx].is_valid()) { - VTR_ASSERT_SAFE(model_group_id_[neighbor_model_idx] == group_id); + if (model_group_id_[neighbor_model_id].is_valid()) { + VTR_ASSERT_SAFE(model_group_id_[neighbor_model_id] == group_id); continue; } // Put the neighbor in this group and push it to the queue. - model_group_id_[neighbor_model_idx] = group_id; - node_queue.push(neighbor_model_idx); + model_group_id_[neighbor_model_id] = group_id; + node_queue.push(neighbor_model_id); } } VTR_LOGV(log_verbosity >= 20, - "\t(%d -> %d)\n", model_idx, model_group_id_[model_idx]); + "\t(%zu -> %zu)\n", model_id, model_group_id_[model_id]); group_ids_.push_back(group_id); } // Create a lookup between each group and the models it contains. groups_.resize(groups().size()); - for (int model_idx = 0; model_idx < (int)num_models; model_idx++) { - groups_[model_group_id_[model_idx]].push_back(model_idx); + for (LogicalModelId model_id : models.all_models()) { + groups_[model_group_id_[model_id]].push_back(model_id); } // Debug printing for each group. if (log_verbosity >= 20) { for (ModelGroupId group_id : groups()) { - const std::vector& group = groups_[group_id]; + const std::vector& group = groups_[group_id]; VTR_LOG("Group %zu:\n", group_id); VTR_LOG("\tSize = %zu\n", group.size()); VTR_LOG("\tContained models:\n"); - for (int model_idx : group) { - VTR_LOG("\t\t%s\n", model_name[model_idx]); + for (LogicalModelId model_id : group) { + VTR_LOG("\t\t%s\n", models.model_name(model_id).c_str()); } } } diff --git a/vpr/src/analytical_place/model_grouper.h b/vpr/src/analytical_place/model_grouper.h index d5a9113d6c1..6e9e56ce03a 100644 --- a/vpr/src/analytical_place/model_grouper.h +++ b/vpr/src/analytical_place/model_grouper.h @@ -9,6 +9,7 @@ #pragma once #include +#include "logic_types.h" #include "vtr_assert.h" #include "vtr_range.h" #include "vtr_strong_id.h" @@ -17,7 +18,6 @@ // Forward declarations. class Prepacker; -struct t_model; /// @brief Tag for the ModelGroupId struct model_group_id_tag; @@ -69,8 +69,7 @@ class ModelGrouper { * The verbosity of log messages in the grouper class. */ ModelGrouper(const Prepacker& prepacker, - t_model* user_models, - t_model* library_models, + const LogicalModels& models, int log_verbosity); /** @@ -83,10 +82,10 @@ class ModelGrouper { /** * @brief Gets the group ID of the given model. */ - inline ModelGroupId get_model_group_id(int model_index) const { - VTR_ASSERT_SAFE_MSG(model_index < (int)model_group_id_.size(), + inline ModelGroupId get_model_group_id(LogicalModelId model_id) const { + VTR_ASSERT_SAFE_MSG(model_id.is_valid(), "Model index outside of range for model_group_id_"); - ModelGroupId group_id = model_group_id_[model_index]; + ModelGroupId group_id = model_group_id_[model_id]; VTR_ASSERT_SAFE_MSG(group_id.is_valid(), "Model is not in a group"); return group_id; @@ -95,7 +94,7 @@ class ModelGrouper { /** * @brief Gets the models in the given group. */ - inline const std::vector& get_models_in_group(ModelGroupId group_id) const { + inline const std::vector& get_models_in_group(ModelGroupId group_id) const { VTR_ASSERT_SAFE_MSG(group_id.is_valid(), "Invalid group id"); VTR_ASSERT_SAFE_MSG(groups_[group_id].size() != 0, @@ -108,8 +107,8 @@ class ModelGrouper { vtr::vector_map group_ids_; /// @brief A lookup between models and the group ID that contains them. - std::vector model_group_id_; + vtr::vector model_group_id_; /// @brief A lookup between each group ID and the models in that group. - vtr::vector> groups_; + vtr::vector> groups_; }; diff --git a/vpr/src/analytical_place/partial_legalizer.cpp b/vpr/src/analytical_place/partial_legalizer.cpp index 1f5103ba02b..38e585ae1b1 100644 --- a/vpr/src/analytical_place/partial_legalizer.cpp +++ b/vpr/src/analytical_place/partial_legalizer.cpp @@ -66,27 +66,6 @@ std::unique_ptr make_partial_legalizer(e_ap_partial_legalizer return nullptr; } -/** - * @brief Get the number of models in the device architecture. - * - * FIXME: These are stored in such an annoying way. It should be much easier - * to get this information! - */ -static inline size_t get_num_models() { - size_t num_models = 0; - t_model* curr_model = g_vpr_ctx.device().arch->models; - while (curr_model != nullptr) { - num_models++; - curr_model = curr_model->next; - } - curr_model = g_vpr_ctx.device().arch->model_library; - while (curr_model != nullptr) { - num_models++; - curr_model = curr_model->next; - } - return num_models; -} - /** * @brief Helper method to get the direct neighbors of the given bin. * @@ -142,7 +121,7 @@ static inline vtr::Point get_center_of_rect(vtr::Rect rect) { return rect.bottom_left() + vtr::Point(rect.width() / 2.0, rect.height() / 2.0); } -void FlowBasedLegalizer::compute_neighbors_of_bin(FlatPlacementBinId src_bin_id, size_t num_models) { +void FlowBasedLegalizer::compute_neighbors_of_bin(FlatPlacementBinId src_bin_id, const LogicalModels& models) { // Make sure that this bin does not already have neighbors. VTR_ASSERT_DEBUG(bin_neighbors_.size() == 0); @@ -165,10 +144,11 @@ void FlowBasedLegalizer::compute_neighbors_of_bin(FlatPlacementBinId src_bin_id, // Flags to check if a specific model has been found in the given direction. // In this case, direction is the direction of the largest component of the // manhattan distance between the source bin and the target bin. - std::vector up_found(num_models, false); - std::vector down_found(num_models, false); - std::vector left_found(num_models, false); - std::vector right_found(num_models, false); + size_t num_models = models.all_models().size(); + vtr::vector up_found(num_models, false); + vtr::vector down_found(num_models, false); + vtr::vector left_found(num_models, false); + vtr::vector right_found(num_models, false); // Flags to check if all models have been found in a given direction. bool all_up_found = false; bool all_down_found = false; @@ -186,17 +166,17 @@ void FlowBasedLegalizer::compute_neighbors_of_bin(FlatPlacementBinId src_bin_id, // type. This method returns true if every model has been found in the given // direction (i.e. dir_found is now all true). auto add_neighbor_if_new_dir = [&](FlatPlacementBinId target_bin_id, - std::vector& dir_found) { + vtr::vector& dir_found) { bool all_found = true; // Go through all possible models - for (size_t i = 0; i < num_models; i++) { + for (LogicalModelId model_id : models.all_models()) { // If this model has been found in this direction, continue. - if (dir_found[i]) + if (dir_found[model_id]) continue; // If this bin has this model in its capacity, we found a neighbor! const PrimitiveVector& target_bin_capacity = density_manager_->get_bin_capacity(target_bin_id); - if (target_bin_capacity.get_dim_val(i) > 0) { - dir_found[i] = true; + if (target_bin_capacity.get_dim_val((size_t)model_id) > 0) { + dir_found[model_id] = true; neighbors.insert(target_bin_id); } else { all_found = false; @@ -271,9 +251,9 @@ FlowBasedLegalizer::FlowBasedLegalizer(const APNetlist& netlist, , bin_neighbors_(density_manager_->flat_placement_bins().bins().size()) { // Connect the bins. - size_t num_models = get_num_models(); for (FlatPlacementBinId bin_id : density_manager_->flat_placement_bins().bins()) { - compute_neighbors_of_bin(bin_id, num_models); + // TODO: Pass the models in. + compute_neighbors_of_bin(bin_id, g_vpr_ctx.device().arch->models); } } @@ -703,42 +683,27 @@ void FlowBasedLegalizer::legalize(PartialPlacement& p_placement) { } PerModelPrefixSum2D::PerModelPrefixSum2D(const FlatPlacementDensityManager& density_manager, - t_model* user_models, - t_model* library_models, - std::function lookup) { - // Get the number of models in the architecture. - // TODO: We really need to clean up how models are stored in VPR... - t_model* cur = user_models; - int num_models = 0; - while (cur != nullptr) { - num_models++; - cur = cur->next; - } - cur = library_models; - while (cur != nullptr) { - num_models++; - cur = cur->next; - } - + const LogicalModels& models, + std::function lookup) { // Get the size that the prefix sums should be. size_t width, height, layers; std::tie(width, height, layers) = density_manager.get_overall_placeable_region_size(); // Create each of the prefix sums. - model_prefix_sum_.resize(num_models); - for (int model_index = 0; model_index < num_models; model_index++) { - model_prefix_sum_[model_index] = vtr::PrefixSum2D( + model_prefix_sum_.resize(models.all_models().size()); + for (LogicalModelId model_id : models.all_models()) { + model_prefix_sum_[model_id] = vtr::PrefixSum2D( width, height, [&](size_t x, size_t y) { - return lookup(model_index, x, y); + return lookup(model_id, x, y); }); } } -float PerModelPrefixSum2D::get_model_sum(int model_index, +float PerModelPrefixSum2D::get_model_sum(LogicalModelId model_index, const vtr::Rect& region) const { - VTR_ASSERT_SAFE(model_index < (int)model_prefix_sum_.size() && model_index >= 0); + VTR_ASSERT_SAFE(model_index.is_valid()); // Get the sum over the given region. return model_prefix_sum_[model_index].get_sum(region.xmin(), region.ymin(), @@ -746,12 +711,12 @@ float PerModelPrefixSum2D::get_model_sum(int model_index, region.ymax() - 1); } -PrimitiveVector PerModelPrefixSum2D::get_sum(const std::vector& model_indices, +PrimitiveVector PerModelPrefixSum2D::get_sum(const std::vector& model_indices, const vtr::Rect& region) const { PrimitiveVector res; - for (int model_index : model_indices) { - VTR_ASSERT_SAFE(res.get_dim_val(model_index) == 0.0f); - res.set_dim_val(model_index, get_model_sum(model_index, region)); + for (LogicalModelId model_index : model_indices) { + VTR_ASSERT_SAFE(res.get_dim_val((size_t)model_index) == 0.0f); + res.set_dim_val((size_t)model_index, get_model_sum(model_index, region)); } return res; } @@ -765,19 +730,17 @@ BiPartitioningPartialLegalizer::BiPartitioningPartialLegalizer( , density_manager_(density_manager) , model_grouper_(prepacker, g_vpr_ctx.device().arch->models, - g_vpr_ctx.device().arch->model_library, log_verbosity) { // Compute the capacity prefix sum. Capacity is assumed to not change // between iterations of the partial legalizer. capacity_prefix_sum_ = PerModelPrefixSum2D( *density_manager, g_vpr_ctx.device().arch->models, - g_vpr_ctx.device().arch->model_library, - [&](int model_index, size_t x, size_t y) { + [&](LogicalModelId model_index, size_t x, size_t y) { // Get the bin at this grid location. FlatPlacementBinId bin_id = density_manager_->get_bin(x, y, 0); // Get the capacity of the bin for this model. - float cap = density_manager_->get_bin_capacity(bin_id).get_dim_val(model_index); + float cap = density_manager_->get_bin_capacity(bin_id).get_dim_val((size_t)model_index); VTR_ASSERT_SAFE(cap >= 0.0f); // Bins may be large, but the prefix sum assumes a 1x1 grid of // values. Normalize by the area of the bin to turn this into @@ -831,7 +794,7 @@ void BiPartitioningPartialLegalizer::legalize(PartialPlacement& p_placement) { std::vector overfilled_models = overfill.get_non_zero_dims(); // For each model, insert its group into the set. Set will handle dupes. for (int model_index : overfilled_models) { - groups_to_spread.insert(model_grouper_.get_model_group_id(model_index)); + groups_to_spread.insert(model_grouper_.get_model_group_id((LogicalModelId)model_index)); } } @@ -905,9 +868,9 @@ static bool is_vector_in_group(const PrimitiveVector& vec, ModelGroupId group_id, const ModelGrouper& model_grouper) { VTR_ASSERT_SAFE(vec.is_non_negative()); - const std::vector& models_in_group = model_grouper.get_models_in_group(group_id); - for (int model_index : models_in_group) { - float dim_val = vec.get_dim_val(model_index); + const std::vector& models_in_group = model_grouper.get_models_in_group(group_id); + for (LogicalModelId model_index : models_in_group) { + float dim_val = vec.get_dim_val((size_t)model_index); if (dim_val != 0.0f) return true; } @@ -1010,9 +973,9 @@ std::vector BiPartitioningPartialLegalizer::get_overfil static bool is_region_overfilled(const vtr::Rect& region, const PerModelPrefixSum2D& capacity_prefix_sum, const PerModelPrefixSum2D& utilization_prefix_sum, - const std::vector& model_indices) { + const std::vector& model_indices) { // Go through each model in the model group we are interested in. - for (int model_index : model_indices) { + for (LogicalModelId model_index : model_indices) { // Get the capacity of this region for this model. float region_model_capacity = capacity_prefix_sum.get_model_sum(model_index, region); @@ -1052,13 +1015,12 @@ std::vector BiPartitioningPartialLegalizer::get_min_windows_aro PerModelPrefixSum2D utilization_prefix_sum( *density_manager_, g_vpr_ctx.device().arch->models, - g_vpr_ctx.device().arch->model_library, - [&](int model_index, size_t x, size_t y) { + [&](LogicalModelId model_index, size_t x, size_t y) { FlatPlacementBinId bin_id = density_manager_->get_bin(x, y, 0); // This is computed the same way as the capacity prefix sum above. const vtr::Rect& bin_region = density_manager_->flat_placement_bins().bin_region(bin_id); float bin_area = bin_region.width() * bin_region.height(); - float util = density_manager_->get_bin_utilization(bin_id).get_dim_val(model_index); + float util = density_manager_->get_bin_utilization(bin_id).get_dim_val((size_t)model_index); VTR_ASSERT_SAFE(util >= 0.0f); return util / bin_area; }); @@ -1329,7 +1291,7 @@ PartitionedWindow BiPartitioningPartialLegalizer::partition_window( // the two partitions are perfectly balanced (equal on both sides). float best_score = -1.0f; PartitionedWindow partitioned_window; - const std::vector& model_indices = model_grouper_.get_models_in_group(group_id); + const std::vector& model_indices = model_grouper_.get_models_in_group(group_id); // First, try all of the vertical partitions. double min_pivot_x = std::floor(window.region.xmin()) + 1.0; @@ -1429,7 +1391,7 @@ void BiPartitioningPartialLegalizer::partition_blocks_in_window( SpreadingWindow& upper_window = partitioned_window.upper_window; // Get the capacity of each window partition. - const std::vector& model_indices = model_grouper_.get_models_in_group(group_id); + const std::vector& model_indices = model_grouper_.get_models_in_group(group_id); PrimitiveVector lower_window_capacity = capacity_prefix_sum_.get_sum(model_indices, lower_window.region); PrimitiveVector upper_window_capacity = capacity_prefix_sum_.get_sum(model_indices, diff --git a/vpr/src/analytical_place/partial_legalizer.h b/vpr/src/analytical_place/partial_legalizer.h index 5f82c787724..3920194eee0 100644 --- a/vpr/src/analytical_place/partial_legalizer.h +++ b/vpr/src/analytical_place/partial_legalizer.h @@ -20,6 +20,7 @@ #include "ap_flow_enums.h" #include "flat_placement_bins.h" #include "flat_placement_density_manager.h" +#include "logic_types.h" #include "model_grouper.h" #include "primitive_vector.h" #include "vtr_geometry.h" @@ -181,7 +182,7 @@ class FlowBasedLegalizer : public PartialLegalizer { * @param src_bin_id The bin to compute the neighbors for. * @param num_models The number of models in the architecture. */ - void compute_neighbors_of_bin(FlatPlacementBinId src_bin_id, size_t num_models); + void compute_neighbors_of_bin(FlatPlacementBinId src_bin_id, const LogicalModels& models); /** * @brief Debugging method which verifies that all the bins are valid. @@ -316,26 +317,25 @@ class PerModelPrefixSum2D { * the model index, x, and y to be populated. */ PerModelPrefixSum2D(const FlatPlacementDensityManager& density_manager, - t_model* user_models, - t_model* library_models, - std::function lookup); + const LogicalModels& models, + std::function lookup); /** * @brief Get the sum for a given model over the given region. */ - float get_model_sum(int model_index, + float get_model_sum(LogicalModelId model_index, const vtr::Rect& region) const; /** * @brief Get the multi-dimensional sum over the given model indices over * the given region. */ - PrimitiveVector get_sum(const std::vector& model_indices, + PrimitiveVector get_sum(const std::vector& model_indices, const vtr::Rect& region) const; private: /// @brief Per-Model Prefix Sums - std::vector> model_prefix_sum_; + vtr::vector> model_prefix_sum_; }; /** diff --git a/vpr/src/base/SetupVPR.cpp b/vpr/src/base/SetupVPR.cpp index f08d79518c5..f911039c184 100644 --- a/vpr/src/base/SetupVPR.cpp +++ b/vpr/src/base/SetupVPR.cpp @@ -1,6 +1,7 @@ #include #include +#include "SetupVPR.h" #include "physical_types_util.h" #include "vtr_assert.h" #include "vtr_util.h" @@ -14,7 +15,6 @@ #include "globals.h" #include "read_xml_arch_file.h" #include "read_fpga_interchange_arch.h" -#include "SetupVPR.h" #include "pb_type_graph.h" #include "pack_types.h" #include "lb_type_rr_graph.h" @@ -89,8 +89,6 @@ void SetupVPR(const t_options* options, const bool readArchFile, t_file_name_opts* fileNameOpts, t_arch* arch, - t_model** user_models, - t_model** library_models, t_netlist_opts* netlistOpts, t_packer_opts* packerOpts, t_placer_opts* placerOpts, @@ -113,6 +111,8 @@ void SetupVPR(const t_options* options, auto& device_ctx = g_vpr_ctx.mutable_device(); + device_ctx.arch = arch; + if (options->CircuitName.value().empty()) { VPR_FATAL_ERROR(VPR_ERROR_BLIF_F, "No blif file found in arguments (did you specify an architecture file?)\n"); @@ -177,9 +177,6 @@ void SetupVPR(const t_options* options, } VTR_LOG("\n"); - *user_models = arch->models; - *library_models = arch->model_library; - device_ctx.EMPTY_PHYSICAL_TILE_TYPE = nullptr; int num_inputs = 0; int num_outputs = 0; diff --git a/vpr/src/base/SetupVPR.h b/vpr/src/base/SetupVPR.h index 45bf510c18c..9492da360d6 100644 --- a/vpr/src/base/SetupVPR.h +++ b/vpr/src/base/SetupVPR.h @@ -1,7 +1,6 @@ #ifndef SETUPVPR_H #define SETUPVPR_H #include -#include "logic_types.h" #include "read_options.h" #include "physical_types.h" #include "vpr_types.h" @@ -11,8 +10,6 @@ void SetupVPR(const t_options* Options, const bool readArchFile, t_file_name_opts* FileNameOpts, t_arch* Arch, - t_model** user_models, - t_model** library_models, t_netlist_opts* NetlistOpts, t_packer_opts* PackerOpts, t_placer_opts* PlacerOpts, diff --git a/vpr/src/base/atom_netlist.cpp b/vpr/src/base/atom_netlist.cpp index 1cbd2232f1f..63132e95500 100644 --- a/vpr/src/base/atom_netlist.cpp +++ b/vpr/src/base/atom_netlist.cpp @@ -1,13 +1,9 @@ -#include #include -#include -#include #include "atom_netlist.h" - -#include "vtr_assert.h" -#include "vtr_log.h" +#include "logic_types.h" #include "vpr_error.h" +#include "vtr_assert.h" /* * @@ -18,27 +14,27 @@ */ AtomNetlist::AtomNetlist(std::string name, std::string id) : Netlist(name, id) - , inpad_model_(nullptr) - , outpad_model_(nullptr) {} + , inpad_model_(LogicalModelId::INVALID()) + , outpad_model_(LogicalModelId::INVALID()) {} /* * * Blocks * */ -void AtomNetlist::set_block_types(const t_model* inpad, const t_model* outpad) { - VTR_ASSERT(inpad != nullptr); - VTR_ASSERT(outpad != nullptr); +void AtomNetlist::set_block_types(LogicalModelId inpad, LogicalModelId outpad) { + VTR_ASSERT(inpad.is_valid()); + VTR_ASSERT(outpad.is_valid()); inpad_model_ = inpad; outpad_model_ = outpad; } AtomBlockType AtomNetlist::block_type(const AtomBlockId id) const { - VTR_ASSERT(inpad_model_ != nullptr); - VTR_ASSERT(outpad_model_ != nullptr); + VTR_ASSERT(inpad_model_.is_valid()); + VTR_ASSERT(outpad_model_.is_valid()); - const t_model* blk_model = block_model(id); + LogicalModelId blk_model = block_model(id); AtomBlockType type = AtomBlockType::BLOCK; if (blk_model == inpad_model_) { @@ -51,7 +47,7 @@ AtomBlockType AtomNetlist::block_type(const AtomBlockId id) const { return type; } -const t_model* AtomNetlist::block_model(const AtomBlockId id) const { +LogicalModelId AtomNetlist::block_model(const AtomBlockId id) const { VTR_ASSERT_SAFE(valid_block_id(id)); return block_models_[id]; @@ -137,7 +133,7 @@ std::unordered_set AtomNetlist::net_aliases(const std::string& net_ * Mutators * */ -AtomBlockId AtomNetlist::create_block(const std::string& name, const t_model* model, const TruthTable& truth_table) { +AtomBlockId AtomNetlist::create_block(const std::string& name, LogicalModelId model, const TruthTable& truth_table) { AtomBlockId blk_id = Netlist::create_block(name); //Initialize the data diff --git a/vpr/src/base/atom_netlist.h b/vpr/src/base/atom_netlist.h index b40e18d2d18..d7c47b13da0 100644 --- a/vpr/src/base/atom_netlist.h +++ b/vpr/src/base/atom_netlist.h @@ -97,13 +97,13 @@ class AtomNetlist : public Netlist block_models_; //Architecture model of each block + vtr::vector_map block_models_; //Architecture model of each block vtr::vector_map block_truth_tables_; //Truth tables of each block // Input IOs and output IOs always exist and have their own architecture @@ -270,8 +270,8 @@ class AtomNetlist : public Netlist port_models_; //Architecture port models of each port diff --git a/vpr/src/base/atom_netlist_utils.cpp b/vpr/src/base/atom_netlist_utils.cpp index 5172db9261a..a56ea9ceb44 100644 --- a/vpr/src/base/atom_netlist_utils.cpp +++ b/vpr/src/base/atom_netlist_utils.cpp @@ -1,16 +1,16 @@ #include "atom_netlist_utils.h" -#include #include #include #include #include #include +#include "logic_types.h" #include "vtr_assert.h" #include "vtr_log.h" #include "vpr_error.h" -#include "vpr_utils.h" +#include "vtr_vector_map.h" /** * @brief Marks primitive output pins constant if all inputs to the block are constant @@ -18,15 +18,15 @@ * Since marking one block constant may cause a downstream block to also be constant, * marking is repated until there is no further change */ -int infer_and_mark_constant_pins(AtomNetlist& netlist, e_const_gen_inference const_gen_inference_method, int verbosity); +int infer_and_mark_constant_pins(AtomNetlist& netlist, e_const_gen_inference const_gen_inference_method, const LogicalModels& models, int verbosity); ///@brief Marks all primtive output pins which have no combinationally connected inputs as constant pins int mark_undriven_primitive_outputs_as_constant(AtomNetlist& netlist, int verbosity); ///@brief Marks all primtive output pins of blk which have only constant inputs as constant pins -int infer_and_mark_block_pins_constant(AtomNetlist& netlist, AtomBlockId blk, e_const_gen_inference const_gen_inference_method, int verbosity); +int infer_and_mark_block_pins_constant(AtomNetlist& netlist, AtomBlockId blk, e_const_gen_inference const_gen_inference_method, const LogicalModels& models, int verbosity); int infer_and_mark_block_combinational_outputs_constant(AtomNetlist& netlist, AtomBlockId blk, e_const_gen_inference const_gen_inference_method, int verbosity); -int infer_and_mark_block_sequential_outputs_constant(AtomNetlist& netlist, AtomBlockId blk, e_const_gen_inference const_gen_inference_method, int verbosity); +int infer_and_mark_block_sequential_outputs_constant(AtomNetlist& netlist, AtomBlockId blk, e_const_gen_inference const_gen_inference_method, const LogicalModels& models, int verbosity); ///@brief Returns the set of input ports which are combinationally connected to output_port std::vector find_combinationally_connected_input_ports(const AtomNetlist& netlist, AtomPortId output_port); @@ -34,27 +34,27 @@ std::vector find_combinationally_connected_input_ports(const AtomNet ///@brief Returns the set of clock ports which are combinationally connected to output_port std::vector find_combinationally_connected_clock_ports(const AtomNetlist& netlist, AtomPortId output_port); -bool is_buffer_lut(const AtomNetlist& netlist, const AtomBlockId blk); -bool is_removable_block(const AtomNetlist& netlist, const AtomBlockId blk, std::string* reason = nullptr); -bool is_removable_input(const AtomNetlist& netlist, const AtomBlockId blk, std::string* reason = nullptr); +bool is_buffer_lut(const AtomNetlist& netlist, const AtomBlockId blk, const LogicalModels& models); +bool is_removable_block(const AtomNetlist& netlist, const AtomBlockId blk, const LogicalModels& models, std::string* reason = nullptr); +bool is_removable_input(const AtomNetlist& netlist, const AtomBlockId blk, const LogicalModels& models, std::string* reason = nullptr); bool is_removable_output(const AtomNetlist& netlist, const AtomBlockId blk, std::string* reason = nullptr); /** * @brief Attempts to remove the specified buffer LUT blk from the netlist. * @return true if successful */ -bool remove_buffer_lut(AtomNetlist& netlist, AtomBlockId blk, int verbosity); +bool remove_buffer_lut(AtomNetlist& netlist, AtomBlockId blk, const LogicalModels& models, int verbosity); std::string make_unconn(size_t& unconn_count, PinType type); void cube_to_minterms_recurr(std::vector cube, std::vector& minterms); -void print_netlist_as_blif(std::string filename, const AtomNetlist& netlist) { +void print_netlist_as_blif(std::string filename, const AtomNetlist& netlist, const LogicalModels& models) { FILE* f = std::fopen(filename.c_str(), "w"); - print_netlist_as_blif(f, netlist); + print_netlist_as_blif(f, netlist, models); std::fclose(f); } -void print_netlist_as_blif(FILE* f, const AtomNetlist& netlist) { +void print_netlist_as_blif(FILE* f, const AtomNetlist& netlist, const LogicalModels& models) { constexpr const char* INDENT = " "; size_t unconn_count = 0; @@ -137,10 +137,11 @@ void print_netlist_as_blif(FILE* f, const AtomNetlist& netlist) { } //Latch + LogicalModelId latch_model = models.get_model_by_name(LogicalModels::MODEL_LATCH); for (auto blk_id : netlist.blocks()) { if (netlist.block_type(blk_id) == AtomBlockType::BLOCK) { - const t_model* blk_model = netlist.block_model(blk_id); - if (blk_model->name != std::string(MODEL_LATCH)) continue; + LogicalModelId blk_model = netlist.block_model(blk_id); + if (blk_model != latch_model) continue; //Nets std::string d_net; @@ -224,10 +225,11 @@ void print_netlist_as_blif(FILE* f, const AtomNetlist& netlist) { } //Names + LogicalModelId names_model = models.get_model_by_name(LogicalModels::MODEL_NAMES); for (auto blk_id : netlist.blocks()) { if (netlist.block_type(blk_id) == AtomBlockType::BLOCK) { - const t_model* blk_model = netlist.block_model(blk_id); - if (blk_model->name != std::string(MODEL_NAMES)) continue; + LogicalModelId blk_model = netlist.block_model(blk_id); + if (blk_model != names_model) continue; std::vector nets; @@ -290,14 +292,15 @@ void print_netlist_as_blif(FILE* f, const AtomNetlist& netlist) { } //Subckt - - std::set subckt_models; + LogicalModelId input_model = models.get_model_by_name(LogicalModels::MODEL_INPUT); + LogicalModelId output_model = models.get_model_by_name(LogicalModels::MODEL_OUTPUT); + std::set subckt_models; for (auto blk_id : netlist.blocks()) { - const t_model* blk_model = netlist.block_model(blk_id); - if (blk_model->name == std::string(MODEL_LATCH) - || blk_model->name == std::string(MODEL_NAMES) - || blk_model->name == std::string(MODEL_INPUT) - || blk_model->name == std::string(MODEL_OUTPUT)) { + LogicalModelId blk_model = netlist.block_model(blk_id); + if (blk_model == latch_model + || blk_model == names_model + || blk_model == input_model + || blk_model == output_model) { continue; } @@ -363,11 +366,12 @@ void print_netlist_as_blif(FILE* f, const AtomNetlist& netlist) { fprintf(f, "\n"); //The subckt models - for (const t_model* model : subckt_models) { - fprintf(f, ".model %s\n", model->name); + for (LogicalModelId model_id : subckt_models) { + const t_model& model = models.get_model(model_id); + fprintf(f, ".model %s\n", model.name); fprintf(f, ".inputs"); - const t_model_ports* port = model->inputs; + const t_model_ports* port = model.inputs; while (port) { VTR_ASSERT(port->size >= 0); if (port->size == 1) { @@ -384,7 +388,7 @@ void print_netlist_as_blif(FILE* f, const AtomNetlist& netlist) { fprintf(f, "\n"); fprintf(f, ".outputs"); - port = model->outputs; + port = model.outputs; while (port) { VTR_ASSERT(port->size >= 0); if (port->size == 1) { @@ -407,26 +411,11 @@ void print_netlist_as_blif(FILE* f, const AtomNetlist& netlist) { } } -std::string atom_pin_arch_name(const AtomNetlist& netlist, const AtomPinId pin) { - std::string arch_name; - - AtomBlockId blk = netlist.pin_block(pin); - AtomPortId port = netlist.pin_port(pin); - arch_name += netlist.block_model(blk)->name; - arch_name += "."; - arch_name += netlist.port_model(port)->name; - arch_name += "["; - arch_name += std::to_string(netlist.pin_port_bit(pin)); - arch_name += "]"; - - return arch_name; -} - -int mark_constant_generators(AtomNetlist& netlist, e_const_gen_inference const_gen_inference_method, int verbosity) { +int mark_constant_generators(AtomNetlist& netlist, e_const_gen_inference const_gen_inference_method, const LogicalModels& models, int verbosity) { int num_undriven_pins_marked_const = mark_undriven_primitive_outputs_as_constant(netlist, verbosity); VTR_LOGV(verbosity > 0, "Inferred %4d additional primitive pins as constant generators since they have no combinationally connected inputs\n", num_undriven_pins_marked_const); - int num_inferred_pins_marked_const = infer_and_mark_constant_pins(netlist, const_gen_inference_method, verbosity); + int num_inferred_pins_marked_const = infer_and_mark_constant_pins(netlist, const_gen_inference_method, models, verbosity); VTR_LOGV(verbosity > 0, "Inferred %4d additional primitive pins as constant generators due to constant inputs\n", num_inferred_pins_marked_const); return num_undriven_pins_marked_const + num_inferred_pins_marked_const; @@ -489,7 +478,7 @@ int mark_undriven_primitive_outputs_as_constant(AtomNetlist& netlist, int verbos return num_pins_marked_constant; } -int infer_and_mark_constant_pins(AtomNetlist& netlist, e_const_gen_inference const_gen_inference_method, int verbosity) { +int infer_and_mark_constant_pins(AtomNetlist& netlist, e_const_gen_inference const_gen_inference_method, const LogicalModels& models, int verbosity) { size_t num_pins_inferred_constant = 0; //It is possible that by marking one constant generator @@ -505,7 +494,7 @@ int infer_and_mark_constant_pins(AtomNetlist& netlist, e_const_gen_inference con for (auto blk : netlist.blocks()) { if (!blk) continue; - num_pins_marked += infer_and_mark_block_pins_constant(netlist, blk, const_gen_inference_method, verbosity); + num_pins_marked += infer_and_mark_block_pins_constant(netlist, blk, const_gen_inference_method, models, verbosity); } num_pins_inferred_constant += num_pins_marked; @@ -514,12 +503,12 @@ int infer_and_mark_constant_pins(AtomNetlist& netlist, e_const_gen_inference con return num_pins_inferred_constant; } -int infer_and_mark_block_pins_constant(AtomNetlist& netlist, AtomBlockId block, e_const_gen_inference const_gen_inference_method, int verbosity) { +int infer_and_mark_block_pins_constant(AtomNetlist& netlist, AtomBlockId block, e_const_gen_inference const_gen_inference_method, const LogicalModels& models, int verbosity) { size_t num_pins_marked_constant = 0; num_pins_marked_constant += infer_and_mark_block_combinational_outputs_constant(netlist, block, const_gen_inference_method, verbosity); - num_pins_marked_constant += infer_and_mark_block_sequential_outputs_constant(netlist, block, const_gen_inference_method, verbosity); + num_pins_marked_constant += infer_and_mark_block_sequential_outputs_constant(netlist, block, const_gen_inference_method, models, verbosity); return num_pins_marked_constant; } @@ -581,7 +570,7 @@ int infer_and_mark_block_combinational_outputs_constant(AtomNetlist& netlist, At return num_pins_marked_constant; } -int infer_and_mark_block_sequential_outputs_constant(AtomNetlist& netlist, AtomBlockId blk, e_const_gen_inference const_gen_inference_method, int verbosity) { +int infer_and_mark_block_sequential_outputs_constant(AtomNetlist& netlist, AtomBlockId blk, e_const_gen_inference const_gen_inference_method, const LogicalModels& models, int verbosity) { //Only if sequential constant generator inference enabled if (const_gen_inference_method != e_const_gen_inference::COMB_SEQ) { return 0; @@ -639,7 +628,7 @@ int infer_and_mark_block_sequential_outputs_constant(AtomNetlist& netlist, AtomB VTR_LOGV(verbosity > 1, "Marking sequential pin '%s' as constant since all inputs to block '%s' (%s) are constant\n", netlist.pin_name(output_pin).c_str(), netlist.block_name(blk).c_str(), - netlist.block_model(blk)->name); + models.get_model(netlist.block_model(blk)).name); netlist.set_pin_is_constant(output_pin, true); ++num_pins_marked_constant; } @@ -692,7 +681,7 @@ std::vector find_combinationally_connected_clock_ports(const AtomNet return upstream_ports; } -void absorb_buffer_luts(AtomNetlist& netlist, int verbosity) { +void absorb_buffer_luts(AtomNetlist& netlist, const LogicalModels& models, int verbosity) { //First we look through the netlist to find LUTs with identity logic functions //we then remove those luts, replacing the net's they drove with the inputs to the //buffer lut @@ -701,8 +690,8 @@ void absorb_buffer_luts(AtomNetlist& netlist, int verbosity) { //Remove the buffer luts for (auto blk : netlist.blocks()) { - if (is_buffer_lut(netlist, blk)) { - if (remove_buffer_lut(netlist, blk, verbosity)) { + if (is_buffer_lut(netlist, blk, models)) { + if (remove_buffer_lut(netlist, blk, models, verbosity)) { ++removed_buffer_count; } } @@ -712,11 +701,10 @@ void absorb_buffer_luts(AtomNetlist& netlist, int verbosity) { //TODO: absorb inverter LUTs? } -bool is_buffer_lut(const AtomNetlist& netlist, const AtomBlockId blk) { +bool is_buffer_lut(const AtomNetlist& netlist, const AtomBlockId blk, const LogicalModels& models) { if (netlist.block_type(blk) == AtomBlockType::BLOCK) { - const t_model* blk_model = netlist.block_model(blk); - - if (blk_model->name != std::string(MODEL_NAMES)) return false; + const LogicalModelId names_model = models.get_model_by_name(LogicalModels::MODEL_NAMES); + if (netlist.block_model(blk) != names_model) return false; auto input_ports = netlist.block_input_ports(blk); auto output_ports = netlist.block_output_ports(blk); @@ -773,7 +761,7 @@ bool is_buffer_lut(const AtomNetlist& netlist, const AtomBlockId blk) { return false; } -bool remove_buffer_lut(AtomNetlist& netlist, AtomBlockId blk, int verbosity) { +bool remove_buffer_lut(AtomNetlist& netlist, AtomBlockId blk, const LogicalModels& models, int verbosity) { //General net connectivity, numbers equal pin ids // // 1 in 2 ----- m+1 out @@ -822,13 +810,23 @@ bool remove_buffer_lut(AtomNetlist& netlist, AtomBlockId blk, int verbosity) { auto input_net = netlist.pin_net(input_pin); auto output_net = netlist.pin_net(output_pin); - VTR_LOGV_WARN(verbosity > 1, "Attempting to remove buffer '%s' (%s) from net '%s' to net '%s'\n", netlist.block_name(blk).c_str(), netlist.block_model(blk)->name, netlist.net_name(input_net).c_str(), netlist.net_name(output_net).c_str()); + VTR_LOGV_WARN(verbosity > 1, + "Attempting to remove buffer '%s' (%s) from net '%s' to net '%s'\n", + netlist.block_name(blk).c_str(), + models.model_name(netlist.block_model(blk)).c_str(), + netlist.net_name(input_net).c_str(), + netlist.net_name(output_net).c_str()); //Collect the new driver and sink pins AtomPinId new_driver = netlist.net_driver(input_net); if (!new_driver) { - VTR_LOGV_WARN(verbosity > 2, "Buffer '%s' has no input and will not be absorbed (left to be swept)\n", netlist.block_name(blk).c_str(), netlist.block_model(blk)->name, netlist.net_name(input_net).c_str(), netlist.net_name(output_net).c_str()); + VTR_LOGV_WARN(verbosity > 2, + "Buffer '%s' has no input and will not be absorbed (left to be swept)\n", + netlist.block_name(blk).c_str(), + models.model_name(netlist.block_model(blk)).c_str(), + netlist.net_name(input_net).c_str(), + netlist.net_name(output_net).c_str()); return false; //Dangling/undriven input, leave buffer to be swept } @@ -909,7 +907,7 @@ bool remove_buffer_lut(AtomNetlist& netlist, AtomBlockId blk, int verbosity) { return true; } -bool is_removable_block(const AtomNetlist& netlist, const AtomBlockId blk_id, std::string* reason) { +bool is_removable_block(const AtomNetlist& netlist, const AtomBlockId blk_id, const LogicalModels& models, std::string* reason) { //Any block with no fanout is removable for (AtomPinId pin_id : netlist.block_output_pins(blk_id)) { if (!pin_id) continue; @@ -923,7 +921,7 @@ bool is_removable_block(const AtomNetlist& netlist, const AtomBlockId blk_id, st //If the model relative to this block is has the never prune flag set //it cannot be removed, even if it does not have a fanout auto blk_model = netlist.block_model(blk_id); - if (blk_model->never_prune == true) { + if (models.get_model(blk_model).never_prune == true) { return false; } @@ -931,13 +929,13 @@ bool is_removable_block(const AtomNetlist& netlist, const AtomBlockId blk_id, st return true; } -bool is_removable_input(const AtomNetlist& netlist, const AtomBlockId blk_id, std::string* reason) { +bool is_removable_input(const AtomNetlist& netlist, const AtomBlockId blk_id, const LogicalModels& models, std::string* reason) { AtomBlockType type = netlist.block_type(blk_id); //Only return true if an INPAD if (type != AtomBlockType::INPAD) return false; - return is_removable_block(netlist, blk_id, reason); + return is_removable_block(netlist, blk_id, models, reason); } bool is_removable_output(const AtomNetlist& netlist, const AtomBlockId blk_id, std::string* reason) { @@ -996,6 +994,7 @@ size_t sweep_iterative(AtomNetlist& netlist, bool should_sweep_blocks, bool should_sweep_constant_primary_outputs, e_const_gen_inference const_gen_inference_method, + const LogicalModels& models, int verbosity) { size_t dangling_nets_swept = 0; size_t dangling_blocks_swept = 0; @@ -1023,12 +1022,12 @@ size_t sweep_iterative(AtomNetlist& netlist, pass_constant_generators_marked = 0; if (should_sweep_ios) { - pass_dangling_inputs_swept += sweep_inputs(netlist, verbosity); + pass_dangling_inputs_swept += sweep_inputs(netlist, models, verbosity); pass_dangling_outputs_swept += sweep_outputs(netlist, verbosity); } if (should_sweep_blocks) { - pass_dangling_blocks_swept += sweep_blocks(netlist, verbosity); + pass_dangling_blocks_swept += sweep_blocks(netlist, models, verbosity); } if (should_sweep_nets) { @@ -1039,7 +1038,7 @@ size_t sweep_iterative(AtomNetlist& netlist, pass_constant_outputs_swept += sweep_constant_primary_outputs(netlist, verbosity); } - pass_constant_generators_marked += mark_constant_generators(netlist, const_gen_inference_method, verbosity); + pass_constant_generators_marked += mark_constant_generators(netlist, const_gen_inference_method, models, verbosity); dangling_nets_swept += pass_dangling_nets_swept; dangling_blocks_swept += pass_dangling_blocks_swept; @@ -1070,7 +1069,7 @@ size_t sweep_iterative(AtomNetlist& netlist, + constant_outputs_swept; } -size_t sweep_blocks(AtomNetlist& netlist, int verbosity) { +size_t sweep_blocks(AtomNetlist& netlist, const LogicalModels& models, int verbosity) { //Identify any blocks (not inputs or outputs) for removal std::unordered_set blocks_to_remove; for (auto blk_id : netlist.blocks()) { @@ -1083,7 +1082,7 @@ size_t sweep_blocks(AtomNetlist& netlist, int verbosity) { //We remove any blocks with no fanout std::string reason; - if (is_removable_block(netlist, blk_id, &reason)) { + if (is_removable_block(netlist, blk_id, models, &reason)) { blocks_to_remove.insert(blk_id); VTR_LOGV_WARN(verbosity > 1, "Block '%s' will be swept (%s)\n", netlist.block_name(blk_id).c_str(), reason.c_str()); @@ -1098,14 +1097,14 @@ size_t sweep_blocks(AtomNetlist& netlist, int verbosity) { return blocks_to_remove.size(); } -size_t sweep_inputs(AtomNetlist& netlist, int verbosity) { +size_t sweep_inputs(AtomNetlist& netlist, const LogicalModels& models, int verbosity) { //Identify any inputs for removal std::unordered_set inputs_to_remove; for (auto blk_id : netlist.blocks()) { if (!blk_id) continue; std::string reason; - if (is_removable_input(netlist, blk_id, &reason)) { + if (is_removable_input(netlist, blk_id, models, &reason)) { inputs_to_remove.insert(blk_id); VTR_LOGV_WARN(verbosity > 1, "Primary input '%s' will be swept (%s)\n", netlist.block_name(blk_id).c_str(), reason.c_str()); @@ -1333,10 +1332,10 @@ void cube_to_minterms_recurr(std::vector cube, std::vector find_netlist_physical_clock_nets(const AtomNetlist& netlist) { +std::set find_netlist_physical_clock_nets(const AtomNetlist& netlist, const LogicalModels& models) { std::set clock_nets; //The clock nets - std::map> clock_gen_ports; //Records info about clock generating ports + vtr::vector_map> clock_gen_ports; //Records info about clock generating ports //Look through all the blocks (except I/Os) to find sink clock pins, or //clock generators @@ -1350,18 +1349,19 @@ std::set find_netlist_physical_clock_nets(const AtomNetlist& netlist) if (type != AtomBlockType::BLOCK) continue; //Save any clock generating ports on this model type - const t_model* model = netlist.block_model(blk_id); - VTR_ASSERT(model); - if (clock_gen_ports.find(model) == clock_gen_ports.end()) { + LogicalModelId model_id = netlist.block_model(blk_id); + VTR_ASSERT(model_id.is_valid()); + if (clock_gen_ports.find(model_id) == clock_gen_ports.end()) { //First time we've seen this model, initialize it - clock_gen_ports[model] = {}; + clock_gen_ports.insert(model_id, {}); //Look at all the ports to find clock generators - for (const t_model_ports* model_port = model->outputs; model_port; model_port = model_port->next) { + const t_model& model = models.get_model(model_id); + for (const t_model_ports* model_port = model.outputs; model_port; model_port = model_port->next) { VTR_ASSERT(model_port->dir == OUT_PORT); if (model_port->is_clock) { //Clock generator - clock_gen_ports[model].push_back(model_port); + clock_gen_ports[model_id].push_back(model_port); } } } @@ -1377,11 +1377,11 @@ std::set find_netlist_physical_clock_nets(const AtomNetlist& netlist) } //Look for any generated clocks - if (!clock_gen_ports[model].empty()) { + if (!clock_gen_ports[model_id].empty()) { //This is a clock generator //Check all the clock generating ports - for (const t_model_ports* model_port : clock_gen_ports[model]) { + for (const t_model_ports* model_port : clock_gen_ports[model_id]) { AtomPortId clk_gen_port = netlist.find_atom_port(blk_id, model_port); if (!clk_gen_port) continue; //Port not connected on this block @@ -1402,8 +1402,8 @@ std::set find_netlist_physical_clock_nets(const AtomNetlist& netlist) } ///@brief Finds all logical clock drivers in the netlist (by back-tracing through logic) -std::set find_netlist_logical_clock_drivers(const AtomNetlist& netlist) { - std::set clock_nets = find_netlist_physical_clock_nets(netlist); +std::set find_netlist_logical_clock_drivers(const AtomNetlist& netlist, const LogicalModels& models) { + std::set clock_nets = find_netlist_physical_clock_nets(netlist, models); //We now have a set of nets which drive clock pins // @@ -1412,6 +1412,7 @@ std::set find_netlist_logical_clock_drivers(const AtomNetlist& netlis //to find the true source size_t assumed_buffer_count = 0; std::set prev_clock_nets; + LogicalModelId names_model_id = models.get_model_by_name(LogicalModels::MODEL_NAMES); while (prev_clock_nets != clock_nets) { //Still tracing back prev_clock_nets = clock_nets; clock_nets.clear(); @@ -1423,7 +1424,7 @@ std::set find_netlist_logical_clock_drivers(const AtomNetlist& netlis std::vector upstream_ports; - if (netlist.block_model(driver_blk)->name == std::string(".names")) { + if (netlist.block_model(driver_blk) == names_model_id) { //For .names we allow tracing back through data connections //which allows us to traceback through white-box .names buffers upstream_ports = find_combinationally_connected_input_ports(netlist, driver_port); @@ -1448,7 +1449,7 @@ std::set find_netlist_logical_clock_drivers(const AtomNetlist& netlis VTR_ASSERT(upstream_net); VTR_LOG_WARN("Assuming clocks may propagate through %s (%s) from pin %s to %s (assuming a non-inverting buffer).\n", - netlist.block_name(driver_blk).c_str(), netlist.block_model(driver_blk)->name, + netlist.block_name(driver_blk).c_str(), models.model_name(netlist.block_model(driver_blk)).c_str(), netlist.pin_name(upstream_pin).c_str(), netlist.pin_name(driver_pin).c_str()); clock_nets.insert(upstream_net); @@ -1483,8 +1484,8 @@ std::set find_netlist_logical_clock_drivers(const AtomNetlist& netlis } ///@brief Print information about clocks -void print_netlist_clock_info(const AtomNetlist& netlist) { - std::set netlist_clock_drivers = find_netlist_logical_clock_drivers(netlist); +void print_netlist_clock_info(const AtomNetlist& netlist, const LogicalModels& models) { + std::set netlist_clock_drivers = find_netlist_logical_clock_drivers(netlist, models); VTR_LOG("Netlist contains %zu clocks\n", netlist_clock_drivers.size()); //Print out pin/block fanout info for each block @@ -1500,9 +1501,3 @@ void print_netlist_clock_info(const AtomNetlist& netlist) { VTR_LOG(" Netlist Clock '%s' Fanout: %zu pins (%.1f%%), %zu blocks (%.1f%%)\n", netlist.net_name(net_id).c_str(), fanout, 100. * float(fanout) / netlist.pins().size(), clk_blks.size(), 100 * float(clk_blks.size()) / netlist.blocks().size()); } } - -bool is_buffer(const AtomNetlist& netlist, const AtomBlockId blk) { - //For now only support LUT buffers - //TODO: In the future could add support for non-LUT buffers - return is_buffer_lut(netlist, blk); -} diff --git a/vpr/src/base/atom_netlist_utils.h b/vpr/src/base/atom_netlist_utils.h index aaa559d4a73..5bf0791bfad 100644 --- a/vpr/src/base/atom_netlist_utils.h +++ b/vpr/src/base/atom_netlist_utils.h @@ -9,16 +9,18 @@ * @brief Useful utilities for working with the AtomNetlist class */ +class LogicalModels; + /** * @brief Walk through the netlist detecting constant generators * * @note Initial constant generators (e.g. vcc/gnd) should have already * been marked on the netlist. */ -int mark_constant_generators(AtomNetlist& netlist, e_const_gen_inference const_gen_inference_method, int verbosity); +int mark_constant_generators(AtomNetlist& netlist, e_const_gen_inference const_gen_inference_method, const LogicalModels& models, int verbosity); ///@brief Modifies the netlist by absorbing buffer LUTs -void absorb_buffer_luts(AtomNetlist& netlist, int verbosity); +void absorb_buffer_luts(AtomNetlist& netlist, const LogicalModels& models, int verbosity); /* * Modify the netlist by sweeping away unused nets/blocks/inputs @@ -35,16 +37,17 @@ size_t sweep_iterative(AtomNetlist& netlist, bool should_sweep_dangling_nets, bool should_sweep_constant_primary_outputs, e_const_gen_inference const_gen_inference_method, + const LogicalModels& models, int verbosity); ///@brief Sweeps blocks that have no fanout -size_t sweep_blocks(AtomNetlist& netlist, int verbosity); +size_t sweep_blocks(AtomNetlist& netlist, const LogicalModels& models, int verbosity); ///@brief Sweeps nets with no drivers and/or no sinks size_t sweep_nets(AtomNetlist& netlist, int verbosity); ///@brief Sweeps primary-inputs with no fanout -size_t sweep_inputs(AtomNetlist& netlist, int verbosity); +size_t sweep_inputs(AtomNetlist& netlist, const LogicalModels& models, int verbosity); ///@brief Sweeps primary-outputs with no fanin size_t sweep_outputs(AtomNetlist& netlist, int verbosity); @@ -55,9 +58,6 @@ size_t sweep_constant_primary_outputs(AtomNetlist& netlist, int verbosity); * Truth-table operations */ -///@brief Returns true if the specified block is a logical buffer -bool is_buffer(const AtomNetlist& netlist, const AtomBlockId blk); - /** * @brief Deterimine whether a truth table encodes the logic functions 'On' set (returns true) * or 'Off' set (returns false) @@ -96,11 +96,8 @@ std::vector cube_to_minterms(std::vector cube); /* * Print the netlist for debugging */ -void print_netlist_as_blif(std::string filename, const AtomNetlist& netlist); -void print_netlist_as_blif(FILE* f, const AtomNetlist& netlist); - -///@brief Returns a user-friendly architectural identifier for the specified atom pin -std::string atom_pin_arch_name(const AtomNetlist& netlist, const AtomPinId pin); +void print_netlist_as_blif(std::string filename, const AtomNetlist& netlist, const LogicalModels& models); +void print_netlist_as_blif(FILE* f, const AtomNetlist& netlist, const LogicalModels& models); /* * Identify all clock nets @@ -112,7 +109,7 @@ std::string atom_pin_arch_name(const AtomNetlist& netlist, const AtomPinId pin); * @note The returned nets may be logically equivalent (e.g. driven by buffers * connected to a common net) */ -std::set find_netlist_physical_clock_nets(const AtomNetlist& netlist); +std::set find_netlist_physical_clock_nets(const AtomNetlist& netlist, const LogicalModels& models); /** * @brief Returns the set of pins which logically drive unique clocks in the netlist @@ -121,8 +118,8 @@ std::set find_netlist_physical_clock_nets(const AtomNetlist& netlist) * so logically unique should be viewed as true only to the extent of VPR's * understanding */ -std::set find_netlist_logical_clock_drivers(const AtomNetlist& netlist); +std::set find_netlist_logical_clock_drivers(const AtomNetlist& netlist, const LogicalModels& models); ///@brief Prints out information about netlist clocks -void print_netlist_clock_info(const AtomNetlist& netlist); +void print_netlist_clock_info(const AtomNetlist& netlist, const LogicalModels& models); #endif diff --git a/vpr/src/base/check_netlist.cpp b/vpr/src/base/check_netlist.cpp index a80e3d7d76c..3d777f3ec4b 100644 --- a/vpr/src/base/check_netlist.cpp +++ b/vpr/src/base/check_netlist.cpp @@ -7,6 +7,7 @@ #include #include +#include "logic_types.h" #include "physical_types_util.h" #include "vtr_assert.h" #include "vtr_log.h" @@ -128,6 +129,7 @@ static int check_connections_to_global_clb_pins(ClusterNetId net_id, int verbosi static int check_clb_conn(ClusterBlockId iblk, int num_conn) { auto& cluster_ctx = g_vpr_ctx.clustering(); auto& clb_nlist = cluster_ctx.clb_nlist; + const LogicalModels& models = g_vpr_ctx.device().arch->models; int error = 0; t_logical_block_type_ptr type = clb_nlist.block_type(iblk); @@ -136,7 +138,7 @@ static int check_clb_conn(ClusterBlockId iblk, int num_conn) { for (auto pin_id : clb_nlist.block_pins(iblk)) { auto pin_type = clb_nlist.pin_type(pin_id); - if (pin_type == PinType::SINK && !clb_nlist.block_contains_primary_output(iblk)) { + if (pin_type == PinType::SINK && !clb_nlist.block_contains_primary_output(iblk, models)) { //Input only and not a Primary-Output block VTR_LOG_WARN( "Logic block #%d (%s) has only 1 input pin '%s'" @@ -144,7 +146,7 @@ static int check_clb_conn(ClusterBlockId iblk, int num_conn) { iblk, clb_nlist.block_name(iblk).c_str(), clb_nlist.pin_name(pin_id).c_str()); } - if (pin_type == PinType::DRIVER && !clb_nlist.block_contains_primary_input(iblk)) { + if (pin_type == PinType::DRIVER && !clb_nlist.block_contains_primary_input(iblk, models)) { //Output only and not a Primary-Input block VTR_LOG_WARN( "Logic block #%d (%s) has only 1 output pin '%s'." diff --git a/vpr/src/base/clustered_netlist.cpp b/vpr/src/base/clustered_netlist.cpp index 2f2fce860a4..8e446d2b4c8 100644 --- a/vpr/src/base/clustered_netlist.cpp +++ b/vpr/src/base/clustered_netlist.cpp @@ -1,5 +1,6 @@ #include "clustered_netlist.h" #include "globals.h" +#include "logic_types.h" #include "physical_types_util.h" #include "vtr_assert.h" @@ -57,16 +58,18 @@ ClusterPinId ClusteredNetlist::block_pin(const ClusterBlockId blk, const int log return block_logical_pins_[blk][logical_pin_index]; } -bool ClusteredNetlist::block_contains_primary_input(const ClusterBlockId blk) const { +bool ClusteredNetlist::block_contains_primary_input(const ClusterBlockId blk, const LogicalModels& models) const { const t_pb* pb = block_pb(blk); - const t_pb* primary_input_pb = pb->find_pb_for_model(".input"); + LogicalModelId input_model_id = models.get_model_by_name(LogicalModels::MODEL_INPUT); + const t_pb* primary_input_pb = pb->find_pb_for_model(input_model_id); return primary_input_pb != nullptr; } ///@brief Returns true if the specified block contains a primary output (e.g. BLIF .output primitive) -bool ClusteredNetlist::block_contains_primary_output(const ClusterBlockId blk) const { +bool ClusteredNetlist::block_contains_primary_output(const ClusterBlockId blk, const LogicalModels& models) const { const t_pb* pb = block_pb(blk); - const t_pb* primary_output_pb = pb->find_pb_for_model(".output"); + LogicalModelId output_model_id = models.get_model_by_name(LogicalModels::MODEL_OUTPUT); + const t_pb* primary_output_pb = pb->find_pb_for_model(output_model_id); return primary_output_pb != nullptr; } diff --git a/vpr/src/base/clustered_netlist.h b/vpr/src/base/clustered_netlist.h index a32e371741c..e8399484adb 100644 --- a/vpr/src/base/clustered_netlist.h +++ b/vpr/src/base/clustered_netlist.h @@ -144,10 +144,10 @@ class ClusteredNetlist : public Netlist delay_calc, + const LogicalModels& models, struct t_analysis_opts opts) : verilog_os_(verilog_os) , blif_os_(blif_os) , sdf_os_(sdf_os) , delay_calc_(delay_calc) + , models_(models) , opts_(opts) { auto& atom_ctx = g_vpr_ctx.atom(); @@ -935,23 +937,24 @@ class NetlistWriterVisitor : public NetlistVisitor { if (atom_pb == AtomBlockId::INVALID()) { return; } - const t_model* model = atom_ctx.netlist().block_model(atom_pb); + LogicalModelId model_id = atom_ctx.netlist().block_model(atom_pb); + std::string model_name = models_.model_name(model_id); - if (model->name == std::string(MODEL_INPUT)) { + if (model_name == LogicalModels::MODEL_INPUT) { inputs_.emplace_back(make_io(atom, PortType::INPUT)); - } else if (model->name == std::string(MODEL_OUTPUT)) { + } else if (model_name == LogicalModels::MODEL_OUTPUT) { outputs_.emplace_back(make_io(atom, PortType::OUTPUT)); - } else if (model->name == std::string(MODEL_NAMES)) { + } else if (model_name == LogicalModels::MODEL_NAMES) { cell_instances_.push_back(make_lut_instance(atom)); - } else if (model->name == std::string(MODEL_LATCH)) { + } else if (model_name == LogicalModels::MODEL_LATCH) { cell_instances_.push_back(make_latch_instance(atom)); - } else if (model->name == std::string("single_port_ram")) { + } else if (model_name == std::string("single_port_ram")) { cell_instances_.push_back(make_ram_instance(atom)); - } else if (model->name == std::string("dual_port_ram")) { + } else if (model_name == std::string("dual_port_ram")) { cell_instances_.push_back(make_ram_instance(atom)); - } else if (model->name == std::string("multiply")) { + } else if (model_name == std::string("multiply")) { cell_instances_.push_back(make_multiply_instance(atom)); - } else if (model->name == std::string("adder")) { + } else if (model_name == std::string("adder")) { cell_instances_.push_back(make_adder_instance(atom)); } else { cell_instances_.push_back(make_blackbox_instance(atom)); @@ -1406,7 +1409,7 @@ class NetlistWriterVisitor : public NetlistVisitor { VTR_ASSERT(pb_type->class_type == MEMORY_CLASS); - std::string type = pb_type->model->name; + std::string type = models_.model_name(pb_type->model_id); std::string inst_name = join_identifier(type, atom->name); std::map params; std::map attrs; @@ -1551,7 +1554,7 @@ class NetlistWriterVisitor : public NetlistVisitor { const t_pb_graph_node* pb_graph_node = atom->pb_graph_node; const t_pb_type* pb_type = pb_graph_node->pb_type; - std::string type_name = pb_type->model->name; + std::string type_name = models_.model_name(pb_type->model_id); std::string inst_name = join_identifier(type_name, atom->name); std::map params; std::map attrs; @@ -1646,7 +1649,7 @@ class NetlistWriterVisitor : public NetlistVisitor { const t_pb_graph_node* pb_graph_node = atom->pb_graph_node; const t_pb_type* pb_type = pb_graph_node->pb_type; - std::string type_name = pb_type->model->name; + std::string type_name = models_.model_name(pb_type->model_id); std::string inst_name = join_identifier(type_name, atom->name); std::map params; std::map attrs; @@ -1743,7 +1746,7 @@ class NetlistWriterVisitor : public NetlistVisitor { const t_pb_type* pb_type = pb_graph_node->pb_type; auto& timing_ctx = g_vpr_ctx.timing(); - std::string type_name = pb_type->model->name; + std::string type_name = models_.model_name(pb_type->model_id); std::string inst_name = join_identifier(type_name, atom->name); std::map params; std::map attrs; @@ -1924,8 +1927,9 @@ class NetlistWriterVisitor : public NetlistVisitor { const t_pb* atom) { //LUT primitive auto& atom_ctx = g_vpr_ctx.atom(); - const t_model* model = atom_ctx.netlist().block_model(atom_ctx.lookup().atom_pb_bimap().pb_atom(atom)); - VTR_ASSERT(model->name == std::string(MODEL_NAMES)); + LogicalModelId model_id = atom_ctx.netlist().block_model(atom_ctx.lookup().atom_pb_bimap().pb_atom(atom)); + std::string model_name = models_.model_name(model_id); + VTR_ASSERT(model_name == LogicalModels::MODEL_NAMES); #ifdef DEBUG_LUT_MASK std::cout << "Loading LUT mask for: " << atom->name << std::endl; @@ -2204,6 +2208,11 @@ class NetlistWriterVisitor : public NetlistVisitor { std::map, tatum::NodeId> pin_id_to_tnode_lookup_; std::shared_ptr delay_calc_; + + protected: + const LogicalModels& models_; + + private: struct t_analysis_opts opts_; }; @@ -2218,8 +2227,9 @@ class MergedNetlistWriterVisitor : public NetlistWriterVisitor { std::ostream& blif_os, /// delay_calc, + const LogicalModels& models, struct t_analysis_opts opts) - : NetlistWriterVisitor(verilog_os, blif_os, sdf_os, delay_calc, opts) {} + : NetlistWriterVisitor(verilog_os, blif_os, sdf_os, delay_calc, models, opts) {} std::map portmap; @@ -2230,27 +2240,28 @@ class MergedNetlistWriterVisitor : public NetlistWriterVisitor { if (atom_pb == AtomBlockId::INVALID()) { return; } - const t_model* model = atom_ctx.netlist().block_model(atom_pb); + LogicalModelId model_id = atom_ctx.netlist().block_model(atom_pb); + std::string model_name = models_.model_name(model_id); - if (model->name == std::string(MODEL_INPUT)) { + if (model_name == LogicalModels::MODEL_INPUT) { auto merged_io_name = make_io(atom, PortType::INPUT); if (merged_io_name != "") inputs_.emplace_back(merged_io_name); - } else if (model->name == std::string(MODEL_OUTPUT)) { + } else if (model_name == LogicalModels::MODEL_OUTPUT) { auto merged_io_name = make_io(atom, PortType::OUTPUT); if (merged_io_name != "") outputs_.emplace_back(merged_io_name); - } else if (model->name == std::string(MODEL_NAMES)) { + } else if (model_name == LogicalModels::MODEL_NAMES) { cell_instances_.push_back(make_lut_instance(atom)); - } else if (model->name == std::string(MODEL_LATCH)) { + } else if (model_name == LogicalModels::MODEL_LATCH) { cell_instances_.push_back(make_latch_instance(atom)); - } else if (model->name == std::string("single_port_ram")) { + } else if (model_name == std::string("single_port_ram")) { cell_instances_.push_back(make_ram_instance(atom)); - } else if (model->name == std::string("dual_port_ram")) { + } else if (model_name == std::string("dual_port_ram")) { cell_instances_.push_back(make_ram_instance(atom)); - } else if (model->name == std::string("multiply")) { + } else if (model_name == std::string("multiply")) { cell_instances_.push_back(make_multiply_instance(atom)); - } else if (model->name == std::string("adder")) { + } else if (model_name == std::string("adder")) { cell_instances_.push_back(make_adder_instance(atom)); } else { cell_instances_.push_back(make_blackbox_instance(atom)); @@ -2640,7 +2651,7 @@ std::string join_identifier(std::string lhs, std::string rhs) { // ///@brief Main routine for this file. See netlist_writer.h for details. -void netlist_writer(const std::string basename, std::shared_ptr delay_calc, struct t_analysis_opts opts) { +void netlist_writer(const std::string basename, std::shared_ptr delay_calc, const LogicalModels& models, t_analysis_opts opts) { std::string verilog_filename = basename + "_post_synthesis.v"; std::string blif_filename = basename + "_post_synthesis.blif"; std::string sdf_filename = basename + "_post_synthesis.sdf"; @@ -2653,7 +2664,7 @@ void netlist_writer(const std::string basename, std::shared_ptr delay_calc, struct t_analysis_opts opts) { +void merged_netlist_writer(const std::string basename, std::shared_ptr delay_calc, const LogicalModels& models, t_analysis_opts opts) { std::string verilog_filename = basename + "_merged_post_implementation.v"; VTR_LOG("Writing Merged Implementation Netlist: %s\n", verilog_filename.c_str()); @@ -2671,7 +2682,7 @@ void merged_netlist_writer(const std::string basename, std::shared_ptr #include "AnalysisDelayCalculator.h" +class LogicalModels; + /** * @brief Writes out the post-synthesis implementation netlists in BLIF and Verilog formats, * along with an SDF for delay annotations. @@ -14,7 +16,7 @@ * All written filenames end in {basename}_post_synthesis.{fmt} where {basename} is the * basename argument and {fmt} is the file format (e.g. v, blif, sdf) */ -void netlist_writer(const std::string basename, std::shared_ptr delay_calc, t_analysis_opts opts); +void netlist_writer(const std::string basename, std::shared_ptr delay_calc, const LogicalModels& models, t_analysis_opts opts); /** * @brief Writes out the post implementation netlist in Verilog format. @@ -26,4 +28,4 @@ void netlist_writer(const std::string basename, std::shared_ptr delay_calc, t_analysis_opts opts); +void merged_netlist_writer(const std::string basename, std::shared_ptr delay_calc, const LogicalModels& models, t_analysis_opts opts); diff --git a/vpr/src/base/read_blif.cpp b/vpr/src/base/read_blif.cpp index 807e8c4a8c4..1edda3fa975 100644 --- a/vpr/src/base/read_blif.cpp +++ b/vpr/src/base/read_blif.cpp @@ -18,41 +18,35 @@ #include #include #include -#include #include //std::isdigit #include "blifparse.hpp" #include "atom_netlist.h" +#include "logic_types.h" #include "vtr_assert.h" #include "vtr_util.h" #include "vtr_log.h" #include "vtr_logic.h" -#include "vtr_time.h" #include "vtr_digest.h" -#include "vpr_types.h" #include "vpr_error.h" -#include "globals.h" #include "read_blif.h" -#include "arch_types.h" -#include "echo_files.h" #include "hash.h" vtr::LogicValue to_vtr_logic_value(blifparse::LogicValue); struct BlifAllocCallback : public blifparse::Callback { public: - BlifAllocCallback(e_circuit_format blif_format, AtomNetlist& main_netlist, const std::string netlist_id, const t_model* user_models, const t_model* library_models) + BlifAllocCallback(e_circuit_format blif_format, AtomNetlist& main_netlist, const std::string netlist_id, const LogicalModels& models) : main_netlist_(main_netlist) , netlist_id_(netlist_id) - , user_arch_models_(user_models) - , library_arch_models_(library_models) + , models_(models) , blif_format_(blif_format) { VTR_ASSERT(blif_format_ == e_circuit_format::BLIF || blif_format_ == e_circuit_format::EBLIF); - inpad_model_ = find_model(MODEL_INPUT); - outpad_model_ = find_model(MODEL_OUTPUT); + inpad_model_ = models.get_model_by_name(LogicalModels::MODEL_INPUT); + outpad_model_ = models.get_model_by_name(LogicalModels::MODEL_OUTPUT); main_netlist_.set_block_types(inpad_model_, outpad_model_); } @@ -81,17 +75,18 @@ struct BlifAllocCallback : public blifparse::Callback { } void inputs(std::vector input_names) override { - const t_model* blk_model = find_model(MODEL_INPUT); + LogicalModelId blk_model_id = models_.get_model_by_name(LogicalModels::MODEL_INPUT); + const t_model& blk_model = models_.get_model(blk_model_id); - VTR_ASSERT_MSG(!blk_model->inputs, "Inpad model has an input port"); - VTR_ASSERT_MSG(blk_model->outputs, "Inpad model has no output port"); - VTR_ASSERT_MSG(blk_model->outputs->size == 1, "Inpad model has non-single-bit output port"); - VTR_ASSERT_MSG(!blk_model->outputs->next, "Inpad model has multiple output ports"); + VTR_ASSERT_MSG(!blk_model.inputs, "Inpad model has an input port"); + VTR_ASSERT_MSG(blk_model.outputs, "Inpad model has no output port"); + VTR_ASSERT_MSG(blk_model.outputs->size == 1, "Inpad model has non-single-bit output port"); + VTR_ASSERT_MSG(!blk_model.outputs->next, "Inpad model has multiple output ports"); - std::string pin_name = blk_model->outputs->name; + std::string pin_name = blk_model.outputs->name; for (const auto& input : input_names) { - AtomBlockId blk_id = curr_model().create_block(input, blk_model); - AtomPortId port_id = curr_model().create_port(blk_id, blk_model->outputs); + AtomBlockId blk_id = curr_model().create_block(input, blk_model_id); + AtomPortId port_id = curr_model().create_port(blk_id, blk_model.outputs); AtomNetId net_id = curr_model().create_net(input); curr_model().create_pin(port_id, 0, net_id, PinType::DRIVER); } @@ -99,19 +94,20 @@ struct BlifAllocCallback : public blifparse::Callback { } void outputs(std::vector output_names) override { - const t_model* blk_model = find_model(MODEL_OUTPUT); + LogicalModelId blk_model_id = models_.get_model_by_name(LogicalModels::MODEL_OUTPUT); + const t_model& blk_model = models_.get_model(blk_model_id); - VTR_ASSERT_MSG(!blk_model->outputs, "Outpad model has an output port"); - VTR_ASSERT_MSG(blk_model->inputs, "Outpad model has no input port"); - VTR_ASSERT_MSG(blk_model->inputs->size == 1, "Outpad model has non-single-bit input port"); - VTR_ASSERT_MSG(!blk_model->inputs->next, "Outpad model has multiple input ports"); + VTR_ASSERT_MSG(!blk_model.outputs, "Outpad model has an output port"); + VTR_ASSERT_MSG(blk_model.inputs, "Outpad model has no input port"); + VTR_ASSERT_MSG(blk_model.inputs->size == 1, "Outpad model has non-single-bit input port"); + VTR_ASSERT_MSG(!blk_model.inputs->next, "Outpad model has multiple input ports"); - std::string pin_name = blk_model->inputs->name; + std::string pin_name = blk_model.inputs->name; for (const auto& output : output_names) { //Since we name blocks based on their drivers we need to uniquify outpad names, //which we do with a prefix - AtomBlockId blk_id = curr_model().create_block(OUTPAD_NAME_PREFIX + output, blk_model); - AtomPortId port_id = curr_model().create_port(blk_id, blk_model->inputs); + AtomBlockId blk_id = curr_model().create_block(OUTPAD_NAME_PREFIX + output, blk_model_id); + AtomPortId port_id = curr_model().create_port(blk_id, blk_model.inputs); AtomNetId net_id = curr_model().create_net(output); curr_model().create_pin(port_id, 0, net_id, PinType::SINK); } @@ -119,20 +115,21 @@ struct BlifAllocCallback : public blifparse::Callback { } void names(std::vector nets, std::vector> so_cover) override { - const t_model* blk_model = find_model(MODEL_NAMES); + LogicalModelId blk_model_id = models_.get_model_by_name(LogicalModels::MODEL_NAMES); + const t_model& blk_model = models_.get_model(blk_model_id); VTR_ASSERT_MSG(nets.size() > 0, "BLIF .names has no connections"); - VTR_ASSERT_MSG(blk_model->inputs, ".names model has no input port"); - VTR_ASSERT_MSG(!blk_model->inputs->next, ".names model has multiple input ports"); - if (static_cast(nets.size()) - 1 > blk_model->inputs->size) { + VTR_ASSERT_MSG(blk_model.inputs, ".names model has no input port"); + VTR_ASSERT_MSG(!blk_model.inputs->next, ".names model has multiple input ports"); + if (static_cast(nets.size()) - 1 > blk_model.inputs->size) { vpr_throw(VPR_ERROR_BLIF_F, filename_.c_str(), lineno_, "BLIF .names input size (%zu) greater than .names model input size (%d)", - nets.size() - 1, blk_model->inputs->size); + nets.size() - 1, blk_model.inputs->size); } - VTR_ASSERT_MSG(blk_model->outputs, ".names has no output port"); - VTR_ASSERT_MSG(!blk_model->outputs->next, ".names model has multiple output ports"); - VTR_ASSERT_MSG(blk_model->outputs->size == 1, ".names model has non-single-bit output"); + VTR_ASSERT_MSG(blk_model.outputs, ".names has no output port"); + VTR_ASSERT_MSG(!blk_model.outputs->next, ".names model has multiple output ports"); + VTR_ASSERT_MSG(blk_model.outputs->size == 1, ".names model has non-single-bit output"); //Convert the single-output cover to a netlist truth table AtomNetlist::TruthTable truth_table; @@ -143,11 +140,11 @@ struct BlifAllocCallback : public blifparse::Callback { } } - AtomBlockId blk_id = curr_model().create_block(nets[nets.size() - 1], blk_model, truth_table); + AtomBlockId blk_id = curr_model().create_block(nets[nets.size() - 1], blk_model_id, truth_table); set_curr_block(blk_id); //Create inputs - AtomPortId input_port_id = curr_model().create_port(blk_id, blk_model->inputs); + AtomPortId input_port_id = curr_model().create_port(blk_id, blk_model.inputs); for (size_t i = 0; i < nets.size() - 1; ++i) { AtomNetId net_id = curr_model().create_net(nets[i]); @@ -187,7 +184,7 @@ struct BlifAllocCallback : public blifparse::Callback { //Create output AtomNetId net_id = curr_model().create_net(nets[nets.size() - 1]); - AtomPortId output_port_id = curr_model().create_port(blk_id, blk_model->outputs); + AtomPortId output_port_id = curr_model().create_port(blk_id, blk_model.outputs); curr_model().create_pin(output_port_id, 0, net_id, PinType::DRIVER, output_is_const); } @@ -202,17 +199,18 @@ struct BlifAllocCallback : public blifparse::Callback { 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); + LogicalModelId blk_model_id = models_.get_model_by_name(LogicalModels::MODEL_LATCH); + const t_model& blk_model = models_.get_model(blk_model_id); - VTR_ASSERT_MSG(blk_model->inputs, "Has one input port"); - VTR_ASSERT_MSG(blk_model->inputs->next, "Has two input port"); - VTR_ASSERT_MSG(!blk_model->inputs->next->next, "Has no more than two input port"); - VTR_ASSERT_MSG(blk_model->outputs, "Has one output port"); - VTR_ASSERT_MSG(!blk_model->outputs->next, "Has no more than one input port"); + VTR_ASSERT_MSG(blk_model.inputs, "Has one input port"); + VTR_ASSERT_MSG(blk_model.inputs->next, "Has two input port"); + VTR_ASSERT_MSG(!blk_model.inputs->next->next, "Has no more than two input port"); + VTR_ASSERT_MSG(blk_model.outputs, "Has one output port"); + 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; - const t_model_ports* q_model_port = blk_model->outputs; + const t_model_ports* d_model_port = blk_model.inputs; + const 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")); VTR_ASSERT(clk_model_port->name == std::string("clk")); @@ -226,7 +224,7 @@ struct BlifAllocCallback : public blifparse::Callback { AtomNetlist::TruthTable truth_table(1); truth_table[0].push_back(to_vtr_logic_value(init)); - AtomBlockId blk_id = curr_model().create_block(output, blk_model, truth_table); + AtomBlockId blk_id = curr_model().create_block(output, blk_model_id, truth_table); set_curr_block(blk_id); //The input @@ -248,7 +246,8 @@ struct BlifAllocCallback : public blifparse::Callback { void subckt(std::string subckt_model, std::vector ports, std::vector nets) override { VTR_ASSERT(ports.size() == nets.size()); - const t_model* blk_model = find_model(subckt_model); + LogicalModelId blk_model_id = models_.get_model_by_name(subckt_model); + const t_model& blk_model = models_.get_model(blk_model_id); //We name the subckt based on the net it's first output pin drives std::string subckt_name; @@ -269,21 +268,21 @@ struct BlifAllocCallback : public blifparse::Callback { //Since this is unusual, warn the user VTR_LOGF_WARN(filename_.c_str(), lineno_, "Subckt of type '%s' at %s:%d has no output pins, and has been named '%s'\n", - blk_model->name, filename_.c_str(), lineno_, subckt_name.c_str()); + blk_model.name, filename_.c_str(), lineno_, subckt_name.c_str()); } //The name for every block should be unique, check that there is no name conflict AtomBlockId blk_id = curr_model().find_block(subckt_name); if (blk_id) { - const t_model* conflicting_model = curr_model().block_model(blk_id); + LogicalModelId conflicting_model = curr_model().block_model(blk_id); vpr_throw(VPR_ERROR_BLIF_F, filename_.c_str(), lineno_, "Duplicate blocks named '%s' found in netlist." " Existing block of type '%s' conflicts with subckt of type '%s'.", - subckt_name.c_str(), conflicting_model->name, subckt_model.c_str()); + subckt_name.c_str(), models_.get_model(conflicting_model).name, subckt_model.c_str()); } //Create the block - blk_id = curr_model().create_block(subckt_name, blk_model); + blk_id = curr_model().create_block(subckt_name, blk_model_id); set_curr_block(blk_id); for (size_t i = 0; i < ports.size(); ++i) { @@ -443,30 +442,7 @@ struct BlifAllocCallback : public blifparse::Callback { } private: - const t_model* find_model(std::string_view name) { - 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 (name == arch_model->name) { - //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'\n", - name.data()); - } - return arch_model; - } - - const t_model_ports* find_model_port(const t_model* blk_model, const std::string& port_name) { + const t_model_ports* find_model_port(const t_model& blk_model, const std::string& port_name) { //We need to handle both single, and multi-bit port names // //By convention multi-bit port names have the bit index stored in square brackets @@ -485,7 +461,7 @@ struct BlifAllocCallback : public blifparse::Callback { VTR_ASSERT(bit_index >= 0); //We now look through all the ports on the model looking for the matching port - for (const t_model_ports* ports : {blk_model->inputs, blk_model->outputs}) { + for (const t_model_ports* ports : {blk_model.inputs, blk_model.outputs}) { const t_model_ports* curr_port = ports; while (curr_port) { if (trimmed_port_name == curr_port->name) { @@ -497,7 +473,7 @@ struct BlifAllocCallback : public blifparse::Callback { //Out of range vpr_throw(VPR_ERROR_BLIF_F, filename_.c_str(), lineno_, "Port '%s' on architecture model '%s' exceeds port width (%d bits)\n", - port_name.c_str(), blk_model->name, curr_port->size); + port_name.c_str(), blk_model.name, curr_port->size); } } curr_port = curr_port->next; @@ -507,7 +483,7 @@ struct BlifAllocCallback : public blifparse::Callback { //No match vpr_throw(VPR_ERROR_BLIF_F, filename_.c_str(), lineno_, "Found no matching port '%s' on architecture model '%s'\n", - port_name.c_str(), blk_model->name); + port_name.c_str(), blk_model.name); return nullptr; } @@ -563,7 +539,8 @@ struct BlifAllocCallback : public blifparse::Callback { } bool verify_blackbox_model(AtomNetlist& blif_model) { - const t_model* arch_model = find_model(blif_model.netlist_name()); + LogicalModelId arch_model_id = models_.get_model_by_name(blif_model.netlist_name()); + const t_model& arch_model = models_.get_model(arch_model_id); //Verify each port on the model // @@ -639,10 +616,9 @@ struct BlifAllocCallback : public blifparse::Callback { AtomNetlist& main_netlist_; /// #include "atom_netlist_fwd.h" #include "read_circuit.h" +class LogicalModels; + bool is_string_param(const std::string& param); bool is_binary_param(const std::string& param); bool is_real_param(const std::string& param); AtomNetlist read_blif(e_circuit_format circuit_format, const char* blif_file, - const t_model* user_models, - const t_model* library_models); + const LogicalModels& models); #endif /*READ_BLIF_H*/ diff --git a/vpr/src/base/read_circuit.cpp b/vpr/src/base/read_circuit.cpp index 4d6fab3f25d..f1112d92016 100644 --- a/vpr/src/base/read_circuit.cpp +++ b/vpr/src/base/read_circuit.cpp @@ -1,4 +1,5 @@ #include "read_circuit.h" +#include "logic_types.h" #include "read_blif.h" #include "read_interchange_netlist.h" #include "atom_netlist.h" @@ -16,15 +17,14 @@ static void process_circuit(AtomNetlist& netlist, bool should_sweep_dangling_nets, bool should_sweep_dangling_blocks, bool should_sweep_constant_primary_outputs, + const LogicalModels& models, int verbosity); -static void show_circuit_stats(const AtomNetlist& netlist); +static void show_circuit_stats(const AtomNetlist& netlist, const LogicalModels& models); AtomNetlist read_and_process_circuit(e_circuit_format circuit_format, t_vpr_setup& vpr_setup, t_arch& arch) { // Options const char* circuit_file = vpr_setup.PackerOpts.circuit_file_name.c_str(); - const t_model* user_models = vpr_setup.user_models; - const t_model* library_models = vpr_setup.library_models; e_const_gen_inference const_gen_inference = vpr_setup.NetlistOpts.const_gen_inference; bool should_absorb_buffers = vpr_setup.NetlistOpts.absorb_buffer_luts; bool should_sweep_dangling_primary_ios = vpr_setup.NetlistOpts.sweep_dangling_primary_ios; @@ -54,7 +54,7 @@ AtomNetlist read_and_process_circuit(e_circuit_format circuit_format, t_vpr_setu switch (circuit_format) { case e_circuit_format::BLIF: case e_circuit_format::EBLIF: - netlist = read_blif(circuit_format, circuit_file, user_models, library_models); + netlist = read_blif(circuit_format, circuit_file, arch.models); break; case e_circuit_format::FPGA_INTERCHANGE: netlist = read_interchange_netlist(circuit_file, arch); @@ -68,7 +68,7 @@ AtomNetlist read_and_process_circuit(e_circuit_format circuit_format, t_vpr_setu } if (isEchoFileEnabled(E_ECHO_ATOM_NETLIST_ORIG)) { - print_netlist_as_blif(getEchoFileName(E_ECHO_ATOM_NETLIST_ORIG), netlist); + print_netlist_as_blif(getEchoFileName(E_ECHO_ATOM_NETLIST_ORIG), netlist, arch.models); } process_circuit(netlist, @@ -78,13 +78,14 @@ AtomNetlist read_and_process_circuit(e_circuit_format circuit_format, t_vpr_setu should_sweep_dangling_nets, should_sweep_dangling_blocks, should_sweep_constant_primary_outputs, + arch.models, verbosity); if (isEchoFileEnabled(E_ECHO_ATOM_NETLIST_CLEANED)) { - print_netlist_as_blif(getEchoFileName(E_ECHO_ATOM_NETLIST_CLEANED), netlist); + print_netlist_as_blif(getEchoFileName(E_ECHO_ATOM_NETLIST_CLEANED), netlist, arch.models); } - show_circuit_stats(netlist); + show_circuit_stats(netlist, arch.models); return netlist; } @@ -96,13 +97,14 @@ static void process_circuit(AtomNetlist& netlist, bool should_sweep_dangling_nets, bool should_sweep_dangling_blocks, bool should_sweep_constant_primary_outputs, + const LogicalModels& models, int verbosity) { { vtr::ScopedStartFinishTimer t("Clean circuit"); //Clean-up lut buffers if (should_absorb_buffers) { - absorb_buffer_luts(netlist, verbosity); + absorb_buffer_luts(netlist, models, verbosity); } //Remove the special 'unconn' net @@ -126,6 +128,7 @@ static void process_circuit(AtomNetlist& netlist, should_sweep_dangling_blocks, should_sweep_constant_primary_outputs, const_gen_inference_method, + models, verbosity); } @@ -142,17 +145,19 @@ static void process_circuit(AtomNetlist& netlist, } } -static void show_circuit_stats(const AtomNetlist& netlist) { +static void show_circuit_stats(const AtomNetlist& netlist, const LogicalModels& models) { // Count the block statistics std::map block_type_counts; std::map lut_size_counts; + LogicalModelId names_model_id = models.get_model_by_name(LogicalModels::MODEL_NAMES); for (auto blk_id : netlist.blocks()) { // For each model, count the number of occurrences in the netlist. - const t_model* blk_model = netlist.block_model(blk_id); - ++block_type_counts[blk_model->name]; + LogicalModelId blk_model_id = netlist.block_model(blk_id); + std::string blk_model_name = models.get_model(blk_model_id).name; + ++block_type_counts[blk_model_name]; // If this block is a LUT, also count the occurences of this size of LUT // for more logging information. - if (blk_model->name == std::string(MODEL_NAMES)) { + if (blk_model_id == names_model_id) { // May have zero (no input LUT) or one input port auto in_ports = netlist.block_input_ports(blk_id); VTR_ASSERT(in_ports.size() <= 1 && "Expected number of input ports for LUT to be 0 or 1"); @@ -205,7 +210,7 @@ static void show_circuit_stats(const AtomNetlist& netlist) { VTR_LOG(" %-*s: %7zu\n", max_block_type_len, kv.first.c_str(), kv.second); // If this block is a LUT, print the different sizes of LUTs in the // design. - if (kv.first == std::string(MODEL_NAMES)) { + if (kv.first == LogicalModels::MODEL_NAMES) { for (const auto& lut_kv : lut_size_counts) { VTR_LOG(" %-*s: %7zu\n", max_lut_size_len, lut_kv.first.c_str(), lut_kv.second); } @@ -215,7 +220,7 @@ static void show_circuit_stats(const AtomNetlist& netlist) { for (const auto& kv : net_stats) { VTR_LOG(" %-*s: %7.1f\n", max_net_type_len, kv.first.c_str(), kv.second); } - VTR_LOG(" Netlist Clocks: %zu\n", find_netlist_logical_clock_drivers(netlist).size()); + VTR_LOG(" Netlist Clocks: %zu\n", find_netlist_logical_clock_drivers(netlist, models).size()); if (netlist.blocks().empty()) { VTR_LOG_WARN("Netlist contains no blocks\n"); diff --git a/vpr/src/base/read_circuit.h b/vpr/src/base/read_circuit.h index 90be01a3891..89f42f7ec61 100644 --- a/vpr/src/base/read_circuit.h +++ b/vpr/src/base/read_circuit.h @@ -1,8 +1,10 @@ #ifndef VPR_READ_CIRCUIT_H #define VPR_READ_CIRCUIT_H -#include "logic_types.h" + #include "atom_netlist_fwd.h" -#include "vpr_types.h" + +struct t_vpr_setup; +struct t_arch; enum class e_circuit_format { AUTO, ///outputs); + blk_id = main_netlist_.create_block(port_name, input_model_id); + port_id = main_netlist_.create_port(blk_id, input_model.outputs); net_id = main_netlist_.create_net(port_name); main_netlist_.create_pin(port_id, 0, net_id, PinType::DRIVER); break; case LogicalNetlist::Netlist::Direction::OUTPUT: - blk_id = main_netlist_.create_block(port_name, output_model); - port_id = main_netlist_.create_port(blk_id, output_model->inputs); + blk_id = main_netlist_.create_block(port_name, output_model_id); + port_id = main_netlist_.create_port(blk_id, output_model.inputs); net_id = main_netlist_.create_net(port_name); main_netlist_.create_pin(port_id, 0, net_id, PinType::SINK); break; @@ -188,13 +187,14 @@ struct NetlistReader { } void read_names() { - const t_model* blk_model = find_model(MODEL_NAMES); + LogicalModelId blk_model_id = models_.get_model_by_name(LogicalModels::MODEL_NAMES); + const t_model& blk_model = models_.get_model(blk_model_id); // Set the max size of the LUT int lut_size = 0; for (auto lut : arch_.lut_cells) lut_size = std::max((int)lut.inputs.size(), lut_size); - blk_model->inputs[0].size = lut_size; + blk_model.inputs[0].size = lut_size; auto top_cell = nr_.getCellList()[nr_.getTopInst().getCell()]; auto decl_list = nr_.getCellDecls(); @@ -317,10 +317,10 @@ struct NetlistReader { VTR_LOG("Found constant-one generator '%s'\n", inst_name.c_str()); } - AtomBlockId blk_id = main_netlist_.create_block(inst_name, blk_model, truth_table); + AtomBlockId blk_id = main_netlist_.create_block(inst_name, blk_model_id, truth_table); - AtomPortId iport_id = main_netlist_.create_port(blk_id, blk_model->inputs); - AtomPortId oport_id = main_netlist_.create_port(blk_id, blk_model->outputs); + AtomPortId iport_id = main_netlist_.create_port(blk_id, blk_model.inputs); + AtomPortId oport_id = main_netlist_.create_port(blk_id, blk_model.outputs); auto cell_lib = decl_list[inst_list[inst_idx].getCell()]; auto port_net_map = port_net_maps_.at(inst_idx); @@ -373,7 +373,8 @@ struct NetlistReader { auto cell_idx = inst_pair.second; auto model_name = str_list[decl_list[cell_idx].getName()]; - const t_model* blk_model = find_model(model_name); + LogicalModelId blk_model_id = models_.get_model_by_name(model_name); + const t_model& blk_model = models_.get_model(blk_model_id); std::string inst_name = str_list[inst_list[inst_idx].getName()]; VTR_ASSERT(inst_name.empty() == 0); @@ -381,11 +382,11 @@ struct NetlistReader { //The name for every block should be unique, check that there is no name conflict AtomBlockId blk_id = main_netlist_.find_block(inst_name); if (blk_id) { - const t_model* conflicting_model = main_netlist_.block_model(blk_id); + LogicalModelId conflicting_model = main_netlist_.block_model(blk_id); vpr_throw(VPR_ERROR_IC_NETLIST_F, netlist_file_, -1, "Duplicate blocks named '%s' found in netlist." " Existing block of type '%s' conflicts with subckt of type '%s'.", - inst_name.c_str(), conflicting_model->name, blk_model->name); + inst_name.c_str(), models_.get_model(conflicting_model).name, blk_model.name); } auto port_net_map = port_net_maps_.at(inst_idx); @@ -400,7 +401,7 @@ struct NetlistReader { continue; //Create the block - blk_id = main_netlist_.create_block(inst_name, blk_model); + blk_id = main_netlist_.create_block(inst_name, blk_model_id); std::unordered_set added_ports; for (auto port_net : port_net_map) { @@ -440,7 +441,7 @@ struct NetlistReader { } // Bind unconnected ports to VCC by default - for (const t_model_ports* ports : {blk_model->inputs, blk_model->outputs}) { + for (const t_model_ports* ports : {blk_model.inputs, blk_model.outputs}) { for (const t_model_ports* port = ports; port != nullptr; port = port->next) { AtomPortId port_id = main_netlist_.create_port(blk_id, port); @@ -465,18 +466,9 @@ struct NetlistReader { // // Utilities // - const t_model* find_model(std::string name) { - for (const auto models : {arch_.models, arch_.model_library}) - for (const t_model* model = models; model != nullptr; model = model->next) - if (name == model->name) - return model; - - vpr_throw(VPR_ERROR_IC_NETLIST_F, netlist_file_, -1, "Failed to find matching architecture model for '%s'\n", name.c_str()); - } - - const t_model_ports* find_model_port(const t_model* blk_model, std::string name) { + const t_model_ports* find_model_port(const t_model& blk_model, std::string name) { //We now look through all the ports on the model looking for the matching port - for (const t_model_ports* ports : {blk_model->inputs, blk_model->outputs}) + for (const t_model_ports* ports : {blk_model.inputs, blk_model.outputs}) for (const t_model_ports* port = ports; port != nullptr; port = port->next) if (name == std::string(port->name)) return port; @@ -484,7 +476,7 @@ struct NetlistReader { //No match vpr_throw(VPR_ERROR_IC_NETLIST_F, netlist_file_, -1, "Found no matching port '%s' on architecture model '%s'\n", - name.c_str(), blk_model->name); + name.c_str(), blk_model.name); return nullptr; } @@ -568,7 +560,7 @@ AtomNetlist read_interchange_netlist(const char* ic_netlist_file, auto netlist_reader = message_reader.getRoot(); - NetlistReader reader(netlist, netlist_reader, netlist_id, ic_netlist_file, arch); + NetlistReader reader(netlist, netlist_reader, netlist_id, ic_netlist_file, arch.models, arch); return netlist; diff --git a/vpr/src/base/read_interchange_netlist.h b/vpr/src/base/read_interchange_netlist.h index 1b17b86ea5d..02a7546c660 100644 --- a/vpr/src/base/read_interchange_netlist.h +++ b/vpr/src/base/read_interchange_netlist.h @@ -1,8 +1,9 @@ #ifndef READ_INTERCHANGE_NETLIST_H #define READ_INTERCHANGE_NETLIST_H -#include "logic_types.h" + #include "atom_netlist_fwd.h" -#include "read_circuit.h" + +struct t_arch; AtomNetlist read_interchange_netlist(const char* ic_netlist_file, t_arch& arch); diff --git a/vpr/src/base/read_netlist.cpp b/vpr/src/base/read_netlist.cpp index 5a39ccfef37..b498b8671b2 100644 --- a/vpr/src/base/read_netlist.cpp +++ b/vpr/src/base/read_netlist.cpp @@ -1092,7 +1092,7 @@ static size_t mark_constant_generators_rec(const t_pb* pb, const t_pb_routes& pb } } } - } else if (strcmp(pb->pb_graph_node->pb_type->blif_model, MODEL_INPUT) != 0) { + } else if (strcmp(pb->pb_graph_node->pb_type->blif_model, LogicalModels::MODEL_INPUT) != 0) { const_gen = true; for (i = 0; i < pb->pb_graph_node->num_input_ports && const_gen == true; i++) { for (j = 0; j < pb->pb_graph_node->num_input_pins[i] && const_gen == true; j++) { @@ -1184,7 +1184,7 @@ 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.netlist().block_model(blk), + VTR_ASSERT_MSG(gnode->pb_type->model_id == atom_ctx.netlist().block_model(blk), "Atom block PB must match BLIF model"); for (int iport = 0; iport < gnode->num_input_ports; ++iport) { diff --git a/vpr/src/base/vpr_api.cpp b/vpr/src/base/vpr_api.cpp index 928839410f2..2c84a6a7681 100644 --- a/vpr/src/base/vpr_api.cpp +++ b/vpr/src/base/vpr_api.cpp @@ -285,8 +285,6 @@ void vpr_init_with_options(const t_options* options, t_vpr_setup* vpr_setup, t_a true, &vpr_setup->FileNameOpts, arch, - &vpr_setup->user_models, - &vpr_setup->library_models, &vpr_setup->NetlistOpts, &vpr_setup->PackerOpts, &vpr_setup->PlacerOpts, @@ -336,17 +334,17 @@ void vpr_init_with_options(const t_options* options, t_vpr_setup* vpr_setup, t_a auto& timing_ctx = g_vpr_ctx.mutable_timing(); { vtr::ScopedStartFinishTimer t("Build Timing Graph"); - timing_ctx.graph = TimingGraphBuilder(atom_ctx.netlist(), atom_ctx.mutable_lookup()).timing_graph(options->allow_dangling_combinational_nodes); + timing_ctx.graph = TimingGraphBuilder(atom_ctx.netlist(), atom_ctx.mutable_lookup(), arch->models).timing_graph(options->allow_dangling_combinational_nodes); VTR_LOG(" Timing Graph Nodes: %zu\n", timing_ctx.graph->nodes().size()); VTR_LOG(" Timing Graph Edges: %zu\n", timing_ctx.graph->edges().size()); VTR_LOG(" Timing Graph Levels: %zu\n", timing_ctx.graph->levels().size()); } { - print_netlist_clock_info(atom_ctx.netlist()); + print_netlist_clock_info(atom_ctx.netlist(), arch->models); } { vtr::ScopedStartFinishTimer t("Load Timing Constraints"); - timing_ctx.constraints = read_sdc(vpr_setup->Timing, atom_ctx.netlist(), atom_ctx.lookup(), *timing_ctx.graph); + timing_ctx.constraints = read_sdc(vpr_setup->Timing, atom_ctx.netlist(), atom_ctx.lookup(), arch->models, *timing_ctx.graph); } { set_terminate_if_timing_fails(options->terminate_if_timing_fails); @@ -512,8 +510,6 @@ void vpr_create_device_grid(const t_vpr_setup& vpr_setup, const t_arch& Arch) { auto& cluster_ctx = g_vpr_ctx.clustering(); auto& device_ctx = g_vpr_ctx.mutable_device(); - device_ctx.arch = &Arch; - /* *Load the device grid */ @@ -648,6 +644,7 @@ bool vpr_pack(t_vpr_setup& vpr_setup, const t_arch& arch) { // The Prepacker object performs prepacking and stores the pack molecules. // As long as the molecules are used, this object must persist. const Prepacker prepacker(g_vpr_ctx.atom().netlist(), + arch.models, g_vpr_ctx.device().logical_block_types); // Setup pre-clustering timing analysis @@ -732,7 +729,6 @@ bool vpr_load_flat_placement(t_vpr_setup& vpr_setup, const t_arch& arch) { // set up the device grid for the legalizer auto& device_ctx = g_vpr_ctx.mutable_device(); - device_ctx.arch = &arch; device_ctx.grid = create_device_grid(vpr_setup.device_layout, arch.grid_layouts); if (device_ctx.grid.get_num_layers() > 1) { VPR_FATAL_ERROR(VPR_ERROR_PACK, "Legalizer currently only supports single layer devices.\n"); @@ -1289,8 +1285,6 @@ void vpr_setup_vpr(t_options* Options, const bool readArchFile, t_file_name_opts* FileNameOpts, t_arch* Arch, - t_model** user_models, - t_model** library_models, t_netlist_opts* NetlistOpts, t_packer_opts* PackerOpts, t_placer_opts* PlacerOpts, @@ -1314,8 +1308,6 @@ void vpr_setup_vpr(t_options* Options, readArchFile, FileNameOpts, Arch, - user_models, - library_models, NetlistOpts, PackerOpts, PlacerOpts, @@ -1476,12 +1468,12 @@ void vpr_analysis(const Netlist<>& net_list, //Write the post-synthesis netlist if (vpr_setup.AnalysisOpts.gen_post_synthesis_netlist) { netlist_writer(atom_ctx.netlist().netlist_name(), analysis_delay_calc, - vpr_setup.AnalysisOpts); + Arch.models, vpr_setup.AnalysisOpts); } //Write the post-implementation merged netlist if (vpr_setup.AnalysisOpts.gen_post_implementation_merged_netlist) { - merged_netlist_writer(atom_ctx.netlist().netlist_name(), analysis_delay_calc, vpr_setup.AnalysisOpts); + merged_netlist_writer(atom_ctx.netlist().netlist_name(), analysis_delay_calc, Arch.models, vpr_setup.AnalysisOpts); } //Do power analysis diff --git a/vpr/src/base/vpr_api.h b/vpr/src/base/vpr_api.h index 7eda169ba5e..28324e60da1 100644 --- a/vpr/src/base/vpr_api.h +++ b/vpr/src/base/vpr_api.h @@ -178,8 +178,6 @@ void vpr_setup_vpr(t_options* Options, const bool readArchFile, t_file_name_opts* FileNameOpts, t_arch* Arch, - t_model** user_models, - t_model** library_models, t_netlist_opts* NetlistOpts, t_packer_opts* PackerOpts, t_placer_opts* PlacerOpts, diff --git a/vpr/src/base/vpr_types.cpp b/vpr/src/base/vpr_types.cpp index 22a644a2d07..4d97816558b 100644 --- a/vpr/src/base/vpr_types.cpp +++ b/vpr/src/base/vpr_types.cpp @@ -2,6 +2,7 @@ #include #include "vpr_types.h" #include "globals.h" +#include "logic_types.h" t_ext_pin_util_targets::t_ext_pin_util_targets(float default_in_util, float default_out_util) { defaults_.input_pin_util = default_in_util; @@ -362,10 +363,10 @@ t_pb* t_pb::find_mutable_pb(const t_pb_graph_node* gnode) { return nullptr; //Not found } -const t_pb* t_pb::find_pb_for_model(const std::string& blif_model) const { +const t_pb* t_pb::find_pb_for_model(LogicalModelId blif_model_id) const { //Base case - const t_model* model = pb_graph_node->pb_type->model; - if (model && model->name == blif_model) { + LogicalModelId model_id = pb_graph_node->pb_type->model_id; + if (model_id.is_valid() && model_id == blif_model_id) { return this; } @@ -376,7 +377,7 @@ const t_pb* t_pb::find_pb_for_model(const std::string& blif_model) const { for (int ipb = 0; ipb < get_num_children_of_type(ichild_type); ++ipb) { const t_pb* child_pb = &child_pbs[ichild_type][ipb]; - const t_pb* matching_pb = child_pb->find_pb_for_model(blif_model); + const t_pb* matching_pb = child_pb->find_pb_for_model(blif_model_id); if (matching_pb) { return this; } diff --git a/vpr/src/base/vpr_types.h b/vpr/src/base/vpr_types.h index f71720325a5..106070c4c97 100644 --- a/vpr/src/base/vpr_types.h +++ b/vpr/src/base/vpr_types.h @@ -311,7 +311,7 @@ class t_pb { */ t_pb* find_mutable_pb(const t_pb_graph_node* gnode); - const t_pb* find_pb_for_model(const std::string& blif_model) const; + const t_pb* find_pb_for_model(LogicalModelId blif_model_id) const; ///@brief Returns the root pb containing this pb const t_pb* root_pb() const; @@ -1502,8 +1502,6 @@ struct t_server_opts { struct t_vpr_setup { bool TimingEnabled; ///models; AtomPortId port_id = atom_ctx.netlist().pin_port(pin_id); const t_model_ports* model_port = atom_ctx.netlist().port_model(port_id); @@ -634,8 +635,8 @@ void find_pin_index_at_model_scope(const AtomPinId pin_id, const AtomBlockId blk // Note that we do this on the model since the atom netlist doesn't include unused ports int pin_cnt = 0; *pin_index = -1; //initialize - const t_model* model = atom_ctx.netlist().block_model(blk_id); - for (const t_model_ports* port : {model->inputs, model->outputs}) { + const t_model& model = models.get_model(atom_ctx.netlist().block_model(blk_id)); + for (const t_model_ports* port : {model.inputs, model.outputs}) { while (port) { if (port == model_port) { //This is the port the pin is associated with, record it's index diff --git a/vpr/src/pack/cluster_legalizer.cpp b/vpr/src/pack/cluster_legalizer.cpp index 947fbed2fbd..0c0040ac3e7 100644 --- a/vpr/src/pack/cluster_legalizer.cpp +++ b/vpr/src/pack/cluster_legalizer.cpp @@ -323,6 +323,7 @@ static enum e_block_pack_status check_chain_root_placement_feasibility(const t_p */ static bool primitive_memory_sibling_feasible(const AtomBlockId blk_id, const t_pb_type* cur_pb_type, const AtomBlockId sibling_blk_id) { const AtomContext& atom_ctx = g_vpr_ctx.atom(); + const LogicalModels& models = g_vpr_ctx.device().arch->models; VTR_ASSERT(cur_pb_type->class_type == MEMORY_CLASS); @@ -343,8 +344,8 @@ static bool primitive_memory_sibling_feasible(const AtomBlockId blk_id, const t_ //Since the atom netlist stores only in-use ports, we iterate over the model to ensure //all ports are compared - const t_model* model = cur_pb_type->model; - for (t_model_ports* port : {model->inputs, model->outputs}) { + const t_model& model = models.get_model(cur_pb_type->model_id); + for (t_model_ports* port : {model.inputs, model.outputs}) { for (; port; port = port->next) { if (data_ports.count(port)) { //Don't check data ports @@ -441,6 +442,7 @@ try_place_atom_block_rec(const t_pb_graph_node* pb_graph_node, const vtr::vector_map& clustering_chain_info, AtomPBBimap& atom_to_pb) { const AtomContext& atom_ctx = g_vpr_ctx.atom(); + const LogicalModels& models = g_vpr_ctx.device().arch->models; VTR_ASSERT_SAFE(cb != nullptr); e_block_pack_status block_pack_status = e_block_pack_status::BLK_PASSED; @@ -553,7 +555,7 @@ try_place_atom_block_rec(const t_pb_graph_node* pb_graph_node, VTR_LOGV(verbosity > 4 && block_pack_status == e_block_pack_status::BLK_PASSED, "\t\t\tPlaced atom '%s' (%s) at %s\n", atom_ctx.netlist().block_name(blk_id).c_str(), - atom_ctx.netlist().block_model(blk_id)->name, + models.model_name(atom_ctx.netlist().block_model(blk_id)).c_str(), pb->hierarchical_type_name().c_str()); } @@ -1133,6 +1135,8 @@ e_block_pack_status ClusterLegalizer::try_pack_molecule(PackMoleculeId molecule_ // constraints. const FloorplanningContext& floorplanning_ctx = g_vpr_ctx.floorplanning(); + const LogicalModels& models = g_vpr_ctx.device().arch->models; + // Get the molecule object. const t_pack_molecule& molecule = prepacker_.get_molecule(molecule_id); @@ -1140,7 +1144,7 @@ e_block_pack_status ClusterLegalizer::try_pack_molecule(PackMoleculeId molecule_ AtomBlockId root_atom = molecule.atom_block_ids[molecule.root]; VTR_LOG("\t\tTry pack molecule: '%s' (%s)", atom_ctx.netlist().block_name(root_atom).c_str(), - atom_ctx.netlist().block_model(root_atom)->name); + models.model_name(atom_ctx.netlist().block_model(root_atom)).c_str()); VTR_LOGV(molecule.pack_pattern, " molecule_type %s molecule_size %zu", molecule.pack_pattern->name, @@ -1600,6 +1604,7 @@ ClusterLegalizer::ClusterLegalizer(const AtomNetlist& atom_netlist, const t_pack_high_fanout_thresholds& high_fanout_thresholds, ClusterLegalizationStrategy cluster_legalization_strategy, bool enable_pin_feasibility_filter, + const LogicalModels& models, int log_verbosity) : prepacker_(prepacker) { // Verify that the inputs are valid. @@ -1620,7 +1625,7 @@ ClusterLegalizer::ClusterLegalizer(const AtomNetlist& atom_netlist, // Get a reference to the rr graphs. lb_type_rr_graphs_ = lb_type_rr_graphs; // Find all NoC router atoms. - std::vector noc_atoms = find_noc_router_atoms(atom_netlist); + std::vector noc_atoms = find_noc_router_atoms(atom_netlist, models); update_noc_reachability_partitions(noc_atoms, atom_netlist, high_fanout_thresholds, diff --git a/vpr/src/pack/cluster_legalizer.h b/vpr/src/pack/cluster_legalizer.h index 418bff73d95..8cdd42df298 100644 --- a/vpr/src/pack/cluster_legalizer.h +++ b/vpr/src/pack/cluster_legalizer.h @@ -27,6 +27,7 @@ // Forward declarations class Prepacker; +class LogicalModels; class t_intra_cluster_placement_stats; class t_pb_graph_node; struct t_lb_router_data; @@ -269,6 +270,7 @@ class ClusterLegalizer { * performed. * @param enable_pin_feasibility_filter * A flag to turn on/off the check for pin usage feasibility. + * @param models * @param log_verbosity * Controls how verbose the log messages will be within this class. */ @@ -279,6 +281,7 @@ class ClusterLegalizer { const t_pack_high_fanout_thresholds& high_fanout_thresholds, ClusterLegalizationStrategy cluster_legalization_strategy, bool enable_pin_feasibility_filter, + const LogicalModels& models, int log_verbosity); // This class allocates and deallocates memory within. This class should not diff --git a/vpr/src/pack/cluster_util.cpp b/vpr/src/pack/cluster_util.cpp index dd307168a36..fcb4f88f926 100644 --- a/vpr/src/pack/cluster_util.cpp +++ b/vpr/src/pack/cluster_util.cpp @@ -7,9 +7,12 @@ #include "cluster_legalizer.h" #include "clustered_netlist.h" #include "globals.h" +#include "logic_types.h" #include "output_clustering.h" #include "prepack.h" #include "vpr_context.h" +#include "vtr_vector.h" +#include "vtr_vector_map.h" /*Print the contents of each cluster to an echo file*/ static void echo_clusters(char* filename, const ClusterLegalizer& cluster_legalizer) { @@ -151,26 +154,29 @@ void rebuild_attraction_groups(AttractionInfo& attraction_groups, /*****************************************/ -std::map> identify_primitive_candidate_block_types() { - std::map> model_candidates; +vtr::vector> identify_primitive_candidate_block_types() { const AtomNetlist& atom_nlist = g_vpr_ctx.atom().netlist(); const DeviceContext& device_ctx = g_vpr_ctx.device(); + const LogicalModels& models = device_ctx.arch->models; + size_t num_models = models.all_models().size(); + vtr::vector> model_candidates(num_models); - std::set unique_models; + std::set unique_models; // Find all logic models used in the netlist for (auto blk : atom_nlist.blocks()) { - auto model = atom_nlist.block_model(blk); + LogicalModelId model = atom_nlist.block_model(blk); unique_models.insert(model); } /* For each technology-mapped logic model, find logical block types * that can accommodate that logic model */ - for (auto model : unique_models) { - model_candidates[model] = {}; + for (LogicalModelId model : unique_models) { + VTR_ASSERT(model.is_valid()); + VTR_ASSERT(model_candidates[model].empty()); for (auto const& type : device_ctx.logical_block_types) { - if (block_type_contains_blif_model(&type, model->name)) { + if (block_type_contains_blif_model(&type, models.model_name(model))) { model_candidates[model].push_back(&type); } } @@ -268,16 +274,15 @@ void print_pb_type_count(const ClusteredNetlist& clb_nlist) { VTR_LOG("\n"); } -t_logical_block_type_ptr identify_logic_block_type(const std::map>& primitive_candidate_block_types) { - std::string lut_name = ".names"; +t_logical_block_type_ptr identify_logic_block_type(const vtr::vector>& primitive_candidate_block_types, + const LogicalModels& models) { + LogicalModelId lut_model_id = models.get_model_by_name(LogicalModels::MODEL_NAMES); - for (auto& model : primitive_candidate_block_types) { - std::string model_name(model.first->name); - if (model_name == lut_name) - return model.second[0]; - } + VTR_ASSERT(lut_model_id.is_valid()); + if (primitive_candidate_block_types[lut_model_id].size() == 0) + return nullptr; - return nullptr; + return primitive_candidate_block_types[lut_model_id][0]; } t_pb_type* identify_le_block_type(t_logical_block_type_ptr logic_block_type) { diff --git a/vpr/src/pack/cluster_util.h b/vpr/src/pack/cluster_util.h index 4f4c2b5bec8..82fcf805047 100644 --- a/vpr/src/pack/cluster_util.h +++ b/vpr/src/pack/cluster_util.h @@ -4,6 +4,7 @@ #include #include #include "cluster_legalizer.h" +#include "logic_types.h" #include "vtr_vector.h" class AtomNetId; @@ -54,7 +55,7 @@ void print_pack_status(int tot_num_molecules, void rebuild_attraction_groups(AttractionInfo& attraction_groups, const ClusterLegalizer& cluster_legalizer); -std::map> identify_primitive_candidate_block_types(); +vtr::vector> identify_primitive_candidate_block_types(); /** * @brief Identify which nets in the atom netlist are driven by the same atom @@ -90,7 +91,8 @@ void print_pb_type_count(const ClusteredNetlist& clb_nlist); * @brief This function identifies the logic block type which is defined by the * block type which has a lut primitive. */ -t_logical_block_type_ptr identify_logic_block_type(const std::map>& primitive_candidate_block_types); +t_logical_block_type_ptr identify_logic_block_type(const vtr::vector>& primitive_candidate_block_types, + const LogicalModels& models); /* * @brief This function returns the pb_type that is similar to Logic Element (LE) diff --git a/vpr/src/pack/greedy_candidate_selector.cpp b/vpr/src/pack/greedy_candidate_selector.cpp index b202035ec59..10255890d67 100644 --- a/vpr/src/pack/greedy_candidate_selector.cpp +++ b/vpr/src/pack/greedy_candidate_selector.cpp @@ -19,12 +19,14 @@ #include "cluster_legalizer.h" #include "cluster_placement.h" #include "greedy_clusterer.h" +#include "logic_types.h" #include "prepack.h" #include "timing_info.h" #include "vpr_types.h" #include "vtr_assert.h" #include "vtr_ndmatrix.h" #include "vtr_vector.h" +#include "vtr_vector_map.h" /* * @brief Get gain of packing molecule into current cluster. @@ -86,13 +88,14 @@ GreedyCandidateSelector::GreedyCandidateSelector( const t_packer_opts& packer_opts, bool allow_unrelated_clustering, const t_molecule_stats& max_molecule_stats, - const std::map>& primitive_candidate_block_types, + const vtr::vector>& primitive_candidate_block_types, const t_pack_high_fanout_thresholds& high_fanout_thresholds, const std::unordered_set& is_clock, const std::unordered_set& is_global, const std::unordered_set& net_output_feeds_driving_block_input, const PreClusterTimingManager& pre_cluster_timing_manager, const APPackContext& appack_ctx, + const LogicalModels& models, int log_verbosity) : atom_netlist_(atom_netlist) , prepacker_(prepacker) @@ -110,7 +113,7 @@ GreedyCandidateSelector::GreedyCandidateSelector( // Initialize unrelated clustering data if unrelated clustering is enabled. if (allow_unrelated_clustering_) { - initialize_unrelated_clustering_data(max_molecule_stats); + initialize_unrelated_clustering_data(max_molecule_stats, models); } /* TODO: This is memory inefficient, fix if causes problems */ @@ -119,7 +122,7 @@ GreedyCandidateSelector::GreedyCandidateSelector( clb_inter_blk_nets_.resize(atom_netlist.blocks().size()); } -void GreedyCandidateSelector::initialize_unrelated_clustering_data(const t_molecule_stats& max_molecule_stats) { +void GreedyCandidateSelector::initialize_unrelated_clustering_data(const t_molecule_stats& max_molecule_stats, const LogicalModels& models) { // Create a sorted list of molecules, sorted on decreasing molecule base // gain. (Highest gain). std::vector molecules_vector; @@ -177,7 +180,7 @@ void GreedyCandidateSelector::initialize_unrelated_clustering_data(const t_molec t_flat_pl_loc mol_pos = get_molecule_pos(mol_id, prepacker_, appack_ctx_); //Figure out how many external inputs are used by this molecule - t_molecule_stats molecule_stats = prepacker_.calc_molecule_stats(mol_id, atom_netlist_); + t_molecule_stats molecule_stats = prepacker_.calc_molecule_stats(mol_id, atom_netlist_, models); int ext_inps = molecule_stats.num_used_ext_inputs; //Insert the molecule into the unclustered lists by number of external inputs @@ -196,7 +199,7 @@ void GreedyCandidateSelector::initialize_unrelated_clustering_data(const t_molec // molecules for each number of used external inputs. for (PackMoleculeId mol_id : molecules_vector) { //Figure out how many external inputs are used by this molecule - t_molecule_stats molecule_stats = prepacker_.calc_molecule_stats(mol_id, atom_netlist_); + t_molecule_stats molecule_stats = prepacker_.calc_molecule_stats(mol_id, atom_netlist_, models); int ext_inps = molecule_stats.num_used_ext_inputs; //Insert the molecule into the unclustered lists by number of external inputs @@ -885,10 +888,10 @@ void GreedyCandidateSelector::add_cluster_molecule_candidates_by_attraction_grou AttractionGroup& group = attraction_groups.get_attraction_group_info(grp_id); std::vector available_atoms; for (AtomBlockId atom_id : group.group_atoms) { - const auto& atom_model = atom_netlist_.block_model(atom_id); - auto itr = primitive_candidate_block_types_.find(atom_model); - VTR_ASSERT(itr != primitive_candidate_block_types_.end()); - const std::vector& candidate_types = itr->second; + LogicalModelId atom_model = atom_netlist_.block_model(atom_id); + VTR_ASSERT(atom_model.is_valid()); + VTR_ASSERT(!primitive_candidate_block_types_[atom_model].empty()); + const auto& candidate_types = primitive_candidate_block_types_[atom_model]; //Only consider molecules that are unpacked and of the correct type if (!cluster_legalizer.is_atom_clustered(atom_id) diff --git a/vpr/src/pack/greedy_candidate_selector.h b/vpr/src/pack/greedy_candidate_selector.h index 2b3eb23a1f5..a7af8d448b7 100644 --- a/vpr/src/pack/greedy_candidate_selector.h +++ b/vpr/src/pack/greedy_candidate_selector.h @@ -16,11 +16,13 @@ #include "attraction_groups.h" #include "cluster_legalizer.h" #include "greedy_clusterer.h" +#include "logic_types.h" #include "physical_types.h" #include "prepack.h" #include "vtr_ndmatrix.h" #include "vtr_vector.h" #include "vtr_random.h" +#include "vtr_vector_map.h" // Forward declarations class AtomNetlist; @@ -29,7 +31,6 @@ class FlatPlacementInfo; class PreClusterTimingManager; class Prepacker; class t_pack_high_fanout_thresholds; -struct t_model; struct t_molecule_stats; struct t_packer_opts; @@ -240,13 +241,14 @@ class GreedyCandidateSelector { const t_packer_opts& packer_opts, bool allow_unrelated_clustering, const t_molecule_stats& max_molecule_stats, - const std::map>& primitive_candidate_block_types, + const vtr::vector>& primitive_candidate_block_types, const t_pack_high_fanout_thresholds& high_fanout_thresholds, const std::unordered_set& is_clock, const std::unordered_set& is_global, const std::unordered_set& net_output_feeds_driving_block_input, const PreClusterTimingManager& pre_cluster_timing_manager, const APPackContext& appack_ctx, + const LogicalModels& models, int log_verbosity); /** @@ -375,7 +377,8 @@ class GreedyCandidateSelector { * clustering. */ void initialize_unrelated_clustering_data( - const t_molecule_stats& max_molecule_stats); + const t_molecule_stats& max_molecule_stats, + const LogicalModels& models); // ===================================================================== // // Cluster Gain Stats Updating @@ -547,7 +550,7 @@ class GreedyCandidateSelector { /// @brief Pre-computed vector of logical block types that could implement /// the given model in the architecture. - const std::map>& primitive_candidate_block_types_; + const vtr::vector>& primitive_candidate_block_types_; /// @brief The high-fanout thresholds per logical block type. Used to ignore /// certain nets when calculating the gain for the next candidate diff --git a/vpr/src/pack/greedy_clusterer.cpp b/vpr/src/pack/greedy_clusterer.cpp index 7673005af93..b7845c4f564 100644 --- a/vpr/src/pack/greedy_clusterer.cpp +++ b/vpr/src/pack/greedy_clusterer.cpp @@ -49,11 +49,11 @@ #include "cluster_util.h" #include "greedy_candidate_selector.h" #include "greedy_seed_selector.h" +#include "logic_types.h" #include "physical_types.h" #include "prepack.h" #include "vpr_context.h" #include "vtr_math.h" -#include "vtr_vector.h" namespace { @@ -116,7 +116,7 @@ GreedyClusterer::do_clustering(ClusterLegalizer& cluster_legalizer, clustering_stats.num_molecules = prepacker.molecules().size(); // Calculate the max molecule stats, which is used for gain calculation. - const t_molecule_stats max_molecule_stats = prepacker.calc_max_molecule_stats(atom_netlist_); + const t_molecule_stats max_molecule_stats = prepacker.calc_max_molecule_stats(atom_netlist_, arch_.models); // Create the greedy candidate selector. This will be used to select // candidate molecules to add to the clusters. @@ -132,6 +132,7 @@ GreedyClusterer::do_clustering(ClusterLegalizer& cluster_legalizer, net_output_feeds_driving_block_input_, pre_cluster_timing_manager_, appack_ctx_, + arch_.models, log_verbosity_); // Create the greedy seed selector. @@ -139,6 +140,7 @@ GreedyClusterer::do_clustering(ClusterLegalizer& cluster_legalizer, prepacker, packer_opts_.cluster_seed_type, max_molecule_stats, + arch_.models, pre_cluster_timing_manager_); // Pick the first seed molecule. @@ -366,11 +368,10 @@ LegalizationClusterId GreedyClusterer::start_new_cluster( /* Allocate a dummy initial cluster and load a atom block as a seed and check if it is legal */ AtomBlockId root_atom = seed_mol.atom_block_ids[seed_mol.root]; const std::string& root_atom_name = atom_netlist_.block_name(root_atom); - const t_model* root_model = atom_netlist_.block_model(root_atom); - - auto itr = primitive_candidate_block_types_.find(root_model); - VTR_ASSERT(itr != primitive_candidate_block_types_.end()); - std::vector candidate_types = itr->second; + LogicalModelId root_model_id = atom_netlist_.block_model(root_atom); + VTR_ASSERT(root_model_id.is_valid()); + VTR_ASSERT(!primitive_candidate_block_types_[root_model_id].empty()); + std::vector candidate_types = primitive_candidate_block_types_[root_model_id]; if (balance_block_type_utilization) { //We sort the candidate types in ascending order by their current utilization. @@ -395,7 +396,7 @@ LegalizationClusterId GreedyClusterer::start_new_cluster( } if (log_verbosity_ > 2) { - VTR_LOG("\tSeed: '%s' (%s)", root_atom_name.c_str(), root_model->name); + VTR_LOG("\tSeed: '%s' (%s)", root_atom_name.c_str(), arch_.models.get_model(root_model_id).name); VTR_LOGV(seed_mol.pack_pattern, " molecule_type %s molecule_size %zu", seed_mol.pack_pattern->name, seed_mol.atom_block_ids.size()); VTR_LOG("\n"); @@ -435,7 +436,7 @@ LegalizationClusterId GreedyClusterer::start_new_cluster( VPR_FATAL_ERROR(VPR_ERROR_PACK, "Can not find any logic block that can implement molecule.\n" "\tAtom %s (%s)\n", - root_atom_name.c_str(), root_model->name); + root_atom_name.c_str(), arch_.models.model_name(root_model_id).c_str()); } } @@ -510,8 +511,9 @@ bool GreedyClusterer::try_add_candidate_mol_to_cluster(PackMoleculeId candidate_ AtomBlockId blk_id = candidate_mol.atom_block_ids[candidate_mol.root]; VTR_ASSERT(blk_id.is_valid()); std::string blk_name = atom_netlist_.block_name(blk_id); - const t_model* blk_model = atom_netlist_.block_model(blk_id); - VTR_LOG("'%s' (%s)", blk_name.c_str(), blk_model->name); + LogicalModelId blk_model_id = atom_netlist_.block_model(blk_id); + std::string blk_model_name = arch_.models.model_name(blk_model_id); + VTR_LOG("'%s' (%s)", blk_name.c_str(), blk_model_name.c_str()); VTR_LOGV(candidate_mol.pack_pattern, " molecule %s molecule_size %zu", candidate_mol.pack_pattern->name, candidate_mol.atom_block_ids.size()); @@ -524,7 +526,7 @@ bool GreedyClusterer::try_add_candidate_mol_to_cluster(PackMoleculeId candidate_ void GreedyClusterer::report_le_physical_block_usage(const ClusterLegalizer& cluster_legalizer) { // find the cluster type that has lut primitives - auto logic_block_type = identify_logic_block_type(primitive_candidate_block_types_); + auto logic_block_type = identify_logic_block_type(primitive_candidate_block_types_, arch_.models); // find a LE pb_type within the found logic_block_type auto le_pb_type = identify_le_block_type(logic_block_type); diff --git a/vpr/src/pack/greedy_clusterer.h b/vpr/src/pack/greedy_clusterer.h index 4c805ffa594..cb92a0dbccf 100644 --- a/vpr/src/pack/greedy_clusterer.h +++ b/vpr/src/pack/greedy_clusterer.h @@ -12,8 +12,10 @@ #include #include #include "cluster_legalizer.h" +#include "logic_types.h" #include "physical_types.h" #include "prepack.h" +#include "vtr_vector.h" // Forward declarations class APPackContext; @@ -247,7 +249,7 @@ class GreedyClusterer { const APPackContext& appack_ctx_; /// @brief Pre-computed logical block types for each model in the architecture. - const std::map> primitive_candidate_block_types_; + const vtr::vector> primitive_candidate_block_types_; /// @brief The verbosity of log messages produced by the clusterer. /// diff --git a/vpr/src/pack/greedy_seed_selector.cpp b/vpr/src/pack/greedy_seed_selector.cpp index c9d1b9397c5..9850500400a 100644 --- a/vpr/src/pack/greedy_seed_selector.cpp +++ b/vpr/src/pack/greedy_seed_selector.cpp @@ -10,19 +10,16 @@ #include #include #include "PreClusterTimingManager.h" -#include "flat_placement_types.h" #include "atom_netlist.h" #include "cluster_legalizer.h" -#include "device_grid.h" #include "echo_files.h" -#include "globals.h" #include "greedy_clusterer.h" +#include "logic_types.h" #include "prepack.h" #include "vpr_error.h" #include "vpr_types.h" #include "vtr_assert.h" #include "vtr_math.h" -#include "vtr_ndmatrix.h" #include "vtr_vector.h" /** @@ -34,6 +31,7 @@ static inline float get_seed_gain(AtomBlockId blk_id, const AtomNetlist& atom_netlist, const Prepacker& prepacker, + const LogicalModels& models, const e_cluster_seed seed_type, const t_molecule_stats& max_molecule_stats, const vtr::vector& atom_criticality) { @@ -49,7 +47,7 @@ static inline float get_seed_gain(AtomBlockId blk_id, // instead. case e_cluster_seed::MAX_INPUTS: { PackMoleculeId blk_mol_id = prepacker.get_atom_molecule(blk_id); - const t_molecule_stats molecule_stats = prepacker.calc_molecule_stats(blk_mol_id, atom_netlist); + const t_molecule_stats molecule_stats = prepacker.calc_molecule_stats(blk_mol_id, atom_netlist, models); return molecule_stats.num_used_ext_inputs; } // By blended gain (criticality and inputs used). @@ -60,7 +58,7 @@ static inline float get_seed_gain(AtomBlockId blk_id, float seed_blend_fac = 0.5f; PackMoleculeId blk_mol_id = prepacker.get_atom_molecule(blk_id); - const t_molecule_stats molecule_stats = prepacker.calc_molecule_stats(blk_mol_id, atom_netlist); + const t_molecule_stats molecule_stats = prepacker.calc_molecule_stats(blk_mol_id, atom_netlist, models); VTR_ASSERT(max_molecule_stats.num_used_ext_inputs > 0); float used_ext_input_pin_ratio = vtr::safe_ratio(molecule_stats.num_used_ext_inputs, max_molecule_stats.num_used_ext_inputs); @@ -74,7 +72,7 @@ static inline float get_seed_gain(AtomBlockId blk_id, // harder to pack. case e_cluster_seed::MAX_PINS: { PackMoleculeId blk_mol_id = prepacker.get_atom_molecule(blk_id); - const t_molecule_stats molecule_stats = prepacker.calc_molecule_stats(blk_mol_id, atom_netlist); + const t_molecule_stats molecule_stats = prepacker.calc_molecule_stats(blk_mol_id, atom_netlist, models); return molecule_stats.num_pins; } // By input pins per molecule (i.e. available pins on primitives, not pins in use). @@ -82,12 +80,12 @@ static inline float get_seed_gain(AtomBlockId blk_id, // harder to pack. case e_cluster_seed::MAX_INPUT_PINS: { PackMoleculeId blk_mol_id = prepacker.get_atom_molecule(blk_id); - const t_molecule_stats molecule_stats = prepacker.calc_molecule_stats(blk_mol_id, atom_netlist); + const t_molecule_stats molecule_stats = prepacker.calc_molecule_stats(blk_mol_id, atom_netlist, models); return molecule_stats.num_input_pins; } case e_cluster_seed::BLEND2: { PackMoleculeId mol_id = prepacker.get_atom_molecule(blk_id); - const t_molecule_stats molecule_stats = prepacker.calc_molecule_stats(mol_id, atom_netlist); + const t_molecule_stats molecule_stats = prepacker.calc_molecule_stats(mol_id, atom_netlist, models); float pin_ratio = vtr::safe_ratio(molecule_stats.num_pins, max_molecule_stats.num_pins); float input_pin_ratio = vtr::safe_ratio(molecule_stats.num_input_pins, max_molecule_stats.num_input_pins); @@ -134,7 +132,8 @@ static inline void print_seed_gains(const char* fname, const std::vector& seed_atoms, const vtr::vector& atom_gain, const vtr::vector& atom_criticality, - const AtomNetlist& atom_netlist) { + const AtomNetlist& atom_netlist, + const LogicalModels& models) { FILE* fp = vtr::fopen(fname, "w"); // For pretty formatting determine the maximum name length @@ -143,8 +142,8 @@ static inline void print_seed_gains(const char* fname, for (auto blk_id : atom_netlist.blocks()) { max_name_len = std::max(max_name_len, (int)atom_netlist.block_name(blk_id).size()); - const t_model* model = atom_netlist.block_model(blk_id); - max_type_len = std::max(max_type_len, (int)strlen(model->name)); + std::string model_name = models.model_name(atom_netlist.block_model(blk_id)); + max_type_len = std::max(max_type_len, model_name.size()); } fprintf(fp, "%-*s %-*s %8s %8s\n", max_name_len, "atom_block_name", max_type_len, "atom_block_type", "gain", "criticality"); @@ -153,8 +152,8 @@ static inline void print_seed_gains(const char* fname, std::string name = atom_netlist.block_name(blk_id); fprintf(fp, "%-*s ", max_name_len, name.c_str()); - const t_model* model = atom_netlist.block_model(blk_id); - fprintf(fp, "%-*s ", max_type_len, model->name); + std::string model_name = models.model_name(atom_netlist.block_model(blk_id)); + fprintf(fp, "%-*s ", max_type_len, model_name.c_str()); fprintf(fp, "%*f ", std::max((int)strlen("gain"), 8), atom_gain[blk_id]); fprintf(fp, "%*f ", std::max((int)strlen("criticality"), 8), atom_criticality[blk_id]); @@ -168,6 +167,7 @@ GreedySeedSelector::GreedySeedSelector(const AtomNetlist& atom_netlist, const Prepacker& prepacker, const e_cluster_seed seed_type, const t_molecule_stats& max_molecule_stats, + const LogicalModels& models, const PreClusterTimingManager& pre_cluster_timing_manager) : seed_atoms_(atom_netlist.blocks().begin(), atom_netlist.blocks().end()) { // Seed atoms list is initialized with all atoms in the atom netlist. @@ -193,6 +193,7 @@ GreedySeedSelector::GreedySeedSelector(const AtomNetlist& atom_netlist, atom_gains[blk_id] = get_seed_gain(blk_id, atom_netlist, prepacker, + models, seed_type, max_molecule_stats, atom_criticality); @@ -214,7 +215,7 @@ GreedySeedSelector::GreedySeedSelector(const AtomNetlist& atom_netlist, // Print the seed gains if requested. if (getEchoEnabled() && isEchoFileEnabled(E_ECHO_CLUSTERING_BLOCK_CRITICALITIES)) { print_seed_gains(getEchoFileName(E_ECHO_CLUSTERING_BLOCK_CRITICALITIES), - seed_atoms_, atom_gains, atom_criticality, atom_netlist); + seed_atoms_, atom_gains, atom_criticality, atom_netlist, models); } // Set the starting seed index (the index of the first molecule to propose). diff --git a/vpr/src/pack/greedy_seed_selector.h b/vpr/src/pack/greedy_seed_selector.h index 5f152f65236..0207949bef1 100644 --- a/vpr/src/pack/greedy_seed_selector.h +++ b/vpr/src/pack/greedy_seed_selector.h @@ -14,6 +14,7 @@ // Forward declarations class AtomNetlist; class ClusterLegalizer; +class LogicalModels; class PreClusterTimingManager; struct t_molecule_stats; @@ -53,6 +54,7 @@ class GreedySeedSelector { const Prepacker& prepacker, const e_cluster_seed seed_type, const t_molecule_stats& max_molecule_stats, + const LogicalModels& models, const PreClusterTimingManager& pre_cluster_timing_manager); /** diff --git a/vpr/src/pack/noc_aware_cluster_util.cpp b/vpr/src/pack/noc_aware_cluster_util.cpp index aba034992f2..3b14608d47a 100644 --- a/vpr/src/pack/noc_aware_cluster_util.cpp +++ b/vpr/src/pack/noc_aware_cluster_util.cpp @@ -2,21 +2,22 @@ #include "noc_aware_cluster_util.h" #include "atom_netlist.h" #include "globals.h" +#include "logic_types.h" #include "vpr_types.h" #include -std::vector find_noc_router_atoms(const AtomNetlist& atom_netlist) { +std::vector find_noc_router_atoms(const AtomNetlist& atom_netlist, const LogicalModels& models) { // NoC router atoms are expected to have a specific blif model - const std::string noc_router_blif_model_name = "noc_router_adapter_block"; + LogicalModelId noc_route_blif_model_id = models.get_model_by_name("noc_router_adapter_block"); // stores found NoC router atoms std::vector noc_router_atoms; // iterate over all atoms and find those whose blif model matches for (auto atom_id : atom_netlist.blocks()) { - const t_model* model = atom_netlist.block_model(atom_id); - if (noc_router_blif_model_name == model->name) { + LogicalModelId model_id = atom_netlist.block_model(atom_id); + if (model_id == noc_route_blif_model_id) { noc_router_atoms.push_back(atom_id); } } diff --git a/vpr/src/pack/noc_aware_cluster_util.h b/vpr/src/pack/noc_aware_cluster_util.h index a414d147bcf..dbdb79d5785 100644 --- a/vpr/src/pack/noc_aware_cluster_util.h +++ b/vpr/src/pack/noc_aware_cluster_util.h @@ -22,6 +22,7 @@ class AtomNetlist; class AtomBlockId; +class LogicalModels; class t_pack_high_fanout_thresholds; /** @@ -30,7 +31,7 @@ class t_pack_high_fanout_thresholds; * * @return The atom block IDs of the NoC router blocks in the netlist. */ -std::vector find_noc_router_atoms(const AtomNetlist& atom_netlist); +std::vector find_noc_router_atoms(const AtomNetlist& atom_netlist, const LogicalModels& models); /** * @brief Runs BFS starting from NoC routers to find all connected diff --git a/vpr/src/pack/pack.cpp b/vpr/src/pack/pack.cpp index ec96e7c4d7c..85a21c229e6 100644 --- a/vpr/src/pack/pack.cpp +++ b/vpr/src/pack/pack.cpp @@ -120,6 +120,7 @@ bool try_pack(const t_packer_opts& packer_opts, high_fanout_thresholds, ClusterLegalizationStrategy::SKIP_INTRA_LB_ROUTE, packer_opts.enable_pin_feasibility_filter, + arch.models, packer_opts.pack_verbosity); VTR_LOG("Packing with pin utilization targets: %s\n", cluster_legalizer.get_target_external_pin_util().to_string().c_str()); VTR_LOG("Packing with high fanout thresholds: %s\n", high_fanout_thresholds.to_string().c_str()); diff --git a/vpr/src/pack/pb_type_graph.cpp b/vpr/src/pack/pb_type_graph.cpp index 02784e4321a..266f3d38f79 100644 --- a/vpr/src/pack/pb_type_graph.cpp +++ b/vpr/src/pack/pb_type_graph.cpp @@ -25,7 +25,6 @@ #include "vpr_error.h" #include "vpr_types.h" -#include "arch_types.h" #include "physical_types.h" #include "globals.h" #include "vpr_utils.h" @@ -295,7 +294,7 @@ static void alloc_and_load_pb_graph(t_pb_graph_node* pb_graph_node, 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) { - if (strcmp(pb_graph_node->pb_type->blif_model, MODEL_OUTPUT) == 0) { + if (strcmp(pb_graph_node->pb_type->blif_model, LogicalModels::MODEL_OUTPUT) == 0) { pb_graph_node->input_pins[i_input][j].type = PB_PIN_OUTPAD; } else if (pb_graph_node->num_clock_ports != 0) { pb_graph_node->input_pins[i_input][j].type = PB_PIN_SEQUENTIAL; @@ -315,7 +314,7 @@ static void alloc_and_load_pb_graph(t_pb_graph_node* pb_graph_node, 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) { - if (strcmp(pb_graph_node->pb_type->blif_model, MODEL_INPUT) == 0) { + if (strcmp(pb_graph_node->pb_type->blif_model, LogicalModels::MODEL_INPUT) == 0) { pb_graph_node->output_pins[i_output][j].type = PB_PIN_INPAD; } else if (pb_graph_node->num_clock_ports != 0) { pb_graph_node->output_pins[i_output][j].type = PB_PIN_SEQUENTIAL; diff --git a/vpr/src/pack/prepack.cpp b/vpr/src/pack/prepack.cpp index 6f80d5927a5..344d8184a88 100644 --- a/vpr/src/pack/prepack.cpp +++ b/vpr/src/pack/prepack.cpp @@ -21,6 +21,7 @@ #include "atom_netlist.h" #include "echo_files.h" +#include "logic_types.h" #include "physical_types.h" #include "vpr_error.h" #include "vpr_types.h" @@ -70,7 +71,8 @@ static void free_pack_pattern_block(t_pack_pattern_block* pattern_block, t_pack_ static bool try_expand_molecule(t_pack_molecule& molecule, const AtomBlockId blk_id, const std::multimap& atom_molecules, - const AtomNetlist& atom_nlist); + const AtomNetlist& atom_nlist, + const LogicalModels& models); static void print_pack_molecules(const char* fname, const std::vector& list_of_pack_patterns, @@ -108,7 +110,8 @@ static void init_molecule_chain_info(const AtomBlockId blk_id, static AtomBlockId get_sink_block(const AtomBlockId block_id, const t_pack_pattern_connections& connections, - const AtomNetlist& atom_nlist); + const AtomNetlist& atom_nlist, + const LogicalModels& models); static AtomBlockId get_driving_block(const AtomBlockId block_id, const t_pack_pattern_connections& connections, @@ -775,6 +778,7 @@ static void backward_expand_pack_pattern_from_edge(const t_pb_graph_edge* expans */ void Prepacker::alloc_and_load_pack_molecules(std::multimap& atom_molecules_multimap, const AtomNetlist& atom_nlist, + const LogicalModels& models, const std::vector& logical_block_types) { std::vector is_used(list_of_pack_patterns.size(), false); @@ -811,7 +815,8 @@ void Prepacker::alloc_and_load_pack_molecules(std::multimapname); + models.get_model(atom_nlist.block_model(blk_id)).name); } VTR_ASSERT_SAFE(nullptr != best); @@ -920,7 +925,8 @@ static void free_pack_pattern_block(t_pack_pattern_block* pattern_block, t_pack_ PackMoleculeId Prepacker::try_create_molecule(const int pack_pattern_index, AtomBlockId blk_id, std::multimap& atom_molecules_multimap, - const AtomNetlist& atom_nlist) { + const AtomNetlist& atom_nlist, + const LogicalModels& models) { auto pack_pattern = &list_of_pack_patterns[pack_pattern_index]; // Check pack pattern validity @@ -944,7 +950,7 @@ PackMoleculeId Prepacker::try_create_molecule(const int pack_pattern_index, molecule.root = pack_pattern->root_block->block_id; molecule.chain_id = MoleculeChainId::INVALID(); - if (!try_expand_molecule(molecule, blk_id, atom_molecules_multimap, atom_nlist)) { + if (!try_expand_molecule(molecule, blk_id, atom_molecules_multimap, atom_nlist, models)) { // Failed to create molecule return PackMoleculeId::INVALID(); } @@ -988,7 +994,8 @@ PackMoleculeId Prepacker::try_create_molecule(const int pack_pattern_index, static bool try_expand_molecule(t_pack_molecule& molecule, const AtomBlockId blk_id, const std::multimap& atom_molecules, - const AtomNetlist& atom_nlist) { + const AtomNetlist& atom_nlist, + const LogicalModels& models) { // root block of the pack pattern, which is the starting point of this pattern const auto pattern_root_block = molecule.pack_pattern->root_block; // bool array indicating whether a position in a pack pattern is optional or should @@ -1045,7 +1052,7 @@ static bool try_expand_molecule(t_pack_molecule& molecule, // this block is the driver of this connection if (block_connection->from_block == pattern_block) { // find the block this connection is driving and add it to the queue - auto sink_blk_id = get_sink_block(block_id, *block_connection, atom_nlist); + auto sink_blk_id = get_sink_block(block_id, *block_connection, atom_nlist, models); // add this sink block id with its corresponding pattern block to the queue pattern_block_queue.push(std::make_pair(block_connection->to_block, sink_blk_id)); // this block is being driven by this connection @@ -1077,7 +1084,8 @@ static bool try_expand_molecule(t_pack_molecule& molecule, */ static AtomBlockId get_sink_block(const AtomBlockId block_id, const t_pack_pattern_connections& connections, - const AtomNetlist& atom_nlist) { + const AtomNetlist& atom_nlist, + const LogicalModels& models) { const t_model_ports* from_port_model = connections.from_pin->port->model_port; const int from_pin_number = connections.from_pin->pin_number; auto from_port_id = atom_nlist.find_atom_port(block_id, from_port_model); @@ -1099,10 +1107,11 @@ static AtomBlockId get_sink_block(const AtomBlockId block_id, // Iterate through all sink blocks and check whether any of them // is compatible with the block specified in the pack pattern. bool connected_to_latch = false; + LogicalModelId latch_model_id = models.get_model_by_name(LogicalModels::MODEL_LATCH); AtomBlockId pattern_sink_block_id = AtomBlockId::INVALID(); for (const auto& sink_pin_id : net_sinks) { auto sink_block_id = atom_nlist.pin_block(sink_pin_id); - if (atom_nlist.block_model(sink_block_id)->name == std::string(MODEL_LATCH)) { + if (atom_nlist.block_model(sink_block_id) == latch_model_id) { connected_to_latch = true; } if (primitive_type_feasible(sink_block_id, to_pb_type)) { @@ -1680,6 +1689,7 @@ static void print_chain_starting_points(t_pack_patterns* chain_pattern) { } Prepacker::Prepacker(const AtomNetlist& atom_nlist, + const LogicalModels& models, const std::vector& logical_block_types) { vtr::ScopedStartFinishTimer prepacker_timer("Prepacker"); @@ -1690,6 +1700,7 @@ Prepacker::Prepacker(const AtomNetlist& atom_nlist, expected_lowest_cost_pb_gnode.resize(atom_nlist.blocks().size(), nullptr); alloc_and_load_pack_molecules(atom_molecules_multimap, atom_nlist, + models, logical_block_types); // The multimap is a legacy thing. Since blocks can be part of multiple pack @@ -1709,7 +1720,8 @@ Prepacker::Prepacker(const AtomNetlist& atom_nlist, // this information and store it in the prepacker class. This may be // expensive to calculate for large molecules. t_molecule_stats Prepacker::calc_molecule_stats(PackMoleculeId molecule_id, - const AtomNetlist& atom_nlist) const { + const AtomNetlist& atom_nlist, + const LogicalModels& models) const { VTR_ASSERT(molecule_id.is_valid()); t_molecule_stats molecule_stats; @@ -1721,13 +1733,14 @@ t_molecule_stats Prepacker::calc_molecule_stats(PackMoleculeId molecule_id, ++molecule_stats.num_blocks; //Record number of valid blocks in molecule - const t_model* model = atom_nlist.block_model(blk); + LogicalModelId model_id = atom_nlist.block_model(blk); + const t_model& model = models.get_model(model_id); - for (const t_model_ports* input_port = model->inputs; input_port != nullptr; input_port = input_port->next) { + for (const t_model_ports* input_port = model.inputs; input_port != nullptr; input_port = input_port->next) { molecule_stats.num_input_pins += input_port->size; } - for (const t_model_ports* output_port = model->outputs; output_port != nullptr; output_port = output_port->next) { + for (const t_model_ports* output_port = model.outputs; output_port != nullptr; output_port = output_port->next) { molecule_stats.num_output_pins += output_port->size; } } @@ -1780,11 +1793,11 @@ t_molecule_stats Prepacker::calc_molecule_stats(PackMoleculeId molecule_id, return molecule_stats; } -t_molecule_stats Prepacker::calc_max_molecule_stats(const AtomNetlist& atom_nlist) const { +t_molecule_stats Prepacker::calc_max_molecule_stats(const AtomNetlist& atom_nlist, const LogicalModels& models) const { t_molecule_stats max_molecules_stats; for (PackMoleculeId molecule_id : molecules()) { //Calculate per-molecule statistics - t_molecule_stats cur_molecule_stats = calc_molecule_stats(molecule_id, atom_nlist); + t_molecule_stats cur_molecule_stats = calc_molecule_stats(molecule_id, atom_nlist, models); //Record the maximums (member-wise) over all molecules max_molecules_stats.num_blocks = std::max(max_molecules_stats.num_blocks, cur_molecule_stats.num_blocks); diff --git a/vpr/src/pack/prepack.h b/vpr/src/pack/prepack.h index 5222046ddb6..08c960f3105 100644 --- a/vpr/src/pack/prepack.h +++ b/vpr/src/pack/prepack.h @@ -20,6 +20,7 @@ // Forward declarations class t_pack_molecule; +class LogicalModels; struct t_logical_block_type; // A unique ID used to identify a molecule generated by the prepacker. @@ -192,9 +193,11 @@ class Prepacker { * necessary data strucutres. * * @param atom_nlist The atom netlist to prepack. + * @param models * @param logical_block_types A list of the logical block types on the device. */ Prepacker(const AtomNetlist& atom_nlist, + const LogicalModels& models, const std::vector& logical_block_types); /** @@ -236,12 +239,14 @@ class Prepacker { * @brief Calculates molecule statistics for a single molecule. */ t_molecule_stats calc_molecule_stats(PackMoleculeId molecule_id, - const AtomNetlist& atom_netlist) const; + const AtomNetlist& atom_netlist, + const LogicalModels& models) const; /** * @brief Calculates maximum molecule statistics accross all molecules, */ - t_molecule_stats calc_max_molecule_stats(const AtomNetlist& netlist) const; + t_molecule_stats calc_max_molecule_stats(const AtomNetlist& netlist, + const LogicalModels& models) const; /** * @brief Gets the largest number of blocks (atoms) that any molecule contains. @@ -303,6 +308,7 @@ class Prepacker { */ void alloc_and_load_pack_molecules(std::multimap& atom_molecules_multimap, const AtomNetlist& atom_nlist, + const LogicalModels& models, const std::vector& logical_block_types); /** @@ -321,7 +327,8 @@ class Prepacker { PackMoleculeId try_create_molecule(const int pack_pattern_index, AtomBlockId blk_id, std::multimap& atom_molecules_multimap, - const AtomNetlist& atom_nlist); + const AtomNetlist& atom_nlist, + const LogicalModels& models); private: /** diff --git a/vpr/src/place/placement_log_printer.cpp b/vpr/src/place/placement_log_printer.cpp index 1ce8c239dc7..f4fccecbcc1 100644 --- a/vpr/src/place/placement_log_printer.cpp +++ b/vpr/src/place/placement_log_printer.cpp @@ -314,8 +314,9 @@ void generate_post_place_timing_reports(const t_placer_opts& placer_opts, const BlkLocRegistry& blk_loc_registry) { const auto& timing_ctx = g_vpr_ctx.timing(); const auto& atom_ctx = g_vpr_ctx.atom(); + const LogicalModels& models = g_vpr_ctx.device().arch->models; - VprTimingGraphResolver resolver(atom_ctx.netlist(), atom_ctx.lookup(), *timing_ctx.graph, + VprTimingGraphResolver resolver(atom_ctx.netlist(), atom_ctx.lookup(), models, *timing_ctx.graph, delay_calc, is_flat, blk_loc_registry); resolver.set_detail_level(analysis_opts.timing_report_detail); diff --git a/vpr/src/power/power.cpp b/vpr/src/power/power.cpp index e049f611331..888507ae804 100644 --- a/vpr/src/power/power.cpp +++ b/vpr/src/power/power.cpp @@ -133,7 +133,7 @@ static void power_usage_primitive(t_power_usage* power_usage, t_pb* pb, t_pb_gra auto& device_ctx = g_vpr_ctx.device(); auto& power_ctx = g_vpr_ctx.power(); - if (strcmp(pb_graph_node->pb_type->blif_model, MODEL_NAMES) == 0) { + if (strcmp(pb_graph_node->pb_type->blif_model, LogicalModels::MODEL_NAMES) == 0) { /* LUT */ std::string SRAM_values; @@ -174,7 +174,7 @@ static void power_usage_primitive(t_power_usage* power_usage, t_pb* pb, t_pb_gra power_add_usage(power_usage, &sub_power_usage); delete[] input_probabilities; delete[] input_densities; - } else if (strcmp(pb_graph_node->pb_type->blif_model, MODEL_LATCH) == 0) { + } else if (strcmp(pb_graph_node->pb_type->blif_model, LogicalModels::MODEL_LATCH) == 0) { /* Flip-Flop */ t_pb_graph_pin* D_pin = &pb_graph_node->input_pins[0][0]; diff --git a/vpr/src/power/power_sizing.cpp b/vpr/src/power/power_sizing.cpp index 914bf13afde..9f35996eb2b 100644 --- a/vpr/src/power/power_sizing.cpp +++ b/vpr/src/power/power_sizing.cpp @@ -24,6 +24,7 @@ #include #include +#include "logic_types.h" #include "vtr_util.h" #include "vtr_assert.h" #include "vtr_memory.h" @@ -404,11 +405,11 @@ static double power_count_transistors_primitive(t_pb_type* pb_type) { auto& power_ctx = g_vpr_ctx.power(); - if (strcmp(pb_type->blif_model, MODEL_NAMES) == 0) { + if (strcmp(pb_type->blif_model, LogicalModels::MODEL_NAMES) == 0) { /* LUT */ transistor_cnt = power_count_transistors_LUT(pb_type->num_input_pins, power_ctx.arch->LUT_transistor_size); - } else if (strcmp(pb_type->blif_model, MODEL_LATCH) == 0) { + } else if (strcmp(pb_type->blif_model, LogicalModels::MODEL_LATCH) == 0) { /* Latch */ transistor_cnt = power_count_transistors_FF(power_ctx.arch->FF_size); } else { diff --git a/vpr/src/route/route_common.cpp b/vpr/src/route/route_common.cpp index 68701b46731..43501cd04aa 100644 --- a/vpr/src/route/route_common.cpp +++ b/vpr/src/route/route_common.cpp @@ -3,8 +3,8 @@ #include "atom_netlist_utils.h" #include "connection_router_interface.h" #include "describe_rr_node.h" -#include "draw_global.h" #include "route_common.h" +#include "logic_types.h" #include "physical_types_util.h" #include "route_export.h" @@ -64,6 +64,7 @@ static t_clb_opins_used alloc_and_load_clb_opins_used_locally(); static void adjust_one_rr_occ_and_acc_cost(RRNodeId inode, int add_or_sub, float acc_fac); static vtr::vector load_is_clock_net(const Netlist<>& net_list, + const LogicalModels& models, bool is_flat); static bool classes_in_same_block(ParentBlockId blk_id, int first_class_ptc_num, int second_class_ptc_num, bool is_flat); @@ -266,7 +267,7 @@ void init_route_structs(const Netlist<>& net_list, net_list, is_flat); - route_ctx.is_clock_net = load_is_clock_net(net_list, is_flat); + route_ctx.is_clock_net = load_is_clock_net(net_list, device_ctx.arch->models, is_flat); route_ctx.route_bb = load_route_bb(net_list, bb_factor); route_ctx.rr_blk_source = load_rr_clb_sources(device_ctx.rr_graph, @@ -603,11 +604,12 @@ static vtr::vector> load_rr_clb_sources(con } static vtr::vector load_is_clock_net(const Netlist<>& net_list, + const LogicalModels& models, bool is_flat) { vtr::vector is_clock_net(net_list.nets().size()); auto& atom_ctx = g_vpr_ctx.atom(); - std::set clock_nets = find_netlist_physical_clock_nets(atom_ctx.netlist()); + std::set clock_nets = find_netlist_physical_clock_nets(atom_ctx.netlist(), models); for (auto net_id : net_list.nets()) { std::size_t net_id_num = std::size_t(net_id); diff --git a/vpr/src/route/route_utils.cpp b/vpr/src/route/route_utils.cpp index aab9e952315..687ca44d063 100644 --- a/vpr/src/route/route_utils.cpp +++ b/vpr/src/route/route_utils.cpp @@ -219,8 +219,9 @@ void generate_route_timing_reports(const t_router_opts& router_opts, auto& timing_ctx = g_vpr_ctx.timing(); auto& atom_ctx = g_vpr_ctx.atom(); const auto& blk_loc_registry = g_vpr_ctx.placement().blk_loc_registry(); + const LogicalModels& models = g_vpr_ctx.device().arch->models; - VprTimingGraphResolver resolver(atom_ctx.netlist(), atom_ctx.lookup(), *timing_ctx.graph, delay_calc, is_flat, blk_loc_registry); + VprTimingGraphResolver resolver(atom_ctx.netlist(), atom_ctx.lookup(), models, *timing_ctx.graph, delay_calc, is_flat, blk_loc_registry); resolver.set_detail_level(analysis_opts.timing_report_detail); tatum::TimingReporter timing_reporter(resolver, *timing_ctx.graph, *timing_ctx.constraints); diff --git a/vpr/src/server/pathhelper.cpp b/vpr/src/server/pathhelper.cpp index b1f581aa620..aa703f444b0 100644 --- a/vpr/src/server/pathhelper.cpp +++ b/vpr/src/server/pathhelper.cpp @@ -40,12 +40,13 @@ CritPathsResultPtr calc_critical_path(const std::string& report_type, int crit_p auto& timing_ctx = g_vpr_ctx.timing(); auto& atom_ctx = g_vpr_ctx.atom(); const auto& blk_loc_registry = g_vpr_ctx.placement().blk_loc_registry(); + const LogicalModels& models = g_vpr_ctx.device().arch->models; t_analysis_opts analysis_opts; analysis_opts.timing_report_detail = details_level; analysis_opts.timing_report_npaths = crit_path_num; - VprTimingGraphResolver resolver(atom_ctx.netlist(), atom_ctx.lookup(), *timing_ctx.graph, *routing_delay_calc, is_flat_routing, blk_loc_registry); + VprTimingGraphResolver resolver(atom_ctx.netlist(), atom_ctx.lookup(), models, *timing_ctx.graph, *routing_delay_calc, is_flat_routing, blk_loc_registry); resolver.set_detail_level(analysis_opts.timing_report_detail); tatum::TimingReporter timing_reporter(resolver, *timing_ctx.graph, *timing_ctx.constraints); diff --git a/vpr/src/timing/PreClusterDelayCalculator.h b/vpr/src/timing/PreClusterDelayCalculator.h index 069aaa13530..7b7ee903bbb 100644 --- a/vpr/src/timing/PreClusterDelayCalculator.h +++ b/vpr/src/timing/PreClusterDelayCalculator.h @@ -11,17 +11,22 @@ #include "atom_netlist.h" #include "atom_lookup.h" +#include "logic_types.h" #include "physical_types.h" #include "prepack.h" +class LogicalModels; + class PreClusterDelayCalculator : public tatum::DelayCalculator { public: PreClusterDelayCalculator(const AtomNetlist& netlist, const AtomLookup& netlist_lookup, + const LogicalModels& models, float intercluster_net_delay, const Prepacker& prepacker) noexcept : netlist_(netlist) , netlist_lookup_(netlist_lookup) + , models_(models) , inter_cluster_net_delay_(intercluster_net_delay) , prepacker_(prepacker) { //nop @@ -153,8 +158,8 @@ class PreClusterDelayCalculator : public tatum::DelayCalculator { if (!clock_gpin) { AtomBlockId blk = netlist_.pin_block(io_pin); - const t_model* model = netlist_.block_model(blk); - VPR_FATAL_ERROR(VPR_ERROR_TIMING, "Failed to find clock pin associated with pin '%s' (model '%s')", netlist_.pin_name(io_pin).c_str(), model->name); + std::string model_name = models_.get_model(netlist_.block_model(blk)).name; + VPR_FATAL_ERROR(VPR_ERROR_TIMING, "Failed to find clock pin associated with pin '%s' (model '%s')", netlist_.pin_name(io_pin).c_str(), model_name.c_str()); } return clock_gpin; } @@ -162,6 +167,7 @@ class PreClusterDelayCalculator : public tatum::DelayCalculator { private: const AtomNetlist& netlist_; const AtomLookup& netlist_lookup_; + const LogicalModels& models_; const float inter_cluster_net_delay_; const Prepacker& prepacker_; }; diff --git a/vpr/src/timing/PreClusterTimingGraphResolver.cpp b/vpr/src/timing/PreClusterTimingGraphResolver.cpp index d1d8c2d8754..665da067646 100644 --- a/vpr/src/timing/PreClusterTimingGraphResolver.cpp +++ b/vpr/src/timing/PreClusterTimingGraphResolver.cpp @@ -5,10 +5,12 @@ PreClusterTimingGraphResolver::PreClusterTimingGraphResolver( const AtomNetlist& netlist, const AtomLookup& netlist_lookup, + const LogicalModels& models, const tatum::TimingGraph& timing_graph, const tatum::DelayCalculator& delay_calc) : netlist_(netlist) , netlist_lookup_(netlist_lookup) + , models_(models) , timing_graph_(timing_graph) , delay_calc_(delay_calc) {} @@ -22,7 +24,7 @@ std::string PreClusterTimingGraphResolver::node_type_name(tatum::NodeId node) co AtomPinId pin = netlist_lookup_.tnode_atom_pin(node); AtomBlockId blk = netlist_.pin_block(pin); - std::string name = netlist_.block_model(blk)->name; + std::string name = models_.model_name(netlist_.block_model(blk)); if (detail_level() == e_timing_report_detail::AGGREGATED) { //Annotate primitive grid location, if known @@ -72,7 +74,7 @@ tatum::EdgeDelayBreakdown PreClusterTimingGraphResolver::edge_delay_breakdown(ta //component.inst_name = netlist_.block_name(atom_blk); component.type_name = "primitive '"; - component.type_name += netlist_.block_model(atom_blk)->name; + component.type_name += models_.model_name(netlist_.block_model(atom_blk)); component.type_name += "'"; if (edge_type == tatum::EdgeType::PRIMITIVE_COMBINATIONAL) { diff --git a/vpr/src/timing/PreClusterTimingGraphResolver.h b/vpr/src/timing/PreClusterTimingGraphResolver.h index ce859c1ecd6..6469c4f8b66 100644 --- a/vpr/src/timing/PreClusterTimingGraphResolver.h +++ b/vpr/src/timing/PreClusterTimingGraphResolver.h @@ -6,11 +6,14 @@ #include "atom_lookup.h" #include "AnalysisDelayCalculator.h" +class LogicalModels; + class PreClusterTimingGraphResolver : public tatum::TimingGraphNameResolver { public: PreClusterTimingGraphResolver( const AtomNetlist& netlist, const AtomLookup& netlist_lookup, + const LogicalModels& models, const tatum::TimingGraph& timing_graph, const tatum::DelayCalculator& delay_calc); @@ -26,6 +29,7 @@ class PreClusterTimingGraphResolver : public tatum::TimingGraphNameResolver { const AtomNetlist& netlist_; const AtomLookup& netlist_lookup_; + const LogicalModels& models_; const tatum::TimingGraph& timing_graph_; const tatum::DelayCalculator& delay_calc_; e_timing_report_detail detail_level_ = e_timing_report_detail::NETLIST; diff --git a/vpr/src/timing/PreClusterTimingManager.cpp b/vpr/src/timing/PreClusterTimingManager.cpp index 44407d61522..7e9d7a6a0d1 100644 --- a/vpr/src/timing/PreClusterTimingManager.cpp +++ b/vpr/src/timing/PreClusterTimingManager.cpp @@ -78,6 +78,7 @@ PreClusterTimingManager::PreClusterTimingManager(bool timing_driven, // Initialize the timing analyzer clustering_delay_calc_ = std::make_shared(atom_netlist, atom_lookup, + arch.models, inter_cluster_net_delay, prepacker); timing_info_ = make_setup_timing_info(clustering_delay_calc_, timing_update_type); @@ -101,6 +102,7 @@ PreClusterTimingManager::PreClusterTimingManager(bool timing_driven, auto& timing_ctx = g_vpr_ctx.timing(); PreClusterTimingGraphResolver resolver(atom_netlist, atom_lookup, + arch.models, *timing_ctx.graph, *clustering_delay_calc_); resolver.set_detail_level(analysis_opts.timing_report_detail); diff --git a/vpr/src/timing/VprTimingGraphResolver.cpp b/vpr/src/timing/VprTimingGraphResolver.cpp index 33ea251d52d..d884c3e15ff 100644 --- a/vpr/src/timing/VprTimingGraphResolver.cpp +++ b/vpr/src/timing/VprTimingGraphResolver.cpp @@ -1,15 +1,18 @@ #include "VprTimingGraphResolver.h" #include "atom_netlist.h" #include "atom_lookup.h" +#include "logic_types.h" VprTimingGraphResolver::VprTimingGraphResolver(const AtomNetlist& netlist, const AtomLookup& netlist_lookup, + const LogicalModels& models, const tatum::TimingGraph& timing_graph, const AnalysisDelayCalculator& delay_calc, bool is_flat, const BlkLocRegistry& blk_loc_registry) : netlist_(netlist) , netlist_lookup_(netlist_lookup) + , models_(models) , timing_graph_(timing_graph) , delay_calc_(delay_calc) , is_flat_(is_flat) @@ -25,7 +28,7 @@ std::string VprTimingGraphResolver::node_type_name(tatum::NodeId node) const { AtomPinId pin = netlist_lookup_.tnode_atom_pin(node); AtomBlockId blk = netlist_.pin_block(pin); - std::string name = netlist_.block_model(blk)->name; + std::string name = models_.model_name(netlist_.block_model(blk)); if (detail_level() == e_timing_report_detail::AGGREGATED || detail_level() == e_timing_report_detail::DETAILED_ROUTING @@ -78,7 +81,7 @@ tatum::EdgeDelayBreakdown VprTimingGraphResolver::edge_delay_breakdown(tatum::Ed //component.inst_name = netlist_.block_name(atom_blk); component.type_name = "primitive '"; - component.type_name += netlist_.block_model(atom_blk)->name; + component.type_name += models_.model_name(netlist_.block_model(atom_blk)); component.type_name += "'"; if (edge_type == tatum::EdgeType::PRIMITIVE_COMBINATIONAL) { diff --git a/vpr/src/timing/VprTimingGraphResolver.h b/vpr/src/timing/VprTimingGraphResolver.h index 7bb9eb3ba6a..0f63c3d9370 100644 --- a/vpr/src/timing/VprTimingGraphResolver.h +++ b/vpr/src/timing/VprTimingGraphResolver.h @@ -7,11 +7,13 @@ #include "AnalysisDelayCalculator.h" class BlkLocRegistry; +class LogicalModels; class VprTimingGraphResolver : public tatum::TimingGraphNameResolver { public: VprTimingGraphResolver(const AtomNetlist& netlist, const AtomLookup& netlist_lookup, + const LogicalModels& models, const tatum::TimingGraph& timing_graph, const AnalysisDelayCalculator& delay_calc, bool is_flat, @@ -33,6 +35,7 @@ class VprTimingGraphResolver : public tatum::TimingGraphNameResolver { const AtomNetlist& netlist_; const AtomLookup& netlist_lookup_; + const LogicalModels& models_; const tatum::TimingGraph& timing_graph_; const AnalysisDelayCalculator& delay_calc_; e_timing_report_detail detail_level_ = e_timing_report_detail::NETLIST; diff --git a/vpr/src/timing/read_sdc.cpp b/vpr/src/timing/read_sdc.cpp index e8db27b9a28..8c29af538c2 100644 --- a/vpr/src/timing/read_sdc.cpp +++ b/vpr/src/timing/read_sdc.cpp @@ -19,6 +19,7 @@ void apply_default_timing_constraints(const AtomNetlist& netlist, const AtomLookup& lookup, + const LogicalModels& models, tatum::TimingConstraints& timing_constraints); void apply_combinational_default_timing_constraints(const AtomNetlist& netlist, @@ -56,17 +57,19 @@ class SdcParseCallback : public sdcparse::Callback { public: SdcParseCallback(const AtomNetlist& netlist, const AtomLookup& lookup, + const LogicalModels& models, tatum::TimingConstraints& timing_constraints, tatum::TimingGraph& tg) : netlist_(netlist) , lookup_(lookup) + , models_(models) , tc_(timing_constraints) , tg_(tg) {} public: //sdcparse::Callback interface //Start of parsing void start_parse() override { - netlist_clock_drivers_ = find_netlist_logical_clock_drivers(netlist_); + netlist_clock_drivers_ = find_netlist_logical_clock_drivers(netlist_, models_); netlist_primary_ios_ = find_netlist_primary_ios(netlist_); } @@ -1036,6 +1039,7 @@ class SdcParseCallback : public sdcparse::Callback { private: const AtomNetlist& netlist_; const AtomLookup& lookup_; + const LogicalModels& models_; tatum::TimingConstraints& tc_; tatum::TimingGraph& tg_; @@ -1060,32 +1064,33 @@ class SdcParseCallback : public sdcparse::Callback { std::unique_ptr read_sdc(const t_timing_inf& timing_inf, const AtomNetlist& netlist, const AtomLookup& lookup, + const LogicalModels& models, tatum::TimingGraph& timing_graph) { auto timing_constraints = std::make_unique(); if (!timing_inf.timing_analysis_enabled) { VTR_LOG("\n"); VTR_LOG("Timing analysis off\n"); - apply_default_timing_constraints(netlist, lookup, *timing_constraints); + apply_default_timing_constraints(netlist, lookup, models, *timing_constraints); } else { FILE* sdc_file = fopen(timing_inf.SDCFile.c_str(), "r"); if (sdc_file == nullptr) { //No SDC file VTR_LOG("\n"); VTR_LOG("SDC file '%s' not found\n", timing_inf.SDCFile.c_str()); - apply_default_timing_constraints(netlist, lookup, *timing_constraints); + apply_default_timing_constraints(netlist, lookup, models, *timing_constraints); } else { VTR_ASSERT(sdc_file != nullptr); //Parse the file - SdcParseCallback callback(netlist, lookup, *timing_constraints, timing_graph); + SdcParseCallback callback(netlist, lookup, models, *timing_constraints, timing_graph); sdc_parse_file(sdc_file, callback, timing_inf.SDCFile.c_str()); fclose(sdc_file); if (callback.num_commands() == 0) { VTR_LOG("\n"); VTR_LOG("SDC file '%s' contained no SDC commands\n", timing_inf.SDCFile.c_str()); - apply_default_timing_constraints(netlist, lookup, *timing_constraints); + apply_default_timing_constraints(netlist, lookup, models, *timing_constraints); } else { VTR_LOG("\n"); VTR_LOG("Applied %zu SDC commands from '%s'\n", callback.num_commands(), timing_inf.SDCFile.c_str()); @@ -1119,8 +1124,9 @@ std::unique_ptr read_sdc(const t_timing_inf& timing_in //appropriate to the type of circuit. void apply_default_timing_constraints(const AtomNetlist& netlist, const AtomLookup& lookup, + const LogicalModels& models, tatum::TimingConstraints& tc) { - std::set netlist_clock_drivers = find_netlist_logical_clock_drivers(netlist); + std::set netlist_clock_drivers = find_netlist_logical_clock_drivers(netlist, models); if (netlist_clock_drivers.size() == 0) { apply_combinational_default_timing_constraints(netlist, lookup, tc); diff --git a/vpr/src/timing/read_sdc.h b/vpr/src/timing/read_sdc.h index 4e759360f15..bae43206952 100644 --- a/vpr/src/timing/read_sdc.h +++ b/vpr/src/timing/read_sdc.h @@ -9,9 +9,12 @@ #include "atom_lookup_fwd.h" #include "vpr_types.h" +class LogicalModels; + std::unique_ptr read_sdc(const t_timing_inf& timing_inf, const AtomNetlist& netlist, const AtomLookup& lookup, + const LogicalModels& models, tatum::TimingGraph& timing_graph); #endif diff --git a/vpr/src/timing/timing_graph_builder.cpp b/vpr/src/timing/timing_graph_builder.cpp index 78bbbe63ba2..1e183c81289 100644 --- a/vpr/src/timing/timing_graph_builder.cpp +++ b/vpr/src/timing/timing_graph_builder.cpp @@ -218,12 +218,11 @@ */ #include +#include "logic_types.h" #include "vtr_log.h" -#include "vtr_linear_map.h" #include "timing_graph_builder.h" #include "vpr_error.h" -#include "vpr_utils.h" #include "atom_netlist.h" #include "atom_netlist_utils.h" @@ -251,10 +250,11 @@ tatum::util::linear_map remap_valid(const tatum::util::linear_map& d } TimingGraphBuilder::TimingGraphBuilder(const AtomNetlist& netlist, - AtomLookup& netlist_lookup) + AtomLookup& netlist_lookup, + const LogicalModels& models) : netlist_(netlist) , netlist_lookup_(netlist_lookup) - , netlist_clock_drivers_(find_netlist_logical_clock_drivers(netlist_)) { + , netlist_clock_drivers_(find_netlist_logical_clock_drivers(netlist_, models)) { //pass } diff --git a/vpr/src/timing/timing_graph_builder.h b/vpr/src/timing/timing_graph_builder.h index 1f1624eed81..40b571a8bb1 100644 --- a/vpr/src/timing/timing_graph_builder.h +++ b/vpr/src/timing/timing_graph_builder.h @@ -5,6 +5,8 @@ #include "atom_netlist_fwd.h" #include "atom_lookup.h" +class LogicalModels; + /* * Class for constructing a Timing Graph (a tatum::TimingGraph, for use with the Tatum * STA engine) from the provided AtomNetlist. It also updates the provided AtomLookup @@ -19,7 +21,8 @@ class TimingGraphBuilder { public: TimingGraphBuilder(const AtomNetlist& netlist, - AtomLookup& netlist_lookup); + AtomLookup& netlist_lookup, + const LogicalModels& models); std::unique_ptr timing_graph(bool allow_dangling_combinational_nodes); diff --git a/vpr/src/util/vpr_utils.cpp b/vpr/src/util/vpr_utils.cpp index 2574c505b57..c31c7ab08be 100644 --- a/vpr/src/util/vpr_utils.cpp +++ b/vpr/src/util/vpr_utils.cpp @@ -45,38 +45,6 @@ static void free_pb_graph_pin_lookup_from_index(t_pb_graph_pin** pb_graph_pin_lo /******************** Subroutine definitions *********************************/ -const t_model* find_model(const t_model* models, const std::string& name, bool required) { - for (const t_model* model = models; model != nullptr; model = model->next) { - if (name == model->name) { - return model; - } - } - - if (required) { - VPR_FATAL_ERROR(VPR_ERROR_ARCH, "Failed to find architecture modedl '%s'\n", name.c_str()); - } - - return nullptr; -} - -const t_model_ports* find_model_port(const t_model* model, const std::string& name, bool required) { - VTR_ASSERT(model); - - for (const t_model_ports* model_ports : {model->inputs, model->outputs}) { - for (const t_model_ports* port = model_ports; port != nullptr; port = port->next) { - if (port->name == name) { - return port; - } - } - } - - if (required) { - VPR_FATAL_ERROR(VPR_ERROR_ARCH, "Failed to find port '%s; on architecture model '%s'\n", name.c_str(), model->name); - } - - return nullptr; -} - /** * print tabs given number of tabs to file */ @@ -830,7 +798,7 @@ bool primitive_type_feasible(const AtomBlockId blk_id, const t_pb_type* cur_pb_t } auto& atom_ctx = g_vpr_ctx.atom(); - if (cur_pb_type->model != atom_ctx.netlist().block_model(blk_id)) { + if (cur_pb_type->model_id != atom_ctx.netlist().block_model(blk_id)) { //Primitive and atom do not match return false; } @@ -987,7 +955,7 @@ const t_pb_graph_pin* find_pb_graph_pin(const AtomNetlist& netlist, const AtomPB 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); + VTR_ASSERT(netlist.block_model(blk_id) == pb_gnode->pb_type->model_id); //Get the pin index AtomPortId port_id = netlist.pin_port(pin_id); diff --git a/vpr/src/util/vpr_utils.h b/vpr/src/util/vpr_utils.h index f2b62cfac1c..762efd36c5d 100644 --- a/vpr/src/util/vpr_utils.h +++ b/vpr/src/util/vpr_utils.h @@ -15,9 +15,6 @@ class DeviceGrid; class UserRouteConstraints; -const t_model* find_model(const t_model* models, const std::string& name, bool required = true); -const t_model_ports* find_model_port(const t_model* model, const std::string& name, bool required = true); - void print_tabs(FILE* fpout, int num_tab); bool is_clb_external_pin(ClusterBlockId blk_id, int pb_pin_id); diff --git a/vpr/test/test_interchange_device.cpp b/vpr/test/test_interchange_device.cpp index f344adace1b..324d757830a 100644 --- a/vpr/test/test_interchange_device.cpp +++ b/vpr/test/test_interchange_device.cpp @@ -1,8 +1,7 @@ #include "catch2/catch_test_macros.hpp" +#include "logic_types.h" #include "read_fpga_interchange_arch.h" -#include "arch_util.h" -#include "vpr_api.h" #include #include #include @@ -21,21 +20,24 @@ TEST_CASE("read_interchange_models", "[vpr]") { std::unordered_set models = {"IB", "OB", "DFFR", "DFFS", "GND", "VCC"}; // Check that there are exactly the expected models - for (auto* model = arch.models; model != nullptr; model = model->next) { - std::string name = model->name; - REQUIRE(models.find(name) != models.end()); - models.erase(name); + for (LogicalModelId model_id : arch.models.user_models()) { + std::string model_name = arch.models.model_name(model_id); + REQUIRE(models.find(model_name) != models.end()); + models.erase(model_name); } REQUIRE(models.size() == 0); - std::unordered_set lib_models = {MODEL_INPUT, MODEL_OUTPUT, MODEL_LATCH, MODEL_NAMES}; + std::unordered_set lib_models = {LogicalModels::MODEL_INPUT, + LogicalModels::MODEL_OUTPUT, + LogicalModels::MODEL_LATCH, + LogicalModels::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); + for (LogicalModelId model_id : arch.models.library_models()) { + std::string model_name = arch.models.model_name(model_id); + REQUIRE(lib_models.find(model_name) != lib_models.end()); + lib_models.erase(model_name); } REQUIRE(lib_models.size() == 0); diff --git a/vpr/test/test_interchange_netlist.cpp b/vpr/test/test_interchange_netlist.cpp index ac1fdfb15f9..1e8804469fb 100644 --- a/vpr/test/test_interchange_netlist.cpp +++ b/vpr/test/test_interchange_netlist.cpp @@ -1,11 +1,10 @@ #include "catch2/catch_test_macros.hpp" +#include "globals.h" #include "read_circuit.h" #include "read_fpga_interchange_arch.h" -#include "arch_util.h" -#include "vpr_api.h" +#include "vpr_types.h" #include -#include #include namespace { @@ -21,8 +20,6 @@ TEST_CASE("read_interchange_netlist", "[vpr]") { FPGAInterchangeReadArch(kArchFile, /*timing_enabled=*/true, &arch, physical_tile_types, logical_block_types); - vpr_setup.user_models = arch.models; - vpr_setup.library_models = arch.model_library; vpr_setup.PackerOpts.circuit_file_name = "lut.netlist"; /* Read blif file and sweep unused components */