From 89e29931c956cfb60546cd95ecf2e51f1f73472c Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Tue, 13 Jul 2021 20:33:07 -0400 Subject: [PATCH 01/31] initial commit: adding main files used for new feature --- utils/vqm2blif/src/base/hard_block_recog.cpp | 0 utils/vqm2blif/src/base/hard_block_recog.h | 28 ++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 utils/vqm2blif/src/base/hard_block_recog.cpp create mode 100644 utils/vqm2blif/src/base/hard_block_recog.h diff --git a/utils/vqm2blif/src/base/hard_block_recog.cpp b/utils/vqm2blif/src/base/hard_block_recog.cpp new file mode 100644 index 00000000000..e69de29bb2d diff --git a/utils/vqm2blif/src/base/hard_block_recog.h b/utils/vqm2blif/src/base/hard_block_recog.h new file mode 100644 index 00000000000..b7ce988f98f --- /dev/null +++ b/utils/vqm2blif/src/base/hard_block_recog.h @@ -0,0 +1,28 @@ +/* This file contains datastructures and functions used to +* filter out LUTs/flip flops used for hard block port connections +* and then instantiate a new hard block type in the netlist.*/ + + +#ifndef HARD_BLOCK_RECOG_H +#define HARD_BLOCK_RECOG_H + + + + + + + + + + + + + + + + + + + + +#endif \ No newline at end of file From bded9bfdc6b921157ccb09869c256d46f24568a2 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Wed, 4 Aug 2021 14:24:20 -0400 Subject: [PATCH 02/31] added main data structures and their initializer functions. Also added a destructor --- utils/vqm2blif/src/base/hard_block_recog.cpp | 225 +++++++++++++++++++ utils/vqm2blif/src/base/hard_block_recog.h | 164 +++++++++++++- 2 files changed, 382 insertions(+), 7 deletions(-) diff --git a/utils/vqm2blif/src/base/hard_block_recog.cpp b/utils/vqm2blif/src/base/hard_block_recog.cpp index e69de29bb2d..b54a3945a7c 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.cpp +++ b/utils/vqm2blif/src/base/hard_block_recog.cpp @@ -0,0 +1,225 @@ +// add higher level comments here + + + +#include "hard_block_recog.h" + + +void filter_and_create_hard_blocks(t_module* main_module, t_arch* main_arch, std::vector* hard_block_names, std::string arch_file_name, std::string vqm_file_name) +{ + t_hard_block_recog hard_block_node_refs_and_info; + + try + { + initialize_hard_block_models(main_arch, hard_block_names, &hard_block_node_refs_and_info); + } + catch(const vtr::VtrError& error) + { + throw vtr::VtrError((std::string)error.what() + "The FPGA architecture is described in " + arch_file_name + "."); + } + + + + + + + // need to delete all the dynamic memory used to store + // all the hard block port information + delete_hard_block_port_info(&(hard_block_node_refs_and_info.hard_block_type_name_to_port_info)); + + return; +} + +void initialize_hard_block_models(t_arch* main_arch, std::vector* hard_block_names, t_hard_block_recog* storage_of_hard_block_info) +{ + t_model* hard_block_model = NULL; + std::vector::iterator hard_block_name_traverser; + bool single_hard_block_init_result = false; + + for (hard_block_name_traverser = hard_block_names->begin(); hard_block_name_traverser != hard_block_names->end(); hard_block_name_traverser++) + { + // function already made + hard_block_model = find_arch_model_by_name(*hard_block_name_traverser, main_arch->models); + + if (hard_block_model == NULL) + { + throw vtr::VtrError("The provided hard block model '" + *hard_block_name_traverser + "' was not found within the corresponding FPGA architecture."); + } + else + { + single_hard_block_init_result = create_and_initialize_all_hard_block_ports(hard_block_model, storage_of_hard_block_info); + + if (!single_hard_block_init_result) + { + throw vtr::VtrError("Hard block model '" + *hard_block_name_traverser + "' found in the architecture has no input/output ports."); + } + } + + } + + return; + +} + +bool create_and_initialize_all_hard_block_ports(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; + bool result = true; + + 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); + + // handle input ports + hard_block_port_index += extract_and_store_hard_block_model_ports(storage_of_hard_block_info, input_ports, hard_block_arch_model_name,hard_block_port_index, INPUT_PORTS); + + // handle output ports + hard_block_port_index += extract_and_store_hard_block_model_ports(storage_of_hard_block_info, output_ports, hard_block_arch_model_name,hard_block_port_index, OUTPUT_PORTS); + + if (hard_block_port_index == HARD_BLOCK_WITH_NO_PORTS) + { + + result = false; + + } + + return result; +} + +void create_hard_block_port_info_structure(t_hard_block_recog* storage_of_hard_block_info, std::string hard_block_type_name) +{ + t_hard_block_port_info curr_hard_block_port_storage; + + (curr_hard_block_port_storage.hard_block_ports).pointer = NULL; + (curr_hard_block_port_storage.hard_block_ports).allocated_size = 0; + (curr_hard_block_port_storage.hard_block_ports).array_size = 0; + + storage_of_hard_block_info->hard_block_type_name_to_port_info.insert({hard_block_type_name,curr_hard_block_port_storage}); + + return; + +} + +int extract_and_store_hard_block_model_ports(t_hard_block_recog* storage_of_hard_block_info, t_model_ports* curr_hard_block_model_port, std::string curr_hard_block_name,int port_index, std::string port_type) +{ + t_array_ref* equivalent_hard_block_node_port_array = NULL; + int starting_port_index = port_index; + + while (curr_hard_block_model_port != NULL) + { + equivalent_hard_block_node_port_array = convert_hard_block_model_port_to_hard_block_node_port(curr_hard_block_model_port); + + store_hard_block_port_info(storage_of_hard_block_info, curr_hard_block_name, curr_hard_block_model_port->name, &equivalent_hard_block_node_port_array, &port_index); + + curr_hard_block_model_port = curr_hard_block_model_port->next; + + } + + if (starting_port_index == port_index) + { + VTR_LOG_WARN("Model '%s' found in the architecture file does not have %s ports\n", curr_hard_block_name.c_str(), port_type.c_str()); + } + + return port_index; +} + +t_array_ref* convert_hard_block_model_port_to_hard_block_node_port(t_model_ports* hard_block_model_port) +{ + t_node_port_association* curr_hard_block_node_port = NULL; + t_array_ref* port_array = NULL; + char* curr_hard_block_model_port_name = hard_block_model_port->name; + int port_size = hard_block_model_port->size; + + //create memory to store the port array + port_array = (t_array_ref*)vtr::malloc(sizeof(t_array_ref)); + + port_array->pointer = NULL; + port_array->array_size = 0; + port_array->allocated_size = 0; + + for (int port_index = 0; port_index < port_size; port_index++) + { + // hard blocks will not have indexed wire assignments + // doesnt do anything different I think + curr_hard_block_node_port = create_unconnected_node_port_association(curr_hard_block_model_port_name, port_index, WIRE_NOT_INDEXED); + + // store the newly created specific port index within the entire port + // array + append_array_element((intptr_t)curr_hard_block_node_port, port_array); + } + + return port_array; + +} + +t_node_port_association* create_unconnected_node_port_association(char *port_name, int port_index, int wire_index) +{ + t_node_port_association* curr_hard_block_node_port = NULL; + + curr_hard_block_node_port = (t_node_port_association*)vtr::malloc(sizeof(t_node_port_association)); + + curr_hard_block_node_port->port_name = (char*)vtr::malloc(sizeof(char) * (strlen(port_name) + 1)); + strcpy(curr_hard_block_node_port->port_name, port_name); + + curr_hard_block_node_port->port_index = port_index; + curr_hard_block_node_port->associated_net = NULL; + curr_hard_block_node_port->wire_index = wire_index; + + return curr_hard_block_node_port; +} + +// need the hard block name itself +void store_hard_block_port_info(t_hard_block_recog* storage_of_hard_block_port_info, std::string curr_hard_block_name,std::string curr_port_name, t_array_ref** curr_port_array, int* port_index) +{ + + std::unordered_map::iterator curr_port_info = ((storage_of_hard_block_port_info->hard_block_type_name_to_port_info).find(curr_hard_block_name)); + + copy_array_ref(*curr_port_array, &(curr_port_info->second).hard_block_ports); + + // insert the port name to the current index + (curr_port_info->second).port_name_to_port_start_index.insert({curr_port_name, *port_index}); + + *port_index += (*curr_port_array)->array_size; + + vtr::free((*curr_port_array)->pointer); + vtr::free(*curr_port_array); + + *curr_port_array = NULL; + + return; +} + +void copy_array_ref(t_array_ref* array_ref_orig, t_array_ref* array_ref_copy) +{ + int array_size = array_ref_orig->array_size; + + for (int index = 0; index < array_size; index++) + { + append_array_element((intptr_t)array_ref_orig->pointer[index], array_ref_copy); + } + + return; +} + +void delete_hard_block_port_info(std::unordered_map* hard_block_name_to_port_info_map) +{ + std::unordered_map::iterator curr_hard_block_port_info = hard_block_name_to_port_info_map->begin(); + + while (curr_hard_block_port_info != (hard_block_name_to_port_info_map->end())) + { + + int number_of_ports = (curr_hard_block_port_info->second).hard_block_ports.array_size; + + uintptr_t* ports_to_delete = (uintptr_t*)((curr_hard_block_port_info->second).hard_block_ports.pointer); + + deallocate_array(ports_to_delete, number_of_ports, free_port_association); + + curr_hard_block_port_info++; + + } + + return; +} \ No newline at end of file diff --git a/utils/vqm2blif/src/base/hard_block_recog.h b/utils/vqm2blif/src/base/hard_block_recog.h index b7ce988f98f..9d07d8b33bf 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.h +++ b/utils/vqm2blif/src/base/hard_block_recog.h @@ -1,28 +1,178 @@ -/* This file contains datastructures and functions used to -* filter out LUTs/flip flops used for hard block port connections -* and then instantiate a new hard block type in the netlist.*/ +/* VQM new primitive hard block recognition header file +* +* The purpose of this file is to identify and instantiate +* user defined hard blocks, which will later be writtent to a .blif file. +* For more information, refer to 'hard_block_recog.cpp'. +* +* This file contains the definition of the main data structures +* that are instantiated when trying to identify and create user +* created hard blocks. +* +* This file also contains all the declarations of functions that can be +* used to interact with and manipulate the main data structures. Additionally, +* some utility functions are added to help identify whether a hard block was * included within the design. For more information, +* refer to 'hard_block_recog.cpp'. +* +*/ + + +// need to use vtr::malloc for memory allocation (only in the files here) +// no need to run VTR assert, after memory allocation, this is checked in the function already #ifndef HARD_BLOCK_RECOG_H #define HARD_BLOCK_RECOG_H +// user VTR libraries +#include "vqm_dll.h" +#include "physical_types.h" +#include "logic_types.h" +#include "vtr_error.h" +#include "vtr_log.h" +#include "vqm_common.h" +#include "vtr_memory.h" + +// user vqm2blif libraries +#include "vqm2blif_util.h" + +// standard libraries +#include +#include +#include + +// useful spacing definitions +#define TOP_LEVEL 0 +#define SECOND_LEVEL 1 + +#define WIRE_NOT_INDEXED -1 + +#define INPUT_PORTS "input" +#define OUTPUT_PORTS "output" + +#define HARD_BLOCK_WITH_NO_PORTS 0 + + + +/* Structure Declarations */ + + +/* +* The purpose of this data structure is to +* store the port information (in an array) for an arbritary user defined +* hard block design. Then a mapping is provided which can +* help identify the specific location within the port array +* that a given port name begins at. +*/ +typedef struct s_hard_block_port_info +{ + // mapping structure to quickly identify where a specific port begins + std::unordered_map port_name_to_port_start_index; + + // An array of all the ports within the hard block is stored here + // refer to 'vqm_dll.h' for more information + t_array_ref hard_block_ports; +} t_hard_block_port_info; +/* +* Each hard block instance that will eventually be written to the blif file +* will need to be stored as a 't_node' type (refer to 'vqm_dll.h'). +* This node will then be stored within a node array and enclosed +* within a 't_module' variable (refer to 'vqm_dll.h'). +* +* +* The purpose of the data structure below is to keep a reference to a +* single hard block node (one instance of a hard block within the design). * This way, the node can be accessed quickly whenever changes need to be +* applied. Additional information about the hard block is also stored as well. +* +* THe node itself is stored internally within the a node array. And +* located inside a module. +*/ +typedef struct s_hard_block +{ + // indicates the name of the user defined hard block + std::string hard_block_name; + // helps keep track of the number of hard block ports we have assigned + // a net to + int hard_block_ports_assigned; + // a reference to the corresponding hard block node that represents this + // particular hard block instance + t_node* hard_block_instance_node_reference; +}t_hard_block; +/* +* Below is the main data structure used for hard block +* identification and creation. This data strcuture contains +* the names and port info of every type of user defined hard blocks. It +* also stores all hard blocks that were instantiated within +* the user design and an accompanying data strcuture to quickly identify +* a specific hard block instance. All functiions will primarily interact +* with this data structure. +*/ +typedef struct s_hard_block_recog +{ + // names of all the user defined hard blocks + //std::vector* hard_block_type_names; // hb_type_names (probably do not need) + + // store the port information of each and every type of + // user defined hard blocks. All ports connected to each + // hard block type are stored. + std::unordered_map hard_block_type_name_to_port_info; + // store each hard blocks instantiated within a + // user design + std::vector hard_block_instances; + /* given a specific hard block instance name, we need to quickly + identify the corresponding hard block structure instance. + We do this by using the map data structure below, + where a hard block instance name is associated with an index + within the hard block instances above. + */ + std::unordered_map hard_block_instance_name_to_index; + /* The lcells and dffeas used to model ports are all stored as nodes. + The nodelist is simply an array. Now deleting lcell nodes while still + creating additional nodes could cause some problems, so we will + delete all these nodes at the end. Therefore we need to keep a + reference for all the lcell and dffeas nodes here.*/ + std::vector luts_dffeas_nodes_to_remove; // look into using array index instead +}t_hard_block_recog; +/* Function Declarations +* +* For more information about functions, refer to +* 'hard_block_recog.cpp' +*/ - - - - +void filter_and_create_hard_blocks(t_module*, t_arch*, std::vector*, std::string, std::string); + +void initialize_hard_block_models(t_arch*, std::vector*, t_hard_block_recog*); + +bool create_and_initialize_all_hard_block_ports(t_model*, t_hard_block_recog*); + +void create_hard_block_port_info_structure(t_hard_block_recog*, std::string); + +int extract_and_store_hard_block_model_ports(t_hard_block_recog*, t_model_ports*, std::string, int, std::string); + +t_array_ref* convert_hard_block_model_port_to_hard_block_node_port(t_model_ports*); + +t_node_port_association* create_unconnected_node_port_association(char*, int ,int); + +void store_hard_block_port_info(t_hard_block_recog*, std::string, std::string, t_array_ref**, int*); + +void copy_array_ref(t_array_ref*, t_array_ref*); + +void delete_hard_block_port_info(std::unordered_map*); + +// utility functions + +void store_hard_block_names(char**, int, std::vector*); #endif \ No newline at end of file From d1a51c15ee3ac5936684ceb2f04876d5c1bda0bf Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Thu, 5 Aug 2021 14:17:42 -0400 Subject: [PATCH 03/31] adding command line support for users to provide names of new primitive block types --- utils/vqm2blif/src/base/vqm2blif_util.cpp | 37 ++++ utils/vqm2blif/src/base/vqm2blif_util.h | 7 +- utils/vqm2blif/src/main.cpp | 218 +++++++++++++++++++++- 3 files changed, 256 insertions(+), 6 deletions(-) diff --git a/utils/vqm2blif/src/base/vqm2blif_util.cpp b/utils/vqm2blif/src/base/vqm2blif_util.cpp index 90ff3e9539d..d06fad16dbb 100644 --- a/utils/vqm2blif/src/base/vqm2blif_util.cpp +++ b/utils/vqm2blif/src/base/vqm2blif_util.cpp @@ -21,6 +21,7 @@ void print_usage (t_boolean terminate){ cout << "\t-include_unused_subckt_pins\n"; cout << "\t-remove_const_nets\n"; cout << "\t-eblif_format\n"; + cout << "\t-identify_and_instantiate_custom_hard_blocks ...\n"; //Hide experimental options by default //cout << "\t-split_multiclock_blocks\n"; //cout << "\t-split_carry_chain_logic\n"; @@ -49,6 +50,42 @@ void verify_format (string* filename, string extension){ //============================================================================================ //============================================================================================ +//============================================================================================ +//============================================================================================ + +void verify_hard_block_name(string curr_hard_block_name){ +// verifies whether the hard block name provided by the user meets verilog naming rules + + // naming rules have 2 main conditions: + // Condition 1: the first charatcer must be a lowercase/uppercase alphabetical character. Or the first character can be a underscore. + // Condition 2: The remaning characters must be a lowercase/uppercase alphabetical character, or a underscore, or a single digit number or the '$' character + std::regex verilog_naming_rules ("^[a-zA-Z_][a-zA-Z_\$0-9]*[a-zA-Z_\$0-9]$"); + + if (!(std::regex_match(curr_hard_block_name, verilog_naming_rules))) + { + // the hard block name did not meet the verilog naming rules + // Display error message to user + std::cout << "ERROR:The provided Hard Block Name '" << curr_hard_block_name << "' did not meet the verilog naming rules.\n"; + + std::cout << "********\n"; + + std::cout << "Please ensure the provided Hard Block Names follow the conditions below:\n"; + + std::cout << "\tCondition 1: The first character of the Hard Block Name should either be a-z, A-Z or _\n"; + + std::cout << "\tCondition 2: The remaining characters of the Hard Block Name should either be a-z, A-Z, 0-9, _ or $\n"; + + exit(1); + + } + + return; + +} + +//============================================================================================ +//============================================================================================ + void construct_filename (char* filename, const char* path, const char* ext){ //Constructs a char* filename from a given path and extension. diff --git a/utils/vqm2blif/src/base/vqm2blif_util.h b/utils/vqm2blif/src/base/vqm2blif_util.h index 39a4d8ec1d5..fa23033c84a 100644 --- a/utils/vqm2blif/src/base/vqm2blif_util.h +++ b/utils/vqm2blif/src/base/vqm2blif_util.h @@ -43,6 +43,7 @@ #include #include #include +#include #include "vqm_dll.h" //VQM Parser #include "hash.h" //Hash Table Functions @@ -82,7 +83,8 @@ enum v_OptionBaseToken OT_REMOVE_CONST_NETS, OT_INCLUDE_UNUSED_SUBCKT_PINS, OT_EBLIF_FORMAT, - OT_UNKNOWN + OT_UNKNOWN, + OT_IDENTIFY_AND_INSTANTIATE_CUSTOM_HARD_BLOCKS }; struct cstrcomp{ //operator structure to compare C-strings within a map class @@ -115,6 +117,9 @@ struct RamInfo { void verify_format (string* filename, string extension); //verifies a given string ends in ".extension" +// verifies whether the hard block name provided by the user meets verilog naming rules +void verify_hard_block_name(string curr_hard_block_name); + void construct_filename (char* filename, const char* path, const char* ext); //constructs a filename based on the path and termination passed //Naming Conventions diff --git a/utils/vqm2blif/src/main.cpp b/utils/vqm2blif/src/main.cpp index cfc9f033f9a..3114743a376 100644 --- a/utils/vqm2blif/src/main.cpp +++ b/utils/vqm2blif/src/main.cpp @@ -81,6 +81,8 @@ #include "lut_stats.h" #include "vtr_error.h" #include "physical_types.h" +#include "hard_block_recog.h" +#include "hard_block_recog_test.h" #include @@ -140,13 +142,24 @@ t_boolean print_unused_subckt_pins; //user-set flag which controls whether subck //this option to be true. t_boolean eblif_format; //If true, writes circuit in extended BLIF (.eblif) format (supported by YOSYS & VPR) +t_boolean identify_and_instantiate_custom_hard_blocks; // user-set flag. Which if true, helps find and filter user-defined hard blocks within the netlist (based on the supplied hard block names) and then instantiates the hard blocks within the blif file. + // or if false, then the netlist is processed without identifying any hard blocks. + // this option should only be used if the original user-design contained custom hard-blocks. + // The user-defined hard block names need to be provided + //============================================================================================ // FUNCTION DECLARATIONS //============================================================================================ +// Srivatsan, test function to better understand how the module data structure /works + +void print_module(t_module* my_module); + +void print_arch_modules(t_arch* my_arch, std::vector* my_logical_types); + //Setup Functions void cmd_line_parse (int argc, char** argv, string* sourcefile, string* archfile, - string* outfile); + string* outfile, std::vector* hard_block_list); void setup_tokens (tokmap* tokens); //Execution Functions @@ -231,7 +244,20 @@ void echo_blif_model (char* echo_file, const char* vqm_filename, int main(int argc, char* argv[]) { + //char* test = "test"; + //char* test_two = "test_two"; + //test_copy_array_ref(10000); + //test_create_unconnected_node_port_association(10, -1, test); + //test_create_hard_block_port_info_structure(test); + //test_convert_hard_block_model_port_to_hard_block_node_port(test, 25); + //test_store_hard_block_port_info(test,test_two,"router", 45); + //test_extract_and_store_hard_block_model_port(test, test_two, 500, 1000, "router"); + + //test_delete_hard_block_port_info(test, "router", 10000); + //test_initialize_hard_block_models(); + + //test_create_and_initialize_all_hard_block_ports(); t_blif_model my_model; //holds top-level model data for the .blif netlist //***The primary goal of the program is to populate and dump this structure appropriately.*** @@ -263,6 +289,9 @@ int main(int argc, char* argv[]) //used to construct output filenames from project name //char* filename necessitated by vqm_parse_file() + // a list which stores all the user supplied custom hard block names + std::vector hard_block_list; + //************************************************************************************************* // Begin Conversion //************************************************************************************************* @@ -271,7 +300,14 @@ int main(int argc, char* argv[]) cout << "This parser reads a .vqm file and converts it to .blif format.\n\n" ; //verify command-line is correct, populate input variables and global mode flags. - cmd_line_parse(argc, argv, &source_file, &arch_file, &out_file); + cmd_line_parse(argc, argv, &source_file, &arch_file, &out_file, &hard_block_list); + + std::vector::iterator it; + + for (it = hard_block_list.begin(); it != hard_block_list.end(); it++) + { + std::cout << *it << "\n"; + } setup_lut_support_map (); //initialize LUT support for cleanup and elaborate functions @@ -291,6 +327,8 @@ int main(int argc, char* argv[]) //VQM Parser Call, requires char* filename my_module = vqm_parse_file(temp_name); + //print_module(my_module); + unsigned long processEnd = clock(); cout << "\n>> VQM Parsing took " << (float)(processEnd - processStart)/CLOCKS_PER_SEC << " seconds.\n" ; @@ -369,8 +407,23 @@ int main(int argc, char* argv[]) //file contains cleaned data read from the .vqm structures. } } - - + + //print_arch_modules(&arch, &logical_block_types); + + // only process the netlist for any custom hard blocks if the user provided valid hard block names + if (identify_and_instantiate_custom_hard_blocks) + { + try + { + filter_and_create_hard_blocks(my_module,&arch,&hard_block_list, arch_file, source_file); + } + catch(const vtr::VtrError& error) + { + VTR_LOG_ERROR("%s\n", ((std::string)error.what()).c_str()); + exit(1); + } + } + //Reorganize netlist data into structures conducive to .blif writing. if (verbose_mode){ cout << "\n>> Initializing BLIF model\n" ; @@ -429,7 +482,7 @@ int main(int argc, char* argv[]) //============================================================================================ void cmd_line_parse (int argc, char** argv, string* sourcefile, string* archfile, - string* outfile){ + string* outfile, std::vector* hard_block_list){ /* Interpret the command-line arguments, accepting the input files, output file, and various * mode settings from the user. * @@ -471,6 +524,10 @@ void cmd_line_parse (int argc, char** argv, string* sourcefile, string* archfile remove_const_nets = T_FALSE; print_unused_subckt_pins = T_FALSE; eblif_format = T_FALSE; + identify_and_instantiate_custom_hard_blocks = T_FALSE; + + // temporary storage to hold hard block names from the argument list + std::string curr_hard_block_name; //Now read the command line to configure input variables. for (int i = 1; i < argc; i++){ @@ -591,6 +648,64 @@ void cmd_line_parse (int argc, char** argv, string* sourcefile, string* archfile case OT_EBLIF_FORMAT: eblif_format = T_TRUE; break; + case OT_IDENTIFY_AND_INSTANTIATE_CUSTOM_HARD_BLOCKS: + // first check whether an accompanying hard block name was supplied + if ( i+1 == argc ){ + // no hard block name was supplied so throw an error + cout << "ERROR: Missing Hard Block Names.\n" ; + print_usage (T_TRUE); + } + + // now we loop through and process the following arguments + while (T_TRUE) + { + // first check whether the next argument is a new option or a supplied hard block name + it = CmdTokens.find(argv[i+1]); + + // case where the next argument is a command line option + if (it != CmdTokens.end()) + { + // When we come here, we need to finish processing further command line arguments for hard block names. Since we have a different command-line option. + + // case one below is when the user didnt provide any hard block names and just provided the next command-line option + if (!identify_and_instantiate_custom_hard_blocks) + { + // since no hard block names were supplied, we throw an error + cout << "ERROR: Missing Hard Block Names.\n"; + print_usage (T_TRUE); + } + else + { + // the user already provided a legal hard block name, so if we come here then the user simply just wanted to use another command line option, so we just leave this case statement. + break; + } + } + else + { + // when we are here, the user provided an argument which is potentially a valid hard block name + curr_hard_block_name.assign(argv[i+1]); + + // check if the provided name is valid + verify_hard_block_name(curr_hard_block_name); + + // if we are here then the provided name was valid. + identify_and_instantiate_custom_hard_blocks = T_TRUE; + + hard_block_list->push_back(curr_hard_block_name); // add the hard block name to the list + + // update argument index to show that we have processed the current hard block name successfully + i++; + } + + // we handle the case where the next argument is empty (if we continued then an exception will be thrown in the find function above) + if (i+1 == argc) + { + // at this point we would have read a vlid input. + // Safe to assume that the user just finished providing hard block names + break; + } + } + break; default: //Should never get here; unknown tokens aren't mapped. cout << "\nERROR: Token " << argv[i] << " mishandled.\n" ; @@ -643,6 +758,7 @@ void setup_tokens (tokmap* tokens){ tokens->insert(tokpair("-remove_const_nets", OT_REMOVE_CONST_NETS)); tokens->insert(tokpair("-include_unused_subckt_pins", OT_INCLUDE_UNUSED_SUBCKT_PINS)); tokens->insert(tokpair("-eblif_format", OT_EBLIF_FORMAT)); + tokens->insert(tokpair("-identify_and_instantiate_custom_hard_blocks", OT_IDENTIFY_AND_INSTANTIATE_CUSTOM_HARD_BLOCKS)); } //============================================================================================ @@ -2172,6 +2288,98 @@ void echo_blif_model (char* echo_file, const char* vqm_filename, model_out.close(); } +// this is a test function to see how the t_module data structure works (by printing everything) + +void print_module(t_module* my_module) +{ + t_node* temp_node = NULL; + t_node_port_association* temp_ports = NULL; + // go through all the nodes in the design + for (auto i = 0; i < my_module->number_of_nodes; i++) + { + temp_node = my_module->array_of_nodes[i]; + + for (auto j = 0; j < temp_node->number_of_ports; j++) + { + temp_ports = temp_node->array_of_ports[j]; + } + } + + return; +} + +// this is a test function to see how the t_arch data structure works +// For the hard block functionality we just care about the modules +// so print information regarding that +void print_arch_modules(t_arch* my_arch, std::vector* my_logical_types) +{ + t_model* temp = my_arch->models; + t_model_ports* temp_input_ports = NULL; + t_model_ports* temp_output_ports = NULL; + + std::string temp_name; + + char* output_port_name = NULL; + char* input_port_name = NULL; + + // iterator to traverse the logical_types + std::vector::iterator it; + + // code related to the logical types + t_pb_type* temp_logical_type = NULL; + t_port* temp_port = NULL; + + while (temp != NULL) + { + temp_input_ports = temp->inputs; + temp_output_ports = temp->outputs; + + temp_name = temp->name; + + /*if(temp_name.compare("stratixiv_ram_block.opmode{dual_port}.output_type{reg}.port_a_address_width{2}.port_b_address_width{2}") == 0) + { + // breakpoint here + std::cout << "test" << "\n"; + }*/ + + if(temp_name.compare("router") == 0) + { + // breakpoint here + std::cout << "test" << "\n"; + } + + // lets go through all the ports + while (temp_input_ports != NULL) + { + input_port_name = temp_input_ports->name; + + temp_input_ports = temp_input_ports->next; + } + + while (temp_output_ports != NULL) + { + output_port_name = temp_output_ports->name; + + temp_output_ports = temp_output_ports->next; + } + + temp = temp->next; + } + + // we now traverse the logical types + for(it = my_logical_types->begin(); it != my_logical_types->end(); it++) + { + temp_logical_type = it->pb_type; + + for (int i = 0; i < temp_logical_type->num_ports; i++) + { + temp_port = &(temp_logical_type->ports[i]); + } + } + + return; +} + //============================================================================================ //============================================================================================ #ifdef NO_CONSTS From abb0d9471fff4877e09bd5650fb41547b74a65ff Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Fri, 6 Aug 2021 16:01:17 -0400 Subject: [PATCH 04/31] added a new data structure to store port direction as well --- utils/vqm2blif/src/base/hard_block_recog.cpp | 7 +++++-- utils/vqm2blif/src/base/hard_block_recog.h | 6 +++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/utils/vqm2blif/src/base/hard_block_recog.cpp b/utils/vqm2blif/src/base/hard_block_recog.cpp index b54a3945a7c..b2b6c4654bd 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.cpp +++ b/utils/vqm2blif/src/base/hard_block_recog.cpp @@ -112,7 +112,7 @@ int extract_and_store_hard_block_model_ports(t_hard_block_recog* storage_of_hard { equivalent_hard_block_node_port_array = convert_hard_block_model_port_to_hard_block_node_port(curr_hard_block_model_port); - store_hard_block_port_info(storage_of_hard_block_info, curr_hard_block_name, curr_hard_block_model_port->name, &equivalent_hard_block_node_port_array, &port_index); + store_hard_block_port_info(storage_of_hard_block_info, curr_hard_block_name, curr_hard_block_model_port->name, curr_hard_block_model_port->dir, &equivalent_hard_block_node_port_array, &port_index); curr_hard_block_model_port = curr_hard_block_model_port->next; @@ -172,7 +172,7 @@ t_node_port_association* create_unconnected_node_port_association(char *port_nam } // need the hard block name itself -void store_hard_block_port_info(t_hard_block_recog* storage_of_hard_block_port_info, std::string curr_hard_block_name,std::string curr_port_name, t_array_ref** curr_port_array, int* port_index) +void store_hard_block_port_info(t_hard_block_recog* storage_of_hard_block_port_info, std::string curr_hard_block_name,std::string curr_port_name, PORTS current_port_dir,t_array_ref** curr_port_array, int* port_index) { std::unordered_map::iterator curr_port_info = ((storage_of_hard_block_port_info->hard_block_type_name_to_port_info).find(curr_hard_block_name)); @@ -182,6 +182,9 @@ void store_hard_block_port_info(t_hard_block_recog* storage_of_hard_block_port_i // insert the port name to the current index (curr_port_info->second).port_name_to_port_start_index.insert({curr_port_name, *port_index}); + //insert the port direction of the current port + (curr_port_info->second).port_name_to_port_dir.insert({curr_port_name, current_port_dir}); + *port_index += (*curr_port_array)->array_size; vtr::free((*curr_port_array)->pointer); diff --git a/utils/vqm2blif/src/base/hard_block_recog.h b/utils/vqm2blif/src/base/hard_block_recog.h index 9d07d8b33bf..5573bf8ba66 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.h +++ b/utils/vqm2blif/src/base/hard_block_recog.h @@ -31,6 +31,7 @@ #include "vtr_log.h" #include "vqm_common.h" #include "vtr_memory.h" +#include "logic_types.h" // user vqm2blif libraries #include "vqm2blif_util.h" @@ -67,6 +68,9 @@ typedef struct s_hard_block_port_info { // mapping structure to quickly identify where a specific port begins std::unordered_map port_name_to_port_start_index; + + // mapping structure to quickly identify the direction of a port + std::unordered_map port_name_to_port_dir; // An array of all the ports within the hard block is stored here // refer to 'vqm_dll.h' for more information @@ -165,7 +169,7 @@ t_array_ref* convert_hard_block_model_port_to_hard_block_node_port(t_model_ports t_node_port_association* create_unconnected_node_port_association(char*, int ,int); -void store_hard_block_port_info(t_hard_block_recog*, std::string, std::string, t_array_ref**, int*); +void store_hard_block_port_info(t_hard_block_recog*, std::string, std::string,PORTS, t_array_ref**, int*); void copy_array_ref(t_array_ref*, t_array_ref*); From 7cb63a96cd960e68b39e889a5beac3b2f1d8988e Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Mon, 9 Aug 2021 16:32:51 -0400 Subject: [PATCH 05/31] updated command line input parser to allow for hard block names that are escaped --- utils/vqm2blif/src/base/vqm2blif_util.cpp | 41 ++++++++++++++++++++--- utils/vqm2blif/src/base/vqm2blif_util.h | 5 ++- utils/vqm2blif/src/main.cpp | 3 ++ 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/utils/vqm2blif/src/base/vqm2blif_util.cpp b/utils/vqm2blif/src/base/vqm2blif_util.cpp index d06fad16dbb..b67c17f8741 100644 --- a/utils/vqm2blif/src/base/vqm2blif_util.cpp +++ b/utils/vqm2blif/src/base/vqm2blif_util.cpp @@ -50,8 +50,7 @@ void verify_format (string* filename, string extension){ //============================================================================================ //============================================================================================ -//============================================================================================ -//============================================================================================ + void verify_hard_block_name(string curr_hard_block_name){ // verifies whether the hard block name provided by the user meets verilog naming rules @@ -59,9 +58,13 @@ void verify_hard_block_name(string curr_hard_block_name){ // naming rules have 2 main conditions: // Condition 1: the first charatcer must be a lowercase/uppercase alphabetical character. Or the first character can be a underscore. // Condition 2: The remaning characters must be a lowercase/uppercase alphabetical character, or a underscore, or a single digit number or the '$' character - std::regex verilog_naming_rules ("^[a-zA-Z_][a-zA-Z_\$0-9]*[a-zA-Z_\$0-9]$"); + std::regex verilog_naming_rules_one ("^[a-zA-Z_][a-zA-Z_\$0-9]*[a-zA-Z_\$0-9]$"); - if (!(std::regex_match(curr_hard_block_name, verilog_naming_rules))) + // verilog names can also contain any characters, as long as they are escaped with a '\' at the start of the identifer. For example, \reset- + // we check this below + std::regex verilog_naming_rules_two ("[\\](.*)", std::regex_constants::extended); + + if ((!(std::regex_match(curr_hard_block_name, verilog_naming_rules_one))) && (!(std::regex_match(curr_hard_block_name, verilog_naming_rules_two)))) { // the hard block name did not meet the verilog naming rules // Display error message to user @@ -75,6 +78,8 @@ void verify_hard_block_name(string curr_hard_block_name){ std::cout << "\tCondition 2: The remaining characters of the Hard Block Name should either be a-z, A-Z, 0-9, _ or $\n"; + std::cout << "Alternatively, any character can be used for the hard block name, as long as the name is escaped using '\\' character. For example, '\\reset-' would be legal.\n"; + exit(1); } @@ -86,6 +91,34 @@ void verify_hard_block_name(string curr_hard_block_name){ //============================================================================================ //============================================================================================ +//============================================================================================ +//============================================================================================ + +void cleanup_hard_block_name(string* curr_hard_block_name){ +// if the hard block name was escaped by '\', we need to remove the '\' character from the name + + // matching token below tries to determine whether the current hard block name was escaped with '\' + std::regex verilog_naming_rules ("[\\](.*)", std::regex_constants::extended); + + // stores the hard block name without the '\' character + std::smatch matches; + + // store the matched strings and also determine whether + // the hard block name is actually escaped. if not escqaped, then we do not need to do anything + if (std::regex_match(*curr_hard_block_name, matches, verilog_naming_rules, std::regex_constants::match_default)) + { + // if we are here, there should be two string matches + // the first match is the entire hard block name with the escape character '\' + // the second match should just be the hard block name without the escape character '\' + + // below we just store the second match + curr_hard_block_name->assign(matches[matches.size() - 1]); + } + + return; + +} + void construct_filename (char* filename, const char* path, const char* ext){ //Constructs a char* filename from a given path and extension. diff --git a/utils/vqm2blif/src/base/vqm2blif_util.h b/utils/vqm2blif/src/base/vqm2blif_util.h index fa23033c84a..35324652f34 100644 --- a/utils/vqm2blif/src/base/vqm2blif_util.h +++ b/utils/vqm2blif/src/base/vqm2blif_util.h @@ -118,7 +118,10 @@ struct RamInfo { void verify_format (string* filename, string extension); //verifies a given string ends in ".extension" // verifies whether the hard block name provided by the user meets verilog naming rules -void verify_hard_block_name(string curr_hard_block_name); +void verify_hard_block_name(string curr_hard_block_name); + +// if the hard block name was escaped by '\', we need to remove the '\' character from the name (refer to function above) +void cleanup_hard_block_name(string* curr_hard_block_name); void construct_filename (char* filename, const char* path, const char* ext); //constructs a filename based on the path and termination passed diff --git a/utils/vqm2blif/src/main.cpp b/utils/vqm2blif/src/main.cpp index 3114743a376..9564cdebfb1 100644 --- a/utils/vqm2blif/src/main.cpp +++ b/utils/vqm2blif/src/main.cpp @@ -688,6 +688,9 @@ void cmd_line_parse (int argc, char** argv, string* sourcefile, string* archfile // check if the provided name is valid verify_hard_block_name(curr_hard_block_name); + // if the hard block name was escaped by '\', then we need to remove the '\' character from the string (look at 'verify_hard_block_name' function for more info) + cleanup_hard_block_name(&curr_hard_block_name); + // if we are here then the provided name was valid. identify_and_instantiate_custom_hard_blocks = T_TRUE; From 806d2d3e044f8080a19efc1d602883ee8e6ad856 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Mon, 9 Aug 2021 19:50:48 -0400 Subject: [PATCH 06/31] made changes to indicate that users would supply hard block type names, not specific hard block instance names --- utils/vqm2blif/src/base/hard_block_recog.cpp | 29 ++++++++------ utils/vqm2blif/src/base/hard_block_recog.h | 26 +++++++++++++ utils/vqm2blif/src/base/vqm2blif_util.cpp | 36 +++++++++--------- utils/vqm2blif/src/base/vqm2blif_util.h | 8 ++-- utils/vqm2blif/src/main.cpp | 40 ++++++++++---------- 5 files changed, 85 insertions(+), 54 deletions(-) diff --git a/utils/vqm2blif/src/base/hard_block_recog.cpp b/utils/vqm2blif/src/base/hard_block_recog.cpp index b2b6c4654bd..1013138addb 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.cpp +++ b/utils/vqm2blif/src/base/hard_block_recog.cpp @@ -5,13 +5,13 @@ #include "hard_block_recog.h" -void filter_and_create_hard_blocks(t_module* main_module, t_arch* main_arch, std::vector* hard_block_names, std::string arch_file_name, std::string vqm_file_name) +void filter_and_create_hard_blocks(t_module* main_module, t_arch* main_arch, std::vector* hard_block_type_names, std::string arch_file_name, std::string vqm_file_name) { t_hard_block_recog hard_block_node_refs_and_info; try { - initialize_hard_block_models(main_arch, hard_block_names, &hard_block_node_refs_and_info); + initialize_hard_block_models(main_arch, hard_block_type_names, &hard_block_node_refs_and_info); } catch(const vtr::VtrError& error) { @@ -30,13 +30,13 @@ void filter_and_create_hard_blocks(t_module* main_module, t_arch* main_arch, std return; } -void initialize_hard_block_models(t_arch* main_arch, std::vector* hard_block_names, t_hard_block_recog* storage_of_hard_block_info) +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_name_traverser; bool single_hard_block_init_result = false; - for (hard_block_name_traverser = hard_block_names->begin(); hard_block_name_traverser != hard_block_names->end(); hard_block_name_traverser++) + for (hard_block_name_traverser = hard_block_type_names->begin(); hard_block_name_traverser != hard_block_type_names->end(); hard_block_name_traverser++) { // function already made hard_block_model = find_arch_model_by_name(*hard_block_name_traverser, main_arch->models); @@ -103,7 +103,7 @@ void create_hard_block_port_info_structure(t_hard_block_recog* storage_of_hard_b } -int extract_and_store_hard_block_model_ports(t_hard_block_recog* storage_of_hard_block_info, t_model_ports* curr_hard_block_model_port, std::string curr_hard_block_name,int port_index, std::string port_type) +int extract_and_store_hard_block_model_ports(t_hard_block_recog* storage_of_hard_block_info, t_model_ports* curr_hard_block_model_port, std::string curr_hard_block_type_name,int port_index, std::string port_type) { t_array_ref* equivalent_hard_block_node_port_array = NULL; int starting_port_index = port_index; @@ -112,7 +112,7 @@ int extract_and_store_hard_block_model_ports(t_hard_block_recog* storage_of_hard { equivalent_hard_block_node_port_array = convert_hard_block_model_port_to_hard_block_node_port(curr_hard_block_model_port); - store_hard_block_port_info(storage_of_hard_block_info, curr_hard_block_name, curr_hard_block_model_port->name, curr_hard_block_model_port->dir, &equivalent_hard_block_node_port_array, &port_index); + store_hard_block_port_info(storage_of_hard_block_info, curr_hard_block_type_name, curr_hard_block_model_port->name, curr_hard_block_model_port->dir, &equivalent_hard_block_node_port_array, &port_index); curr_hard_block_model_port = curr_hard_block_model_port->next; @@ -120,7 +120,7 @@ int extract_and_store_hard_block_model_ports(t_hard_block_recog* storage_of_hard if (starting_port_index == port_index) { - VTR_LOG_WARN("Model '%s' found in the architecture file does not have %s ports\n", curr_hard_block_name.c_str(), port_type.c_str()); + VTR_LOG_WARN("Model '%s' found in the architecture file does not have %s ports\n", curr_hard_block_type_name.c_str(), port_type.c_str()); } return port_index; @@ -172,10 +172,10 @@ t_node_port_association* create_unconnected_node_port_association(char *port_nam } // need the hard block name itself -void store_hard_block_port_info(t_hard_block_recog* storage_of_hard_block_port_info, std::string curr_hard_block_name,std::string curr_port_name, PORTS current_port_dir,t_array_ref** curr_port_array, int* port_index) +void store_hard_block_port_info(t_hard_block_recog* storage_of_hard_block_port_info, std::string curr_hard_block_type_name,std::string curr_port_name, PORTS current_port_dir,t_array_ref** curr_port_array, int* port_index) { - std::unordered_map::iterator curr_port_info = ((storage_of_hard_block_port_info->hard_block_type_name_to_port_info).find(curr_hard_block_name)); + std::unordered_map::iterator curr_port_info = ((storage_of_hard_block_port_info->hard_block_type_name_to_port_info).find(curr_hard_block_type_name)); copy_array_ref(*curr_port_array, &(curr_port_info->second).hard_block_ports); @@ -207,11 +207,16 @@ void copy_array_ref(t_array_ref* array_ref_orig, t_array_ref* array_ref_copy) return; } -void delete_hard_block_port_info(std::unordered_map* hard_block_name_to_port_info_map) +std::string identify_hard_block_type(std::vector* list_, std::string) { - std::unordered_map::iterator curr_hard_block_port_info = hard_block_name_to_port_info_map->begin(); - while (curr_hard_block_port_info != (hard_block_name_to_port_info_map->end())) +} + +void delete_hard_block_port_info(std::unordered_map* hard_block_type_name_to_port_info_map) +{ + std::unordered_map::iterator curr_hard_block_port_info = hard_block_type_name_to_port_info_map->begin(); + + while (curr_hard_block_port_info != (hard_block_type_name_to_port_info_map->end())) { int number_of_ports = (curr_hard_block_port_info->second).hard_block_ports.array_size; diff --git a/utils/vqm2blif/src/base/hard_block_recog.h b/utils/vqm2blif/src/base/hard_block_recog.h index 5573bf8ba66..e0ab895bbaf 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.h +++ b/utils/vqm2blif/src/base/hard_block_recog.h @@ -148,6 +148,28 @@ typedef struct s_hard_block_recog }t_hard_block_recog; +/* +* When we go through the .vqm file, the ports of any user defined hard block * will be represented as a LUT (stratix_lcell), or flip flop (dffeas) (for * more info refer to 'hard_block_recog.cpp'). The generated names found in * the .vqm file for the two previous blocks contain a lot of information * about the hard block. The structure below is used to store the information, +* which includes the hard block name, hard block type, the specfic hard * block port and if the port is a bus, then the specific index. +*/ +typedef struct s_parsed_hard_block_component_info +{ + // name used to identify the unique hard block the current port belongs to + // multiple ports can belong to the same hard block and there can be multiple hard blocks in the design + std::string curr_hard_block_name; + + // the specific type of hard block the current port belongs to + // the user can define multiple hard block types + std::string curr_hard_block_type; + + // the port name defined in the current block (LUT or dffeas) + std::string curr_hard_block_port; + + // index of the port defined in the current block (LUT or dffeas) + int curr_hard_block_port_index; + +}t_parse_hard_block_component_info; + /* Function Declarations * @@ -175,6 +197,10 @@ void copy_array_ref(t_array_ref*, t_array_ref*); void delete_hard_block_port_info(std::unordered_map*); +std::string identify_hard_block_type(std::vector*, std::string); + +void identify_hard_block_port_name_and_index (t_parse_hard_block_component_info*, std::string); + // utility functions void store_hard_block_names(char**, int, std::vector*); diff --git a/utils/vqm2blif/src/base/vqm2blif_util.cpp b/utils/vqm2blif/src/base/vqm2blif_util.cpp index b67c17f8741..eda94102166 100644 --- a/utils/vqm2blif/src/base/vqm2blif_util.cpp +++ b/utils/vqm2blif/src/base/vqm2blif_util.cpp @@ -52,8 +52,8 @@ void verify_format (string* filename, string extension){ -void verify_hard_block_name(string curr_hard_block_name){ -// verifies whether the hard block name provided by the user meets verilog naming rules +void verify_hard_block_type_name(string curr_hard_block_type_name){ +// verifies whether the hard block name (type of hard block) provided by the user meets verilog naming rules // naming rules have 2 main conditions: // Condition 1: the first charatcer must be a lowercase/uppercase alphabetical character. Or the first character can be a underscore. @@ -64,21 +64,21 @@ void verify_hard_block_name(string curr_hard_block_name){ // we check this below std::regex verilog_naming_rules_two ("[\\](.*)", std::regex_constants::extended); - if ((!(std::regex_match(curr_hard_block_name, verilog_naming_rules_one))) && (!(std::regex_match(curr_hard_block_name, verilog_naming_rules_two)))) + if ((!(std::regex_match(curr_hard_block_type_name, verilog_naming_rules_one))) && (!(std::regex_match(curr_hard_block_type_name, verilog_naming_rules_two)))) { - // the hard block name did not meet the verilog naming rules + // the hard block type name did not meet the verilog naming rules // Display error message to user - std::cout << "ERROR:The provided Hard Block Name '" << curr_hard_block_name << "' did not meet the verilog naming rules.\n"; + std::cout << "ERROR:The provided Hard Block Type Name '" << curr_hard_block_type_name << "' did not meet the verilog naming rules.\n"; std::cout << "********\n"; - std::cout << "Please ensure the provided Hard Block Names follow the conditions below:\n"; + std::cout << "Please ensure the provided Hard Block Type Names follow the conditions below:\n"; - std::cout << "\tCondition 1: The first character of the Hard Block Name should either be a-z, A-Z or _\n"; + std::cout << "\tCondition 1: The first character of the Hard Block Type Name should either be a-z, A-Z or _\n"; - std::cout << "\tCondition 2: The remaining characters of the Hard Block Name should either be a-z, A-Z, 0-9, _ or $\n"; + std::cout << "\tCondition 2: The remaining characters of the Hard Block Type Name should either be a-z, A-Z, 0-9, _ or $\n"; - std::cout << "Alternatively, any character can be used for the hard block name, as long as the name is escaped using '\\' character. For example, '\\reset-' would be legal.\n"; + std::cout << "Alternatively, any character can be used for the hard block type name, as long as the name is escaped using '\\' character. For example, '\\reset-' would be legal.\n"; exit(1); @@ -94,25 +94,25 @@ void verify_hard_block_name(string curr_hard_block_name){ //============================================================================================ //============================================================================================ -void cleanup_hard_block_name(string* curr_hard_block_name){ -// if the hard block name was escaped by '\', we need to remove the '\' character from the name +void cleanup_hard_block_type_name(string* curr_hard_block_type_name){ +// if the hard block type name was escaped by '\', we need to remove the '\' character from the name - // matching token below tries to determine whether the current hard block name was escaped with '\' + // matching token below tries to determine whether the current hard block type name was escaped with '\' std::regex verilog_naming_rules ("[\\](.*)", std::regex_constants::extended); - // stores the hard block name without the '\' character + // stores the hard block type name without the '\' character std::smatch matches; // store the matched strings and also determine whether - // the hard block name is actually escaped. if not escqaped, then we do not need to do anything - if (std::regex_match(*curr_hard_block_name, matches, verilog_naming_rules, std::regex_constants::match_default)) + // the hard block type name is actually escaped. if not escaped, then we do not need to do anything + if (std::regex_match(*curr_hard_block_type_name, matches, verilog_naming_rules, std::regex_constants::match_default)) { // if we are here, there should be two string matches - // the first match is the entire hard block name with the escape character '\' - // the second match should just be the hard block name without the escape character '\' + // the first match is the entire hard block type name with the escape character '\' + // the second match should just be the hard block type name without the escape character '\' // below we just store the second match - curr_hard_block_name->assign(matches[matches.size() - 1]); + curr_hard_block_type_name->assign(matches[matches.size() - 1]); } return; diff --git a/utils/vqm2blif/src/base/vqm2blif_util.h b/utils/vqm2blif/src/base/vqm2blif_util.h index 35324652f34..a698473d10e 100644 --- a/utils/vqm2blif/src/base/vqm2blif_util.h +++ b/utils/vqm2blif/src/base/vqm2blif_util.h @@ -117,11 +117,11 @@ struct RamInfo { void verify_format (string* filename, string extension); //verifies a given string ends in ".extension" -// verifies whether the hard block name provided by the user meets verilog naming rules -void verify_hard_block_name(string curr_hard_block_name); +// verifies whether the hard block type name provided by the user meets verilog naming rules +void verify_hard_block_type_name(string curr_hard_block_name); -// if the hard block name was escaped by '\', we need to remove the '\' character from the name (refer to function above) -void cleanup_hard_block_name(string* curr_hard_block_name); +// if the hard block type name was escaped by '\', we need to remove the '\' character from the name (refer to function above) +void cleanup_hard_block_type_name(string* curr_hard_block_name); void construct_filename (char* filename, const char* path, const char* ext); //constructs a filename based on the path and termination passed diff --git a/utils/vqm2blif/src/main.cpp b/utils/vqm2blif/src/main.cpp index 9564cdebfb1..94ac3e5beee 100644 --- a/utils/vqm2blif/src/main.cpp +++ b/utils/vqm2blif/src/main.cpp @@ -290,7 +290,7 @@ int main(int argc, char* argv[]) //char* filename necessitated by vqm_parse_file() // a list which stores all the user supplied custom hard block names - std::vector hard_block_list; + std::vector hard_block_type_name_list; //************************************************************************************************* // Begin Conversion @@ -300,11 +300,11 @@ int main(int argc, char* argv[]) cout << "This parser reads a .vqm file and converts it to .blif format.\n\n" ; //verify command-line is correct, populate input variables and global mode flags. - cmd_line_parse(argc, argv, &source_file, &arch_file, &out_file, &hard_block_list); + cmd_line_parse(argc, argv, &source_file, &arch_file, &out_file, &hard_block_type_name_list); std::vector::iterator it; - for (it = hard_block_list.begin(); it != hard_block_list.end(); it++) + for (it = hard_block_type_name_list.begin(); it != hard_block_type_name_list.end(); it++) { std::cout << *it << "\n"; } @@ -415,7 +415,7 @@ int main(int argc, char* argv[]) { try { - filter_and_create_hard_blocks(my_module,&arch,&hard_block_list, arch_file, source_file); + filter_and_create_hard_blocks(my_module,&arch,&hard_block_type_name_list, arch_file, source_file); } catch(const vtr::VtrError& error) { @@ -482,7 +482,7 @@ int main(int argc, char* argv[]) //============================================================================================ void cmd_line_parse (int argc, char** argv, string* sourcefile, string* archfile, - string* outfile, std::vector* hard_block_list){ + string* outfile, std::vector* hard_block_type_name_list){ /* Interpret the command-line arguments, accepting the input files, output file, and various * mode settings from the user. * @@ -649,54 +649,54 @@ void cmd_line_parse (int argc, char** argv, string* sourcefile, string* archfile eblif_format = T_TRUE; break; case OT_IDENTIFY_AND_INSTANTIATE_CUSTOM_HARD_BLOCKS: - // first check whether an accompanying hard block name was supplied + // first check whether an accompanying hard block type name was supplied (user provides the names of all the various types of custom hard blocks within the design) if ( i+1 == argc ){ - // no hard block name was supplied so throw an error - cout << "ERROR: Missing Hard Block Names.\n" ; + // no hard block type name was supplied so throw an error + cout << "ERROR: Missing Hard Block Type Names.\n" ; print_usage (T_TRUE); } // now we loop through and process the following arguments while (T_TRUE) { - // first check whether the next argument is a new option or a supplied hard block name + // first check whether the next argument is a new option or a supplied hard block type name it = CmdTokens.find(argv[i+1]); // case where the next argument is a command line option if (it != CmdTokens.end()) { - // When we come here, we need to finish processing further command line arguments for hard block names. Since we have a different command-line option. + // When we come here, we need to finish processing further command line arguments for hard block type names. Since we have a different command-line option. - // case one below is when the user didnt provide any hard block names and just provided the next command-line option + // case one below is when the user didnt provide any hard block type names and just provided the next command-line option if (!identify_and_instantiate_custom_hard_blocks) { - // since no hard block names were supplied, we throw an error - cout << "ERROR: Missing Hard Block Names.\n"; + // since no hard block type names were supplied, we throw an error + cout << "ERROR: Missing Hard Block Type Names.\n"; print_usage (T_TRUE); } else { - // the user already provided a legal hard block name, so if we come here then the user simply just wanted to use another command line option, so we just leave this case statement. + // the user already provided a legal hard block type name, so if we come here then the user simply just wanted to use another command line option, so we just leave this case statement. break; } } else { - // when we are here, the user provided an argument which is potentially a valid hard block name + // when we are here, the user provided an argument which is potentially a valid hard block type name curr_hard_block_name.assign(argv[i+1]); // check if the provided name is valid - verify_hard_block_name(curr_hard_block_name); + verify_hard_block_type_name(curr_hard_block_name); - // if the hard block name was escaped by '\', then we need to remove the '\' character from the string (look at 'verify_hard_block_name' function for more info) - cleanup_hard_block_name(&curr_hard_block_name); + // if the hard block type name was escaped by '\', then we need to remove the '\' character from the string (look at 'verify_hard_block_type_name' function for more info) + cleanup_hard_block_type_name(&curr_hard_block_name); // if we are here then the provided name was valid. identify_and_instantiate_custom_hard_blocks = T_TRUE; - hard_block_list->push_back(curr_hard_block_name); // add the hard block name to the list + hard_block_type_name_list->push_back(curr_hard_block_name); // add the hard block type name to the list - // update argument index to show that we have processed the current hard block name successfully + // update argument index to show that we have processed the current hard block type name successfully i++; } From d7e068a567a468115a05cfdea887466d5e302dea Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Tue, 10 Aug 2021 15:32:05 -0400 Subject: [PATCH 07/31] added functionality to parse hard block information from node names found in the vqm file --- utils/vqm2blif/src/base/hard_block_recog.cpp | 68 ++++++++++++++++++-- utils/vqm2blif/src/base/hard_block_recog.h | 17 +++-- utils/vqm2blif/src/base/vqm2blif_util.cpp | 17 ++--- 3 files changed, 83 insertions(+), 19 deletions(-) diff --git a/utils/vqm2blif/src/base/hard_block_recog.cpp b/utils/vqm2blif/src/base/hard_block_recog.cpp index 1013138addb..93bf619378e 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.cpp +++ b/utils/vqm2blif/src/base/hard_block_recog.cpp @@ -33,17 +33,17 @@ void filter_and_create_hard_blocks(t_module* main_module, t_arch* main_arch, std 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_name_traverser; + std::vector::iterator hard_block_type_name_traverser; bool single_hard_block_init_result = false; - for (hard_block_name_traverser = hard_block_type_names->begin(); hard_block_name_traverser != hard_block_type_names->end(); hard_block_name_traverser++) + for (hard_block_type_name_traverser = hard_block_type_names->begin(); hard_block_type_name_traverser != hard_block_type_names->end(); hard_block_type_name_traverser++) { // function already made - hard_block_model = find_arch_model_by_name(*hard_block_name_traverser, main_arch->models); + hard_block_model = find_arch_model_by_name(*hard_block_type_name_traverser, main_arch->models); if (hard_block_model == NULL) { - throw vtr::VtrError("The provided hard block model '" + *hard_block_name_traverser + "' was not found within the corresponding FPGA architecture."); + throw vtr::VtrError("The provided hard block model '" + *hard_block_type_name_traverser + "' was not found within the corresponding FPGA architecture."); } else { @@ -51,7 +51,7 @@ void initialize_hard_block_models(t_arch* main_arch, std::vector* h if (!single_hard_block_init_result) { - throw vtr::VtrError("Hard block model '" + *hard_block_name_traverser + "' found in the architecture has no input/output ports."); + throw vtr::VtrError("Hard block model '" + *hard_block_type_name_traverser + "' found in the architecture has no input/output ports."); } } @@ -207,9 +207,65 @@ void copy_array_ref(t_array_ref* array_ref_orig, t_array_ref* array_ref_copy) return; } -std::string identify_hard_block_type(std::vector* list_, std::string) +std::string identify_hard_block_type(std::vector* hard_block_type_name_list, std::string curr_node_name_component) { + std::vector::iterator hard_block_type_name_traverser; + + std::string hard_block_type_name_to_find; + std::string hard_block_type = ""; + + size_t match_result = 0; + + for (hard_block_type_name_traverser = hard_block_type_name_list->begin(); hard_block_type_name_traverser != hard_block_type_name_list->end(); hard_block_type_name_traverser++) + { + hard_block_type_name_to_find.assign(*hard_block_type_name_traverser + HARD_BLOCK_TYPE_NAME_SEPERATOR); + + match_result = curr_node_name_component.find(hard_block_type_name_to_find); + + if (match_result != std::string::npos) + { + hard_block_type.assign(*hard_block_type_name_traverser); + break; + } + + } + + return hard_block_type; +} +void identify_hard_block_port_name_and_index (t_parsed_hard_block_component_info* curr_hard_block_component, std::string curr_node_name_component) +{ + // identifer to check whether the port defined in the current node name is a bus (ex. payload[1]~QIC_DANGLING_PORT_I) + std::regex port_is_a_bus ("(.*)[[]([0-9]*)\]~(?:.*)"); + + // identifier to check whether the current port defined in the current node name isn't a bus (ex. value~9490_I) + std::regex port_is_not_a_bus ("(.*)~(?:.*)"); + + // when we compare the given node name component with the previous identifiers, the port name and port index are extracted and they are stored in the variable below + std::smatch port_info; + + // handle either the case where the current port defined in the provided node name is either a bus or not + // we should never not match with either case below + if (std::regex_match(curr_node_name_component, port_info, port_is_a_bus, std::regex_constants::match_default)) + { + // if we are here, then the port is a bus + + // store the extarcted port name and index to be used externally + curr_hard_block_component->curr_hard_block_port_name.assign(port_info[PORT_NAME]); + + curr_hard_block_component->curr_hard_block_port_index = std::stoi(port_info[PORT_INDEX]); + } + else if (std::regex_match(curr_node_name_component, port_info, port_is_not_a_bus, std::regex_constants::match_default)) + { + // if we are here then the port was not a bus + + // just store the extracted port name and default poert index to be used externally + curr_hard_block_component->curr_hard_block_port_name.assign(port_info[PORT_NAME]); + + curr_hard_block_component->curr_hard_block_port_index = DEFAULT_PORT_INDEX; + } + + return; } void delete_hard_block_port_info(std::unordered_map* hard_block_type_name_to_port_info_map) diff --git a/utils/vqm2blif/src/base/hard_block_recog.h b/utils/vqm2blif/src/base/hard_block_recog.h index e0ab895bbaf..09b4ce4dda5 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.h +++ b/utils/vqm2blif/src/base/hard_block_recog.h @@ -51,6 +51,13 @@ #define OUTPUT_PORTS "output" #define HARD_BLOCK_WITH_NO_PORTS 0 +#define DEFAULT_PORT_INDEX 0 + +// unique identifier that seperates a hard block type name (module name), from the specific instance name +#define HARD_BLOCK_TYPE_NAME_SEPERATOR ":" + +#define PORT_NAME 1 +#define PORT_INDEX 2 @@ -100,7 +107,7 @@ typedef struct s_hard_block // helps keep track of the number of hard block ports we have assigned // a net to - int hard_block_ports_assigned; + int hard_block_ports_assigned = 0; // a reference to the corresponding hard block node that represents this // particular hard block instance @@ -163,12 +170,12 @@ typedef struct s_parsed_hard_block_component_info std::string curr_hard_block_type; // the port name defined in the current block (LUT or dffeas) - std::string curr_hard_block_port; + std::string curr_hard_block_port_name; // index of the port defined in the current block (LUT or dffeas) - int curr_hard_block_port_index; + int curr_hard_block_port_index = 0; -}t_parse_hard_block_component_info; +}t_parsed_hard_block_component_info; /* Function Declarations @@ -199,7 +206,7 @@ void delete_hard_block_port_info(std::unordered_map*, std::string); -void identify_hard_block_port_name_and_index (t_parse_hard_block_component_info*, std::string); +void identify_hard_block_port_name_and_index (t_parsed_hard_block_component_info*, std::string); // utility functions diff --git a/utils/vqm2blif/src/base/vqm2blif_util.cpp b/utils/vqm2blif/src/base/vqm2blif_util.cpp index eda94102166..a3633338a6b 100644 --- a/utils/vqm2blif/src/base/vqm2blif_util.cpp +++ b/utils/vqm2blif/src/base/vqm2blif_util.cpp @@ -21,7 +21,7 @@ void print_usage (t_boolean terminate){ cout << "\t-include_unused_subckt_pins\n"; cout << "\t-remove_const_nets\n"; cout << "\t-eblif_format\n"; - cout << "\t-identify_and_instantiate_custom_hard_blocks ...\n"; + cout << "\t-identify_and_instantiate_custom_hard_blocks ...\n"; //Hide experimental options by default //cout << "\t-split_multiclock_blocks\n"; //cout << "\t-split_carry_chain_logic\n"; @@ -53,22 +53,23 @@ void verify_format (string* filename, string extension){ void verify_hard_block_type_name(string curr_hard_block_type_name){ -// verifies whether the hard block name (type of hard block) provided by the user meets verilog naming rules +// verifies whether the hard block name (type of hard block) provided by the user meets verilog/VHDL naming rules. VHDL naming rules are a subset of verilog, so we just check verilog. (Using verilog 2001 standard) // naming rules have 2 main conditions: // Condition 1: the first charatcer must be a lowercase/uppercase alphabetical character. Or the first character can be a underscore. - // Condition 2: The remaning characters must be a lowercase/uppercase alphabetical character, or a underscore, or a single digit number or the '$' character - std::regex verilog_naming_rules_one ("^[a-zA-Z_][a-zA-Z_\$0-9]*[a-zA-Z_\$0-9]$"); + // Condition 2: The remaning characters must be a lowercase/uppercase alphabetical character, or a underscore, or a single digit number or the '$' character + // the rules above are checked with the identifier below + std::regex verilog_VHDL_naming_rules_one ("^[a-zA-Z_][a-zA-Z_\$0-9]*[a-zA-Z_\$0-9]$"); // verilog names can also contain any characters, as long as they are escaped with a '\' at the start of the identifer. For example, \reset- - // we check this below - std::regex verilog_naming_rules_two ("[\\](.*)", std::regex_constants::extended); + // we check this using the identifier below + std::regex verilog_VHDL_naming_rules_two ("[\\](.*)", std::regex_constants::extended); // need std::regex_constants::extended as it supports '\\' character - if ((!(std::regex_match(curr_hard_block_type_name, verilog_naming_rules_one))) && (!(std::regex_match(curr_hard_block_type_name, verilog_naming_rules_two)))) + if ((!(std::regex_match(curr_hard_block_type_name, verilog_VHDL_naming_rules_one))) && (!(std::regex_match(curr_hard_block_type_name, verilog_VHDL_naming_rules_two)))) { // the hard block type name did not meet the verilog naming rules // Display error message to user - std::cout << "ERROR:The provided Hard Block Type Name '" << curr_hard_block_type_name << "' did not meet the verilog naming rules.\n"; + std::cout << "ERROR:The provided Hard Block Type Name '" << curr_hard_block_type_name << "' did not meet the verilog/VHDL naming rules.\n"; std::cout << "********\n"; From dc471ac8b8a09db5455bb64fd939f5d5ca557cb3 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Thu, 12 Aug 2021 10:43:52 -0400 Subject: [PATCH 08/31] can recognize duplicate module names from cmd line and added functionality to parse nodes that represent hard block ports in vqm netlist --- utils/vqm2blif/src/base/hard_block_recog.cpp | 103 +++++++++++++++++-- utils/vqm2blif/src/base/hard_block_recog.h | 29 ++++-- utils/vqm2blif/src/main.cpp | 24 ++++- 3 files changed, 136 insertions(+), 20 deletions(-) diff --git a/utils/vqm2blif/src/base/hard_block_recog.cpp b/utils/vqm2blif/src/base/hard_block_recog.cpp index 93bf619378e..4bbbd7ec0d0 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.cpp +++ b/utils/vqm2blif/src/base/hard_block_recog.cpp @@ -207,6 +207,74 @@ void copy_array_ref(t_array_ref* array_ref_orig, t_array_ref* array_ref_copy) return; } +t_parsed_hard_block_port_info extract_hard_block_port_info_from_module_node(t_node* curr_module_node, std::vector* hard_block_type_name_list) +{ + std::string curr_module_node_name = curr_module_node->name; + + // container to hold all the names of the different hierachy levels found for the current node in the netlist(refer to 'split_node_name function' for more info) + std::vector components_of_module_node_name; + + int index_of_node_name_component_with_hard_block_type_info = 0; + int index_of_node_name_component_with_hard_block_port_info = 0; + + // data structure to hold all the extract port information + t_parsed_hard_block_port_info stored_port_info; + + split_node_name(curr_module_node_name, &components_of_module_node_name, VQM_NODE_NAME_DELIMITER); + + // if the node name does not have atleast two hierarhcy levels, then it cannot be a hard block port so we cannot extract any more information. + // a hard block port in the vqm netlist must have atleast the port information and the next top level block name it is connected to. As shown below: + // For example, \router:test_noc_router|payload[8]~QIC_DANGLING_PORT_I is a hard block payload port connected to a router block. + // \Add0~9_I is not a hard block port + if ((components_of_module_node_name.size()) >= 2) + { + // looking at the comment above, regardless of how many hierarchy levels an node has, the lowest level (last index) will contain the port info and the second lowest level (second last index) will contain the hard block type. + // so we store those indices below + index_of_node_name_component_with_hard_block_type_info = components_of_module_node_name.size() - 2; + index_of_node_name_component_with_hard_block_port_info = components_of_module_node_name.size() - 1; + + stored_port_info.hard_block_type.assign(identify_hard_block_type(hard_block_type_name_list, components_of_module_node_name[index_of_node_name_component_with_hard_block_type_info])); + + // if the hard block type was empty, then the current node does not represent a hard block port, therefore we cannot extract any more info + /* For example, sha256_pc:\sha256_gen:10:sha256_pc_gen:sha256_2|altshift_taps:q_w_rtl_2|shift_taps_b8v:auto_generated|altsyncram_6aa1:altsyncram5|ram_block6a17550~I meets all the conditions to get here, but it is a ram block */ + if (!(stored_port_info.hard_block_type.empty())) + { + // if the hard block type was verified then we can go ahead and store its name and also its parsed port name and index + + stored_port_info.hard_block_name.assign(construct_hard_block_name(&components_of_module_node_name, VQM_NODE_NAME_DELIMITER)); + + identify_hard_block_port_name_and_index(&stored_port_info, components_of_module_node_name[index_of_node_name_component_with_hard_block_port_info]); + } + } + + return stored_port_info; + +} + +void split_node_name(std::string original_node_name, std::vector* node_name_components, std::string delimiter) +{ + + // positional trackers to determine the beginning and end position of each hierarchy level (component of the node name) of the current node within the design. The positions are updated as we go through the node name and identify every level of hierarchy. + size_t start_of_current_node_name_component = 0; + size_t end_of_current_node_name_component = 0; + + // go through the node name, then identify and store each hierarchy level of the node (represented as a component of the original node name), found using the delimiter + while ((end_of_current_node_name_component = original_node_name.find(delimiter, start_of_current_node_name_component)) != std::string::npos) + { + // store the current node name component (current hierarchy level) + node_name_components->push_back(original_node_name.substr(start_of_current_node_name_component, end_of_current_node_name_component - start_of_current_node_name_component)); + + // update position for the next node name component (next hierarchy level) + start_of_current_node_name_component = end_of_current_node_name_component + delimiter.length(); + + } + + // since the last component (the port info is not follwed by a delimiter we need to handle it here and store it) + node_name_components->push_back(original_node_name.substr(start_of_current_node_name_component, end_of_current_node_name_component - start_of_current_node_name_component)); + + return; +} + std::string identify_hard_block_type(std::vector* hard_block_type_name_list, std::string curr_node_name_component) { std::vector::iterator hard_block_type_name_traverser; @@ -233,7 +301,26 @@ std::string identify_hard_block_type(std::vector* hard_block_type_n return hard_block_type; } -void identify_hard_block_port_name_and_index (t_parsed_hard_block_component_info* curr_hard_block_component, std::string curr_node_name_component) +std::string construct_hard_block_name(std::vector*node_name_components, std::string delimiter) +{ + // stores the full name of the hard block the current node is part of, the current node represents a port of a hard block + std::string curr_hard_block_name = ""; + + /* the hard block name should not include the specific port the current node represents (so we reduce the size by 1 to remove it when constructing the hard block name) + the last index of the node name components vector contains the port information, so by reducing the size of the vector by one we can ignore the port info when constructing the hard block name */ + int number_of_node_name_components = node_name_components->size() - 1; + + // go through the node name components and combine them together to form the hard block name. + for (int i = 0; i < number_of_node_name_components; i++) + { + curr_hard_block_name += (*node_name_components)[i] + delimiter; + } + + return curr_hard_block_name; + +} + +void identify_hard_block_port_name_and_index (t_parsed_hard_block_port_info* curr_hard_block_port, std::string curr_node_name_component) { // identifer to check whether the port defined in the current node name is a bus (ex. payload[1]~QIC_DANGLING_PORT_I) std::regex port_is_a_bus ("(.*)[[]([0-9]*)\]~(?:.*)"); @@ -250,19 +337,19 @@ void identify_hard_block_port_name_and_index (t_parsed_hard_block_component_info { // if we are here, then the port is a bus - // store the extarcted port name and index to be used externally - curr_hard_block_component->curr_hard_block_port_name.assign(port_info[PORT_NAME]); + // store the extracted port name and index to be used externally + curr_hard_block_port->hard_block_port_name.assign(port_info[PORT_NAME]); - curr_hard_block_component->curr_hard_block_port_index = std::stoi(port_info[PORT_INDEX]); + curr_hard_block_port->hard_block_port_index = std::stoi(port_info[PORT_INDEX]); } else if (std::regex_match(curr_node_name_component, port_info, port_is_not_a_bus, std::regex_constants::match_default)) { // if we are here then the port was not a bus + // not need to update port index as the default value represents a port that is not a bus - // just store the extracted port name and default poert index to be used externally - curr_hard_block_component->curr_hard_block_port_name.assign(port_info[PORT_NAME]); - - curr_hard_block_component->curr_hard_block_port_index = DEFAULT_PORT_INDEX; + // store the extracted port name + curr_hard_block_port->hard_block_port_name.assign(port_info[PORT_NAME]); + } return; diff --git a/utils/vqm2blif/src/base/hard_block_recog.h b/utils/vqm2blif/src/base/hard_block_recog.h index 09b4ce4dda5..d5371e572b2 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.h +++ b/utils/vqm2blif/src/base/hard_block_recog.h @@ -40,6 +40,7 @@ #include #include #include +#include // useful spacing definitions #define TOP_LEVEL 0 @@ -56,6 +57,11 @@ // unique identifier that seperates a hard block type name (module name), from the specific instance name #define HARD_BLOCK_TYPE_NAME_SEPERATOR ":" +// a node name in reference to a hard block port (dffeas and stratic_lcell blocks) in the vqm netlist file consists of multiple hierarchy levels. +// for example we can have the following name: \router_interconnect:test_router_interconnect|router:noc_router|id[2]~QIC_DANGLING_PORT_I (this has 3 hierarchy levels) +// each level of hierarchy (module within module) is seperated by the delimiter character defined below. The last level of hierarchy is the output net of the block +#define VQM_NODE_NAME_DELIMITER "|" + #define PORT_NAME 1 #define PORT_INDEX 2 @@ -103,7 +109,7 @@ typedef struct s_hard_block_port_info typedef struct s_hard_block { // indicates the name of the user defined hard block - std::string hard_block_name; + std::string hard_block_name = ""; // helps keep track of the number of hard block ports we have assigned // a net to @@ -159,23 +165,24 @@ typedef struct s_hard_block_recog * When we go through the .vqm file, the ports of any user defined hard block * will be represented as a LUT (stratix_lcell), or flip flop (dffeas) (for * more info refer to 'hard_block_recog.cpp'). The generated names found in * the .vqm file for the two previous blocks contain a lot of information * about the hard block. The structure below is used to store the information, * which includes the hard block name, hard block type, the specfic hard * block port and if the port is a bus, then the specific index. */ -typedef struct s_parsed_hard_block_component_info +typedef struct s_parsed_hard_block_port_info { // name used to identify the unique hard block the current port belongs to // multiple ports can belong to the same hard block and there can be multiple hard blocks in the design - std::string curr_hard_block_name; + std::string hard_block_name = ""; // the specific type of hard block the current port belongs to // the user can define multiple hard block types - std::string curr_hard_block_type; + std::string hard_block_type = ""; // the port name defined in the current block (LUT or dffeas) - std::string curr_hard_block_port_name; + std::string hard_block_port_name = ""; // index of the port defined in the current block (LUT or dffeas) - int curr_hard_block_port_index = 0; + // initialized to an index equivalent to what a port thas is not a bus would have + int hard_block_port_index = DEFAULT_PORT_INDEX; -}t_parsed_hard_block_component_info; +}t_parsed_hard_block_port_info; /* Function Declarations @@ -204,9 +211,15 @@ void copy_array_ref(t_array_ref*, t_array_ref*); void delete_hard_block_port_info(std::unordered_map*); +t_parsed_hard_block_port_info extract_hard_block_port_info_from_module_node(t_node*, std::vector*); + std::string identify_hard_block_type(std::vector*, std::string); -void identify_hard_block_port_name_and_index (t_parsed_hard_block_component_info*, std::string); +void identify_hard_block_port_name_and_index (t_parsed_hard_block_port_info*, std::string); + +void split_node_name(std::string, std::vector*, std::string); + +std::string construct_hard_block_name(std::vector*, std::string); // utility functions diff --git a/utils/vqm2blif/src/main.cpp b/utils/vqm2blif/src/main.cpp index 94ac3e5beee..9504c9d83b3 100644 --- a/utils/vqm2blif/src/main.cpp +++ b/utils/vqm2blif/src/main.cpp @@ -256,6 +256,13 @@ int main(int argc, char* argv[]) //test_delete_hard_block_port_info(test, "router", 10000); //test_initialize_hard_block_models(); + //test_identify_hard_block_type(); + //test_identify_hard_block_port_name_and_index(); + + //test_split_node_name(); + //test_construct_hard_block_name(); + + //test_extract_hard_block_port_info_from_module_node(); //test_create_and_initialize_all_hard_block_ports(); t_blif_model my_model; @@ -649,10 +656,10 @@ void cmd_line_parse (int argc, char** argv, string* sourcefile, string* archfile eblif_format = T_TRUE; break; case OT_IDENTIFY_AND_INSTANTIATE_CUSTOM_HARD_BLOCKS: - // first check whether an accompanying hard block type name was supplied (user provides the names of all the various types of custom hard blocks within the design) + // first check whether an accompanying hard block type name was supplied (user provides the names of all the various types of custom hard blocks within the design, essentially this is the module name) if ( i+1 == argc ){ // no hard block type name was supplied so throw an error - cout << "ERROR: Missing Hard Block Type Names.\n" ; + cout << "ERROR: Missing Hard Block Module Names.\n" ; print_usage (T_TRUE); } @@ -671,7 +678,7 @@ void cmd_line_parse (int argc, char** argv, string* sourcefile, string* archfile if (!identify_and_instantiate_custom_hard_blocks) { // since no hard block type names were supplied, we throw an error - cout << "ERROR: Missing Hard Block Type Names.\n"; + cout << "ERROR: Missing Hard Block Module Names.\n"; print_usage (T_TRUE); } else @@ -694,7 +701,16 @@ void cmd_line_parse (int argc, char** argv, string* sourcefile, string* archfile // if we are here then the provided name was valid. identify_and_instantiate_custom_hard_blocks = T_TRUE; - hard_block_type_name_list->push_back(curr_hard_block_name); // add the hard block type name to the list + // check to see whether the user repeated a hard block type name + if ((std::find(hard_block_type_name_list->begin(), hard_block_type_name_list->end(), curr_hard_block_name)) == hard_block_type_name_list->end()) + { + hard_block_type_name_list->push_back(curr_hard_block_name); // add the hard block type name to the list + } + else + { + cout << "ERROR: Hard Block Module name '" << curr_hard_block_name << "' was repeated.\n"; + print_usage (T_TRUE); + } // update argument index to show that we have processed the current hard block type name successfully i++; From a204e4c558af1085077afa8f00ecddda0493bf7e Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Fri, 20 Aug 2021 17:01:05 -0400 Subject: [PATCH 09/31] adding functionality to create empty hard blocks instances and attach them to existing module node array. ALso added functionality to quikly find newly created hard block instances (their node in the module and additional info) --- utils/vqm2blif/src/base/hard_block_recog.cpp | 256 ++++++++++++++++++- utils/vqm2blif/src/base/hard_block_recog.h | 30 ++- utils/vqm2blif/src/main.cpp | 28 +- 3 files changed, 293 insertions(+), 21 deletions(-) diff --git a/utils/vqm2blif/src/base/hard_block_recog.cpp b/utils/vqm2blif/src/base/hard_block_recog.cpp index 4bbbd7ec0d0..167455db458 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.cpp +++ b/utils/vqm2blif/src/base/hard_block_recog.cpp @@ -5,27 +5,34 @@ #include "hard_block_recog.h" -void filter_and_create_hard_blocks(t_module* main_module, t_arch* main_arch, std::vector* hard_block_type_names, std::string arch_file_name, std::string vqm_file_name) +void add_hard_blocks_to_netlist(t_module* main_module, t_arch* main_arch, std::vector* list_hard_block_type_names, std::string arch_file_name, std::string vqm_file_name) { - t_hard_block_recog hard_block_node_refs_and_info; + t_hard_block_recog module_hard_block_node_refs_and_info; try { - initialize_hard_block_models(main_arch, hard_block_type_names, &hard_block_node_refs_and_info); + initialize_hard_block_models(main_arch, list_hard_block_type_names, &module_hard_block_node_refs_and_info); } catch(const vtr::VtrError& error) { throw vtr::VtrError((std::string)error.what() + "The FPGA architecture is described in " + arch_file_name + "."); } - + try + { + process_module_nodes_and_create_hard_blocks(main_module, list_hard_block_type_names, &module_hard_block_node_refs_and_info); + } + catch(const vtr::VtrError& error) + { + throw vtr::VtrError((std::string)error.what() + "The original netlist is described in " + vqm_file_name + "."); + } // need to delete all the dynamic memory used to store // all the hard block port information - delete_hard_block_port_info(&(hard_block_node_refs_and_info.hard_block_type_name_to_port_info)); + delete_hard_block_port_info(&(module_hard_block_node_refs_and_info.hard_block_type_name_to_port_info)); return; } @@ -61,6 +68,59 @@ void initialize_hard_block_models(t_arch* main_arch, std::vector* h } +void process_module_nodes_and_create_hard_blocks(t_module* main_module, std::vector* hard_block_type_name_list, t_hard_block_recog* module_hard_block_node_refs_and_info) +{ + // represents a block in the netlist + // refer to 'vqm_dll.h' for more info on t_node + t_node* curr_module_node = NULL; + + // create a new t_array_ref (refer to 'vqm_dll.h') structure so that we can append new hard block instances we create to the original node array + t_array_ref* node_list_with_hard_blocks = create_t_array_ref_from_array((void**)(main_module->array_of_nodes), main_module->number_of_nodes); + + std::string curr_module_node_type = ""; + std::string curr_node_name = ""; + + int number_of_module_nodes = main_module->number_of_nodes; // before any hard blocks are added + + t_parsed_hard_block_port_info curr_module_node_info; + + int curr_hard_block_instance_index = 0; + + /* iterate through every node in the module and create a new node to represent each and every hard block we identify within the netlist.*/ + for (int i = 0; i < number_of_module_nodes; i++) + { + + curr_module_node = (t_node*)node_list_with_hard_blocks->pointer[i]; + curr_module_node_type.assign(curr_module_node->type); + + // hard block ports are only represented in nodes that are either a LUT or flip flop block + if ((curr_module_node_type.compare("stratix_lcell_comb") == 0) || (curr_module_node_type.compare("dffeas") == 0)) + { + + curr_module_node_info = extract_hard_block_port_info_from_module_node(curr_module_node, hard_block_type_name_list); + + // check to see that the current node represents a hard block port + // a hard block name would not be created if it wasn't + if (!curr_module_node_info.hard_block_name.empty()) + { + + // get the index to the current hard block instance we need to work with + curr_hard_block_instance_index = find_hard_block_instance(module_hard_block_node_refs_and_info, &curr_module_node_info); + + // check to see whether the hard block instance the current node belongs to exists (remember each node here represents a hard block port) + if (curr_hard_block_instance_index == HARD_BLOCK_INSTANCE_DOES_NOT_EXIST) + { + // we need to create a new hard block instance, since it does not exists for the port current node represents + curr_hard_block_instance_index = create_new_hard_block_instance(node_list_with_hard_blocks, module_hard_block_node_refs_and_info, &curr_module_node_info); + } + + } + } + } + + +} + bool create_and_initialize_all_hard_block_ports(t_model* hard_block_arch_model, t_hard_block_recog* storage_of_hard_block_info) { int hard_block_port_index = 0; @@ -207,6 +267,192 @@ void copy_array_ref(t_array_ref* array_ref_orig, t_array_ref* array_ref_copy) return; } +int find_hard_block_instance(t_hard_block_recog* module_hard_block_node_refs_and_info, t_parsed_hard_block_port_info* curr_module_node_info) +{ + int hard_block_instance_index = 0; + + std::unordered_map::iterator curr_hard_block_instance_index_ref; + + std::string curr_hard_block_instance_name = curr_module_node_info->hard_block_name; + + /* if we previously found a module node that represented a different port of the same hard block instance, we would have already created the node to represent the hard block instance. + + Search the current list of already created hard block instances for the hard block instance the current node is a part (remember that the current node represents a port for a hard block). + We are using hard block names to idetify each instance.*/ + curr_hard_block_instance_index_ref = module_hard_block_node_refs_and_info->hard_block_instance_name_to_index.find(curr_hard_block_instance_name); + + // now check the search result to see whether the hard block instance the current node is a part of was already created (if it exists in our internal list) + if (curr_hard_block_instance_index_ref == module_hard_block_node_refs_and_info->hard_block_instance_name_to_index.end()) + { + // if we are here, then the hard block instance the current node belongs to does not exist + // return unique identifier + hard_block_instance_index = HARD_BLOCK_INSTANCE_DOES_NOT_EXIST; + + } + else + { + // if we are here then the the hard block instance the current node is a port of already exists. + //so we store its index to identify it from all the other hard block instaces found in the netlist (all hard block instances are stored in a vector within 't_hard_block_recog') + hard_block_instance_index = curr_hard_block_instance_index_ref->second; + } + + + return hard_block_instance_index; + +} + +int create_new_hard_block_instance(t_array_ref* module_node_list, t_hard_block_recog* module_hard_block_node_refs_and_info, t_parsed_hard_block_port_info* curr_module_node_info) +{ + // index to to the new 't_hard_block' struct being created here that is found within the 'hard_block_instances' vector + int created_hard_block_instance_index = 0; + + // storage for the newly created hard block ports + t_array_ref* created_hard_block_instance_ports = NULL; + + // storage for the new node within the current module that represents the new hard block instance being created here + t_node* hard_block_instance_node = NULL; + + //get the port information for the new hard block instances type + t_hard_block_port_info* port_info_for_curr_hard_block_type = &((module_hard_block_node_refs_and_info->hard_block_type_name_to_port_info.find(curr_module_node_info->hard_block_type))->second); + + // create a new set of ports for the new hard block instance + created_hard_block_instance_ports = create_unconnected_hard_block_instance_ports(port_info_for_curr_hard_block_type); + + // create a new node for the new hard block instance + hard_block_instance_node = create_new_hard_block_instance_node(created_hard_block_instance_ports, curr_module_node_info); + + //store the new hard block instance information created above within a 't_hard_block' struct and get the index to where it is stored + created_hard_block_instance_index = store_new_hard_block_instance_info(module_hard_block_node_refs_and_info, port_info_for_curr_hard_block_type, hard_block_instance_node, curr_module_node_info); + + // append the newly created node that represents the new hard block instance to the node list for the module + append_array_element((intptr_t)hard_block_instance_node, module_node_list); + + // delete the array ref struct used to store the reference to the newly created hard block instance ports + vtr::free(created_hard_block_instance_ports); + + return created_hard_block_instance_index; +} + +t_array_ref* create_unconnected_hard_block_instance_ports(t_hard_block_port_info* curr_hard_block_type_port_info) +{ + t_array_ref* template_for_hard_block_ports = &(curr_hard_block_type_port_info->hard_block_ports); + t_array_ref* hard_block_instance_port_array = NULL; + int number_of_ports = template_for_hard_block_ports->array_size; + + // temporarily store single port parameters + char* port_name = NULL; + int port_index = 0; + int port_wire_index = 0; + + // store the newly created port + t_node_port_association* temp_port = NULL; + + // convert the template hard block ports into a port format + t_node_port_association** template_port_array = (t_node_port_association**)template_for_hard_block_ports->pointer; + + // create memory to store the ports for the newly created hard block instance + hard_block_instance_port_array = (t_array_ref*)vtr::malloc(sizeof(t_array_ref)); + + hard_block_instance_port_array->pointer = NULL; + hard_block_instance_port_array->array_size = 0; + hard_block_instance_port_array->allocated_size = 0; + + // go through the template ports, copy their parameters to a new set of ports that will be for the new hard block instance we are creating + for (int i = 0; i < number_of_ports; i++) + { + port_name = template_port_array[i]->port_name; + port_index = template_port_array[i]->port_index; + port_wire_index = template_port_array[i]->wire_index; + + temp_port = create_unconnected_node_port_association(port_name, port_index, port_wire_index); + + append_array_element((intptr_t)temp_port, hard_block_instance_port_array); + } + + return hard_block_instance_port_array; + +} + +t_node* create_new_hard_block_instance_node(t_array_ref* curr_hard_block_instance_ports, t_parsed_hard_block_port_info* curr_hard_block_instance_info) +{ + t_node* new_hard_block_instance = NULL; + + char* hard_block_instance_name = NULL; + char* hard_block_instance_type = NULL; + + int hard_block_instance_name_size = strlen((curr_hard_block_instance_info->hard_block_name).c_str()) + 1; + int hard_block_instance_type_size = strlen((curr_hard_block_instance_info->hard_block_type).c_str()) + 1; + + // create the node for the new hard block instance + new_hard_block_instance = (t_node*)vtr::malloc(sizeof(t_node)); + + // assign the ports and their count for the new hard block + new_hard_block_instance->array_of_ports = (t_node_port_association**)curr_hard_block_instance_ports->pointer; + + new_hard_block_instance->number_of_ports = curr_hard_block_instance_ports->array_size; + + // hard blocks will not have any parameters so indicate that + new_hard_block_instance->number_of_params = 0; + new_hard_block_instance->array_of_params = NULL; + + // create storage for the name and type of the current hard block and store their values // + + hard_block_instance_name = (char*)vtr::malloc(sizeof(char)*hard_block_instance_name_size); + hard_block_instance_type = (char*)vtr::malloc(sizeof(char)*hard_block_instance_type_size); + + strcpy(hard_block_instance_name, (curr_hard_block_instance_info->hard_block_name).c_str()); + strcpy(hard_block_instance_type, (curr_hard_block_instance_info->hard_block_type).c_str()); + + new_hard_block_instance->name = hard_block_instance_name; + new_hard_block_instance->type = hard_block_instance_type; + + return new_hard_block_instance; + +} + +int store_new_hard_block_instance_info(t_hard_block_recog* module_hard_block_node_refs_and_info, t_hard_block_port_info* curr_hard_block_type_port_info, t_node* new_hard_block_instance_node, t_parsed_hard_block_port_info* curr_module_node_info) +{ + int new_hard_block_instance_index = 0; + + t_hard_block new_hard_block_instance_info; + + // store information regarding the new hard block instance being added to the module node list to a new t_hard_block struct // + + new_hard_block_instance_info.hard_block_instance_node_reference = new_hard_block_instance_node; + + // initially all ports for the newly created hard block instance are unassigned + new_hard_block_instance_info.hard_block_ports_not_assigned = curr_hard_block_type_port_info->hard_block_ports.array_size; + + // insert the hard block (t_hard_block struct) to the list of all hard block instances + module_hard_block_node_refs_and_info->hard_block_instances.push_back(new_hard_block_instance_info); + + // since we added the new hard block instance (t_hard_block struct) at the end of vector, the index will be the last position with the list + new_hard_block_instance_index = module_hard_block_node_refs_and_info->hard_block_instances.size() - 1; + + /* now create a mapping between the new hard block instance name and the index it is located in with the list of all hard block instances, so we can find it quicly using just the hard block instance name*/ + module_hard_block_node_refs_and_info->hard_block_instance_name_to_index.insert(std::pair(curr_module_node_info->hard_block_name,new_hard_block_instance_index)); + + return new_hard_block_instance_index; +} + +t_array_ref* create_t_array_ref_from_array(void** array_to_store, int array_size) +{ + t_array_ref* array_reference = NULL; + int array_allocated_size = 0; + + array_reference = (t_array_ref*)vtr::malloc(sizeof(t_array_ref)); + + array_allocated_size = calculate_array_size_using_bounds(array_size); + + // assign the array and its corresponding information to the array ref struct + array_reference->allocated_size = array_allocated_size; + array_reference->array_size = array_size; + array_reference->pointer = array_to_store; + + return array_reference; + +} + t_parsed_hard_block_port_info extract_hard_block_port_info_from_module_node(t_node* curr_module_node, std::vector* hard_block_type_name_list) { std::string curr_module_node_name = curr_module_node->name; diff --git a/utils/vqm2blif/src/base/hard_block_recog.h b/utils/vqm2blif/src/base/hard_block_recog.h index d5371e572b2..ee64ee9aef6 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.h +++ b/utils/vqm2blif/src/base/hard_block_recog.h @@ -65,6 +65,7 @@ #define PORT_NAME 1 #define PORT_INDEX 2 +#define HARD_BLOCK_INSTANCE_DOES_NOT_EXIST -1 /* Structure Declarations */ @@ -108,12 +109,9 @@ typedef struct s_hard_block_port_info */ typedef struct s_hard_block { - // indicates the name of the user defined hard block - std::string hard_block_name = ""; - - // helps keep track of the number of hard block ports we have assigned - // a net to - int hard_block_ports_assigned = 0; + + // helps keep track of the number of hard block ports we have left to assign a net to + int hard_block_ports_not_assigned = 0; // a reference to the corresponding hard block node that represents this // particular hard block instance @@ -140,7 +138,7 @@ typedef struct s_hard_block_recog // hard block type are stored. std::unordered_map hard_block_type_name_to_port_info; - // store each hard blocks instantiated within a + // store each hard block instantiated within a // user design std::vector hard_block_instances; @@ -148,7 +146,7 @@ typedef struct s_hard_block_recog identify the corresponding hard block structure instance. We do this by using the map data structure below, where a hard block instance name is associated with an index - within the hard block instances above. + within the hard block vector above (stores all instances within the design). */ std::unordered_map hard_block_instance_name_to_index; @@ -191,10 +189,12 @@ typedef struct s_parsed_hard_block_port_info * 'hard_block_recog.cpp' */ -void filter_and_create_hard_blocks(t_module*, t_arch*, std::vector*, std::string, std::string); +void add_hard_blocks_to_netlist(t_module*, t_arch*, std::vector*, std::string, std::string); void initialize_hard_block_models(t_arch*, std::vector*, t_hard_block_recog*); +void process_module_nodes_and_create_hard_blocks(t_module*, std::vector*, t_hard_block_recog*); + bool create_and_initialize_all_hard_block_ports(t_model*, t_hard_block_recog*); void create_hard_block_port_info_structure(t_hard_block_recog*, std::string); @@ -209,6 +209,18 @@ void store_hard_block_port_info(t_hard_block_recog*, std::string, std::string,PO void copy_array_ref(t_array_ref*, t_array_ref*); +int find_hard_block_instance(t_hard_block_recog*, t_parsed_hard_block_port_info*); + +int create_new_hard_block_instance(t_array_ref*, t_hard_block_recog*, t_parsed_hard_block_port_info*); + +t_array_ref* create_unconnected_hard_block_instance_ports(t_hard_block_port_info*); + +t_node* create_new_hard_block_instance_node(t_array_ref*, t_parsed_hard_block_port_info*); + +int store_new_hard_block_instance_info(t_hard_block_recog*, t_hard_block_port_info*, t_node*, t_parsed_hard_block_port_info*); + +t_array_ref* create_t_array_ref_from_array(void**, int); + void delete_hard_block_port_info(std::unordered_map*); t_parsed_hard_block_port_info extract_hard_block_port_info_from_module_node(t_node*, std::vector*); diff --git a/utils/vqm2blif/src/main.cpp b/utils/vqm2blif/src/main.cpp index 9504c9d83b3..aea54b558e4 100644 --- a/utils/vqm2blif/src/main.cpp +++ b/utils/vqm2blif/src/main.cpp @@ -265,6 +265,8 @@ int main(int argc, char* argv[]) //test_extract_hard_block_port_info_from_module_node(); //test_create_and_initialize_all_hard_block_ports(); + + //test_array_ref_initialization(); t_blif_model my_model; //holds top-level model data for the .blif netlist //***The primary goal of the program is to populate and dump this structure appropriately.*** @@ -309,12 +311,12 @@ int main(int argc, char* argv[]) //verify command-line is correct, populate input variables and global mode flags. cmd_line_parse(argc, argv, &source_file, &arch_file, &out_file, &hard_block_type_name_list); - std::vector::iterator it; + /*std::vector::iterator it; for (it = hard_block_type_name_list.begin(); it != hard_block_type_name_list.end(); it++) { std::cout << *it << "\n"; - } + }*/ setup_lut_support_map (); //initialize LUT support for cleanup and elaborate functions @@ -342,13 +344,13 @@ int main(int argc, char* argv[]) cout << "\n>> Verifying module"; verify_module (my_module); - if (debug_mode){ + /*if (debug_mode){ //Print debug info to "_module.echo" construct_filename ( temp_name, project_path.c_str(), "_module.echo" ); cout << "\n>> Dumping to output file " << temp_name << endl ; echo_module ( temp_name, source_file.c_str(), my_module ); //file contains data read from the .vqm structures. - } + }*/ //Parse the architecture file to get full information about the models used. // Note: the architecture file needs to be loaded first, so that it can be used @@ -368,10 +370,20 @@ int main(int argc, char* argv[]) VTR_ASSERT((types) && (numTypes > 0)); VTR_ASSERT(arch.models != NULL); + + //test_create_unconnected_hard_block_instance_ports(my_module, &arch, &hard_block_type_name_list); + + //test_create_new_hard_block_instance_node(&arch, &hard_block_type_name_list); + + //test_store_new_hard_block_instance_info(&arch, &hard_block_type_name_list); + + //test_create_new_hard_block_instance(my_module, &arch, &hard_block_type_name_list); + + test_find_hard_block_instance(my_module, &arch, &hard_block_type_name_list); //Pre-process the netlist // Currently this just 'cleans up' bi-directional inout pins - cout << "\n>> Preprocessing Netlist...\n"; + /* cout << "\n>> Preprocessing Netlist...\n"; processStart = clock(); preprocess_netlist(my_module, &arch, types, numTypes, fix_global_nets, elaborate_ram_clocks, @@ -422,7 +434,7 @@ int main(int argc, char* argv[]) { try { - filter_and_create_hard_blocks(my_module,&arch,&hard_block_type_name_list, arch_file, source_file); + add_hard_blocks_to_netlist(my_module,&arch,&hard_block_type_name_list, arch_file, source_file); } catch(const vtr::VtrError& error) { @@ -480,7 +492,9 @@ int main(int argc, char* argv[]) unsigned long flowEnd = clock(); cout << "\n>> VQM->BLIF Total Runtime: " << (float)(flowEnd - flowStart)/CLOCKS_PER_SEC << " seconds.\n" ; - cout << "\nComplete.\n"; + cout << "\nComplete.\n";*/ + + all_data_cleanup(); return 0; } From 8ad3e96622ad7a1f7d0b162c295983ee5d4c5276 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Fri, 20 Aug 2021 17:13:18 -0400 Subject: [PATCH 10/31] added a function to dynamically create a t_array_ref struct --- utils/vqm2blif/src/base/hard_block_recog.cpp | 26 ++++++++++++-------- utils/vqm2blif/src/base/hard_block_recog.h | 2 ++ 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/utils/vqm2blif/src/base/hard_block_recog.cpp b/utils/vqm2blif/src/base/hard_block_recog.cpp index 167455db458..acfeb3716e7 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.cpp +++ b/utils/vqm2blif/src/base/hard_block_recog.cpp @@ -194,12 +194,8 @@ t_array_ref* convert_hard_block_model_port_to_hard_block_node_port(t_model_ports int port_size = hard_block_model_port->size; //create memory to store the port array - port_array = (t_array_ref*)vtr::malloc(sizeof(t_array_ref)); + port_array = create_and_initialize_t_array_ref_struct(); - port_array->pointer = NULL; - port_array->array_size = 0; - port_array->allocated_size = 0; - for (int port_index = 0; port_index < port_size; port_index++) { // hard blocks will not have indexed wire assignments @@ -267,6 +263,20 @@ void copy_array_ref(t_array_ref* array_ref_orig, t_array_ref* array_ref_copy) return; } +t_array_ref* create_and_initialize_t_array_ref_struct(void) +{ + t_array_ref* empty_array = NULL; + + empty_array = (t_array_ref*)vtr::malloc(sizeof(t_array_ref)); + + empty_array->pointer = NULL; + empty_array->array_size = 0; + empty_array->allocated_size = 0; + + return empty_array; + +} + int find_hard_block_instance(t_hard_block_recog* module_hard_block_node_refs_and_info, t_parsed_hard_block_port_info* curr_module_node_info) { int hard_block_instance_index = 0; @@ -351,11 +361,7 @@ t_array_ref* create_unconnected_hard_block_instance_ports(t_hard_block_port_info t_node_port_association** template_port_array = (t_node_port_association**)template_for_hard_block_ports->pointer; // create memory to store the ports for the newly created hard block instance - hard_block_instance_port_array = (t_array_ref*)vtr::malloc(sizeof(t_array_ref)); - - hard_block_instance_port_array->pointer = NULL; - hard_block_instance_port_array->array_size = 0; - hard_block_instance_port_array->allocated_size = 0; + hard_block_instance_port_array = create_and_initialize_t_array_ref_struct(); // go through the template ports, copy their parameters to a new set of ports that will be for the new hard block instance we are creating for (int i = 0; i < number_of_ports; i++) diff --git a/utils/vqm2blif/src/base/hard_block_recog.h b/utils/vqm2blif/src/base/hard_block_recog.h index ee64ee9aef6..8fe3b2576cf 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.h +++ b/utils/vqm2blif/src/base/hard_block_recog.h @@ -209,6 +209,8 @@ void store_hard_block_port_info(t_hard_block_recog*, std::string, std::string,PO void copy_array_ref(t_array_ref*, t_array_ref*); +t_array_ref* create_and_initialize_t_array_ref_struct(void); + int find_hard_block_instance(t_hard_block_recog*, t_parsed_hard_block_port_info*); int create_new_hard_block_instance(t_array_ref*, t_hard_block_recog*, t_parsed_hard_block_port_info*); From 8fd3bc47838606643832f6ba2b21d71857875a62 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Fri, 27 Aug 2021 05:44:30 -0400 Subject: [PATCH 11/31] added check for LUTs representing hard block output ports. Also added functionality to assign nets to newly created hard block instance ports. --- utils/vqm2blif/src/base/hard_block_recog.cpp | 222 +++++++++++++++++-- utils/vqm2blif/src/base/hard_block_recog.h | 31 ++- 2 files changed, 234 insertions(+), 19 deletions(-) diff --git a/utils/vqm2blif/src/base/hard_block_recog.cpp b/utils/vqm2blif/src/base/hard_block_recog.cpp index acfeb3716e7..c524ba6b952 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.cpp +++ b/utils/vqm2blif/src/base/hard_block_recog.cpp @@ -94,25 +94,38 @@ void process_module_nodes_and_create_hard_blocks(t_module* main_module, std::vec curr_module_node_type.assign(curr_module_node->type); // hard block ports are only represented in nodes that are either a LUT or flip flop block - if ((curr_module_node_type.compare("stratix_lcell_comb") == 0) || (curr_module_node_type.compare("dffeas") == 0)) + if ((curr_module_node_type.compare(LUT_TYPE) == 0) || (curr_module_node_type.compare(DFF_TYPE) == 0)) { curr_module_node_info = extract_hard_block_port_info_from_module_node(curr_module_node, hard_block_type_name_list); // check to see that the current node represents a hard block port - // a hard block name would not be created if it wasn't + // a hard block instance name would not have bee found if it wasn't a hard block port if (!curr_module_node_info.hard_block_name.empty()) { - // get the index to the current hard block instance we need to work with - curr_hard_block_instance_index = find_hard_block_instance(module_hard_block_node_refs_and_info, &curr_module_node_info); + // if we are here, the current node is a LUT or DFF node that represents a hard block instance port // - // check to see whether the hard block instance the current node belongs to exists (remember each node here represents a hard block port) - if (curr_hard_block_instance_index == HARD_BLOCK_INSTANCE_DOES_NOT_EXIST) + /* referring to the diagram at the top, if the node is a lut that represents an output port, its connected net is an internal connection, which is not a legal netlist connection, so we cannot process the node any further. Therefore we only process nodes that are LUTs representing input ports or DFFs. */ + if (is_hard_block_port_legal(curr_module_node)) { - // we need to create a new hard block instance, since it does not exists for the port current node represents - curr_hard_block_instance_index = create_new_hard_block_instance(node_list_with_hard_blocks, module_hard_block_node_refs_and_info, &curr_module_node_info); + + // get the index to the current hard block instance we need to work with + curr_hard_block_instance_index = find_hard_block_instance(module_hard_block_node_refs_and_info, &curr_module_node_info); + + // check to see whether the hard block instance the current node belongs to exists (remember each node here represents a hard block port) + if (curr_hard_block_instance_index == HARD_BLOCK_INSTANCE_DOES_NOT_EXIST) + { + // we need to create a new hard block instance, since it does not exists for the port the current node represents + curr_hard_block_instance_index = create_new_hard_block_instance(node_list_with_hard_blocks, module_hard_block_node_refs_and_info, &curr_module_node_info); + } + + /* the remaining steps below assign the net currently connected to the node being processed (a flip-flop or a LUT) to the hard block instance port the current node represents. The correspponding hard block instance and the specific port were found previously.*/ + assign_net_to_hard_block_instance_port(curr_module_node, &curr_module_node_info, module_hard_block_node_refs_and_info, curr_hard_block_instance_index); } + + /* in this if clause, the current node represents a hard block port, so we cannot have this node be written to the output netlist, so we need to add it to the nodes to delete list */ + module_hard_block_node_refs_and_info->luts_dffeas_nodes_to_remove.push_back(curr_module_node); } } @@ -172,7 +185,7 @@ int extract_and_store_hard_block_model_ports(t_hard_block_recog* storage_of_hard { equivalent_hard_block_node_port_array = convert_hard_block_model_port_to_hard_block_node_port(curr_hard_block_model_port); - store_hard_block_port_info(storage_of_hard_block_info, curr_hard_block_type_name, curr_hard_block_model_port->name, curr_hard_block_model_port->dir, &equivalent_hard_block_node_port_array, &port_index); + store_hard_block_port_info(storage_of_hard_block_info, curr_hard_block_type_name, curr_hard_block_model_port->name, &equivalent_hard_block_node_port_array, &port_index); curr_hard_block_model_port = curr_hard_block_model_port->next; @@ -228,7 +241,7 @@ t_node_port_association* create_unconnected_node_port_association(char *port_nam } // need the hard block name itself -void store_hard_block_port_info(t_hard_block_recog* storage_of_hard_block_port_info, std::string curr_hard_block_type_name,std::string curr_port_name, PORTS current_port_dir,t_array_ref** curr_port_array, int* port_index) +void store_hard_block_port_info(t_hard_block_recog* storage_of_hard_block_port_info, std::string curr_hard_block_type_name,std::string curr_port_name, t_array_ref** curr_port_array, int* port_index) { std::unordered_map::iterator curr_port_info = ((storage_of_hard_block_port_info->hard_block_type_name_to_port_info).find(curr_hard_block_type_name)); @@ -236,13 +249,13 @@ void store_hard_block_port_info(t_hard_block_recog* storage_of_hard_block_port_i copy_array_ref(*curr_port_array, &(curr_port_info->second).hard_block_ports); // insert the port name to the current index - (curr_port_info->second).port_name_to_port_start_index.insert({curr_port_name, *port_index}); - - //insert the port direction of the current port - (curr_port_info->second).port_name_to_port_dir.insert({curr_port_name, current_port_dir}); + (curr_port_info->second).port_name_to_port_start_index.insert(std::pair(curr_port_name, *port_index)); *port_index += (*curr_port_array)->array_size; + // store the current port size + (curr_port_info->second).port_name_to_port_size.insert(std::pair(curr_port_name, (*curr_port_array)->array_size)); + vtr::free((*curr_port_array)->pointer); vtr::free(*curr_port_array); @@ -343,6 +356,187 @@ int create_new_hard_block_instance(t_array_ref* module_node_list, t_hard_block_r return created_hard_block_instance_index; } +void assign_net_to_hard_block_instance_port(t_node* curr_module_node, t_parsed_hard_block_port_info* curr_module_node_info, t_hard_block_recog* module_hard_block_node_refs_and_info, int curr_hard_block_instance_index) +{ + t_hard_block* curr_hard_block_instance = &(module_hard_block_node_refs_and_info->hard_block_instances[curr_hard_block_instance_index]); + + std::unordered_map::iterator curr_hard_block_type_port_info = module_hard_block_node_refs_and_info->hard_block_type_name_to_port_info.find(curr_module_node_info->hard_block_type); + + int port_to_assign_index = 0; + + t_pin_def* net_to_assign = get_net_to_assign_to_hard_block_instance_port(curr_module_node); + + port_to_assign_index = identify_port_index_within_hard_block_model_port_array(&(curr_hard_block_type_port_info->second), curr_module_node_info, curr_module_node); + + // assign the net to tocrresponding hard block instance port + curr_hard_block_instance->hard_block_instance_node_reference->array_of_ports[port_to_assign_index]->associated_net = net_to_assign; + + return; +} + +t_pin_def* get_net_to_assign_to_hard_block_instance_port(t_node* curr_module_node) +{ + t_pin_def* net_to_assign = NULL; + t_node_port_association* port_connected_to_net = NULL; + + int number_of_ports_in_node = curr_module_node->number_of_ports; + + std::string curr_module_node_type = curr_module_node->type; + std::string curr_module_node_name = curr_module_node->name; + + std::string curr_port_name; + + // store what type of port we expect the net to be connected to + std::string expected_port_type; + + /* for a detailed error message, we identify what type of port + the net we want should be connected to for the module node */ + + if (!(curr_module_node_type.compare(LUT_TYPE))) + { + + // we are here if the current node is LUT + + // if the current node is a LUT, then the LUT represents an input port and so the LUT input should be connected to the net + expected_port_type.assign(INPUT_PORTS); + } + else + { + // we are here if the current node is a DFF + + // if the current node is a DFF, then the DFF represents an output port and so the DFF output should be connected to the net + expected_port_type.assign(OUTPUT_PORTS); + } + + for (int i = 0; i < number_of_ports_in_node; i++) + { + + curr_port_name.assign(curr_module_node->array_of_ports[i]->port_name); + + if (!(curr_module_node_type.compare(LUT_TYPE))) + { + // if the node is a LUT // + if (curr_port_name.compare(LUT_OUTPUT_PORT)) + { + // if the port is not the LUT output ie. "combout" port // + + /* if we are here then we know that the LUT the current node + represents mus be an input port for hard block instance it is part of. We also know that this type of LUT only has an input and output port in the vqm netlist. Finally we know that the current port must be an input, so its connected net is what we want to assign to the hard block instance port. */ + port_connected_to_net = curr_module_node->array_of_ports[i]; + + break; + } + + } + else + { + // if the node is a flip flop // + if (!(curr_port_name.compare(DFF_OUTPUT_PORT))) + { + // if the port is a D flip flop output ie. "q" port // + + /* if we are here then we know that the DFF the current node + represents mus be an output port for hard block instance it is part of. Finally we know that the current port must be an output, so its connected net is what we want to assign to the hard block instance port. */ + port_connected_to_net = curr_module_node->array_of_ports[i]; + + break; + } + } + } + + if (port_connected_to_net != NULL) + { + net_to_assign = port_connected_to_net->associated_net; + } + else + { + /* we did not find any ports that fit the conditions above + and this means that the current node, which represents a hard block + instance port does not have an accompanying net. This should never happen, so throw an error and indicate to the user */ + throw vtr::VtrError("The vqm netlist node '" + curr_module_node_name + "' does not have an " + expected_port_type + " port."); + + } + + return net_to_assign; +} + +int identify_port_index_within_hard_block_model_port_array(t_hard_block_port_info* curr_hard_block_type_port_info, t_parsed_hard_block_port_info* curr_module_node_info, t_node* curr_module_node) +{ + int identified_port_index = 0; + + + int port_end_index = 0; + + // error related identifiers + std::string curr_module_node_name = curr_module_node->name; + + // identifier to store the port size of the current port + std::unordered_map::iterator found_port_size; + + /* use the mapping structure within the hard block port info struct + to find the index the port can be found in within the port array of a given hard block. If the port is vectored, then the index returned is the beginning of the vectored port (ie. vectored_port[0])*/ + std::unordered_map::iterator found_port_start_index = curr_hard_block_type_port_info->port_name_to_port_start_index.find(curr_module_node_info->hard_block_port_name); + + // check to see whether the port name exists + if (found_port_start_index == (curr_hard_block_type_port_info->port_name_to_port_start_index.end())) + { + // port does not exist, so throw and error and indicate it to the user + throw vtr::VtrError("The vqm netlist node '" + curr_module_node_name + "' represents a port:" + curr_module_node_info->hard_block_port_name +" within hard block model:" + curr_module_node_info->hard_block_type + ". But this port does not exist within the given hard block model as described in the architecture file."); + } + + + // at this point the port belongs to the hard block model // + + /* now we assign the found base port index and increment it by the parsed index from the node name (ie hard_block_port_index from t_parsed_hard_block_port_info). + + For example support a port array is arranged as follows: + index: 0 1 2 3 + port_array: port_1[0] port_1[1] port_1[2] port_1[2] + + Now if we want the index of port_1[1], the base port index would be 0, then we need to increment by 1. This is why the increment is requried. + + If the port is not vectored, the increment value would be 0. So the case is handled + */ + identified_port_index = found_port_start_index->second; + identified_port_index += curr_module_node_info->hard_block_port_index; + + // now we check whether the port index is within the port range // + + // finf the port size of the current port (using internal mapping structure found in the hard block port info struct) + // this should result in a valid value as we already verfied whether the port exists + found_port_size = curr_hard_block_type_port_info->port_name_to_port_size.find(curr_module_node_info->hard_block_port_name); + + // calculate port end index + port_end_index = found_port_start_index->second + (found_port_size->second - 1); + + // verify if the current port index is out of ranged by chekcing if it is larger than the maximum index for the port + if (identified_port_index > port_end_index) + { + // port index is out of range, so throw and error and indicate it to the user + throw vtr::VtrError("The vqm netlist node '" + curr_module_node_name + "' represents a port:" + curr_module_node_info->hard_block_port_name +" at index:" + std::to_string(curr_module_node_info->hard_block_port_index) + " hard block model:" + curr_module_node_info->hard_block_type + ". But this port index is out of range in the given hard block model as described in the architecture file."); + } + + return identified_port_index; + +} + +bool is_hard_block_port_legal(t_node* curr_module_node) +{ + + bool result = false; + + std::string curr_module_node_type = curr_module_node->type; + + // now we check the direction of the port as input or whether the node is a DFF + if ((curr_module_node->number_of_ports == LUT_OUTPUT_PORT_SIZE) || (!(curr_module_node_type.compare(DFF_TYPE)))) + { + result = true; + } + + return result; + +} + t_array_ref* create_unconnected_hard_block_instance_ports(t_hard_block_port_info* curr_hard_block_type_port_info) { t_array_ref* template_for_hard_block_ports = &(curr_hard_block_type_port_info->hard_block_ports); diff --git a/utils/vqm2blif/src/base/hard_block_recog.h b/utils/vqm2blif/src/base/hard_block_recog.h index 8fe3b2576cf..fc82888de6a 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.h +++ b/utils/vqm2blif/src/base/hard_block_recog.h @@ -67,6 +67,19 @@ #define HARD_BLOCK_INSTANCE_DOES_NOT_EXIST -1 +// define how flip flops and LUT will be identified within a given node type (within t_node struct) +#define LUT_TYPE "stratix_lcell_comb" +#define DFF_TYPE "dffeas" + +// define the number of ports a LUT that represents a hard block instance output port would have +#define LUT_OUTPUT_PORT_SIZE 1 + +// names of the output port for a LUT and DFF +#define LUT_OUTPUT_PORT "combout" +#define DFF_OUTPUT_PORT "q" + + + /* Structure Declarations */ @@ -81,11 +94,11 @@ typedef struct s_hard_block_port_info { // mapping structure to quickly identify where a specific port begins - std::unordered_map port_name_to_port_start_index; - - // mapping structure to quickly identify the direction of a port - std::unordered_map port_name_to_port_dir; + std::unordered_map port_name_to_port_start_index; + // mapping structure to determine the size of each port + std::unordered_map port_name_to_port_size; + // An array of all the ports within the hard block is stored here // refer to 'vqm_dll.h' for more information t_array_ref hard_block_ports; @@ -205,7 +218,7 @@ t_array_ref* convert_hard_block_model_port_to_hard_block_node_port(t_model_ports t_node_port_association* create_unconnected_node_port_association(char*, int ,int); -void store_hard_block_port_info(t_hard_block_recog*, std::string, std::string,PORTS, t_array_ref**, int*); +void store_hard_block_port_info(t_hard_block_recog*, std::string, std::string,t_array_ref**, int*); void copy_array_ref(t_array_ref*, t_array_ref*); @@ -213,6 +226,14 @@ t_array_ref* create_and_initialize_t_array_ref_struct(void); int find_hard_block_instance(t_hard_block_recog*, t_parsed_hard_block_port_info*); +void assign_net_to_hard_block_instance_port(t_node*, t_parsed_hard_block_port_info*, t_hard_block_recog*, int); + +t_pin_def* get_net_to_assign_to_hard_block_instance_port(t_node*); + +int identify_port_index_within_hard_block_model_port_array(t_hard_block_port_info*, t_parsed_hard_block_port_info*, t_node*); + +bool is_hard_block_port_legal(t_node*); + int create_new_hard_block_instance(t_array_ref*, t_hard_block_recog*, t_parsed_hard_block_port_info*); t_array_ref* create_unconnected_hard_block_instance_ports(t_hard_block_port_info*); From dc4d5dbead829e6df012ae0f999d5f2b7ab74a74 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Mon, 30 Aug 2021 16:00:51 -0400 Subject: [PATCH 12/31] fixed error where LUT identifier in vqm file was incorrect --- utils/vqm2blif/src/base/hard_block_recog.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/vqm2blif/src/base/hard_block_recog.h b/utils/vqm2blif/src/base/hard_block_recog.h index fc82888de6a..4933e283bd4 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.h +++ b/utils/vqm2blif/src/base/hard_block_recog.h @@ -68,7 +68,7 @@ #define HARD_BLOCK_INSTANCE_DOES_NOT_EXIST -1 // define how flip flops and LUT will be identified within a given node type (within t_node struct) -#define LUT_TYPE "stratix_lcell_comb" +#define LUT_TYPE "stratixiv_lcell_comb" #define DFF_TYPE "dffeas" // define the number of ports a LUT that represents a hard block instance output port would have @@ -230,7 +230,7 @@ void assign_net_to_hard_block_instance_port(t_node*, t_parsed_hard_block_port_in t_pin_def* get_net_to_assign_to_hard_block_instance_port(t_node*); -int identify_port_index_within_hard_block_model_port_array(t_hard_block_port_info*, t_parsed_hard_block_port_info*, t_node*); +int identify_port_index_within_hard_block_type_port_array(t_hard_block_port_info*, t_parsed_hard_block_port_info*, t_node*); bool is_hard_block_port_legal(t_node*); From b20459e87bee39d92d4edc4ed01758be7a71099e Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Mon, 30 Aug 2021 16:04:48 -0400 Subject: [PATCH 13/31] Fixed logic error with identifying LUT primitives representing hard block output ports. Also fixed some naming conventions (hard block model -> hard block type) --- utils/vqm2blif/src/base/hard_block_recog.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/utils/vqm2blif/src/base/hard_block_recog.cpp b/utils/vqm2blif/src/base/hard_block_recog.cpp index c524ba6b952..82ef5599544 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.cpp +++ b/utils/vqm2blif/src/base/hard_block_recog.cpp @@ -366,7 +366,7 @@ void assign_net_to_hard_block_instance_port(t_node* curr_module_node, t_parsed_h t_pin_def* net_to_assign = get_net_to_assign_to_hard_block_instance_port(curr_module_node); - port_to_assign_index = identify_port_index_within_hard_block_model_port_array(&(curr_hard_block_type_port_info->second), curr_module_node_info, curr_module_node); + port_to_assign_index = identify_port_index_within_hard_block_type_port_array(&(curr_hard_block_type_port_info->second), curr_module_node_info, curr_module_node); // assign the net to tocrresponding hard block instance port curr_hard_block_instance->hard_block_instance_node_reference->array_of_ports[port_to_assign_index]->associated_net = net_to_assign; @@ -421,7 +421,7 @@ t_pin_def* get_net_to_assign_to_hard_block_instance_port(t_node* curr_module_nod // if the port is not the LUT output ie. "combout" port // /* if we are here then we know that the LUT the current node - represents mus be an input port for hard block instance it is part of. We also know that this type of LUT only has an input and output port in the vqm netlist. Finally we know that the current port must be an input, so its connected net is what we want to assign to the hard block instance port. */ + represents must be an input port for hard block instance it is part of. We also know that this type of LUT only has an input and output port in the vqm netlist. Finally we know that the current port must be an input, so it's connected net is what we want to assign to the hard block instance port. */ port_connected_to_net = curr_module_node->array_of_ports[i]; break; @@ -460,11 +460,10 @@ t_pin_def* get_net_to_assign_to_hard_block_instance_port(t_node* curr_module_nod return net_to_assign; } -int identify_port_index_within_hard_block_model_port_array(t_hard_block_port_info* curr_hard_block_type_port_info, t_parsed_hard_block_port_info* curr_module_node_info, t_node* curr_module_node) +int identify_port_index_within_hard_block_type_port_array(t_hard_block_port_info* curr_hard_block_type_port_info, t_parsed_hard_block_port_info* curr_module_node_info, t_node* curr_module_node) { int identified_port_index = 0; - int port_end_index = 0; // error related identifiers @@ -528,7 +527,7 @@ bool is_hard_block_port_legal(t_node* curr_module_node) std::string curr_module_node_type = curr_module_node->type; // now we check the direction of the port as input or whether the node is a DFF - if ((curr_module_node->number_of_ports == LUT_OUTPUT_PORT_SIZE) || (!(curr_module_node_type.compare(DFF_TYPE)))) + if ((curr_module_node->number_of_ports != LUT_OUTPUT_PORT_SIZE) || (!(curr_module_node_type.compare(DFF_TYPE)))) { result = true; } From 514906bfc2abcbc32a5ab8fd4ec8ccb18efcc5da Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Mon, 30 Aug 2021 16:53:00 -0400 Subject: [PATCH 14/31] added functionality to identify error case where a hard block instance port has multiple nets connected to it. Also, now the number of assigned ports for each hard block instance is properly tracked. --- utils/vqm2blif/src/base/hard_block_recog.cpp | 32 ++++++++++++++++++-- utils/vqm2blif/src/base/hard_block_recog.h | 2 ++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/utils/vqm2blif/src/base/hard_block_recog.cpp b/utils/vqm2blif/src/base/hard_block_recog.cpp index 82ef5599544..8f30eceb42c 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.cpp +++ b/utils/vqm2blif/src/base/hard_block_recog.cpp @@ -368,8 +368,10 @@ void assign_net_to_hard_block_instance_port(t_node* curr_module_node, t_parsed_h port_to_assign_index = identify_port_index_within_hard_block_type_port_array(&(curr_hard_block_type_port_info->second), curr_module_node_info, curr_module_node); - // assign the net to tocrresponding hard block instance port - curr_hard_block_instance->hard_block_instance_node_reference->array_of_ports[port_to_assign_index]->associated_net = net_to_assign; + // assign the net to tocrresponding hard block instance port // + handle_net_assignment(curr_module_node, curr_hard_block_instance, port_to_assign_index, net_to_assign, curr_module_node_info); + + //curr_hard_block_instance->hard_block_instance_node_reference->array_of_ports[port_to_assign_index]->associated_net = net_to_assign; return; } @@ -519,6 +521,32 @@ int identify_port_index_within_hard_block_type_port_array(t_hard_block_port_info } +void handle_net_assignment(t_node* curr_module_node, t_hard_block* curr_hard_block_instance, int port_to_assign_index, t_pin_def* net_to_assign, t_parsed_hard_block_port_info* curr_module_node_info) +{ + std::string curr_module_node_name = curr_module_node->name; + + t_node_port_association* port_to_assign = curr_hard_block_instance->hard_block_instance_node_reference->array_of_ports[port_to_assign_index]; + + // need to check whether the current port was previouly assigned to a net + if ((port_to_assign->associated_net) == NULL) + { + // port was not assigned to a net previously // + + // assign the net to the port ("connect" them) + // since we just connected a port, we have one less port to assign, so update the "ports left to assign" tracker + port_to_assign->associated_net = net_to_assign; + curr_hard_block_instance->hard_block_ports_not_assigned -= 1; + } + else + { + // the port was already assigned previouly, this is an error, since we cannot have multiple nets connected to the same port + // so report an error + throw vtr::VtrError("The vqm netlist node '" + curr_module_node_name + "' represents a port:" + curr_module_node_info->hard_block_port_name +" within hard block model:" + curr_module_node_info->hard_block_type + ". But this port was already represented previously, therefore the current netlist node is a duplication of the port. A port can only have one netlist node representing it."); + } + + return; +} + bool is_hard_block_port_legal(t_node* curr_module_node) { diff --git a/utils/vqm2blif/src/base/hard_block_recog.h b/utils/vqm2blif/src/base/hard_block_recog.h index 4933e283bd4..e3fee2a5756 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.h +++ b/utils/vqm2blif/src/base/hard_block_recog.h @@ -232,6 +232,8 @@ t_pin_def* get_net_to_assign_to_hard_block_instance_port(t_node*); int identify_port_index_within_hard_block_type_port_array(t_hard_block_port_info*, t_parsed_hard_block_port_info*, t_node*); +void handle_net_assignment(t_node*, t_hard_block*, int, t_pin_def*, t_parsed_hard_block_port_info*); + bool is_hard_block_port_legal(t_node*); int create_new_hard_block_instance(t_array_ref*, t_hard_block_recog*, t_parsed_hard_block_port_info*); From c32bbd0ecadd8f10a483b0193aef384cf4d884ac Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Mon, 30 Aug 2021 16:59:24 -0400 Subject: [PATCH 15/31] updated error messages --- utils/vqm2blif/src/base/hard_block_recog.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/utils/vqm2blif/src/base/hard_block_recog.cpp b/utils/vqm2blif/src/base/hard_block_recog.cpp index 8f30eceb42c..089a75e4997 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.cpp +++ b/utils/vqm2blif/src/base/hard_block_recog.cpp @@ -50,7 +50,7 @@ void initialize_hard_block_models(t_arch* main_arch, std::vector* h if (hard_block_model == NULL) { - throw vtr::VtrError("The provided hard block model '" + *hard_block_type_name_traverser + "' was not found within the corresponding FPGA architecture."); + throw vtr::VtrError("The provided hard block model: '" + *hard_block_type_name_traverser + "' was not found within the corresponding FPGA architecture."); } else { @@ -58,7 +58,7 @@ void initialize_hard_block_models(t_arch* main_arch, std::vector* h if (!single_hard_block_init_result) { - throw vtr::VtrError("Hard block model '" + *hard_block_type_name_traverser + "' found in the architecture has no input/output ports."); + throw vtr::VtrError("Hard block model: '" + *hard_block_type_name_traverser + "' found in the architecture has no input/output ports."); } } @@ -482,7 +482,7 @@ int identify_port_index_within_hard_block_type_port_array(t_hard_block_port_info if (found_port_start_index == (curr_hard_block_type_port_info->port_name_to_port_start_index.end())) { // port does not exist, so throw and error and indicate it to the user - throw vtr::VtrError("The vqm netlist node '" + curr_module_node_name + "' represents a port:" + curr_module_node_info->hard_block_port_name +" within hard block model:" + curr_module_node_info->hard_block_type + ". But this port does not exist within the given hard block model as described in the architecture file."); + throw vtr::VtrError("The vqm netlist node '" + curr_module_node_name + "' represents a port: '" + curr_module_node_info->hard_block_port_name +"' within hard block model: '" + curr_module_node_info->hard_block_type + "'. But this port does not exist within the given hard block model as described in the architecture file."); } @@ -514,7 +514,7 @@ int identify_port_index_within_hard_block_type_port_array(t_hard_block_port_info if (identified_port_index > port_end_index) { // port index is out of range, so throw and error and indicate it to the user - throw vtr::VtrError("The vqm netlist node '" + curr_module_node_name + "' represents a port:" + curr_module_node_info->hard_block_port_name +" at index:" + std::to_string(curr_module_node_info->hard_block_port_index) + " hard block model:" + curr_module_node_info->hard_block_type + ". But this port index is out of range in the given hard block model as described in the architecture file."); + throw vtr::VtrError("The vqm netlist node '" + curr_module_node_name + "' represents a port: '" + curr_module_node_info->hard_block_port_name +"' at index: " + std::to_string(curr_module_node_info->hard_block_port_index) + ", within hard block model: '" + curr_module_node_info->hard_block_type + "'. But this port index is out of range in the given hard block model as described in the architecture file."); } return identified_port_index; @@ -541,7 +541,7 @@ void handle_net_assignment(t_node* curr_module_node, t_hard_block* curr_hard_blo { // the port was already assigned previouly, this is an error, since we cannot have multiple nets connected to the same port // so report an error - throw vtr::VtrError("The vqm netlist node '" + curr_module_node_name + "' represents a port:" + curr_module_node_info->hard_block_port_name +" within hard block model:" + curr_module_node_info->hard_block_type + ". But this port was already represented previously, therefore the current netlist node is a duplication of the port. A port can only have one netlist node representing it."); + throw vtr::VtrError("The vqm netlist node '" + curr_module_node_name + "' represents a port: '" + curr_module_node_info->hard_block_port_name +"' within hard block model: '" + curr_module_node_info->hard_block_type + "'. But this port was already represented previously, therefore the current netlist node is a duplication of the port. A port can only have one netlist node representing it."); } return; From 688ca21365520def03d9a4c649d0e01a372ebf92 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Tue, 7 Sep 2021 16:39:26 -0400 Subject: [PATCH 16/31] instead of identifying the net when connecting the net to the hard block instance port, we identify the port connected to the net, this way we can also extract wire index information when assigning net to the hard block instance port. Also updated some definitions. --- utils/vqm2blif/src/base/hard_block_recog.cpp | 44 +++++++++----------- utils/vqm2blif/src/base/hard_block_recog.h | 8 ++-- 2 files changed, 24 insertions(+), 28 deletions(-) diff --git a/utils/vqm2blif/src/base/hard_block_recog.cpp b/utils/vqm2blif/src/base/hard_block_recog.cpp index 089a75e4997..24d017b6b9c 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.cpp +++ b/utils/vqm2blif/src/base/hard_block_recog.cpp @@ -33,7 +33,7 @@ void add_hard_blocks_to_netlist(t_module* main_module, t_arch* main_arch, std::v // need to delete all the dynamic memory used to store // all the hard block port information delete_hard_block_port_info(&(module_hard_block_node_refs_and_info.hard_block_type_name_to_port_info)); - + return; } @@ -213,7 +213,7 @@ t_array_ref* convert_hard_block_model_port_to_hard_block_node_port(t_model_ports { // hard blocks will not have indexed wire assignments // doesnt do anything different I think - curr_hard_block_node_port = create_unconnected_node_port_association(curr_hard_block_model_port_name, port_index, WIRE_NOT_INDEXED); + curr_hard_block_node_port = create_unconnected_node_port_association(curr_hard_block_model_port_name, port_index, PORT_WIRE_NOT_INDEXED); // store the newly created specific port index within the entire port // array @@ -364,22 +364,19 @@ void assign_net_to_hard_block_instance_port(t_node* curr_module_node, t_parsed_h int port_to_assign_index = 0; - t_pin_def* net_to_assign = get_net_to_assign_to_hard_block_instance_port(curr_module_node); + t_node_port_association* curr_module_node_port_connected_to_hard_block_instance_net = get_lut_dffeas_port_connected_to_hard_block_instance_net(curr_module_node); port_to_assign_index = identify_port_index_within_hard_block_type_port_array(&(curr_hard_block_type_port_info->second), curr_module_node_info, curr_module_node); - // assign the net to tocrresponding hard block instance port // - handle_net_assignment(curr_module_node, curr_hard_block_instance, port_to_assign_index, net_to_assign, curr_module_node_info); - - //curr_hard_block_instance->hard_block_instance_node_reference->array_of_ports[port_to_assign_index]->associated_net = net_to_assign; + // assign the net to the crresponding hard block instance port // + handle_net_assignment(curr_module_node, curr_hard_block_instance, port_to_assign_index, curr_module_node_port_connected_to_hard_block_instance_net, curr_module_node_info); return; } -t_pin_def* get_net_to_assign_to_hard_block_instance_port(t_node* curr_module_node) +t_node_port_association* get_lut_dffeas_port_connected_to_hard_block_instance_net(t_node* curr_module_node) { - t_pin_def* net_to_assign = NULL; - t_node_port_association* port_connected_to_net = NULL; + t_node_port_association* port_connected_to_hard_block_instance_net = NULL; int number_of_ports_in_node = curr_module_node->number_of_ports; @@ -391,9 +388,6 @@ t_pin_def* get_net_to_assign_to_hard_block_instance_port(t_node* curr_module_nod // store what type of port we expect the net to be connected to std::string expected_port_type; - /* for a detailed error message, we identify what type of port - the net we want should be connected to for the module node */ - if (!(curr_module_node_type.compare(LUT_TYPE))) { @@ -424,7 +418,7 @@ t_pin_def* get_net_to_assign_to_hard_block_instance_port(t_node* curr_module_nod /* if we are here then we know that the LUT the current node represents must be an input port for hard block instance it is part of. We also know that this type of LUT only has an input and output port in the vqm netlist. Finally we know that the current port must be an input, so it's connected net is what we want to assign to the hard block instance port. */ - port_connected_to_net = curr_module_node->array_of_ports[i]; + port_connected_to_hard_block_instance_net = curr_module_node->array_of_ports[i]; break; } @@ -439,27 +433,22 @@ t_pin_def* get_net_to_assign_to_hard_block_instance_port(t_node* curr_module_nod /* if we are here then we know that the DFF the current node represents mus be an output port for hard block instance it is part of. Finally we know that the current port must be an output, so its connected net is what we want to assign to the hard block instance port. */ - port_connected_to_net = curr_module_node->array_of_ports[i]; + port_connected_to_hard_block_instance_net = curr_module_node->array_of_ports[i]; break; } } } - if (port_connected_to_net != NULL) - { - net_to_assign = port_connected_to_net->associated_net; - } - else + if (port_connected_to_hard_block_instance_net == NULL) { - /* we did not find any ports that fit the conditions above + /* we did not find any ports that fit the conditions above and this means that the current node, which represents a hard block instance port does not have an accompanying net. This should never happen, so throw an error and indicate to the user */ throw vtr::VtrError("The vqm netlist node '" + curr_module_node_name + "' does not have an " + expected_port_type + " port."); - } - - return net_to_assign; + + return port_connected_to_hard_block_instance_net; } int identify_port_index_within_hard_block_type_port_array(t_hard_block_port_info* curr_hard_block_type_port_info, t_parsed_hard_block_port_info* curr_module_node_info, t_node* curr_module_node) @@ -521,10 +510,12 @@ int identify_port_index_within_hard_block_type_port_array(t_hard_block_port_info } -void handle_net_assignment(t_node* curr_module_node, t_hard_block* curr_hard_block_instance, int port_to_assign_index, t_pin_def* net_to_assign, t_parsed_hard_block_port_info* curr_module_node_info) +void handle_net_assignment(t_node* curr_module_node, t_hard_block* curr_hard_block_instance, int port_to_assign_index, t_node_port_association* port_connected_to_hard_block_instance_net, t_parsed_hard_block_port_info* curr_module_node_info) { std::string curr_module_node_name = curr_module_node->name; + t_pin_def* net_to_assign = port_connected_to_hard_block_instance_net->associated_net; + t_node_port_association* port_to_assign = curr_hard_block_instance->hard_block_instance_node_reference->array_of_ports[port_to_assign_index]; // need to check whether the current port was previouly assigned to a net @@ -536,6 +527,9 @@ void handle_net_assignment(t_node* curr_module_node, t_hard_block* curr_hard_blo // since we just connected a port, we have one less port to assign, so update the "ports left to assign" tracker port_to_assign->associated_net = net_to_assign; curr_hard_block_instance->hard_block_ports_not_assigned -= 1; + + // assign the wire index of the net that we connect to the hard block port + port_to_assign->wire_index = port_connected_to_hard_block_instance_net->wire_index; } else { diff --git a/utils/vqm2blif/src/base/hard_block_recog.h b/utils/vqm2blif/src/base/hard_block_recog.h index e3fee2a5756..de78dafa184 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.h +++ b/utils/vqm2blif/src/base/hard_block_recog.h @@ -46,7 +46,7 @@ #define TOP_LEVEL 0 #define SECOND_LEVEL 1 -#define WIRE_NOT_INDEXED -1 +#define PORT_WIRE_NOT_INDEXED -1 #define INPUT_PORTS "input" #define OUTPUT_PORTS "output" @@ -62,6 +62,8 @@ // each level of hierarchy (module within module) is seperated by the delimiter character defined below. The last level of hierarchy is the output net of the block #define VQM_NODE_NAME_DELIMITER "|" +#define PORT_NOT_BUS 1 + #define PORT_NAME 1 #define PORT_INDEX 2 @@ -228,11 +230,11 @@ int find_hard_block_instance(t_hard_block_recog*, t_parsed_hard_block_port_info* void assign_net_to_hard_block_instance_port(t_node*, t_parsed_hard_block_port_info*, t_hard_block_recog*, int); -t_pin_def* get_net_to_assign_to_hard_block_instance_port(t_node*); +t_node_port_association* get_lut_dffeas_port_connected_to_hard_block_instance_net(t_node*); int identify_port_index_within_hard_block_type_port_array(t_hard_block_port_info*, t_parsed_hard_block_port_info*, t_node*); -void handle_net_assignment(t_node*, t_hard_block*, int, t_pin_def*, t_parsed_hard_block_port_info*); +void handle_net_assignment(t_node*, t_hard_block*, int, t_node_port_association*, t_parsed_hard_block_port_info*); bool is_hard_block_port_legal(t_node*); From 2b2c079b2c4c690af2cc9f3a961e3e0214a086f0 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Tue, 7 Sep 2021 16:44:32 -0400 Subject: [PATCH 17/31] forgot to update the module node list after adding all the newly created hards block instances --- utils/vqm2blif/src/base/hard_block_recog.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/utils/vqm2blif/src/base/hard_block_recog.cpp b/utils/vqm2blif/src/base/hard_block_recog.cpp index 24d017b6b9c..ad90dfbf16c 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.cpp +++ b/utils/vqm2blif/src/base/hard_block_recog.cpp @@ -131,6 +131,14 @@ void process_module_nodes_and_create_hard_blocks(t_module* main_module, std::vec } } + // update the node list for the current module + main_module->number_of_nodes = node_list_with_hard_blocks->array_size; + main_module->array_of_nodes = (t_node**)(node_list_with_hard_blocks->pointer); + + // we also need to delete the dynamic memory we created + vtr::free(node_list_with_hard_blocks); + + return; } From 5d22fef6128502f33c9176e10e8a2bae98ed74e2 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Tue, 7 Sep 2021 16:50:06 -0400 Subject: [PATCH 18/31] updated hard block port indices for ports that were not a bus so that they would correctly indicate that the port was not a bus --- utils/vqm2blif/src/base/hard_block_recog.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/utils/vqm2blif/src/base/hard_block_recog.cpp b/utils/vqm2blif/src/base/hard_block_recog.cpp index ad90dfbf16c..10727e797d3 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.cpp +++ b/utils/vqm2blif/src/base/hard_block_recog.cpp @@ -228,6 +228,12 @@ t_array_ref* convert_hard_block_model_port_to_hard_block_node_port(t_model_ports append_array_element((intptr_t)curr_hard_block_node_port, port_array); } + // handle the case where the port is not bussed + if (port_size == PORT_NOT_BUS) + { + curr_hard_block_node_port->port_index = PORT_WIRE_NOT_INDEXED; + } + return port_array; } From 476727cd8cac38f5697f2aa39c33ed1ba163beba Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Tue, 7 Sep 2021 20:43:54 -0400 Subject: [PATCH 19/31] cleaned up main program and integrated new hard block type support into program flow --- utils/vqm2blif/src/main.cpp | 156 ++---------------------------------- 1 file changed, 6 insertions(+), 150 deletions(-) diff --git a/utils/vqm2blif/src/main.cpp b/utils/vqm2blif/src/main.cpp index aea54b558e4..2037d16c14a 100644 --- a/utils/vqm2blif/src/main.cpp +++ b/utils/vqm2blif/src/main.cpp @@ -82,7 +82,6 @@ #include "vtr_error.h" #include "physical_types.h" #include "hard_block_recog.h" -#include "hard_block_recog_test.h" #include @@ -151,12 +150,6 @@ t_boolean identify_and_instantiate_custom_hard_blocks; // user-set flag. Which i // FUNCTION DECLARATIONS //============================================================================================ -// Srivatsan, test function to better understand how the module data structure /works - -void print_module(t_module* my_module); - -void print_arch_modules(t_arch* my_arch, std::vector* my_logical_types); - //Setup Functions void cmd_line_parse (int argc, char** argv, string* sourcefile, string* archfile, string* outfile, std::vector* hard_block_list); @@ -244,29 +237,7 @@ void echo_blif_model (char* echo_file, const char* vqm_filename, int main(int argc, char* argv[]) { - //char* test = "test"; - //char* test_two = "test_two"; - //test_copy_array_ref(10000); - //test_create_unconnected_node_port_association(10, -1, test); - //test_create_hard_block_port_info_structure(test); - //test_convert_hard_block_model_port_to_hard_block_node_port(test, 25); - //test_store_hard_block_port_info(test,test_two,"router", 45); - //test_extract_and_store_hard_block_model_port(test, test_two, 500, 1000, "router"); - - //test_delete_hard_block_port_info(test, "router", 10000); - //test_initialize_hard_block_models(); - - //test_identify_hard_block_type(); - //test_identify_hard_block_port_name_and_index(); - - //test_split_node_name(); - //test_construct_hard_block_name(); - //test_extract_hard_block_port_info_from_module_node(); - - //test_create_and_initialize_all_hard_block_ports(); - - //test_array_ref_initialization(); t_blif_model my_model; //holds top-level model data for the .blif netlist //***The primary goal of the program is to populate and dump this structure appropriately.*** @@ -298,7 +269,7 @@ int main(int argc, char* argv[]) //used to construct output filenames from project name //char* filename necessitated by vqm_parse_file() - // a list which stores all the user supplied custom hard block names + // a list which stores all the user supplied custom hard block type names std::vector hard_block_type_name_list; //************************************************************************************************* @@ -311,13 +282,6 @@ int main(int argc, char* argv[]) //verify command-line is correct, populate input variables and global mode flags. cmd_line_parse(argc, argv, &source_file, &arch_file, &out_file, &hard_block_type_name_list); - /*std::vector::iterator it; - - for (it = hard_block_type_name_list.begin(); it != hard_block_type_name_list.end(); it++) - { - std::cout << *it << "\n"; - }*/ - setup_lut_support_map (); //initialize LUT support for cleanup and elaborate functions size_t cptr = out_file.find_last_of("."); @@ -336,21 +300,19 @@ int main(int argc, char* argv[]) //VQM Parser Call, requires char* filename my_module = vqm_parse_file(temp_name); - //print_module(my_module); - unsigned long processEnd = clock(); cout << "\n>> VQM Parsing took " << (float)(processEnd - processStart)/CLOCKS_PER_SEC << " seconds.\n" ; cout << "\n>> Verifying module"; verify_module (my_module); - /*if (debug_mode){ + if (debug_mode){ //Print debug info to "_module.echo" construct_filename ( temp_name, project_path.c_str(), "_module.echo" ); cout << "\n>> Dumping to output file " << temp_name << endl ; echo_module ( temp_name, source_file.c_str(), my_module ); //file contains data read from the .vqm structures. - }*/ + } //Parse the architecture file to get full information about the models used. // Note: the architecture file needs to be loaded first, so that it can be used @@ -370,20 +332,10 @@ int main(int argc, char* argv[]) VTR_ASSERT((types) && (numTypes > 0)); VTR_ASSERT(arch.models != NULL); - - //test_create_unconnected_hard_block_instance_ports(my_module, &arch, &hard_block_type_name_list); - - //test_create_new_hard_block_instance_node(&arch, &hard_block_type_name_list); - - //test_store_new_hard_block_instance_info(&arch, &hard_block_type_name_list); - - //test_create_new_hard_block_instance(my_module, &arch, &hard_block_type_name_list); - - test_find_hard_block_instance(my_module, &arch, &hard_block_type_name_list); //Pre-process the netlist // Currently this just 'cleans up' bi-directional inout pins - /* cout << "\n>> Preprocessing Netlist...\n"; + cout << "\n>> Preprocessing Netlist...\n"; processStart = clock(); preprocess_netlist(my_module, &arch, types, numTypes, fix_global_nets, elaborate_ram_clocks, @@ -427,8 +379,6 @@ int main(int argc, char* argv[]) } } - //print_arch_modules(&arch, &logical_block_types); - // only process the netlist for any custom hard blocks if the user provided valid hard block names if (identify_and_instantiate_custom_hard_blocks) { @@ -492,9 +442,7 @@ int main(int argc, char* argv[]) unsigned long flowEnd = clock(); cout << "\n>> VQM->BLIF Total Runtime: " << (float)(flowEnd - flowStart)/CLOCKS_PER_SEC << " seconds.\n" ; - cout << "\nComplete.\n";*/ - - all_data_cleanup(); + cout << "\nComplete.\n"; return 0; } @@ -670,7 +618,7 @@ void cmd_line_parse (int argc, char** argv, string* sourcefile, string* archfile eblif_format = T_TRUE; break; case OT_IDENTIFY_AND_INSTANTIATE_CUSTOM_HARD_BLOCKS: - // first check whether an accompanying hard block type name was supplied (user provides the names of all the various types of custom hard blocks within the design, essentially this is the module name) + // first check whether an accompanying hard block type name was supplied (user provides the names of all the various types of custom hard blocks within the design, essentially this is the module names in their HDL design) if ( i+1 == argc ){ // no hard block type name was supplied so throw an error cout << "ERROR: Missing Hard Block Module Names.\n" ; @@ -2321,98 +2269,6 @@ void echo_blif_model (char* echo_file, const char* vqm_filename, model_out.close(); } -// this is a test function to see how the t_module data structure works (by printing everything) - -void print_module(t_module* my_module) -{ - t_node* temp_node = NULL; - t_node_port_association* temp_ports = NULL; - // go through all the nodes in the design - for (auto i = 0; i < my_module->number_of_nodes; i++) - { - temp_node = my_module->array_of_nodes[i]; - - for (auto j = 0; j < temp_node->number_of_ports; j++) - { - temp_ports = temp_node->array_of_ports[j]; - } - } - - return; -} - -// this is a test function to see how the t_arch data structure works -// For the hard block functionality we just care about the modules -// so print information regarding that -void print_arch_modules(t_arch* my_arch, std::vector* my_logical_types) -{ - t_model* temp = my_arch->models; - t_model_ports* temp_input_ports = NULL; - t_model_ports* temp_output_ports = NULL; - - std::string temp_name; - - char* output_port_name = NULL; - char* input_port_name = NULL; - - // iterator to traverse the logical_types - std::vector::iterator it; - - // code related to the logical types - t_pb_type* temp_logical_type = NULL; - t_port* temp_port = NULL; - - while (temp != NULL) - { - temp_input_ports = temp->inputs; - temp_output_ports = temp->outputs; - - temp_name = temp->name; - - /*if(temp_name.compare("stratixiv_ram_block.opmode{dual_port}.output_type{reg}.port_a_address_width{2}.port_b_address_width{2}") == 0) - { - // breakpoint here - std::cout << "test" << "\n"; - }*/ - - if(temp_name.compare("router") == 0) - { - // breakpoint here - std::cout << "test" << "\n"; - } - - // lets go through all the ports - while (temp_input_ports != NULL) - { - input_port_name = temp_input_ports->name; - - temp_input_ports = temp_input_ports->next; - } - - while (temp_output_ports != NULL) - { - output_port_name = temp_output_ports->name; - - temp_output_ports = temp_output_ports->next; - } - - temp = temp->next; - } - - // we now traverse the logical types - for(it = my_logical_types->begin(); it != my_logical_types->end(); it++) - { - temp_logical_type = it->pb_type; - - for (int i = 0; i < temp_logical_type->num_ports; i++) - { - temp_port = &(temp_logical_type->ports[i]); - } - } - - return; -} - //============================================================================================ //============================================================================================ #ifdef NO_CONSTS From d42e3194cc4ce2084fa4f3bbf546450b7d8cb9e7 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Wed, 22 Sep 2021 18:15:25 -0400 Subject: [PATCH 20/31] added support so that the unnecessary LUTs and D flip flop nodes that repersent hard blocks ports can be removed from the module now --- utils/vqm2blif/src/base/hard_block_recog.cpp | 34 ++++++++++++++++++-- utils/vqm2blif/src/base/hard_block_recog.h | 15 ++++++--- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/utils/vqm2blif/src/base/hard_block_recog.cpp b/utils/vqm2blif/src/base/hard_block_recog.cpp index 10727e797d3..fcbd6250ceb 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.cpp +++ b/utils/vqm2blif/src/base/hard_block_recog.cpp @@ -27,8 +27,9 @@ void add_hard_blocks_to_netlist(t_module* main_module, t_arch* main_arch, std::v throw vtr::VtrError((std::string)error.what() + "The original netlist is described in " + vqm_file_name + "."); } - - + // at this point we have a list of luts/dffeas nodes found in the module that we need to remove + // so we remove them here + remove_luts_dffeas_nodes_representing_hard_block_ports(main_module, &module_hard_block_node_refs_and_info); // need to delete all the dynamic memory used to store // all the hard block port information @@ -836,6 +837,35 @@ void identify_hard_block_port_name_and_index (t_parsed_hard_block_port_info* cur return; } +void remove_luts_dffeas_nodes_representing_hard_block_ports(t_module* main_module, t_hard_block_recog* module_hard_block_node_refs_and_info) +{ + // reference to the list of luts/dffeas nodes we need to remove + std::vector* list_of_nodes_to_remove = &(module_hard_block_node_refs_and_info->luts_dffeas_nodes_to_remove); + + t_node** module_node_list = main_module->array_of_nodes; + int number_of_nodes_in_module = main_module->number_of_nodes; + + // iterator to go through the list of nodes we will be removing + std::vector::iterator node_to_remove; + + // keep track of all the nodes we removed from the module node array + //int number_of_nodes_removed = 0; + + // go through the list of nodes we need to remove and delete them + // from the node array within the module + for(node_to_remove = list_of_nodes_to_remove->begin(); node_to_remove != list_of_nodes_to_remove->end(); node_to_remove++) + { + remove_node(*node_to_remove, module_node_list, number_of_nodes_in_module); + + //number_of_nodes_removed++; + } + + // we need to fix the gaps created in the node array after removing all luts/dffeas nodes previously + reorganize_module_node_list(main_module); + + return; +} + void delete_hard_block_port_info(std::unordered_map* hard_block_type_name_to_port_info_map) { std::unordered_map::iterator curr_hard_block_port_info = hard_block_type_name_to_port_info_map->begin(); diff --git a/utils/vqm2blif/src/base/hard_block_recog.h b/utils/vqm2blif/src/base/hard_block_recog.h index de78dafa184..5ca761406c7 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.h +++ b/utils/vqm2blif/src/base/hard_block_recog.h @@ -35,6 +35,7 @@ // user vqm2blif libraries #include "vqm2blif_util.h" +#include "cleanup.h" // standard libraries #include @@ -165,11 +166,13 @@ typedef struct s_hard_block_recog */ std::unordered_map hard_block_instance_name_to_index; - /* The lcells and dffeas used to model ports are all stored as nodes. - The nodelist is simply an array. Now deleting lcell nodes while still - creating additional nodes could cause some problems, so we will - delete all these nodes at the end. Therefore we need to keep a - reference for all the lcell and dffeas nodes here.*/ + /* + The luts and dffeas used to model ports are all stored as nodes and + we will need to remove them from the netlist after adding all the + hard blocks to the netlist.The ports that are modelled by the luts and dffeas aren't needed once all the hard blocks within the design are added to the netlist.The luts and dffeas are simply repeating the port information, so we can remove them. + + The nodelist is simply an array. Now deleting lut/dffeas nodes while still creating additional hard block nodes could cause some problems, so we will delete all these nodes at the end. Therefore we need to keep a + reference for all the luts and dffeas nodes that represent hard block ports here, so we can them remove later on.*/ std::vector luts_dffeas_nodes_to_remove; // look into using array index instead }t_hard_block_recog; @@ -260,6 +263,8 @@ void split_node_name(std::string, std::vector*, std::string); std::string construct_hard_block_name(std::vector*, std::string); +void remove_luts_dffeas_nodes_representing_hard_block_ports(t_module*, t_hard_block_recog*); + // utility functions void store_hard_block_names(char**, int, std::vector*); From 669dda638e43d8c4048762f824928fb6739923e6 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Mon, 27 Sep 2021 16:05:36 -0400 Subject: [PATCH 21/31] added a check that verifies whether all the ports of each and every hard block in the netlist has a net assigned to it --- utils/vqm2blif/src/base/hard_block_recog.cpp | 70 +++++++++++++++++++- utils/vqm2blif/src/base/hard_block_recog.h | 4 ++ 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/utils/vqm2blif/src/base/hard_block_recog.cpp b/utils/vqm2blif/src/base/hard_block_recog.cpp index fcbd6250ceb..c75bf05676c 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.cpp +++ b/utils/vqm2blif/src/base/hard_block_recog.cpp @@ -15,16 +15,18 @@ void add_hard_blocks_to_netlist(t_module* main_module, t_arch* main_arch, std::v } catch(const vtr::VtrError& error) { - throw vtr::VtrError((std::string)error.what() + "The FPGA architecture is described in " + arch_file_name + "."); + throw vtr::VtrError((std::string)error.what() + " The FPGA architecture is described in " + arch_file_name + "."); } try { process_module_nodes_and_create_hard_blocks(main_module, list_hard_block_type_names, &module_hard_block_node_refs_and_info); + + verify_hard_blocks(&module_hard_block_node_refs_and_info); } catch(const vtr::VtrError& error) { - throw vtr::VtrError((std::string)error.what() + "The original netlist is described in " + vqm_file_name + "."); + throw vtr::VtrError((std::string)error.what() + " The original netlist is described in " + vqm_file_name + "."); } // at this point we have a list of luts/dffeas nodes found in the module that we need to remove @@ -866,6 +868,63 @@ void remove_luts_dffeas_nodes_representing_hard_block_ports(t_module* main_modul return; } +void verify_hard_blocks(t_hard_block_recog* module_hard_block_node_refs_and_info) +{ + + // IF we find a hard block instance that has ports unassigned, we store its information in the variables below + t_node* incomplete_hard_block_instance = NULL; + t_node_port_association* temp_port = NULL; + std::string incomplete_hard_block_instance_name = ""; + std::string incomplete_hard_block_instance_type = ""; + std::string unassigned_port_name = ""; + + std::vector* list_of_hard_block_instances = &(module_hard_block_node_refs_and_info->hard_block_instances); + + // we order the vector of t_hard_blocks from the largest to smallest number of ports not assigned + std::sort(list_of_hard_block_instances->begin(), list_of_hard_block_instances->end(), sort_hard_blocks_by_valid_connections); + + /* We just need to check the first element of the previously sorted vector of hard block instances in the design to see if has any ports unassigned. If the first element has all ports connected, then this means all other hard block instances in the design have all their ports assigned (since we ordered them from largest to smallest number of ports unassigned). + + If we find that the the hard block instance has a port or more that is unassigned, we go through all the ports and throw an error on the first unassgined port. + */ + if (((list_of_hard_block_instances->begin())->hard_block_ports_not_assigned) != 0) + { + incomplete_hard_block_instance = (list_of_hard_block_instances->begin())->hard_block_instance_node_reference; + + // iterate through all ports in the hard block + for (int i = 0; i < incomplete_hard_block_instance->number_of_ports; i++) + { + temp_port = incomplete_hard_block_instance->array_of_ports[i]; + + // check each port too see if it was unassigned + if (temp_port->associated_net == NULL) + { + // if we are here, then the port was unassigned + + // store some information about the port that is unassgined the hard block instance it is part of + incomplete_hard_block_instance_name.assign( incomplete_hard_block_instance->name); + incomplete_hard_block_instance_type.assign(incomplete_hard_block_instance->type); + unassigned_port_name.assign(temp_port->port_name); + + + // we store ports that are not bussed with an index of -1, we dont want to show that to the user, so we use two different error messages for ports that are a bus and ports which are not + if ((temp_port->port_index) == PORT_WIRE_NOT_INDEXED) + { + throw vtr::VtrError("The hard block instance '" + incomplete_hard_block_instance_name + "', which is of hard block type: '"+ incomplete_hard_block_instance_type + "' has a port: '" + unassigned_port_name +"' that is unassigned. This means that the port was not included in the provided vqm netlist."); + } + else + { + throw vtr::VtrError("The hard block instance '" + incomplete_hard_block_instance_name + "', which is of hard block type: '"+ incomplete_hard_block_instance_type + "' has a port: '" + unassigned_port_name +"[" + std::to_string(temp_port->port_index)+"]' that is unassigned. This means that the port was not found in the provided vqm netlist."); + } + + } + } + } + + return; + +} + void delete_hard_block_port_info(std::unordered_map* hard_block_type_name_to_port_info_map) { std::unordered_map::iterator curr_hard_block_port_info = hard_block_type_name_to_port_info_map->begin(); @@ -884,4 +943,11 @@ void delete_hard_block_port_info(std::unordered_map (instance_two.hard_block_ports_not_assigned)); + } \ No newline at end of file diff --git a/utils/vqm2blif/src/base/hard_block_recog.h b/utils/vqm2blif/src/base/hard_block_recog.h index 5ca761406c7..d26eee956a5 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.h +++ b/utils/vqm2blif/src/base/hard_block_recog.h @@ -265,8 +265,12 @@ std::string construct_hard_block_name(std::vector*, std::string); void remove_luts_dffeas_nodes_representing_hard_block_ports(t_module*, t_hard_block_recog*); +void verify_hard_blocks(t_hard_block_recog*); + // utility functions void store_hard_block_names(char**, int, std::vector*); +bool sort_hard_blocks_by_valid_connections(t_hard_block, t_hard_block); + #endif \ No newline at end of file From 8e321ef8b1184c1c3af3011b84c073db6954cedf Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Mon, 27 Sep 2021 18:21:10 -0400 Subject: [PATCH 22/31] inserted additional logging while executing the new primitive block support feature --- utils/vqm2blif/src/base/hard_block_recog.cpp | 21 ++++++++++++++++++++ utils/vqm2blif/src/main.cpp | 10 +++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/utils/vqm2blif/src/base/hard_block_recog.cpp b/utils/vqm2blif/src/base/hard_block_recog.cpp index c75bf05676c..03ee50daa39 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.cpp +++ b/utils/vqm2blif/src/base/hard_block_recog.cpp @@ -9,8 +9,15 @@ void add_hard_blocks_to_netlist(t_module* main_module, t_arch* main_arch, std::v { t_hard_block_recog module_hard_block_node_refs_and_info; + // variables used for reporting statistics to the user + int number_of_hard_blocks_added = 0; + int number_of_luts_flip_flops_removed = 0; + try { + + std::cout << "\t>> Generating models for custom hard blocks.\n"; + initialize_hard_block_models(main_arch, list_hard_block_type_names, &module_hard_block_node_refs_and_info); } catch(const vtr::VtrError& error) @@ -20,19 +27,33 @@ void add_hard_blocks_to_netlist(t_module* main_module, t_arch* main_arch, std::v try { + + std::cout << "\t>> Processing netlist to infer and add custom hard blocks.\n"; + process_module_nodes_and_create_hard_blocks(main_module, list_hard_block_type_names, &module_hard_block_node_refs_and_info); + std::cout << "\t>> Verifying newly created custom hard blocks.\n"; + verify_hard_blocks(&module_hard_block_node_refs_and_info); + + number_of_hard_blocks_added = module_hard_block_node_refs_and_info.hard_block_instances.size(); + number_of_luts_flip_flops_removed = module_hard_block_node_refs_and_info.luts_dffeas_nodes_to_remove.size(); + + std::cout << "\t>> Inferred and added " << number_of_hard_blocks_added << " hard blocks to the netlist.\n"; } catch(const vtr::VtrError& error) { throw vtr::VtrError((std::string)error.what() + " The original netlist is described in " + vqm_file_name + "."); } + std::cout << "\t>> Cleaning up netlist after adding hard blocks.\n"; + // at this point we have a list of luts/dffeas nodes found in the module that we need to remove // so we remove them here remove_luts_dffeas_nodes_representing_hard_block_ports(main_module, &module_hard_block_node_refs_and_info); + std::cout << "\t>> Removed " << number_of_luts_flip_flops_removed << " luts and flip flops from the netlist.\n"; + // need to delete all the dynamic memory used to store // all the hard block port information delete_hard_block_port_info(&(module_hard_block_node_refs_and_info.hard_block_type_name_to_port_info)); diff --git a/utils/vqm2blif/src/main.cpp b/utils/vqm2blif/src/main.cpp index 2037d16c14a..7e94dbf0135 100644 --- a/utils/vqm2blif/src/main.cpp +++ b/utils/vqm2blif/src/main.cpp @@ -381,7 +381,11 @@ int main(int argc, char* argv[]) // only process the netlist for any custom hard blocks if the user provided valid hard block names if (identify_and_instantiate_custom_hard_blocks) - { + { + cout << "\n>> Identifying and instantiating custom hard blocks within the netlist.\n"; + + processStart = clock(); + try { add_hard_blocks_to_netlist(my_module,&arch,&hard_block_type_name_list, arch_file, source_file); @@ -391,6 +395,10 @@ int main(int argc, char* argv[]) VTR_LOG_ERROR("%s\n", ((std::string)error.what()).c_str()); exit(1); } + + processEnd = clock(); + + cout << "\n>> Custom hard block instantiations took " << (float)(processEnd - processStart)/CLOCKS_PER_SEC << " seconds.\n" ; } //Reorganize netlist data into structures conducive to .blif writing. From 4a401cc8851d4628aafd478a88ba6151ec852f0d Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Tue, 5 Oct 2021 17:17:13 -0400 Subject: [PATCH 23/31] fixed bug where a design that had no hard blocks would fail with the new primitive hard block support feature --- utils/vqm2blif/src/base/hard_block_recog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/vqm2blif/src/base/hard_block_recog.cpp b/utils/vqm2blif/src/base/hard_block_recog.cpp index 03ee50daa39..ca06ae514bd 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.cpp +++ b/utils/vqm2blif/src/base/hard_block_recog.cpp @@ -908,7 +908,7 @@ void verify_hard_blocks(t_hard_block_recog* module_hard_block_node_refs_and_info If we find that the the hard block instance has a port or more that is unassigned, we go through all the ports and throw an error on the first unassgined port. */ - if (((list_of_hard_block_instances->begin())->hard_block_ports_not_assigned) != 0) + if (!(list_of_hard_block_instances->empty()) && (((list_of_hard_block_instances->begin())->hard_block_ports_not_assigned) != 0)) { incomplete_hard_block_instance = (list_of_hard_block_instances->begin())->hard_block_instance_node_reference; From 0cb2a4be2ace878fae35323c06b0cd028435c0b1 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Thu, 14 Oct 2021 15:40:40 -0400 Subject: [PATCH 24/31] improved overall code documentation --- utils/vqm2blif/src/base/hard_block_recog.cpp | 900 ++++++++++++++++++- 1 file changed, 882 insertions(+), 18 deletions(-) diff --git a/utils/vqm2blif/src/base/hard_block_recog.cpp b/utils/vqm2blif/src/base/hard_block_recog.cpp index ca06ae514bd..bf1199f33d3 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.cpp +++ b/utils/vqm2blif/src/base/hard_block_recog.cpp @@ -1,10 +1,160 @@ -// add higher level comments here - +/* +* The purpose of this file is to support netlists that +* contain new types of hard blocks. Specifically, user defined +* hard blocks are indetified within the netlist and then instantiated +* so that they are later written to the generated .blif file. +* +* For example, consider a user design that contains a new hard block +* called "router". This hard block is embedded within the FPGA architecture +* but the Quartus synthesis tool has no reference to what a "router" block is. +* Since the tool has no information to the hard block, the generated netlist +* does not properly model the hard blocks. Instead of declaring a single hard * block in the netlist, it was found that the generated .vqm netlist +* from Quartus inserted a LUT for every input port of the hard block +* and then a LUT & DFF for every output port of the hard block. +* An example is shown below: +* +* Suppose we had the following module in the design (representing a hard +* block): +* +* router router_1 ( +* .input_one (pin_1), +* .input_two (pin_2), +* .output_one (pin_3), +* .output_two (pin_4), +* ); +* +* In the generated netlist from Quartus, the model will be represented as: +* +* router_1 +* -------------------------------------------------------------------- +* | LUT | +* | -------------- | +* pin_1 ---> input_one | | +* | | | | +* | | | | +* | -------------- | +* | | +* | | +* | | +* | LUT | +* | -------------- | +* pin_2 ---> input_two | | +* | | | | +* | | | | +* | -------------- | +* | | +* | | +* | | +* | LUT DFF | +* | ----------- -------------- | +* | | output_one ---------> ------> pin_3 +* | | | | | | +* | | | | | | +* | ----------- -------------- | +* | | +* | | +* | | +* | LUT DFF | +* | ----------- -------------- | +* | | output_two ---------> ------> pin_4 +* | | | | | | +* | | | | | | +* | ----------- -------------- | +* -------------------------------------------------------------------- +* +* Looking at the figure above, the netlist is incorrect. Instead of +* of a single "black box" model, LUTS and DFF have been +* incorrectly added to represent all the "ports" of the hard block. +* +* The functions in this file process the .vqm netlist generated by +* Quartus synthesis to fix the issues mentioned above. +* While processing the netlist, if a LUT or DFF +* is found, then it is "checked" too see whether it represents a +* a hard block "port", if it does then the corresponding hard block +* the "port" belongs to is identified and +* added to the netlist (newly instantiated). The corresponding luts and +* flip flops are then removed from the netlist and their netlist +* connections are then appropriately moved to the newly instantiated +* hard block. +* +* For example, if we take the netlist with the "router" block +* above and we process it using the functions in this file, the +* router block in the resulting netlist will look as follows: +* +* router_1 +* -------------------------------------------------------------------- +* | | +* | | +* pin_1 ---> input_one | +* | | +* | | +* | | +* | | +* | | +* | | +* | | +* | | +* pin_2 ---> input_two | +* | | +* | | +* | | +* | | +* | | +* | | +* | | +* | | +* | output_one ------> pin_3 +* | | +* | | +* | | +* | | +* | | +* | | +* | | +* | | +* | output_two ------> pin_4 +* | | +* | | +* | | +* -------------------------------------------------------------------- +* +* Now the hard block is correctly modelled within the netlist. +*/ #include "hard_block_recog.h" - +/** + * @details This function is the main controller and executes all the + * processing steps involved in indentifying new types of hard + * blocks within the design and adding them to the netlist. + * + * The following steps are performed: + * - The FPGA architecture is parsed to internally model + * each hard block in the design + * - The nodes within the netlist are individually processed + * to determine whether hard blocks are included within the + * design and then added to the netlist + * - The newly added hard blocks are verified to make sure they + * are legal + * - The luts and dffeas within the netlist that represented + * hard block ports are removed + * + * @param main_module This contains all the netlist information, such as luts, + * flip flops, and other types of blocks. All the nets within + * the netlist are also included. + * + * @param main_arch This contains all the information regarding the FPGA + * architeture that the design will be mapped to. + * + * @param list_hard_block_type_names A list of the hard block names that need + * to be properly added to the netlist. + * + * @param arch_file_name Name of the architecture file that contains the FPGA + * architecture information. + * + * @param vqm_file_name Name of the quartus generated .vqm netlist file. + */ void add_hard_blocks_to_netlist(t_module* main_module, t_arch* main_arch, std::vector* list_hard_block_type_names, std::string arch_file_name, std::string vqm_file_name) { t_hard_block_recog module_hard_block_node_refs_and_info; @@ -18,6 +168,8 @@ void add_hard_blocks_to_netlist(t_module* main_module, t_arch* main_arch, std::v std::cout << "\t>> Generating models for custom hard blocks.\n"; + // internally model the new types of hard blocks using the architecture + // file initialize_hard_block_models(main_arch, list_hard_block_type_names, &module_hard_block_node_refs_and_info); } catch(const vtr::VtrError& error) @@ -30,6 +182,9 @@ void add_hard_blocks_to_netlist(t_module* main_module, t_arch* main_arch, std::v std::cout << "\t>> Processing netlist to infer and add custom hard blocks.\n"; + + // go through the netlist nodes and add the new types of hard blocks + // if they are needed process_module_nodes_and_create_hard_blocks(main_module, list_hard_block_type_names, &module_hard_block_node_refs_and_info); std::cout << "\t>> Verifying newly created custom hard blocks.\n"; @@ -61,25 +216,46 @@ void add_hard_blocks_to_netlist(t_module* main_module, t_arch* main_arch, std::v return; } +/** + * @details Given a list of hard block names, an FPGA architecture is + * parsed to find and store information related to the hard blocks + * within the list. The ports and their indexing is stored. + * + * @param main_arch This contains all the information regarding the FPGA + * architeture that the design will be mapped to. + * + * @param hard_block_type_names A list of the hard block names that need + * to be properly added to the netlist. + * + * @param storage_of_hard_block_info This is a data structure of type + * 't_hard_block_recog', which can be found + * in 'hard_block_recog.h'. The port + * information of the hard blocks are stored + * in here. + */ 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; + // iterate through each hard block name within the list for (hard_block_type_name_traverser = hard_block_type_names->begin(); hard_block_type_name_traverser != hard_block_type_names->end(); hard_block_type_name_traverser++) { - // function already made + // 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); + // a check to see if the model was found within the FPGA architecture if (hard_block_model == NULL) { throw vtr::VtrError("The provided hard block model: '" + *hard_block_type_name_traverser + "' was not found within the corresponding FPGA architecture."); } else - { + { + // 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); + // a check to make sure the hard block has both input and output ports if (!single_hard_block_init_result) { throw vtr::VtrError("Hard block model: '" + *hard_block_type_name_traverser + "' found in the architecture has no input/output ports."); @@ -92,6 +268,29 @@ void initialize_hard_block_models(t_arch* main_arch, std::vector* h } +/** + * @details Given a module (which is the netlist), iterate through each + * node to determine whether the node represents a hard block port. + * If the node does represent a port, then a new hard block node + * is created and added to the module and the corresponding port + * is connected to the same net as the node that represented that port. + * If the hard block was already created, then it is not created again. + * Finally the nodes that were identified as representing hard block + * ports are stored for reference. + * + * @param main_module This contains all the netlist information, such as luts, + * flip flops, and other types of blocks. All the nets within + * the netlist are also included. + * + * @param hard_block_type_name_list A list of the hard block names that need + * to be properly added to the netlist. + * + * @param module_hard_block_node_refs_and_info This is a data structure of type + * 't_hard_block_recog', which can be found + * in 'hard_block_recog.h'. The port + * information of the hard blocks are stored + * in here. + */ void process_module_nodes_and_create_hard_blocks(t_module* main_module, std::vector* hard_block_type_name_list, t_hard_block_recog* module_hard_block_node_refs_and_info) { // represents a block in the netlist @@ -166,12 +365,33 @@ void process_module_nodes_and_create_hard_blocks(t_module* main_module, std::vec } +/** + * @details This function creates an array of unconnected + * ports for a hard block. Additionally, a + * 't_hard_block_port_info' structure is created (found + * in 'hard_block_recog.h') to store the unconnected + * port array; so that the port information can be + * found given a hard block type. + * + * @param hard_block_arch_model This is a 't_model' structure (found in + * 'logic_types.h') and contains information + * about a hard block within the FPGA + * architecture. + * + * @param storage_of_hard_block_info This is a data structure of type + * 't_hard_block_recog', which can be found + * in 'hard_block_recog.h'. The port + * information of the hard blocks are stored + * in here. + * + */ bool create_and_initialize_all_hard_block_ports(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; 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; @@ -184,6 +404,7 @@ bool create_and_initialize_all_hard_block_ports(t_model* hard_block_arch_model, // handle output ports hard_block_port_index += extract_and_store_hard_block_model_ports(storage_of_hard_block_info, output_ports, hard_block_arch_model_name,hard_block_port_index, OUTPUT_PORTS); + // check to see if the hard block has no ports if (hard_block_port_index == HARD_BLOCK_WITH_NO_PORTS) { @@ -194,35 +415,111 @@ bool create_and_initialize_all_hard_block_ports(t_model* hard_block_arch_model, return result; } +/** + * @details Creates and initializes a 't_hard_block_port_info' + * structure. This structure is then stored within + * the 't_hard_block_recog' structure. + * + * @param storage_of_hard_block_info This is a data structure of type + * 't_hard_block_recog', which can be found + * in 'hard_block_recog.h'. The port + * information of the hard blocks are stored + * in here. + * + * @param hard_block_type_name The name of a hard block in the architecture + * file. Will be used to index the structure + * created in here when storing it inside + * the 't_hard_block_recog' structure. + */ void create_hard_block_port_info_structure(t_hard_block_recog* storage_of_hard_block_info, std::string hard_block_type_name) { t_hard_block_port_info curr_hard_block_port_storage; + // initialize with default parameters (curr_hard_block_port_storage.hard_block_ports).pointer = NULL; (curr_hard_block_port_storage.hard_block_ports).allocated_size = 0; (curr_hard_block_port_storage.hard_block_ports).array_size = 0; - + + /* store the newly created structure. Since this structure will + preserve port information for a single hard block type within + the FPGA architecture, we will use the corresponding hard block + name as the index when storing this newly created structure. + */ storage_of_hard_block_info->hard_block_type_name_to_port_info.insert({hard_block_type_name,curr_hard_block_port_storage}); return; } +/** + * @details The port information for all new types of hard blocks + * can be found within the FPGA architecture. For each hard block + * the ports can be found in a structure called 't_model_ports' + * (found in 'logic_types.h'). The ports are arranged in a linked lsit + * structure. + * + * THis function goes through the 't_model_ports' and stores them + * within a 't_node_port_association' structure (found in 'vqm_dll.h'). + * And instead of a linked list, the ports are stored in an array + * within a 't_array_ref' structure (found in 'vqm_dll.h'). Finally, + * the port array is stored within the 't_hard_block_port_info' + * (found in 'hard_block_recog.h') that is associated to the specific + * hard block the ports belong to. + * + * We need to do this conversion because the hard blocks that will + * eventually added to the netlist will be of type 't_node' and they + * store ports in the form of a 't_node_port_association' array. + * Additionally, for ports that are bussed, initially, they were + * represented as a single 't_model_port' structure with the size + * of the port included, whereas they need to be seperated into + * individual ports (which is also done here). + * + * @param storage_of_hard_block_info This is a data structure of type + * 't_hard_block_recog', which can be found + * in 'hard_block_recog.h'. The port + * information of the hard blocks are stored + * in here. + * + * @param curr_hard_block_model_port This is a 't_model_port' structure (found + * in 'logic_types.h') that represents a port + * for a hard block. + * + * @param curr_hard_block_type_name A string that represents the specific type + * of hard block the ports that are being + * converted too belong to. + * + * @param port_index A tracker variable that indexes each port within the + * port array. For example, if we had 3 ports (test, test_1 + * , test_2) and they were sized 1,3,5 respectively. Then + * after processing test, port index will be 0, then after + * processing test_1, port_index will be 1, and finally + * port_index will be 5. port index identifies the index at + * which each port starts. + * + * @param port_type A string that describes whether the ports that are + * being processed are input or output ports. + * + */ int extract_and_store_hard_block_model_ports(t_hard_block_recog* storage_of_hard_block_info, t_model_ports* curr_hard_block_model_port, std::string curr_hard_block_type_name,int port_index, std::string port_type) { t_array_ref* equivalent_hard_block_node_port_array = NULL; int starting_port_index = port_index; + /* 't_model_ports' is setup as a linked list structure. + So iterate through the list.*/ while (curr_hard_block_model_port != NULL) { + // convert the current port from the 't_model_port' to 't_node_port_association structure. and store it inside an array. equivalent_hard_block_node_port_array = convert_hard_block_model_port_to_hard_block_node_port(curr_hard_block_model_port); + // take the converted port array from above and store it store_hard_block_port_info(storage_of_hard_block_info, curr_hard_block_type_name, curr_hard_block_model_port->name, &equivalent_hard_block_node_port_array, &port_index); curr_hard_block_model_port = curr_hard_block_model_port->next; } + // check to see whether the hard block has no input or output ports if (starting_port_index == port_index) { VTR_LOG_WARN("Model '%s' found in the architecture file does not have %s ports\n", curr_hard_block_type_name.c_str(), port_type.c_str()); @@ -231,6 +528,18 @@ int extract_and_store_hard_block_model_ports(t_hard_block_recog* storage_of_hard return port_index; } +/** + * @details Given a port for hard block in the form of a + * 't_model_port' structure, this function creates an + * equivalent port in the form of a 't_node_port_association' + * structure. The created ports are then stored within an + * array. + * + * @param hard_block_model_port This is a 't_model_port' structure (found + * in 'logic_types.h') that represents a port + * for a hard block. + * + */ t_array_ref* convert_hard_block_model_port_to_hard_block_node_port(t_model_ports* hard_block_model_port) { t_node_port_association* curr_hard_block_node_port = NULL; @@ -241,6 +550,7 @@ t_array_ref* convert_hard_block_model_port_to_hard_block_node_port(t_model_ports //create memory to store the port array port_array = create_and_initialize_t_array_ref_struct(); + // if a port is a bus, we need to create seperate port structures for each and every signal of the bus for (int port_index = 0; port_index < port_size; port_index++) { // hard blocks will not have indexed wire assignments @@ -262,12 +572,30 @@ t_array_ref* convert_hard_block_model_port_to_hard_block_node_port(t_model_ports } +/** + * @details Creates a unconnected hard block port in the form of the + * form of a 't_node_port_association' structure (found in + * 'vqm_dll.h'). + * + * @param port_name A string describing the name of the port to be + * created. + * + * @param port_index If the port is a bus, then this parameter specifies + * the index within the bus that the port will be + * created for. + * + * @param wire_index If the assigned net to this port is a bus, then this + * parameter specifies the index of the net that is + * associated with this port. + * + */ t_node_port_association* create_unconnected_node_port_association(char *port_name, int port_index, int wire_index) { + // allocate memory for the port t_node_port_association* curr_hard_block_node_port = NULL; - curr_hard_block_node_port = (t_node_port_association*)vtr::malloc(sizeof(t_node_port_association)); + // initialize all the port parameters curr_hard_block_node_port->port_name = (char*)vtr::malloc(sizeof(char) * (strlen(port_name) + 1)); strcpy(curr_hard_block_node_port->port_name, port_name); @@ -278,22 +606,54 @@ t_node_port_association* create_unconnected_node_port_association(char *port_nam return curr_hard_block_node_port; } -// need the hard block name itself +/** + * @details All the port information for a given hard block + * is stored inside an array that is located within + * a 't_hard_block_port_info' structure (found in + * 'hard_block_recog.h'). This function takes a single + * port and appends it to an array of other ports that + * belong to the hard block. This function also stores the + * index of where the previously appended port begins within + * the port array. + * + * @param storage_of_hard_block_port_info This is a data structure of type + * 't_hard_block_recog', which can be found + * in 'hard_block_recog.h'. The port + * information of the hard blocks are stored + * in here. + * + * @param curr_hard_block_type_name A string that represents the name of the + * hard block type the port to store belongs + * to. + * + * @param curr_port_name A string that represents the name of the current + * port to store. + * + * @param curr_port_array A 't_array_def' structure (found in 'vqm_dll.h') + * that contains the current port to store. + * + * @param port_index A integer that defines the index within the port array + * that the current port is located at. + * + */ void store_hard_block_port_info(t_hard_block_recog* storage_of_hard_block_port_info, std::string curr_hard_block_type_name,std::string curr_port_name, t_array_ref** curr_port_array, int* port_index) { std::unordered_map::iterator curr_port_info = ((storage_of_hard_block_port_info->hard_block_type_name_to_port_info).find(curr_hard_block_type_name)); + // appending the current port to the array of ports for the current hard block copy_array_ref(*curr_port_array, &(curr_port_info->second).hard_block_ports); // insert the port name to the current index (curr_port_info->second).port_name_to_port_start_index.insert(std::pair(curr_port_name, *port_index)); + // update the index that the next port will begin at *port_index += (*curr_port_array)->array_size; // store the current port size (curr_port_info->second).port_name_to_port_size.insert(std::pair(curr_port_name, (*curr_port_array)->array_size)); + /* we don't need to the current port anymore, since it is appended to the array of ports for the corresponding hard block. So delete the memory for it.*/ vtr::free((*curr_port_array)->pointer); vtr::free(*curr_port_array); @@ -302,10 +662,22 @@ void store_hard_block_port_info(t_hard_block_recog* storage_of_hard_block_port_i return; } +/** + * @details Given two 't_array_ref' structures (found in 'vqm_dll.h'), + * this function copies the array contents from one structure and + * appends it the other structure. + * + * @param array_ref_orig The 't_array_ref' structure that will have its + * array contents copied. + * + * @param array_ref_copy The 't_array_ref' structure that will have copied + * contents added to its array. + */ void copy_array_ref(t_array_ref* array_ref_orig, t_array_ref* array_ref_copy) { int array_size = array_ref_orig->array_size; + // append the array elements from one 't_array_ref' structure to the other for (int index = 0; index < array_size; index++) { append_array_element((intptr_t)array_ref_orig->pointer[index], array_ref_copy); @@ -314,12 +686,18 @@ void copy_array_ref(t_array_ref* array_ref_orig, t_array_ref* array_ref_copy) return; } +/** + * @details Creates and initializes an empty 't_array_ref' structure. + * + */ t_array_ref* create_and_initialize_t_array_ref_struct(void) { t_array_ref* empty_array = NULL; empty_array = (t_array_ref*)vtr::malloc(sizeof(t_array_ref)); + // initially the 't_array_ref' structure has no contents. + // Making sure that the structure parameters reflect that.s empty_array->pointer = NULL; empty_array->array_size = 0; empty_array->allocated_size = 0; @@ -328,6 +706,33 @@ t_array_ref* create_and_initialize_t_array_ref_struct(void) } +/** + * @details Every time a hard block instance is added to module + * (netlist), a reference is stored inside a list of + * hard blocks within the design. This function returns + * an index to a hard block instance within the above list + * using the hard block instance name. + * + * @param module_hard_block_node_refs_and_info This is a data structure of type + * 't_hard_block_recog', which can be found + * in 'hard_block_recog.h'. This datastructure + * stores a list of references to the hard + * block instances within the design. + * This parameter stores a map data structure + * that associates hard block instance names + * to their index in the list. + * + * @param curr_module_node_info This is a 't_hard_block_port_info' + * structure and can be found in + * 'hard_block_recog.h'. This structure + * stores the port information about + * the hard block type the current + * instance is of. In this function, this + * parameter is used to determine the hard + * block instance name and the type of hard + * block. + * + */ int find_hard_block_instance(t_hard_block_recog* module_hard_block_node_refs_and_info, t_parsed_hard_block_port_info* curr_module_node_info) { int hard_block_instance_index = 0; @@ -362,6 +767,33 @@ int find_hard_block_instance(t_hard_block_recog* module_hard_block_node_refs_and } +/** + * @details This function creates a new hard block instance + * node ('t_node' structure). The newly created node is + * added to the module (netlist). A reference to the node + * is then stored for future access. + * + * @param module_node_list This is a 't_array_def' structure that stores + * all the nodes within the module (netlist) of the + * design. + * + * @param module_hard_block_node_refs_and_info This is a data structure of type + * 't_hard_block_recog', which can be found + * in 'hard_block_recog.h'. This data structure + * stores a list of references to the hard + * block instances within the design. + * + * @param curr_module_node_info This is a 't_hard_block_port_info' + * structure and can be found in + * 'hard_block_recog.h'. This structure + * stores the port information about + * the hard block type the current + * instance is of. In this function, this + * parameter is used to determine the hard + * block instance name and the type of hard + * block. + * + */ int create_new_hard_block_instance(t_array_ref* module_node_list, t_hard_block_recog* module_hard_block_node_refs_and_info, t_parsed_hard_block_port_info* curr_module_node_info) { // index to to the new 't_hard_block' struct being created here that is found within the 'hard_block_instances' vector @@ -394,6 +826,48 @@ int create_new_hard_block_instance(t_array_ref* module_node_list, t_hard_block_r return created_hard_block_instance_index; } +/** + * @details This function takes a lut or dff node that represents a hard + * block port and takes the net connected to it and assigns it + * to the corresponding port in the hard block instance node in the + * module (netlist). + * + * The following steps are performed: + * - The lut or dff node is processed to find the port within those + * nodes that is connected to an external net. + * - The corresponding hard block instance port that is represented by + * the lut or dff is then found. + * - Finally, the net connected to the lut or dff port found previously + * is then assigned to the hard block instance port. + * + * @param curr_module_node A 't_node' structure (found in 'vqm_dll.h') + * that represents a lut or dff within the module + * (netlist). + * + * @param curr_module_node_info This is a 't_hard_block_port_info' + * structure and can be found in + * 'hard_block_recog.h'. This structure + * stores the port information about + * the hard block type the current + * instance is of. In this function, this + * parameter is used to determine the hard + * block instance name and the type of hard + * block. + * + * @param module_hard_block_node_refs_and_info This is a data structure of type + * 't_hard_block_recog', which can be found + * in 'hard_block_recog.h'. This data structure + * stores a list of references to the hard + * block instances within the design. + * + * @param curr_hard_block_instance_index an integer that identifies a single + * hard block instance within the list + * of all hard blocks in the netlist. This + * parameter identifies the hard block + * that contains the corresponding + * lut or dff node. + * + */ void assign_net_to_hard_block_instance_port(t_node* curr_module_node, t_parsed_hard_block_port_info* curr_module_node_info, t_hard_block_recog* module_hard_block_node_refs_and_info, int curr_hard_block_instance_index) { t_hard_block* curr_hard_block_instance = &(module_hard_block_node_refs_and_info->hard_block_instances[curr_hard_block_instance_index]); @@ -412,6 +886,26 @@ void assign_net_to_hard_block_instance_port(t_node* curr_module_node, t_parsed_h return; } +/** + * @details The luts and dff that represent hard block ports + * generally contain a number of ports themselves. This + * function determines the port within the luts and dff + * that is connected to an external (we need to connect this + * net to the hard block port). + * + * We find that for luts, there are generally two ports, an + * input port (dataa, datab, datac, datad, datae, dataf) and + * and output port (combout). When processing luts, this function + * returns the port that is not named 'combout'. + * + * When looking at dff, there are three ports (clk, d, q). When + * processing dff, this function returns the 'q' port. + * + * @param curr_module_node A 't_node' structure (found in 'vqm_dll.h') + * that represents a lut or dff within the module + * (netlist). + * + */ t_node_port_association* get_lut_dffeas_port_connected_to_hard_block_instance_net(t_node* curr_module_node) { t_node_port_association* port_connected_to_hard_block_instance_net = NULL; @@ -489,6 +983,36 @@ t_node_port_association* get_lut_dffeas_port_connected_to_hard_block_instance_ne return port_connected_to_hard_block_instance_net; } +/** + * @details All the ports of a hard block are arranged within + * an. This function returns the index of where a port + * is located within the array. + * + * @param curr_hard_block_type_port_info This is a 't_hard_block_port_info' + * structure and can be found in + * 'hard_block_recog.h'. This structure + * stores the port information about + * the hard block type the current + * instance is of. In this function, this + * parameter is used to determine the + * indices of ports within the port + * array of a hard block. + * + * @param curr_module_node_info This is a 't_hard_block_port_info' + * structure and can be found in + * 'hard_block_recog.h'. This structure + * stores the port information about + * the hard block type the current + * instance is of. In this function, this + * parameter is used to determine the hard + * block instance name and the type of hard + * block. + * + * @param curr_module_node A 't_node' structure (found in 'vqm_dll.h') + * that represents a lut or dff within the module + * (netlist). Used to report error information. + * + */ int identify_port_index_within_hard_block_type_port_array(t_hard_block_port_info* curr_hard_block_type_port_info, t_parsed_hard_block_port_info* curr_module_node_info, t_node* curr_module_node) { int identified_port_index = 0; @@ -530,7 +1054,7 @@ int identify_port_index_within_hard_block_type_port_array(t_hard_block_port_info // now we check whether the port index is within the port range // - // finf the port size of the current port (using internal mapping structure found in the hard block port info struct) + // if the port size of the current port (using internal mapping structure found in the hard block port info struct) // this should result in a valid value as we already verfied whether the port exists found_port_size = curr_hard_block_type_port_info->port_name_to_port_size.find(curr_module_node_info->hard_block_port_name); @@ -548,6 +1072,40 @@ int identify_port_index_within_hard_block_type_port_array(t_hard_block_port_info } +/** + * @details This function connects a port of a given hard block instance node + * to a net within the netlist. The net here is a 't_pin_def' + * structure (found in 'vqm_dll.h'). + * + * @param curr_module_node 't_node' structure + * (found in 'vqm_dll.h') that represents + * a lut or dff node within the module (netlist). + * This is used to get the node name. + * + * @param curr_hard_block_instance a 't_hard_block' structure that represents + * a hard block instance. + * + * @param port_to_assign_index The specific port within the port array that we + * need to connect the net to. + * + * @param port_connected_to_hard_block_instance_net This is a + * 't_node_port_association' structure + * that represents a port that is + * currently connected to the net we + * want to assign to the hard block. + * This port is part of a lut or dff + * node. + * + * @param curr_module_node_info This is a 't_hard_block_port_info' + * structure and can be found in + * 'hard_block_recog.h'. This structure + * stores the port information about + * the hard block type the current + * instance is of. In this function, this + * parameter is used to determine the hard + * block instance name and the type of hard + * block. + */ void handle_net_assignment(t_node* curr_module_node, t_hard_block* curr_hard_block_instance, int port_to_assign_index, t_node_port_association* port_connected_to_hard_block_instance_net, t_parsed_hard_block_port_info* curr_module_node_info) { std::string curr_module_node_name = curr_module_node->name; @@ -579,6 +1137,20 @@ void handle_net_assignment(t_node* curr_module_node, t_hard_block* curr_hard_blo return; } +/** + * @details Looking at the figure at the top, there are essentially + * two types of luts, that represents hard block ports. The first + * type of lut represents input ports and the second type of lut + * represents an output port. + * + * This function checks to see whether a ndde is a lut that represents + * and output or not. + * + * @param curr_module_node A 't_node' structure + * (found in 'vqm_dll.h') that represents + * a lut or dff node within the module (netlist). + * + */ bool is_hard_block_port_legal(t_node* curr_module_node) { @@ -586,7 +1158,7 @@ bool is_hard_block_port_legal(t_node* curr_module_node) std::string curr_module_node_type = curr_module_node->type; - // now we check the direction of the port as input or whether the node is a DFF + // now we check whether the current node is a lut that represents an input port or the current node is a DFF if ((curr_module_node->number_of_ports != LUT_OUTPUT_PORT_SIZE) || (!(curr_module_node_type.compare(DFF_TYPE)))) { result = true; @@ -596,6 +1168,31 @@ bool is_hard_block_port_legal(t_node* curr_module_node) } +/** + * @details This function creates a 't_array_ref' structure + * to store a new array of ports that represent the + * connectivity of a hard block instance within the design. + * + * All the new hard blocks in the design are previously + * processed and a template of their ports are stored inside + * a 't_hard_block_port_info' (found in hard_block_recog.h') structure. + * By template, we mean that all the default information about the + * ports are stored and the ports are unconnected. + * + * In this function, the 't_array_ref' structure is initialized + * by copying the port information stored inside the + * 't_hard_block_port_info' structure. + * + * @param curr_hard_block_type_port_info This is a 't_hard_block_port_info' + * structure and can be found in + * 'hard_block_recog.h'. This structure + * stores the port information about + * the hard block type the current + * instance is of. In this function, this + * parameter is used to copy the port + * information about the hard block. + * + */ t_array_ref* create_unconnected_hard_block_instance_ports(t_hard_block_port_info* curr_hard_block_type_port_info) { t_array_ref* template_for_hard_block_ports = &(curr_hard_block_type_port_info->hard_block_ports); @@ -632,6 +1229,33 @@ t_array_ref* create_unconnected_hard_block_instance_ports(t_hard_block_port_info } +/** + * @details This function creates a 't_node' structure + * for a hard block instance that need to be added to the + * netlist. The following steps are performed on the + * 't_node' structure: + * - store the array of unconnected ports to describe + * the connectivity of this hard block instance + * - store the name of the hard block instance and also its + * type + * + * @param curr_hard_block_instance_ports A 't_array_ref' structure (found in + * 'vqm_dll.h') that contains an array + * of unconnected ports that represent + * the connectivity of a hard block + * instance. + * + * @param curr_hard_block_instance_info This is a 't_hard_block_port_info' + * structure and can be found in + * 'hard_block_recog.h'. This structure + * stores the port information about + * about the hard block type the current + * instance is of. In this function, this + * parameter is used to determine the + * total number of ports in the hard + * block. + * + */ t_node* create_new_hard_block_instance_node(t_array_ref* curr_hard_block_instance_ports, t_parsed_hard_block_port_info* curr_hard_block_instance_info) { t_node* new_hard_block_instance = NULL; @@ -669,6 +1293,51 @@ t_node* create_new_hard_block_instance_node(t_array_ref* curr_hard_block_instanc } +/** + * @details This function performs the following steps: + * - Stores a reference to a newly added hard block node + * to the module (netlist) and as well as information + * about the port assignments of the hard block into a + * 't_hard_block' datastructure (found in 'hard_block_recog.h') + * - The 't_hard_block' is then stored into a vector of other + * hard blocks in the design + * - Finally, the index of the 't_hard_block' structure within the + * previous vector is stored inside a map datastructure and the + * key was the name of the hard block instance within the design. + * This was needed so that the hard block could be found quicly with + * just its name. + * + * @param module_hard_block_node_refs_and_info This is a data structure of type + * 't_hard_block_recog', which can be found + * in 'hard_block_recog.h'. The reference to + * the newly added hard block instance in the + * design will be stored in here. + * + * @param curr_hard_block_type_port_info This is a 't_hard_block_port_info' + * structure and can be found in + * 'hard_block_recog.h'. This structure + * stores the port information about + * about the hard block type the current + * instance is of. In this function, this + * parameter is used to determine the + * total number of ports in the hard + * block. + * + * @param new_hard_block_instance_node A 't_node' structure + * (found in 'vqm_dll.h') that represents + * a single hard block instance within the + * design. + * + * @param curr_module_node_info This is a 't_parsed_hard_block_port_info' + * structure. It is defined in 'hard_block_recog.h'. + * This structure is created to store relevant + * information about a hard block port + * whenever a node is identified as representing + * a hard block port. In this function, this + * parameter provides the name of the corresponding + * hard block instance within the design. + * + */ int store_new_hard_block_instance_info(t_hard_block_recog* module_hard_block_node_refs_and_info, t_hard_block_port_info* curr_hard_block_type_port_info, t_node* new_hard_block_instance_node, t_parsed_hard_block_port_info* curr_module_node_info) { int new_hard_block_instance_index = 0; @@ -694,6 +1363,16 @@ int store_new_hard_block_instance_info(t_hard_block_recog* module_hard_block_nod return new_hard_block_instance_index; } +/** + * @details Given an arbritary array of pointers, this function + * stores the array and its properties into a + * 't_array_ref' structure. + * + * @param array_to_store array of pointers + * + * @param array_size size of the array passed to this function + * + */ t_array_ref* create_t_array_ref_from_array(void** array_to_store, int array_size) { t_array_ref* array_reference = NULL; @@ -701,9 +1380,10 @@ t_array_ref* create_t_array_ref_from_array(void** array_to_store, int array_size array_reference = (t_array_ref*)vtr::malloc(sizeof(t_array_ref)); + // determine how large the array is array_allocated_size = calculate_array_size_using_bounds(array_size); - // assign the array and its corresponding information to the array ref struct + // assign the array and its corresponding size information to the array ref struct array_reference->allocated_size = array_allocated_size; array_reference->array_size = array_size; array_reference->pointer = array_to_store; @@ -712,6 +1392,27 @@ t_array_ref* create_t_array_ref_from_array(void** array_to_store, int array_size } +/** + * @details Given a node within the module (netlist) that is a lut or dff + * which represents a hard block port, this function identifies + * the following information: + * - The name of the hard block instance which the current port that + * the node represents belongs too + * - The specific hard block this node is a part of (figuring out + * which type of hard block the port that the node represents + * belongs too) + * - The name of the port that the current node represents + * - If the port is a bus, then the specific index the current + * node represents + * + * @param curr_module_node A 't_node' structure (found in 'vqm_dll.h') that + * is a lut or dff which represents a port of + * hard block. + * + * @param hard_block_type_name_list A list of the hard block names that need + * to be properly added to the netlist. + * + */ t_parsed_hard_block_port_info extract_hard_block_port_info_from_module_node(t_node* curr_module_node, std::vector* hard_block_type_name_list) { std::string curr_module_node_name = curr_module_node->name; @@ -756,6 +1457,34 @@ t_parsed_hard_block_port_info extract_hard_block_port_info_from_module_node(t_no } +/** + * @details Given a string, this function splits the string into multiple + * pieces by a delimiter character. + * + * All the node names within the module (netlist) are composed of + * multiple elements based on a nodes 'hierarchy' within the design. + * + * For example: + * '\router:test_noc_router|sc_flit[0]~0_I' + * + * In the node name above, the first component is + * '\router:test_noc_router' and the second component + * is 'sc_flit[0]~0_I'. The first component in this example + * describes the name of the module and the second component + * describes the specific port of the module. We want to divide + * the node name into multiple components and this is done within + * this function. + * + * @param original_node_name The name of a node within the module (netlist). + * + * @param node_name_components A list of strings that are seperated components + * of the original_node_name string. + * + * @param delimiter A character that will be used to seperate the + * original_node_name string above into multiple + * pieces. + * + */ void split_node_name(std::string original_node_name, std::vector* node_name_components, std::string delimiter) { @@ -780,21 +1509,55 @@ void split_node_name(std::string original_node_name, std::vector* n return; } +/** + * @details This function iterates through a list of hard + * block names and checks to see if any of the + * names are a substring within a given t_module (netlist) + * node name. If a substring is found, then the matched + * hard block name is returned. The returned name is the + * basically the type of hard block this node belongs to. + * + * @param hard_block_type_name_list A list of the hard block names that need + * to be properly added to the netlist. + * + * @param curr_node_name_component The name of node within the t_module + * structure. + * + */ std::string identify_hard_block_type(std::vector* hard_block_type_name_list, std::string curr_node_name_component) { std::vector::iterator hard_block_type_name_traverser; std::string hard_block_type_name_to_find; + + // stores the matched hard block name. Default is empty, meaning that + // nothing was matched std::string hard_block_type = ""; size_t match_result = 0; + // iterate through each hard block name in the list for (hard_block_type_name_traverser = hard_block_type_name_list->begin(); hard_block_type_name_traverser != hard_block_type_name_list->end(); hard_block_type_name_traverser++) - { + { + // adding the colon operator to the end of the current hard block name + // ex. 'test' -> 'test:' + /* If a node belongs to a hard block, then the hard block name is + generally followed by a colon operator, which is why need to append it. + for a 'router' block we can expect something like this: + \router:test_noc_router|sc_flit[8]~reg0_I, where router is follwed by : + + This also helps ignore invalid cases where a block instantiation has + a hard block name within it, even though the block is not of that hard + block type. + For example: + test_block router_one + */ hard_block_type_name_to_find.assign(*hard_block_type_name_traverser + HARD_BLOCK_TYPE_NAME_SEPERATOR); match_result = curr_node_name_component.find(hard_block_type_name_to_find); + // check to see if the node belongs to the current hard block type + // (the current hard block name is a substring within the node name) if (match_result != std::string::npos) { hard_block_type.assign(*hard_block_type_name_traverser); @@ -806,13 +1569,29 @@ std::string identify_hard_block_type(std::vector* hard_block_type_n return hard_block_type; } +/** + * @details Given a list of strings, this function combines the strings + * together using a delimitter and generates a combined string. + * + * @param node_name_components A list of strings that will be combined + * together to generate a single string output. + * @param delimiter A character that will be used to seperate the list elements + * above in the generated string output. + * + */ std::string construct_hard_block_name(std::vector*node_name_components, std::string delimiter) { // stores the full name of the hard block the current node is part of, the current node represents a port of a hard block std::string curr_hard_block_name = ""; /* the hard block name should not include the specific port the current node represents (so we reduce the size by 1 to remove it when constructing the hard block name) - the last index of the node name components vector contains the port information, so by reducing the size of the vector by one we can ignore the port info when constructing the hard block name */ + the last index of the node name components vector contains the port information, so by reducing the size of the vector by one we can ignore the port info when constructing the hard block name + + For example, if the current node name for a 'router' block was: + '\router:test_noc_router|sc_flit[8]~reg0_I' + we know that the 'sc_flit[8]~reg0_I' is a specific port, so + we can remove it when constructing the hard block name. Which + would just be '\router:test_noc_router|'. */ int number_of_node_name_components = node_name_components->size() - 1; // go through the node name components and combine them together to form the hard block name. @@ -825,6 +1604,33 @@ std::string construct_hard_block_name(std::vector*node_name_compone } +/** + * @details Given a node in the module (netlist) that we know represents + * a hard block port, this function takes a component of the node name + * and determines the specific hard block port and as well as the + * index of the port if it is a bus. The determined values are then + * stored. + * + * @param curr_hard_block_port This is a 't_parsed_hard_block_port_info' + * structure. It is defined in 'hard_block_recog.h'. + * This structure is created to store relevant + * information about a hard block port + * whenever a node is identified as representing + * a hard block port. + * + * @param curr_node_name_component Whenever a node is identified as representing + * a hard block port, only a portion of the name + * contains useful information about the hard block port. + * For example, suppose a node name for a + * 'router' block port was: + * '\router:test_noc_router|sc_flit[8]~reg0_I' + * + * Looking at the name above, only the + * component 'sc_flit[8]~reg0_I' contains + * information above the port. So that + * component is passed for this parameter. + * + */ void identify_hard_block_port_name_and_index (t_parsed_hard_block_port_info* curr_hard_block_port, std::string curr_node_name_component) { // identifer to check whether the port defined in the current node name is a bus (ex. payload[1]~QIC_DANGLING_PORT_I) @@ -860,6 +1666,24 @@ void identify_hard_block_port_name_and_index (t_parsed_hard_block_port_info* cur return; } +/** + * @details This function removes all the nodes in the module (netlist) + * that are luts and dff which represent hard block ports. After + * identifying and adding the necessary hard block to the netlist + * the lut and dff that represent the hard block ports are not + * required, so they need to be removed from the netlist. + * + * @param main_module This contains all the netlist information, such as luts, + * flip flops, and other types of blocks. All the nets within + * the netlist are also included. + * + * @param module_hard_block_node_refs_and_info This is a data structure of type + * 't_hard_block_recog', which can be found + * in 'hard_block_recog.h'. The full list + * of lut and dff nodes that need to be + * removed should be found here. + * + */ void remove_luts_dffeas_nodes_representing_hard_block_ports(t_module* main_module, t_hard_block_recog* module_hard_block_node_refs_and_info) { // reference to the list of luts/dffeas nodes we need to remove @@ -871,16 +1695,12 @@ void remove_luts_dffeas_nodes_representing_hard_block_ports(t_module* main_modul // iterator to go through the list of nodes we will be removing std::vector::iterator node_to_remove; - // keep track of all the nodes we removed from the module node array - //int number_of_nodes_removed = 0; - // go through the list of nodes we need to remove and delete them // from the node array within the module for(node_to_remove = list_of_nodes_to_remove->begin(); node_to_remove != list_of_nodes_to_remove->end(); node_to_remove++) { remove_node(*node_to_remove, module_node_list, number_of_nodes_in_module); - //number_of_nodes_removed++; } // we need to fix the gaps created in the node array after removing all luts/dffeas nodes previously @@ -889,10 +1709,28 @@ void remove_luts_dffeas_nodes_representing_hard_block_ports(t_module* main_modul return; } +/** + * @details This function goes through all the newly added hard block nodes + * to the module (netlsit) and checks to see that every port has a + * valid connected to a net. If a port is unassigned for any hard + * block, then an error is thrown. + * + * We expect every hard block should have all its port assigned to a + * net, even if the connection is 'ground' of 'vdd. Having an + * unconnected port implies that the generate vqm netlist was + * incorrect and we check for this here. + * + * @param module_hard_block_node_refs_and_info This is a data structure of type + * 't_hard_block_recog', which can be found + * in 'hard_block_recog.h'. The full list + * of newly added hard block nodes need to be + * stored in here. + * + */ void verify_hard_blocks(t_hard_block_recog* module_hard_block_node_refs_and_info) { - // IF we find a hard block instance that has ports unassigned, we store its information in the variables below + // If we find a hard block instance that has ports unassigned, we store its information in the variables below t_node* incomplete_hard_block_instance = NULL; t_node_port_association* temp_port = NULL; std::string incomplete_hard_block_instance_name = ""; @@ -946,6 +1784,26 @@ void verify_hard_blocks(t_hard_block_recog* module_hard_block_node_refs_and_info } +/** + * @details This function deletes any memory that was allocated + * to store the port information of the new types of + * hard blocks (internally modelling them). + * + * We need to store all the port information for each + * and every new type of hard block. This is done by + * dynamically creating 't_hard_block_port_info' structures + * for each hard block. We handle the deletion of this + * memory here. + * + * @param hard_block_type_name_to_port_info_map A map datastrcuture + * that contains all the + * 't_hard_block_port_info' structures, + * which store the port information + * for all the new hard blocks. This + * datastrcuture can be found within + * the 't_hard_block_recog' structure. + * + */ void delete_hard_block_port_info(std::unordered_map* hard_block_type_name_to_port_info_map) { std::unordered_map::iterator curr_hard_block_port_info = hard_block_type_name_to_port_info_map->begin(); @@ -966,6 +1824,12 @@ void delete_hard_block_port_info(std::unordered_map Date: Thu, 14 Oct 2021 16:19:17 -0400 Subject: [PATCH 25/31] privatized local functions --- utils/vqm2blif/src/base/hard_block_recog.cpp | 71 ++++++++++++++++ utils/vqm2blif/src/base/hard_block_recog.h | 85 +++++--------------- 2 files changed, 91 insertions(+), 65 deletions(-) diff --git a/utils/vqm2blif/src/base/hard_block_recog.cpp b/utils/vqm2blif/src/base/hard_block_recog.cpp index bf1199f33d3..be03113fa5c 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.cpp +++ b/utils/vqm2blif/src/base/hard_block_recog.cpp @@ -124,6 +124,77 @@ #include "hard_block_recog.h" +//============================================================================================ +// INTERNAL FUNCTION DECLARATIONS +//============================================================================================ + +void initialize_hard_block_models(t_arch*, std::vector*, t_hard_block_recog*); + +void process_module_nodes_and_create_hard_blocks(t_module*, std::vector*, t_hard_block_recog*); + +bool create_and_initialize_all_hard_block_ports(t_model*, t_hard_block_recog*); + +void create_hard_block_port_info_structure(t_hard_block_recog*, std::string); + +int extract_and_store_hard_block_model_ports(t_hard_block_recog*, t_model_ports*, std::string, int, std::string); + +t_array_ref* convert_hard_block_model_port_to_hard_block_node_port(t_model_ports*); + +t_node_port_association* create_unconnected_node_port_association(char*, int ,int); + +void store_hard_block_port_info(t_hard_block_recog*, std::string, std::string,t_array_ref**, int*); + +void copy_array_ref(t_array_ref*, t_array_ref*); + +t_array_ref* create_and_initialize_t_array_ref_struct(void); + +int find_hard_block_instance(t_hard_block_recog*, t_parsed_hard_block_port_info*); + +void assign_net_to_hard_block_instance_port(t_node*, t_parsed_hard_block_port_info*, t_hard_block_recog*, int); + +t_node_port_association* get_lut_dffeas_port_connected_to_hard_block_instance_net(t_node*); + +int identify_port_index_within_hard_block_type_port_array(t_hard_block_port_info*, t_parsed_hard_block_port_info*, t_node*); + +void handle_net_assignment(t_node*, t_hard_block*, int, t_node_port_association*, t_parsed_hard_block_port_info*); + +bool is_hard_block_port_legal(t_node*); + +int create_new_hard_block_instance(t_array_ref*, t_hard_block_recog*, t_parsed_hard_block_port_info*); + +t_array_ref* create_unconnected_hard_block_instance_ports(t_hard_block_port_info*); + +t_node* create_new_hard_block_instance_node(t_array_ref*, t_parsed_hard_block_port_info*); + +int store_new_hard_block_instance_info(t_hard_block_recog*, t_hard_block_port_info*, t_node*, t_parsed_hard_block_port_info*); + +t_array_ref* create_t_array_ref_from_array(void**, int); + +void delete_hard_block_port_info(std::unordered_map*); + +t_parsed_hard_block_port_info extract_hard_block_port_info_from_module_node(t_node*, std::vector*); + +std::string identify_hard_block_type(std::vector*, std::string); + +void identify_hard_block_port_name_and_index (t_parsed_hard_block_port_info*, std::string); + +void split_node_name(std::string, std::vector*, std::string); + +std::string construct_hard_block_name(std::vector*, std::string); + +void remove_luts_dffeas_nodes_representing_hard_block_ports(t_module*, t_hard_block_recog*); + +void verify_hard_blocks(t_hard_block_recog*); + +// utility functions + +void store_hard_block_names(char**, int, std::vector*); + +bool sort_hard_blocks_by_valid_connections(t_hard_block, t_hard_block); + +//============================================================================================ +//============================================================================================ + /** * @details This function is the main controller and executes all the * processing steps involved in indentifying new types of hard diff --git a/utils/vqm2blif/src/base/hard_block_recog.h b/utils/vqm2blif/src/base/hard_block_recog.h index d26eee956a5..f7fb4f6dbab 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.h +++ b/utils/vqm2blif/src/base/hard_block_recog.h @@ -201,76 +201,31 @@ typedef struct s_parsed_hard_block_port_info }t_parsed_hard_block_port_info; -/* Function Declarations +/* Global Function Declarations * * For more information about functions, refer to * 'hard_block_recog.cpp' */ +/* +* Function: add_hard_blocks_to_netlist +* +* Goes through a netlist and removes luts/dff that represent +* specific hard block ports and then the corresponding hard block +* is added to the netlist. +* +* Parameters: +* t_module* - A reference to the netlist of the design +* t_arch* - a pointer to the FPGA architecture that design will +* target +* std::vector* - a reference to a list of hard block names + that need to be identified within the + netlist. +* +* std::string - the name of the architecture file (".xml") + std::string - the name of the Quartus generated netlist file (".vqm") +* +*/ void add_hard_blocks_to_netlist(t_module*, t_arch*, std::vector*, std::string, std::string); -void initialize_hard_block_models(t_arch*, std::vector*, t_hard_block_recog*); - -void process_module_nodes_and_create_hard_blocks(t_module*, std::vector*, t_hard_block_recog*); - -bool create_and_initialize_all_hard_block_ports(t_model*, t_hard_block_recog*); - -void create_hard_block_port_info_structure(t_hard_block_recog*, std::string); - -int extract_and_store_hard_block_model_ports(t_hard_block_recog*, t_model_ports*, std::string, int, std::string); - -t_array_ref* convert_hard_block_model_port_to_hard_block_node_port(t_model_ports*); - -t_node_port_association* create_unconnected_node_port_association(char*, int ,int); - -void store_hard_block_port_info(t_hard_block_recog*, std::string, std::string,t_array_ref**, int*); - -void copy_array_ref(t_array_ref*, t_array_ref*); - -t_array_ref* create_and_initialize_t_array_ref_struct(void); - -int find_hard_block_instance(t_hard_block_recog*, t_parsed_hard_block_port_info*); - -void assign_net_to_hard_block_instance_port(t_node*, t_parsed_hard_block_port_info*, t_hard_block_recog*, int); - -t_node_port_association* get_lut_dffeas_port_connected_to_hard_block_instance_net(t_node*); - -int identify_port_index_within_hard_block_type_port_array(t_hard_block_port_info*, t_parsed_hard_block_port_info*, t_node*); - -void handle_net_assignment(t_node*, t_hard_block*, int, t_node_port_association*, t_parsed_hard_block_port_info*); - -bool is_hard_block_port_legal(t_node*); - -int create_new_hard_block_instance(t_array_ref*, t_hard_block_recog*, t_parsed_hard_block_port_info*); - -t_array_ref* create_unconnected_hard_block_instance_ports(t_hard_block_port_info*); - -t_node* create_new_hard_block_instance_node(t_array_ref*, t_parsed_hard_block_port_info*); - -int store_new_hard_block_instance_info(t_hard_block_recog*, t_hard_block_port_info*, t_node*, t_parsed_hard_block_port_info*); - -t_array_ref* create_t_array_ref_from_array(void**, int); - -void delete_hard_block_port_info(std::unordered_map*); - -t_parsed_hard_block_port_info extract_hard_block_port_info_from_module_node(t_node*, std::vector*); - -std::string identify_hard_block_type(std::vector*, std::string); - -void identify_hard_block_port_name_and_index (t_parsed_hard_block_port_info*, std::string); - -void split_node_name(std::string, std::vector*, std::string); - -std::string construct_hard_block_name(std::vector*, std::string); - -void remove_luts_dffeas_nodes_representing_hard_block_ports(t_module*, t_hard_block_recog*); - -void verify_hard_blocks(t_hard_block_recog*); - -// utility functions - -void store_hard_block_names(char**, int, std::vector*); - -bool sort_hard_blocks_by_valid_connections(t_hard_block, t_hard_block); - #endif \ No newline at end of file From 78d4c27734eafa6dab60b77d6926d6af4842e5c8 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Tue, 2 Nov 2021 17:18:23 -0400 Subject: [PATCH 26/31] improved code documentation and formatting --- utils/vqm2blif/src/base/hard_block_recog.cpp | 2 +- utils/vqm2blif/src/base/hard_block_recog.h | 73 +++++++++++++------- 2 files changed, 48 insertions(+), 27 deletions(-) diff --git a/utils/vqm2blif/src/base/hard_block_recog.cpp b/utils/vqm2blif/src/base/hard_block_recog.cpp index be03113fa5c..0431f15b2b3 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.cpp +++ b/utils/vqm2blif/src/base/hard_block_recog.cpp @@ -1,7 +1,7 @@ /* * The purpose of this file is to support netlists that * contain new types of hard blocks. Specifically, user defined -* hard blocks are indetified within the netlist and then instantiated +* hard blocks are identified within the netlist and then instantiated * so that they are later written to the generated .blif file. * * For example, consider a user design that contains a new hard block diff --git a/utils/vqm2blif/src/base/hard_block_recog.h b/utils/vqm2blif/src/base/hard_block_recog.h index f7fb4f6dbab..5e4e6e54e1c 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.h +++ b/utils/vqm2blif/src/base/hard_block_recog.h @@ -1,3 +1,6 @@ +#ifndef HARD_BLOCK_RECOG_H +#define HARD_BLOCK_RECOG_H + /* VQM new primitive hard block recognition header file * * The purpose of this file is to identify and instantiate @@ -10,18 +13,16 @@ * * This file also contains all the declarations of functions that can be * used to interact with and manipulate the main data structures. Additionally, -* some utility functions are added to help identify whether a hard block was * included within the design. For more information, -* refer to 'hard_block_recog.cpp'. +* some utility functions are added to help identify whether a hard block was +* included within the design. +* For more information, refer to 'hard_block_recog.cpp'. * */ // need to use vtr::malloc for memory allocation (only in the files here) -// no need to run VTR assert, after memory allocation, this is checked in the function already - +// no need to rcheck for failed malloc (NULL pointer), this is already checked in vtr::malloc -#ifndef HARD_BLOCK_RECOG_H -#define HARD_BLOCK_RECOG_H // user VTR libraries #include "vqm_dll.h" @@ -63,18 +64,27 @@ // each level of hierarchy (module within module) is seperated by the delimiter character defined below. The last level of hierarchy is the output net of the block #define VQM_NODE_NAME_DELIMITER "|" +// a port that is a bus is a vectored port. So a single port name with multiple indices. +// We use the size of the port to determine whether the port is a bus or not. +// A port size of 1 represents a port that is not a bus, whereas a port size greater than 1 represents a bus. +// So a non-bus port size is represented below #define PORT_NOT_BUS 1 +// We use regex to extract the port name and index from the vqm netlist. +// For example, given the string payload[1]~QIC_DANGLING_PORT_I, we would extract 'payload' and '1'. +// For the case where a port is not a bus, we would just extract the port name. +// Now the extracted information is stored in an array of strings, and the indices of where the port name and index are stored is found below. #define PORT_NAME 1 #define PORT_INDEX 2 +// used to identify the case where a hard block instance is not found within the netlist #define HARD_BLOCK_INSTANCE_DOES_NOT_EXIST -1 // define how flip flops and LUT will be identified within a given node type (within t_node struct) #define LUT_TYPE "stratixiv_lcell_comb" #define DFF_TYPE "dffeas" -// define the number of ports a LUT that represents a hard block instance output port would have +// define the number of output ports a LUT that represents a hard block instance output port would have #define LUT_OUTPUT_PORT_SIZE 1 // names of the output port for a LUT and DFF @@ -88,11 +98,12 @@ /* -* The purpose of this data structure is to -* store the port information (in an array) for an arbritary user defined -* hard block design. Then a mapping is provided which can +* The port information (in an array) for an arbritary user defined +* hard block in the design is stored in s_hard_block_port_info. Then a +* mapping is provided which can * help identify the specific location within the port array -* that a given port name begins at. +* that a given port name begins at. This data structure is created +* for each type of hard block. */ typedef struct s_hard_block_port_info { @@ -115,12 +126,13 @@ typedef struct s_hard_block_port_info * This node will then be stored within a node array and enclosed * within a 't_module' variable (refer to 'vqm_dll.h'). * -* -* The purpose of the data structure below is to keep a reference to a -* single hard block node (one instance of a hard block within the design). * This way, the node can be accessed quickly whenever changes need to be +* A reference to a single hard block node (one instance of a hard block +* within the design) is stored inside s_hard_block, so it essentially +* represents a hard block instance. +* This way, the node can be accessed quickly whenever changes need to be * applied. Additional information about the hard block is also stored as well. * -* THe node itself is stored internally within the a node array. And +* The node itself is stored internally within the a node array. And * located inside a module. */ typedef struct s_hard_block @@ -141,13 +153,11 @@ typedef struct s_hard_block * the names and port info of every type of user defined hard blocks. It * also stores all hard blocks that were instantiated within * the user design and an accompanying data strcuture to quickly identify -* a specific hard block instance. All functiions will primarily interact +* a specific hard block instance. All functions will primarily interact * with this data structure. */ typedef struct s_hard_block_recog { - // names of all the user defined hard blocks - //std::vector* hard_block_type_names; // hb_type_names (probably do not need) // store the port information of each and every type of // user defined hard blocks. All ports connected to each @@ -158,7 +168,8 @@ typedef struct s_hard_block_recog // user design std::vector hard_block_instances; - /* given a specific hard block instance name, we need to quickly + /* + Given a specific hard block instance name, we need to quickly identify the corresponding hard block structure instance. We do this by using the map data structure below, where a hard block instance name is associated with an index @@ -169,17 +180,27 @@ typedef struct s_hard_block_recog /* The luts and dffeas used to model ports are all stored as nodes and we will need to remove them from the netlist after adding all the - hard blocks to the netlist.The ports that are modelled by the luts and dffeas aren't needed once all the hard blocks within the design are added to the netlist.The luts and dffeas are simply repeating the port information, so we can remove them. + hard blocks to the netlist.The ports that are modelled by the luts and dffeas + aren't needed once all the hard blocks within the design are added to the netlist. + The luts and dffeas are simply repeating the port information, so we can remove them. - The nodelist is simply an array. Now deleting lut/dffeas nodes while still creating additional hard block nodes could cause some problems, so we will delete all these nodes at the end. Therefore we need to keep a - reference for all the luts and dffeas nodes that represent hard block ports here, so we can them remove later on.*/ + The nodelist is simply an array. Now deleting lut/dffeas nodes while still creating additional + hard block nodes could cause some problems, so we will delete all these nodes at the end. + Therefore we need to keep a reference for all the luts and dffeas nodes that + represent hard block ports here, so we can them remove later on. + */ std::vector luts_dffeas_nodes_to_remove; // look into using array index instead }t_hard_block_recog; /* -* When we go through the .vqm file, the ports of any user defined hard block * will be represented as a LUT (stratix_lcell), or flip flop (dffeas) (for * more info refer to 'hard_block_recog.cpp'). The generated names found in * the .vqm file for the two previous blocks contain a lot of information * about the hard block. The structure below is used to store the information, -* which includes the hard block name, hard block type, the specfic hard * block port and if the port is a bus, then the specific index. +* When we go through the .vqm file, the ports of any user defined hard block +* will be represented as a LUT (stratix_lcell), or flip flop (dffeas) +* (for more info refer to 'hard_block_recog.cpp'). The generated names found +* in the .vqm file for the two previous blocks contain a lot of information +* about the hard block. The structure below is used to store the information, +* which includes the hard block name, hard block type, the specfic hard +* block port and if the port is a bus, then the specific index. */ typedef struct s_parsed_hard_block_port_info { @@ -195,7 +216,7 @@ typedef struct s_parsed_hard_block_port_info std::string hard_block_port_name = ""; // index of the port defined in the current block (LUT or dffeas) - // initialized to an index equivalent to what a port thas is not a bus would have + // initialized to an index equivalent to what a port that is not a bus would have int hard_block_port_index = DEFAULT_PORT_INDEX; }t_parsed_hard_block_port_info; @@ -228,4 +249,4 @@ typedef struct s_parsed_hard_block_port_info */ void add_hard_blocks_to_netlist(t_module*, t_arch*, std::vector*, std::string, std::string); -#endif \ No newline at end of file +#endif From dfc0a8c36df756361efc87318f8de9c263c920c1 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Wed, 3 Nov 2021 17:33:57 -0400 Subject: [PATCH 27/31] modified new feature argument from identify_and_instantiate_custom_hard_blcoks to insert_custom_hard_blocks --- utils/vqm2blif/src/base/vqm2blif_util.cpp | 2 +- utils/vqm2blif/src/base/vqm2blif_util.h | 2 +- utils/vqm2blif/src/main.cpp | 14 +++++++------- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/utils/vqm2blif/src/base/vqm2blif_util.cpp b/utils/vqm2blif/src/base/vqm2blif_util.cpp index a3633338a6b..51f2da88ebc 100644 --- a/utils/vqm2blif/src/base/vqm2blif_util.cpp +++ b/utils/vqm2blif/src/base/vqm2blif_util.cpp @@ -21,7 +21,7 @@ void print_usage (t_boolean terminate){ cout << "\t-include_unused_subckt_pins\n"; cout << "\t-remove_const_nets\n"; cout << "\t-eblif_format\n"; - cout << "\t-identify_and_instantiate_custom_hard_blocks ...\n"; + cout << "\t-insert_custom_hard_blocks ...\n"; //Hide experimental options by default //cout << "\t-split_multiclock_blocks\n"; //cout << "\t-split_carry_chain_logic\n"; diff --git a/utils/vqm2blif/src/base/vqm2blif_util.h b/utils/vqm2blif/src/base/vqm2blif_util.h index a698473d10e..5d99bed50f3 100644 --- a/utils/vqm2blif/src/base/vqm2blif_util.h +++ b/utils/vqm2blif/src/base/vqm2blif_util.h @@ -84,7 +84,7 @@ enum v_OptionBaseToken OT_INCLUDE_UNUSED_SUBCKT_PINS, OT_EBLIF_FORMAT, OT_UNKNOWN, - OT_IDENTIFY_AND_INSTANTIATE_CUSTOM_HARD_BLOCKS + OT_INSERT_CUSTOM_HARD_BLOCKS }; struct cstrcomp{ //operator structure to compare C-strings within a map class diff --git a/utils/vqm2blif/src/main.cpp b/utils/vqm2blif/src/main.cpp index 7e94dbf0135..3d120763c15 100644 --- a/utils/vqm2blif/src/main.cpp +++ b/utils/vqm2blif/src/main.cpp @@ -141,7 +141,7 @@ t_boolean print_unused_subckt_pins; //user-set flag which controls whether subck //this option to be true. t_boolean eblif_format; //If true, writes circuit in extended BLIF (.eblif) format (supported by YOSYS & VPR) -t_boolean identify_and_instantiate_custom_hard_blocks; // user-set flag. Which if true, helps find and filter user-defined hard blocks within the netlist (based on the supplied hard block names) and then instantiates the hard blocks within the blif file. +t_boolean insert_custom_hard_blocks; // user-set flag. Which if true, helps find and filter user-defined hard blocks within the netlist (based on the supplied hard block names) and then instantiates the hard blocks within the blif file. // or if false, then the netlist is processed without identifying any hard blocks. // this option should only be used if the original user-design contained custom hard-blocks. // The user-defined hard block names need to be provided @@ -380,7 +380,7 @@ int main(int argc, char* argv[]) } // only process the netlist for any custom hard blocks if the user provided valid hard block names - if (identify_and_instantiate_custom_hard_blocks) + if (insert_custom_hard_blocks) { cout << "\n>> Identifying and instantiating custom hard blocks within the netlist.\n"; @@ -501,7 +501,7 @@ void cmd_line_parse (int argc, char** argv, string* sourcefile, string* archfile remove_const_nets = T_FALSE; print_unused_subckt_pins = T_FALSE; eblif_format = T_FALSE; - identify_and_instantiate_custom_hard_blocks = T_FALSE; + insert_custom_hard_blocks = T_FALSE; // temporary storage to hold hard block names from the argument list std::string curr_hard_block_name; @@ -625,7 +625,7 @@ void cmd_line_parse (int argc, char** argv, string* sourcefile, string* archfile case OT_EBLIF_FORMAT: eblif_format = T_TRUE; break; - case OT_IDENTIFY_AND_INSTANTIATE_CUSTOM_HARD_BLOCKS: + case OT_INSERT_CUSTOM_HARD_BLOCKS: // first check whether an accompanying hard block type name was supplied (user provides the names of all the various types of custom hard blocks within the design, essentially this is the module names in their HDL design) if ( i+1 == argc ){ // no hard block type name was supplied so throw an error @@ -645,7 +645,7 @@ void cmd_line_parse (int argc, char** argv, string* sourcefile, string* archfile // When we come here, we need to finish processing further command line arguments for hard block type names. Since we have a different command-line option. // case one below is when the user didnt provide any hard block type names and just provided the next command-line option - if (!identify_and_instantiate_custom_hard_blocks) + if (!insert_custom_hard_blocks) { // since no hard block type names were supplied, we throw an error cout << "ERROR: Missing Hard Block Module Names.\n"; @@ -669,7 +669,7 @@ void cmd_line_parse (int argc, char** argv, string* sourcefile, string* archfile cleanup_hard_block_type_name(&curr_hard_block_name); // if we are here then the provided name was valid. - identify_and_instantiate_custom_hard_blocks = T_TRUE; + insert_custom_hard_blocks = T_TRUE; // check to see whether the user repeated a hard block type name if ((std::find(hard_block_type_name_list->begin(), hard_block_type_name_list->end(), curr_hard_block_name)) == hard_block_type_name_list->end()) @@ -747,7 +747,7 @@ void setup_tokens (tokmap* tokens){ tokens->insert(tokpair("-remove_const_nets", OT_REMOVE_CONST_NETS)); tokens->insert(tokpair("-include_unused_subckt_pins", OT_INCLUDE_UNUSED_SUBCKT_PINS)); tokens->insert(tokpair("-eblif_format", OT_EBLIF_FORMAT)); - tokens->insert(tokpair("-identify_and_instantiate_custom_hard_blocks", OT_IDENTIFY_AND_INSTANTIATE_CUSTOM_HARD_BLOCKS)); + tokens->insert(tokpair("-insert_custom_hard_blocks", OT_INSERT_CUSTOM_HARD_BLOCKS)); } //============================================================================================ From 1e005c3be185ed0be8c60fce56a47423cd0e6272 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Fri, 5 Nov 2021 17:52:40 -0400 Subject: [PATCH 28/31] improcing code documentation and formatting --- utils/vqm2blif/src/base/hard_block_recog.cpp | 74 ++++++++++++++------ 1 file changed, 52 insertions(+), 22 deletions(-) diff --git a/utils/vqm2blif/src/base/hard_block_recog.cpp b/utils/vqm2blif/src/base/hard_block_recog.cpp index 0431f15b2b3..0b20594c9e7 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.cpp +++ b/utils/vqm2blif/src/base/hard_block_recog.cpp @@ -8,7 +8,8 @@ * called "router". This hard block is embedded within the FPGA architecture * but the Quartus synthesis tool has no reference to what a "router" block is. * Since the tool has no information to the hard block, the generated netlist -* does not properly model the hard blocks. Instead of declaring a single hard * block in the netlist, it was found that the generated .vqm netlist +* does not properly model the hard blocks. Instead of declaring a single hard +* block in the netlist, it was found that the generated .vqm netlist * from Quartus inserted a LUT for every input port of the hard block * and then a LUT & DFF for every output port of the hard block. * An example is shown below: @@ -216,7 +217,7 @@ bool sort_hard_blocks_by_valid_connections(t_hard_block, t_hard_block); * the netlist are also included. * * @param main_arch This contains all the information regarding the FPGA - * architeture that the design will be mapped to. + * architecture that the design will be mapped to. * * @param list_hard_block_type_names A list of the hard block names that need * to be properly added to the netlist. @@ -234,6 +235,16 @@ void add_hard_blocks_to_netlist(t_module* main_module, t_arch* main_arch, std::v int number_of_hard_blocks_added = 0; int number_of_luts_flip_flops_removed = 0; + + /* + We catch any errors that occur during the initialization procedure. + Some errors that can occur are when the provided hard block names + from the user were not found in the architecture file or the hard + block models in the architecture file do not have any ports. + All the errors in this step are related to the architecture file, so + once we catch the error, we append the architecture file location and + throw another error to force program termination. + */ try { @@ -248,6 +259,12 @@ void add_hard_blocks_to_netlist(t_module* main_module, t_arch* main_arch, std::v throw vtr::VtrError((std::string)error.what() + " The FPGA architecture is described in " + arch_file_name + "."); } + /* + We catch any errors that occur during the procedure of reading the + netlist and inserting custom hard blocks whereever necessary. + All the errors in this step are related to the provided .vqm netlist file, so once we catch the error, we append the netlist file location + and throw another error to force program termination. + */ try { @@ -347,7 +364,9 @@ void initialize_hard_block_models(t_arch* main_arch, std::vector* h * is connected to the same net as the node that represented that port. * If the hard block was already created, then it is not created again. * Finally the nodes that were identified as representing hard block - * ports are stored for reference. + * ports are stored for reference. The nodes are stored so that they + * can be removed from the netlist and deleted, since they are replaced + * by the corresponding hard blocks themselves. * * @param main_module This contains all the netlist information, such as luts, * flip flops, and other types of blocks. All the nets within @@ -455,6 +474,9 @@ void process_module_nodes_and_create_hard_blocks(t_module* main_module, std::vec * information of the hard blocks are stored * in here. * + * @return A boolean value is returned indicating whether the hard block within + * the FPGA had any ports. + * */ bool create_and_initialize_all_hard_block_ports(t_model* hard_block_arch_model, t_hard_block_recog* storage_of_hard_block_info) { @@ -523,9 +545,13 @@ void create_hard_block_port_info_structure(t_hard_block_recog* storage_of_hard_b } /** - * @details The port information for all new types of hard blocks - * can be found within the FPGA architecture. For each hard block - * the ports can be found in a structure called 't_model_ports' + * @details For a given hard block in the architecture, this function converts + * the ports of the hard block from 't_model_ports' to a 't_array_ref' + * type. Then the converted ports are stored. + * + * The port information for all new types of hard blocks + * can be found within the FPGA architecture. For each hard block, + * the ports info can be found in a structure called 't_model_ports' * (found in 'logic_types.h'). The ports are arranged in a linked lsit * structure. * @@ -644,8 +670,8 @@ t_array_ref* convert_hard_block_model_port_to_hard_block_node_port(t_model_ports } /** - * @details Creates a unconnected hard block port in the form of the - * form of a 't_node_port_association' structure (found in + * @details Creates a unconnected hard block port in the form of + * a 't_node_port_association' structure (found in * 'vqm_dll.h'). * * @param port_name A string describing the name of the port to be @@ -778,11 +804,11 @@ t_array_ref* create_and_initialize_t_array_ref_struct(void) } /** - * @details Every time a hard block instance is added to module + * @details Every time a hard block instance is added to the module * (netlist), a reference is stored inside a list of * hard blocks within the design. This function returns - * an index to a hard block instance within the above list - * using the hard block instance name. + * an index to a hard block instance within the list of stored + * hard blocks in the module using the hard block instance name. * * @param module_hard_block_node_refs_and_info This is a data structure of type * 't_hard_block_recog', which can be found @@ -864,6 +890,10 @@ int find_hard_block_instance(t_hard_block_recog* module_hard_block_node_refs_and * block instance name and the type of hard * block. * + * @return An integer that represents an index within a list of hard block + * instances in the netlist (module) that represents the position + * of a hard block instance that was newly added within this function. + * */ int create_new_hard_block_instance(t_array_ref* module_node_list, t_hard_block_recog* module_hard_block_node_refs_and_info, t_parsed_hard_block_port_info* curr_module_node_info) { @@ -1056,7 +1086,8 @@ t_node_port_association* get_lut_dffeas_port_connected_to_hard_block_instance_ne /** * @details All the ports of a hard block are arranged within - * an. This function returns the index of where a port + * an array that is inside a t_array_ref structure. + * This function returns the index of where a port * is located within the array. * * @param curr_hard_block_type_port_info This is a 't_hard_block_port_info' @@ -1135,7 +1166,7 @@ int identify_port_index_within_hard_block_type_port_array(t_hard_block_port_info // verify if the current port index is out of ranged by chekcing if it is larger than the maximum index for the port if (identified_port_index > port_end_index) { - // port index is out of range, so throw and error and indicate it to the user + // port index is out of range, so throw an error and indicate it to the user throw vtr::VtrError("The vqm netlist node '" + curr_module_node_name + "' represents a port: '" + curr_module_node_info->hard_block_port_name +"' at index: " + std::to_string(curr_module_node_info->hard_block_port_index) + ", within hard block model: '" + curr_module_node_info->hard_block_type + "'. But this port index is out of range in the given hard block model as described in the architecture file."); } @@ -1374,9 +1405,8 @@ t_node* create_new_hard_block_instance_node(t_array_ref* curr_hard_block_instanc * hard blocks in the design * - Finally, the index of the 't_hard_block' structure within the * previous vector is stored inside a map datastructure and the - * key was the name of the hard block instance within the design. - * This was needed so that the hard block could be found quicly with - * just its name. + * key was the name of the hard block instance within the design + * and this was done for a quick lookup. * * @param module_hard_block_node_refs_and_info This is a data structure of type * 't_hard_block_recog', which can be found @@ -1783,11 +1813,11 @@ void remove_luts_dffeas_nodes_representing_hard_block_ports(t_module* main_modul /** * @details This function goes through all the newly added hard block nodes * to the module (netlsit) and checks to see that every port has a - * valid connected to a net. If a port is unassigned for any hard + * valid connection to a net. If a port is unassigned for any hard * block, then an error is thrown. * - * We expect every hard block should have all its port assigned to a - * net, even if the connection is 'ground' of 'vdd. Having an + * We expect that every hard block should have all its port assigned + * to a net, even if the connection 'ground' of 'vdd. Having an * unconnected port implies that the generate vqm netlist was * incorrect and we check for this here. * @@ -1866,13 +1896,13 @@ void verify_hard_blocks(t_hard_block_recog* module_hard_block_node_refs_and_info * for each hard block. We handle the deletion of this * memory here. * - * @param hard_block_type_name_to_port_info_map A map datastrcuture + * @param hard_block_type_name_to_port_info_map A map * that contains all the * 't_hard_block_port_info' structures, * which store the port information * for all the new hard blocks. This - * datastrcuture can be found within - * the 't_hard_block_recog' structure. + * data structure can be found within + * 't_hard_block_recog'. * */ void delete_hard_block_port_info(std::unordered_map* hard_block_type_name_to_port_info_map) From 4496a820bef799ab8801438c6d95788b6dad874d Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Sat, 6 Nov 2021 23:30:01 -0400 Subject: [PATCH 29/31] added static to private functions to ensure they are not used elsewhere and also added parameter names to function prototypes --- utils/vqm2blif/src/base/hard_block_recog.cpp | 118 +++++++++---------- utils/vqm2blif/src/base/hard_block_recog.h | 2 +- 2 files changed, 59 insertions(+), 61 deletions(-) diff --git a/utils/vqm2blif/src/base/hard_block_recog.cpp b/utils/vqm2blif/src/base/hard_block_recog.cpp index 0b20594c9e7..d7de66a3912 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.cpp +++ b/utils/vqm2blif/src/base/hard_block_recog.cpp @@ -129,68 +129,66 @@ // INTERNAL FUNCTION DECLARATIONS //============================================================================================ -void initialize_hard_block_models(t_arch*, std::vector*, t_hard_block_recog*); +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); -void process_module_nodes_and_create_hard_blocks(t_module*, std::vector*, t_hard_block_recog*); +static void process_module_nodes_and_create_hard_blocks(t_module* main_module, std::vector* hard_block_type_name_list, t_hard_block_recog* module_hard_block_node_refs_and_info); -bool create_and_initialize_all_hard_block_ports(t_model*, t_hard_block_recog*); +static bool create_and_initialize_all_hard_block_ports(t_model* hard_block_arch_model, t_hard_block_recog* storage_of_hard_block_info); -void create_hard_block_port_info_structure(t_hard_block_recog*, std::string); +static void create_hard_block_port_info_structure(t_hard_block_recog* storage_of_hard_block_info, std::string hard_block_type_name); -int extract_and_store_hard_block_model_ports(t_hard_block_recog*, t_model_ports*, std::string, int, std::string); +static int extract_and_store_hard_block_model_ports(t_hard_block_recog* storage_of_hard_block_info, t_model_ports* curr_hard_block_model_port, std::string curr_hard_block_type_name,int port_index, std::string port_type); -t_array_ref* convert_hard_block_model_port_to_hard_block_node_port(t_model_ports*); +static t_array_ref* convert_hard_block_model_port_to_hard_block_node_port(t_model_ports* hard_block_model_port); -t_node_port_association* create_unconnected_node_port_association(char*, int ,int); +static t_node_port_association* create_unconnected_node_port_association(char *port_name, int port_index, int wire_index); -void store_hard_block_port_info(t_hard_block_recog*, std::string, std::string,t_array_ref**, int*); +static void store_hard_block_port_info(t_hard_block_recog* storage_of_hard_block_port_info, std::string curr_hard_block_type_name,std::string curr_port_name, t_array_ref** curr_port_array, int* port_index); -void copy_array_ref(t_array_ref*, t_array_ref*); +static void copy_array_ref(t_array_ref* array_ref_orig, t_array_ref* array_ref_copy); -t_array_ref* create_and_initialize_t_array_ref_struct(void); +static t_array_ref* create_and_initialize_t_array_ref_struct(void); -int find_hard_block_instance(t_hard_block_recog*, t_parsed_hard_block_port_info*); +static int find_hard_block_instance(t_hard_block_recog* module_hard_block_node_refs_and_info, t_parsed_hard_block_port_info* curr_module_node_info); -void assign_net_to_hard_block_instance_port(t_node*, t_parsed_hard_block_port_info*, t_hard_block_recog*, int); +static void assign_net_to_hard_block_instance_port(t_node* curr_module_node, t_parsed_hard_block_port_info* curr_module_node_info, t_hard_block_recog* module_hard_block_node_refs_and_info, int curr_hard_block_instance_index); -t_node_port_association* get_lut_dffeas_port_connected_to_hard_block_instance_net(t_node*); +static t_node_port_association* get_lut_dffeas_port_connected_to_hard_block_instance_net(t_node* curr_module_node); -int identify_port_index_within_hard_block_type_port_array(t_hard_block_port_info*, t_parsed_hard_block_port_info*, t_node*); +static int identify_port_index_within_hard_block_type_port_array(t_hard_block_port_info* curr_hard_block_type_port_info, t_parsed_hard_block_port_info* curr_module_node_info, t_node* curr_module_node); -void handle_net_assignment(t_node*, t_hard_block*, int, t_node_port_association*, t_parsed_hard_block_port_info*); +static void handle_net_assignment(t_node* curr_module_node, t_hard_block* curr_hard_block_instance, int port_to_assign_index, t_node_port_association* port_connected_to_hard_block_instance_net, t_parsed_hard_block_port_info* curr_module_node_info); -bool is_hard_block_port_legal(t_node*); +static bool is_hard_block_port_legal(t_node* curr_module_node); -int create_new_hard_block_instance(t_array_ref*, t_hard_block_recog*, t_parsed_hard_block_port_info*); +static int create_new_hard_block_instance(t_array_ref* module_node_list, t_hard_block_recog* module_hard_block_node_refs_and_info, t_parsed_hard_block_port_info* curr_module_node_info); -t_array_ref* create_unconnected_hard_block_instance_ports(t_hard_block_port_info*); +static t_array_ref* create_unconnected_hard_block_instance_ports(t_hard_block_port_info* curr_hard_block_type_port_info); -t_node* create_new_hard_block_instance_node(t_array_ref*, t_parsed_hard_block_port_info*); +static t_node* create_new_hard_block_instance_node(t_array_ref* curr_hard_block_instance_ports, t_parsed_hard_block_port_info* curr_hard_block_instance_info); -int store_new_hard_block_instance_info(t_hard_block_recog*, t_hard_block_port_info*, t_node*, t_parsed_hard_block_port_info*); +static int store_new_hard_block_instance_info(t_hard_block_recog* module_hard_block_node_refs_and_info, t_hard_block_port_info* curr_hard_block_type_port_info, t_node* new_hard_block_instance_node, t_parsed_hard_block_port_info* curr_module_node_info); -t_array_ref* create_t_array_ref_from_array(void**, int); +static t_array_ref* create_t_array_ref_from_array(void** array_to_store, int array_size); -void delete_hard_block_port_info(std::unordered_map*); +static void delete_hard_block_port_info(std::unordered_map* hard_block_type_name_to_port_info_map); -t_parsed_hard_block_port_info extract_hard_block_port_info_from_module_node(t_node*, std::vector*); +static t_parsed_hard_block_port_info extract_hard_block_port_info_from_module_node(t_node* curr_module_node, std::vector* hard_block_type_name_list); -std::string identify_hard_block_type(std::vector*, std::string); +static std::string identify_hard_block_type(std::vector* hard_block_type_name_list, std::string curr_node_name_component); -void identify_hard_block_port_name_and_index (t_parsed_hard_block_port_info*, std::string); +static void identify_hard_block_port_name_and_index (t_parsed_hard_block_port_info* curr_hard_block_port, std::string curr_node_name_component); -void split_node_name(std::string, std::vector*, std::string); +static void split_node_name(std::string original_node_name, std::vector* node_name_components, std::string delimiter); -std::string construct_hard_block_name(std::vector*, std::string); +static std::string construct_hard_block_name(std::vector*node_name_components, std::string delimiter); -void remove_luts_dffeas_nodes_representing_hard_block_ports(t_module*, t_hard_block_recog*); +static void remove_luts_dffeas_nodes_representing_hard_block_ports(t_module* main_module, t_hard_block_recog* module_hard_block_node_refs_and_info); -void verify_hard_blocks(t_hard_block_recog*); +static void verify_hard_blocks(t_hard_block_recog* module_hard_block_node_refs_and_info); // utility functions -void store_hard_block_names(char**, int, std::vector*); - bool sort_hard_blocks_by_valid_connections(t_hard_block, t_hard_block); //============================================================================================ @@ -321,7 +319,7 @@ void add_hard_blocks_to_netlist(t_module* main_module, t_arch* main_arch, std::v * information of the hard blocks are stored * in here. */ -void initialize_hard_block_models(t_arch* main_arch, std::vector* hard_block_type_names, t_hard_block_recog* storage_of_hard_block_info) +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; @@ -381,7 +379,7 @@ void initialize_hard_block_models(t_arch* main_arch, std::vector* h * information of the hard blocks are stored * in here. */ -void process_module_nodes_and_create_hard_blocks(t_module* main_module, std::vector* hard_block_type_name_list, t_hard_block_recog* module_hard_block_node_refs_and_info) +static void process_module_nodes_and_create_hard_blocks(t_module* main_module, std::vector* hard_block_type_name_list, t_hard_block_recog* module_hard_block_node_refs_and_info) { // represents a block in the netlist // refer to 'vqm_dll.h' for more info on t_node @@ -478,7 +476,7 @@ void process_module_nodes_and_create_hard_blocks(t_module* main_module, std::vec * the FPGA had any ports. * */ -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(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; @@ -524,7 +522,7 @@ bool create_and_initialize_all_hard_block_ports(t_model* hard_block_arch_model, * created in here when storing it inside * the 't_hard_block_recog' structure. */ -void create_hard_block_port_info_structure(t_hard_block_recog* storage_of_hard_block_info, std::string hard_block_type_name) +static void create_hard_block_port_info_structure(t_hard_block_recog* storage_of_hard_block_info, std::string hard_block_type_name) { t_hard_block_port_info curr_hard_block_port_storage; @@ -597,7 +595,7 @@ void create_hard_block_port_info_structure(t_hard_block_recog* storage_of_hard_b * being processed are input or output ports. * */ -int extract_and_store_hard_block_model_ports(t_hard_block_recog* storage_of_hard_block_info, t_model_ports* curr_hard_block_model_port, std::string curr_hard_block_type_name,int port_index, std::string port_type) +static int extract_and_store_hard_block_model_ports(t_hard_block_recog* storage_of_hard_block_info, t_model_ports* curr_hard_block_model_port, std::string curr_hard_block_type_name,int port_index, std::string port_type) { t_array_ref* equivalent_hard_block_node_port_array = NULL; int starting_port_index = port_index; @@ -637,7 +635,7 @@ int extract_and_store_hard_block_model_ports(t_hard_block_recog* storage_of_hard * for a hard block. * */ -t_array_ref* convert_hard_block_model_port_to_hard_block_node_port(t_model_ports* hard_block_model_port) +static t_array_ref* convert_hard_block_model_port_to_hard_block_node_port(t_model_ports* hard_block_model_port) { t_node_port_association* curr_hard_block_node_port = NULL; t_array_ref* port_array = NULL; @@ -686,7 +684,7 @@ t_array_ref* convert_hard_block_model_port_to_hard_block_node_port(t_model_ports * associated with this port. * */ -t_node_port_association* create_unconnected_node_port_association(char *port_name, int port_index, int wire_index) +static t_node_port_association* create_unconnected_node_port_association(char *port_name, int port_index, int wire_index) { // allocate memory for the port t_node_port_association* curr_hard_block_node_port = NULL; @@ -733,7 +731,7 @@ t_node_port_association* create_unconnected_node_port_association(char *port_nam * that the current port is located at. * */ -void store_hard_block_port_info(t_hard_block_recog* storage_of_hard_block_port_info, std::string curr_hard_block_type_name,std::string curr_port_name, t_array_ref** curr_port_array, int* port_index) +static void store_hard_block_port_info(t_hard_block_recog* storage_of_hard_block_port_info, std::string curr_hard_block_type_name,std::string curr_port_name, t_array_ref** curr_port_array, int* port_index) { std::unordered_map::iterator curr_port_info = ((storage_of_hard_block_port_info->hard_block_type_name_to_port_info).find(curr_hard_block_type_name)); @@ -770,7 +768,7 @@ void store_hard_block_port_info(t_hard_block_recog* storage_of_hard_block_port_i * @param array_ref_copy The 't_array_ref' structure that will have copied * contents added to its array. */ -void copy_array_ref(t_array_ref* array_ref_orig, t_array_ref* array_ref_copy) +static void copy_array_ref(t_array_ref* array_ref_orig, t_array_ref* array_ref_copy) { int array_size = array_ref_orig->array_size; @@ -787,7 +785,7 @@ void copy_array_ref(t_array_ref* array_ref_orig, t_array_ref* array_ref_copy) * @details Creates and initializes an empty 't_array_ref' structure. * */ -t_array_ref* create_and_initialize_t_array_ref_struct(void) +static t_array_ref* create_and_initialize_t_array_ref_struct(void) { t_array_ref* empty_array = NULL; @@ -830,7 +828,7 @@ t_array_ref* create_and_initialize_t_array_ref_struct(void) * block. * */ -int find_hard_block_instance(t_hard_block_recog* module_hard_block_node_refs_and_info, t_parsed_hard_block_port_info* curr_module_node_info) +static int find_hard_block_instance(t_hard_block_recog* module_hard_block_node_refs_and_info, t_parsed_hard_block_port_info* curr_module_node_info) { int hard_block_instance_index = 0; @@ -895,7 +893,7 @@ int find_hard_block_instance(t_hard_block_recog* module_hard_block_node_refs_and * of a hard block instance that was newly added within this function. * */ -int create_new_hard_block_instance(t_array_ref* module_node_list, t_hard_block_recog* module_hard_block_node_refs_and_info, t_parsed_hard_block_port_info* curr_module_node_info) +static int create_new_hard_block_instance(t_array_ref* module_node_list, t_hard_block_recog* module_hard_block_node_refs_and_info, t_parsed_hard_block_port_info* curr_module_node_info) { // index to to the new 't_hard_block' struct being created here that is found within the 'hard_block_instances' vector int created_hard_block_instance_index = 0; @@ -969,7 +967,7 @@ int create_new_hard_block_instance(t_array_ref* module_node_list, t_hard_block_r * lut or dff node. * */ -void assign_net_to_hard_block_instance_port(t_node* curr_module_node, t_parsed_hard_block_port_info* curr_module_node_info, t_hard_block_recog* module_hard_block_node_refs_and_info, int curr_hard_block_instance_index) +static void assign_net_to_hard_block_instance_port(t_node* curr_module_node, t_parsed_hard_block_port_info* curr_module_node_info, t_hard_block_recog* module_hard_block_node_refs_and_info, int curr_hard_block_instance_index) { t_hard_block* curr_hard_block_instance = &(module_hard_block_node_refs_and_info->hard_block_instances[curr_hard_block_instance_index]); @@ -1007,7 +1005,7 @@ void assign_net_to_hard_block_instance_port(t_node* curr_module_node, t_parsed_h * (netlist). * */ -t_node_port_association* get_lut_dffeas_port_connected_to_hard_block_instance_net(t_node* curr_module_node) +static t_node_port_association* get_lut_dffeas_port_connected_to_hard_block_instance_net(t_node* curr_module_node) { t_node_port_association* port_connected_to_hard_block_instance_net = NULL; @@ -1115,7 +1113,7 @@ t_node_port_association* get_lut_dffeas_port_connected_to_hard_block_instance_ne * (netlist). Used to report error information. * */ -int identify_port_index_within_hard_block_type_port_array(t_hard_block_port_info* curr_hard_block_type_port_info, t_parsed_hard_block_port_info* curr_module_node_info, t_node* curr_module_node) +static int identify_port_index_within_hard_block_type_port_array(t_hard_block_port_info* curr_hard_block_type_port_info, t_parsed_hard_block_port_info* curr_module_node_info, t_node* curr_module_node) { int identified_port_index = 0; @@ -1208,7 +1206,7 @@ int identify_port_index_within_hard_block_type_port_array(t_hard_block_port_info * block instance name and the type of hard * block. */ -void handle_net_assignment(t_node* curr_module_node, t_hard_block* curr_hard_block_instance, int port_to_assign_index, t_node_port_association* port_connected_to_hard_block_instance_net, t_parsed_hard_block_port_info* curr_module_node_info) +static void handle_net_assignment(t_node* curr_module_node, t_hard_block* curr_hard_block_instance, int port_to_assign_index, t_node_port_association* port_connected_to_hard_block_instance_net, t_parsed_hard_block_port_info* curr_module_node_info) { std::string curr_module_node_name = curr_module_node->name; @@ -1253,7 +1251,7 @@ void handle_net_assignment(t_node* curr_module_node, t_hard_block* curr_hard_blo * a lut or dff node within the module (netlist). * */ -bool is_hard_block_port_legal(t_node* curr_module_node) +static bool is_hard_block_port_legal(t_node* curr_module_node) { bool result = false; @@ -1295,7 +1293,7 @@ bool is_hard_block_port_legal(t_node* curr_module_node) * information about the hard block. * */ -t_array_ref* create_unconnected_hard_block_instance_ports(t_hard_block_port_info* curr_hard_block_type_port_info) +static t_array_ref* create_unconnected_hard_block_instance_ports(t_hard_block_port_info* curr_hard_block_type_port_info) { t_array_ref* template_for_hard_block_ports = &(curr_hard_block_type_port_info->hard_block_ports); t_array_ref* hard_block_instance_port_array = NULL; @@ -1358,7 +1356,7 @@ t_array_ref* create_unconnected_hard_block_instance_ports(t_hard_block_port_info * block. * */ -t_node* create_new_hard_block_instance_node(t_array_ref* curr_hard_block_instance_ports, t_parsed_hard_block_port_info* curr_hard_block_instance_info) +static t_node* create_new_hard_block_instance_node(t_array_ref* curr_hard_block_instance_ports, t_parsed_hard_block_port_info* curr_hard_block_instance_info) { t_node* new_hard_block_instance = NULL; @@ -1439,7 +1437,7 @@ t_node* create_new_hard_block_instance_node(t_array_ref* curr_hard_block_instanc * hard block instance within the design. * */ -int store_new_hard_block_instance_info(t_hard_block_recog* module_hard_block_node_refs_and_info, t_hard_block_port_info* curr_hard_block_type_port_info, t_node* new_hard_block_instance_node, t_parsed_hard_block_port_info* curr_module_node_info) +static int store_new_hard_block_instance_info(t_hard_block_recog* module_hard_block_node_refs_and_info, t_hard_block_port_info* curr_hard_block_type_port_info, t_node* new_hard_block_instance_node, t_parsed_hard_block_port_info* curr_module_node_info) { int new_hard_block_instance_index = 0; @@ -1474,7 +1472,7 @@ int store_new_hard_block_instance_info(t_hard_block_recog* module_hard_block_nod * @param array_size size of the array passed to this function * */ -t_array_ref* create_t_array_ref_from_array(void** array_to_store, int array_size) +static t_array_ref* create_t_array_ref_from_array(void** array_to_store, int array_size) { t_array_ref* array_reference = NULL; int array_allocated_size = 0; @@ -1514,7 +1512,7 @@ t_array_ref* create_t_array_ref_from_array(void** array_to_store, int array_size * to be properly added to the netlist. * */ -t_parsed_hard_block_port_info extract_hard_block_port_info_from_module_node(t_node* curr_module_node, std::vector* hard_block_type_name_list) +static t_parsed_hard_block_port_info extract_hard_block_port_info_from_module_node(t_node* curr_module_node, std::vector* hard_block_type_name_list) { std::string curr_module_node_name = curr_module_node->name; @@ -1586,7 +1584,7 @@ t_parsed_hard_block_port_info extract_hard_block_port_info_from_module_node(t_no * pieces. * */ -void split_node_name(std::string original_node_name, std::vector* node_name_components, std::string delimiter) +static void split_node_name(std::string original_node_name, std::vector* node_name_components, std::string delimiter) { // positional trackers to determine the beginning and end position of each hierarchy level (component of the node name) of the current node within the design. The positions are updated as we go through the node name and identify every level of hierarchy. @@ -1625,7 +1623,7 @@ void split_node_name(std::string original_node_name, std::vector* n * structure. * */ -std::string identify_hard_block_type(std::vector* hard_block_type_name_list, std::string curr_node_name_component) +static std::string identify_hard_block_type(std::vector* hard_block_type_name_list, std::string curr_node_name_component) { std::vector::iterator hard_block_type_name_traverser; @@ -1680,7 +1678,7 @@ std::string identify_hard_block_type(std::vector* hard_block_type_n * above in the generated string output. * */ -std::string construct_hard_block_name(std::vector*node_name_components, std::string delimiter) +static std::string construct_hard_block_name(std::vector*node_name_components, std::string delimiter) { // stores the full name of the hard block the current node is part of, the current node represents a port of a hard block std::string curr_hard_block_name = ""; @@ -1732,7 +1730,7 @@ std::string construct_hard_block_name(std::vector*node_name_compone * component is passed for this parameter. * */ -void identify_hard_block_port_name_and_index (t_parsed_hard_block_port_info* curr_hard_block_port, std::string curr_node_name_component) +static void identify_hard_block_port_name_and_index (t_parsed_hard_block_port_info* curr_hard_block_port, std::string curr_node_name_component) { // identifer to check whether the port defined in the current node name is a bus (ex. payload[1]~QIC_DANGLING_PORT_I) std::regex port_is_a_bus ("(.*)[[]([0-9]*)\]~(?:.*)"); @@ -1785,7 +1783,7 @@ void identify_hard_block_port_name_and_index (t_parsed_hard_block_port_info* cur * removed should be found here. * */ -void remove_luts_dffeas_nodes_representing_hard_block_ports(t_module* main_module, t_hard_block_recog* module_hard_block_node_refs_and_info) +static void remove_luts_dffeas_nodes_representing_hard_block_ports(t_module* main_module, t_hard_block_recog* module_hard_block_node_refs_and_info) { // reference to the list of luts/dffeas nodes we need to remove std::vector* list_of_nodes_to_remove = &(module_hard_block_node_refs_and_info->luts_dffeas_nodes_to_remove); @@ -1828,7 +1826,7 @@ void remove_luts_dffeas_nodes_representing_hard_block_ports(t_module* main_modul * stored in here. * */ -void verify_hard_blocks(t_hard_block_recog* module_hard_block_node_refs_and_info) +static void verify_hard_blocks(t_hard_block_recog* module_hard_block_node_refs_and_info) { // If we find a hard block instance that has ports unassigned, we store its information in the variables below @@ -1905,7 +1903,7 @@ void verify_hard_blocks(t_hard_block_recog* module_hard_block_node_refs_and_info * 't_hard_block_recog'. * */ -void delete_hard_block_port_info(std::unordered_map* hard_block_type_name_to_port_info_map) +static void delete_hard_block_port_info(std::unordered_map* hard_block_type_name_to_port_info_map) { std::unordered_map::iterator curr_hard_block_port_info = hard_block_type_name_to_port_info_map->begin(); diff --git a/utils/vqm2blif/src/base/hard_block_recog.h b/utils/vqm2blif/src/base/hard_block_recog.h index 5e4e6e54e1c..ee2b4c091dc 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.h +++ b/utils/vqm2blif/src/base/hard_block_recog.h @@ -247,6 +247,6 @@ typedef struct s_parsed_hard_block_port_info std::string - the name of the Quartus generated netlist file (".vqm") * */ -void add_hard_blocks_to_netlist(t_module*, t_arch*, std::vector*, std::string, std::string); +void add_hard_blocks_to_netlist(t_module* main_module, t_arch* main_arch, std::vector* list_hard_block_type_names, std::string arch_file_name, std::string vqm_file_name); #endif From 8608a0ea65ec4e5a47e75e4ff27f73a5c8e3181f Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Wed, 10 Nov 2021 13:08:39 -0500 Subject: [PATCH 30/31] removed hard coding of device specific parameters relevant to the generated vqm file. Now the program includes a device option that automatically loads the parameters for a given device. --- utils/vqm2blif/src/base/hard_block_recog.cpp | 28 ++++++++------- utils/vqm2blif/src/base/hard_block_recog.h | 5 ++- utils/vqm2blif/src/base/vqm2blif_util.cpp | 38 ++++++++++++++++++++ utils/vqm2blif/src/base/vqm2blif_util.h | 30 +++++++++++++++- utils/vqm2blif/src/main.cpp | 27 ++++++++++---- 5 files changed, 107 insertions(+), 21 deletions(-) diff --git a/utils/vqm2blif/src/base/hard_block_recog.cpp b/utils/vqm2blif/src/base/hard_block_recog.cpp index d7de66a3912..518795fe3fc 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.cpp +++ b/utils/vqm2blif/src/base/hard_block_recog.cpp @@ -153,13 +153,13 @@ static int find_hard_block_instance(t_hard_block_recog* module_hard_block_node_r static void assign_net_to_hard_block_instance_port(t_node* curr_module_node, t_parsed_hard_block_port_info* curr_module_node_info, t_hard_block_recog* module_hard_block_node_refs_and_info, int curr_hard_block_instance_index); -static t_node_port_association* get_lut_dffeas_port_connected_to_hard_block_instance_net(t_node* curr_module_node); +static t_node_port_association* get_lut_dffeas_port_connected_to_hard_block_instance_net(t_node* curr_module_node, DeviceInfo target_device_info); static int identify_port_index_within_hard_block_type_port_array(t_hard_block_port_info* curr_hard_block_type_port_info, t_parsed_hard_block_port_info* curr_module_node_info, t_node* curr_module_node); static void handle_net_assignment(t_node* curr_module_node, t_hard_block* curr_hard_block_instance, int port_to_assign_index, t_node_port_association* port_connected_to_hard_block_instance_net, t_parsed_hard_block_port_info* curr_module_node_info); -static bool is_hard_block_port_legal(t_node* curr_module_node); +static bool is_hard_block_port_legal(t_node* curr_module_node, DeviceInfo target_device_info); static int create_new_hard_block_instance(t_array_ref* module_node_list, t_hard_block_recog* module_hard_block_node_refs_and_info, t_parsed_hard_block_port_info* curr_module_node_info); @@ -225,7 +225,7 @@ bool sort_hard_blocks_by_valid_connections(t_hard_block, t_hard_block); * * @param vqm_file_name Name of the quartus generated .vqm netlist file. */ -void add_hard_blocks_to_netlist(t_module* main_module, t_arch* main_arch, std::vector* list_hard_block_type_names, std::string arch_file_name, std::string vqm_file_name) +void add_hard_blocks_to_netlist(t_module* main_module, t_arch* main_arch, std::vector* list_hard_block_type_names, std::string arch_file_name, std::string vqm_file_name, std::string device) { t_hard_block_recog module_hard_block_node_refs_and_info; @@ -233,6 +233,8 @@ void add_hard_blocks_to_netlist(t_module* main_module, t_arch* main_arch, std::v int number_of_hard_blocks_added = 0; int number_of_luts_flip_flops_removed = 0; + // based on the device supplied, store the corresponding parameters related to that device + module_hard_block_node_refs_and_info.target_device_info = (device_parameter_database.find(device))->second; /* We catch any errors that occur during the initialization procedure. @@ -405,7 +407,7 @@ static void process_module_nodes_and_create_hard_blocks(t_module* main_module, s curr_module_node_type.assign(curr_module_node->type); // hard block ports are only represented in nodes that are either a LUT or flip flop block - if ((curr_module_node_type.compare(LUT_TYPE) == 0) || (curr_module_node_type.compare(DFF_TYPE) == 0)) + if ((curr_module_node_type.compare((module_hard_block_node_refs_and_info->target_device_info).lut_type_name) == 0) || (curr_module_node_type.compare((module_hard_block_node_refs_and_info->target_device_info).dff_type_name) == 0)) { curr_module_node_info = extract_hard_block_port_info_from_module_node(curr_module_node, hard_block_type_name_list); @@ -418,7 +420,7 @@ static void process_module_nodes_and_create_hard_blocks(t_module* main_module, s // if we are here, the current node is a LUT or DFF node that represents a hard block instance port // /* referring to the diagram at the top, if the node is a lut that represents an output port, its connected net is an internal connection, which is not a legal netlist connection, so we cannot process the node any further. Therefore we only process nodes that are LUTs representing input ports or DFFs. */ - if (is_hard_block_port_legal(curr_module_node)) + if (is_hard_block_port_legal(curr_module_node, module_hard_block_node_refs_and_info->target_device_info)) { // get the index to the current hard block instance we need to work with @@ -975,7 +977,7 @@ static void assign_net_to_hard_block_instance_port(t_node* curr_module_node, t_p int port_to_assign_index = 0; - t_node_port_association* curr_module_node_port_connected_to_hard_block_instance_net = get_lut_dffeas_port_connected_to_hard_block_instance_net(curr_module_node); + t_node_port_association* curr_module_node_port_connected_to_hard_block_instance_net = get_lut_dffeas_port_connected_to_hard_block_instance_net(curr_module_node, module_hard_block_node_refs_and_info->target_device_info); port_to_assign_index = identify_port_index_within_hard_block_type_port_array(&(curr_hard_block_type_port_info->second), curr_module_node_info, curr_module_node); @@ -1005,7 +1007,7 @@ static void assign_net_to_hard_block_instance_port(t_node* curr_module_node, t_p * (netlist). * */ -static t_node_port_association* get_lut_dffeas_port_connected_to_hard_block_instance_net(t_node* curr_module_node) +static t_node_port_association* get_lut_dffeas_port_connected_to_hard_block_instance_net(t_node* curr_module_node, DeviceInfo target_device_info) { t_node_port_association* port_connected_to_hard_block_instance_net = NULL; @@ -1019,7 +1021,7 @@ static t_node_port_association* get_lut_dffeas_port_connected_to_hard_block_inst // store what type of port we expect the net to be connected to std::string expected_port_type; - if (!(curr_module_node_type.compare(LUT_TYPE))) + if (!(curr_module_node_type.compare(target_device_info.lut_type_name))) { // we are here if the current node is LUT @@ -1040,10 +1042,10 @@ static t_node_port_association* get_lut_dffeas_port_connected_to_hard_block_inst curr_port_name.assign(curr_module_node->array_of_ports[i]->port_name); - if (!(curr_module_node_type.compare(LUT_TYPE))) + if (!(curr_module_node_type.compare(target_device_info.lut_type_name))) { // if the node is a LUT // - if (curr_port_name.compare(LUT_OUTPUT_PORT)) + if (curr_port_name.compare(target_device_info.lut_output_port)) { // if the port is not the LUT output ie. "combout" port // @@ -1058,7 +1060,7 @@ static t_node_port_association* get_lut_dffeas_port_connected_to_hard_block_inst else { // if the node is a flip flop // - if (!(curr_port_name.compare(DFF_OUTPUT_PORT))) + if (!(curr_port_name.compare(target_device_info.dff_output_port))) { // if the port is a D flip flop output ie. "q" port // @@ -1251,7 +1253,7 @@ static void handle_net_assignment(t_node* curr_module_node, t_hard_block* curr_h * a lut or dff node within the module (netlist). * */ -static bool is_hard_block_port_legal(t_node* curr_module_node) +static bool is_hard_block_port_legal(t_node* curr_module_node, DeviceInfo target_device_info) { bool result = false; @@ -1259,7 +1261,7 @@ static bool is_hard_block_port_legal(t_node* curr_module_node) std::string curr_module_node_type = curr_module_node->type; // now we check whether the current node is a lut that represents an input port or the current node is a DFF - if ((curr_module_node->number_of_ports != LUT_OUTPUT_PORT_SIZE) || (!(curr_module_node_type.compare(DFF_TYPE)))) + if ((curr_module_node->number_of_ports != target_device_info.lut_output_port_size) || (!(curr_module_node_type.compare(target_device_info.dff_type_name)))) { result = true; } diff --git a/utils/vqm2blif/src/base/hard_block_recog.h b/utils/vqm2blif/src/base/hard_block_recog.h index ee2b4c091dc..e842122ee8a 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.h +++ b/utils/vqm2blif/src/base/hard_block_recog.h @@ -191,6 +191,9 @@ typedef struct s_hard_block_recog */ std::vector luts_dffeas_nodes_to_remove; // look into using array index instead + // variable to store parameters specific to the fpga device used + DeviceInfo target_device_info; + }t_hard_block_recog; /* @@ -247,6 +250,6 @@ typedef struct s_parsed_hard_block_port_info std::string - the name of the Quartus generated netlist file (".vqm") * */ -void add_hard_blocks_to_netlist(t_module* main_module, t_arch* main_arch, std::vector* list_hard_block_type_names, std::string arch_file_name, std::string vqm_file_name); +void add_hard_blocks_to_netlist(t_module* main_module, t_arch* main_arch, std::vector* list_hard_block_type_names, std::string arch_file_name, std::string vqm_file_name, std::string device); #endif diff --git a/utils/vqm2blif/src/base/vqm2blif_util.cpp b/utils/vqm2blif/src/base/vqm2blif_util.cpp index 51f2da88ebc..41ee839a9e5 100644 --- a/utils/vqm2blif/src/base/vqm2blif_util.cpp +++ b/utils/vqm2blif/src/base/vqm2blif_util.cpp @@ -22,6 +22,7 @@ void print_usage (t_boolean terminate){ cout << "\t-remove_const_nets\n"; cout << "\t-eblif_format\n"; cout << "\t-insert_custom_hard_blocks ...\n"; + cout << "\t-device (if not provided then default is 'stratixiv')\n"; //Hide experimental options by default //cout << "\t-split_multiclock_blocks\n"; //cout << "\t-split_carry_chain_logic\n"; @@ -92,6 +93,43 @@ void verify_hard_block_type_name(string curr_hard_block_type_name){ //============================================================================================ //============================================================================================ +void verify_device(string device_name) +{ + /* + The list of devices that this program can support and their parameters are stored within a map structure ('device_parameter_database'). We + check whether the provided device by the user supported by comparing it + to the devices within the map. + */ + + std::map::const_iterator device_support_status; + + device_support_status = device_parameter_database.find(device_name); + + // checks to see whether we support the given device + if (device_support_status == device_parameter_database.end()) + { + // if we are here then we don't support the user supplied device + std::cout << "ERROR:The provided device is not supported."; + std::cout << " Only the following devices are supported:\n"; + + device_support_status = device_parameter_database.begin(); + + while (device_support_status != device_parameter_database.end()) + { + std::cout << device_support_status->first << "\n"; + device_support_status++; + } + + exit(1); + } + + return; + +} + +//============================================================================================ +//============================================================================================ + //============================================================================================ //============================================================================================ diff --git a/utils/vqm2blif/src/base/vqm2blif_util.h b/utils/vqm2blif/src/base/vqm2blif_util.h index 5d99bed50f3..14f48c27606 100644 --- a/utils/vqm2blif/src/base/vqm2blif_util.h +++ b/utils/vqm2blif/src/base/vqm2blif_util.h @@ -84,7 +84,8 @@ enum v_OptionBaseToken OT_INCLUDE_UNUSED_SUBCKT_PINS, OT_EBLIF_FORMAT, OT_UNKNOWN, - OT_INSERT_CUSTOM_HARD_BLOCKS + OT_INSERT_CUSTOM_HARD_BLOCKS, + OT_DEVICE }; struct cstrcomp{ //operator structure to compare C-strings within a map class @@ -108,6 +109,17 @@ struct RamInfo { t_node_port_association* port_b_output_clock = nullptr; }; +// stores relevant information for a given FPGA device +// currently, just storing the strings used to idenitify luts and dff primitives and their ports within the vqm netlist +// add additional parameters as needed +struct DeviceInfo { + std::string lut_type_name; + std::string lut_output_port; + int lut_output_port_size; + + std::string dff_type_name; + std::string dff_output_port; +}; //============================================================================================ // GLOBAL FUNCTIONS @@ -120,6 +132,9 @@ void verify_format (string* filename, string extension); //verifies a given stri // verifies whether the hard block type name provided by the user meets verilog naming rules void verify_hard_block_type_name(string curr_hard_block_name); +// checks to see that the device name supplied matches the devices we can support +void verify_device(string device_name); + // if the hard block type name was escaped by '\', we need to remove the '\' character from the name (refer to function above) void cleanup_hard_block_type_name(string* curr_hard_block_name); @@ -172,6 +187,19 @@ extern e_clean clean_mode; //user-set flag dictating how to clean away buffers/i extern t_boolean buffd_outs; //user-set flag that regulates whether to keep buffered outputs +//============================================================================================ +// DEVICE SPECIFIC INFORMATION +//============================================================================================ + +/* + A database that stores parameters for different types of FPGA devices. + Currently only the stratix 4 device parameters are stored. +*/ +const map device_parameter_database { + // stratix 4 device + {"stratixiv", {"stratixiv_lcell_comb", "combout", 1, "dffeas", "q" }} +}; + #endif diff --git a/utils/vqm2blif/src/main.cpp b/utils/vqm2blif/src/main.cpp index 3d120763c15..0495eb7231f 100644 --- a/utils/vqm2blif/src/main.cpp +++ b/utils/vqm2blif/src/main.cpp @@ -151,8 +151,8 @@ t_boolean insert_custom_hard_blocks; // user-set flag. Which if true, helps find //============================================================================================ //Setup Functions -void cmd_line_parse (int argc, char** argv, string* sourcefile, string* archfile, - string* outfile, std::vector* hard_block_list); +void cmd_line_parse (int argc, char** argv, string* sourcefile, string* archfile, string* outfile, + string* device, std::vector* hard_block_list); void setup_tokens (tokmap* tokens); //Execution Functions @@ -272,6 +272,10 @@ int main(int argc, char* argv[]) // a list which stores all the user supplied custom hard block type names std::vector hard_block_type_name_list; + // indicates the type of device the circuit is targetting + // we set the default value to the stratix 4 device + string device = "stratixiv"; + //************************************************************************************************* // Begin Conversion //************************************************************************************************* @@ -280,7 +284,7 @@ int main(int argc, char* argv[]) cout << "This parser reads a .vqm file and converts it to .blif format.\n\n" ; //verify command-line is correct, populate input variables and global mode flags. - cmd_line_parse(argc, argv, &source_file, &arch_file, &out_file, &hard_block_type_name_list); + cmd_line_parse(argc, argv, &source_file, &arch_file, &out_file, &device,&hard_block_type_name_list); setup_lut_support_map (); //initialize LUT support for cleanup and elaborate functions @@ -388,7 +392,7 @@ int main(int argc, char* argv[]) try { - add_hard_blocks_to_netlist(my_module,&arch,&hard_block_type_name_list, arch_file, source_file); + add_hard_blocks_to_netlist(my_module,&arch,&hard_block_type_name_list, arch_file, source_file, device); } catch(const vtr::VtrError& error) { @@ -458,8 +462,8 @@ int main(int argc, char* argv[]) // SETUP FUNCTIONS //============================================================================================ -void cmd_line_parse (int argc, char** argv, string* sourcefile, string* archfile, - string* outfile, std::vector* hard_block_type_name_list){ +void cmd_line_parse (int argc, char** argv, string* sourcefile, string* archfile, string* outfile, + string* device, std::vector* hard_block_type_name_list){ /* Interpret the command-line arguments, accepting the input files, output file, and various * mode settings from the user. * @@ -695,6 +699,16 @@ void cmd_line_parse (int argc, char** argv, string* sourcefile, string* archfile } } break; + case OT_DEVICE: + if ( i+1 == argc ){ + cout << "\nERROR: Missing device type.\n" ; + print_usage(T_TRUE); + } + //Store the next argument as the device type + device->assign((string)argv[i+1]); + verify_device(*device); // make sure we can support the provided device + i++; //Increment past the next argument + break; default: //Should never get here; unknown tokens aren't mapped. cout << "\nERROR: Token " << argv[i] << " mishandled.\n" ; @@ -748,6 +762,7 @@ void setup_tokens (tokmap* tokens){ tokens->insert(tokpair("-include_unused_subckt_pins", OT_INCLUDE_UNUSED_SUBCKT_PINS)); tokens->insert(tokpair("-eblif_format", OT_EBLIF_FORMAT)); tokens->insert(tokpair("-insert_custom_hard_blocks", OT_INSERT_CUSTOM_HARD_BLOCKS)); + tokens->insert(tokpair("-device", OT_DEVICE)); } //============================================================================================ From 29f8f5cb57bd2e7830d6fdd662f82d89daf0eb54 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Wed, 10 Nov 2021 13:46:01 -0500 Subject: [PATCH 31/31] removed unnecessary device parameters that were hard coded --- utils/vqm2blif/src/base/hard_block_recog.h | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/utils/vqm2blif/src/base/hard_block_recog.h b/utils/vqm2blif/src/base/hard_block_recog.h index e842122ee8a..c24d7bd76cd 100644 --- a/utils/vqm2blif/src/base/hard_block_recog.h +++ b/utils/vqm2blif/src/base/hard_block_recog.h @@ -80,20 +80,6 @@ // used to identify the case where a hard block instance is not found within the netlist #define HARD_BLOCK_INSTANCE_DOES_NOT_EXIST -1 -// define how flip flops and LUT will be identified within a given node type (within t_node struct) -#define LUT_TYPE "stratixiv_lcell_comb" -#define DFF_TYPE "dffeas" - -// define the number of output ports a LUT that represents a hard block instance output port would have -#define LUT_OUTPUT_PORT_SIZE 1 - -// names of the output port for a LUT and DFF -#define LUT_OUTPUT_PORT "combout" -#define DFF_OUTPUT_PORT "q" - - - - /* Structure Declarations */