diff --git a/ODIN_II/SRC/BLIFElaborate.cpp b/ODIN_II/SRC/BLIFElaborate.cpp index fb62ab0ed4d..5f45b962c41 100644 --- a/ODIN_II/SRC/BLIFElaborate.cpp +++ b/ODIN_II/SRC/BLIFElaborate.cpp @@ -301,6 +301,7 @@ void blif_elaborate_node(nnode_t* node, short traverse_number, netlist_t* netlis case PAD_NODE: //fallthrough case INPUT_NODE: //fallthrough case OUTPUT_NODE: //fallthrough + case HARD_IP: //fallthrough case BUF_NODE: //fallthrough case BITWISE_NOT: //fallthrough case BITWISE_AND: //fallthrough @@ -312,7 +313,6 @@ void blif_elaborate_node(nnode_t* node, short traverse_number, netlist_t* netlis /* some are already resolved for this phase */ break; } - case HARD_IP: case ADDER_FUNC: case CARRY_FUNC: case CLOCK_NODE: diff --git a/ODIN_II/SRC/BLIFReader.cpp b/ODIN_II/SRC/BLIFReader.cpp index 103214dc0e5..e33dd71d442 100644 --- a/ODIN_II/SRC/BLIFReader.cpp +++ b/ODIN_II/SRC/BLIFReader.cpp @@ -349,31 +349,36 @@ void BLIF::Reader::create_hard_block_nodes(hard_block_models* models) { char* subcircuit_stripped_name = get_stripped_name(subcircuit_name); /* check for coarse-grain configuration */ if (configuration.coarsen) { - new_node->type = yosys_subckt_strmap[subcircuit_name]; + if (yosys_subckt_strmap.find(subcircuit_name) != yosys_subckt_strmap.end()) + new_node->type = yosys_subckt_strmap[subcircuit_name]; - if (subcircuit_stripped_name && new_node->type == NO_OP) + if (new_node->type == NO_OP && yosys_subckt_strmap.find(subcircuit_stripped_name) != yosys_subckt_strmap.end()) new_node->type = yosys_subckt_strmap[subcircuit_stripped_name]; if (new_node->type == NO_OP) { char new_name[READ_BLIF_BUFFER]; vtr::free(new_node->name); /* in case of weird names, need to add memories manually */ - if (ports->count == 5) { + int sc_spot = -1; + char* yosys_subckt_str = NULL; + if ((yosys_subckt_str = retrieve_node_type_from_subckt_name(subcircuit_stripped_name)) != NULL) { /* specify node type */ - new_node->type = yosys_subckt_strmap[SINGLE_PORT_RAM_string]; + new_node->type = yosys_subckt_strmap[yosys_subckt_str]; /* specify node name */ - odin_sprintf(new_name, "\\%s~%ld", SINGLE_PORT_RAM_string, hard_block_number - 1); - new_node->name = make_full_ref_name(new_name, NULL, NULL, NULL, -1); - } else if (ports->count == 9) { + odin_sprintf(new_name, "\\%s~%ld", yosys_subckt_str, hard_block_number - 1); + } else if ((sc_spot = sc_lookup_string(hard_block_names, subcircuit_stripped_name)) != -1) { /* specify node type */ - new_node->type = yosys_subckt_strmap[DUAL_PORT_RAM_string]; + new_node->type = HARD_IP; /* specify node name */ - odin_sprintf(new_name, "\\%s~%ld", DUAL_PORT_RAM_string, hard_block_number - 1); - new_node->name = make_full_ref_name(new_name, NULL, NULL, NULL, -1); + odin_sprintf(new_name, "\\%s~%ld", subcircuit_stripped_name, hard_block_number - 1); } else { error_message(PARSE_BLIF, unknown_location, - "Unsupported sub-circuit type (%s) in BLIF file.\n", subcircuit_name); + "Unsupported subcircuit type (%s) in BLIF file.\n", subcircuit_name); } + new_node->name = make_full_ref_name(new_name, NULL, NULL, NULL, -1); + + // CLEAN UP + vtr::free(yosys_subckt_str); } if (new_node->type == BRAM) { @@ -410,7 +415,7 @@ void BLIF::Reader::create_hard_block_nodes(hard_block_models* models) { if (!model) error_message(PARSE_BLIF, unknown_location, - "Failed to retrieve sub-circuit model (%s)\n", subcircuit_name); + "Failed to retrieve subcircuit model (%s)\n", subcircuit_name); /* Add input and output ports to the new node. */ else { @@ -481,7 +486,7 @@ void BLIF::Reader::create_hard_block_nodes(hard_block_models* models) { } // Create a fake ast node. - if (!configuration.coarsen) { + if (!configuration.coarsen || new_node->type == HARD_IP) { new_node->related_ast_node = create_node_w_type(HARD_BLOCK, my_location); new_node->related_ast_node->children = (ast_node_t**)vtr::calloc(1, sizeof(ast_node_t*)); new_node->related_ast_node->identifier_node = create_tree_node_id(vtr::strdup(subcircuit_name), my_location); @@ -2147,8 +2152,11 @@ void BLIF::Reader::hard_block_sensitivities(const char* subckt_name, nnode_t* ne char* ptr; char* buffer = NULL; attr_t* attributes = new_node->attributes; + operation_list op = (yosys_subckt_strmap.find(subckt_name) != yosys_subckt_strmap.end()) + ? yosys_subckt_strmap[subckt_name] + : NO_OP; - if (need_params(yosys_subckt_strmap[subckt_name])) { + if (need_params(op)) { while (getbline(buffer, READ_BLIF_BUFFER, file)) { my_location.line += 1; ptr = vtr::strtok(buffer, TOKENS, file, buffer); diff --git a/ODIN_II/SRC/BLIFWriter.cpp b/ODIN_II/SRC/BLIFWriter.cpp index 78b30a8040d..21ced99c6b6 100644 --- a/ODIN_II/SRC/BLIFWriter.cpp +++ b/ODIN_II/SRC/BLIFWriter.cpp @@ -74,8 +74,15 @@ inline void BLIF::Writer::_write(const netlist_t* netlist) { output_blif(this->output_file, netlist); } -inline void BLIF::Writer::_create_file(const file_type_e /* file_type */) { - this->output_file = create_blif(global_args.output_file.value().c_str()); +inline void BLIF::Writer::_create_file(const char* file_name, const file_type_e file_type) { + // validate the file_name pionter + oassert(file_name); + // validate the file type + if (file_type != _BLIF) + error_message(UTIL, unknown_location, + "BLIF back-end entity cannot create file types(%d) other than BLIF", file_type); + // create the BLIF file and set it as the output file + this->output_file = create_blif(file_name); } /** * --------------------------------------------------------------------------------------------- diff --git a/ODIN_II/SRC/GenericIO.cpp b/ODIN_II/SRC/GenericIO.cpp index 73b8da7e9bf..0f2938cff0d 100644 --- a/ODIN_II/SRC/GenericIO.cpp +++ b/ODIN_II/SRC/GenericIO.cpp @@ -44,7 +44,7 @@ void GenericIO::_write(const netlist_t* /* netlist */) { "Function \"%s\" is called for reading the input file without definition provided!\n", __PRETTY_FUNCTION__); } -void GenericIO::_create_file(const file_type_e /* file_type */) { +void GenericIO::_create_file(const char* /* file_name */, const file_type_e /* file_type */) { error_message(UTIL, unknown_location, "Function \"%s\" is called for reading the input file without definition provided!\n", __PRETTY_FUNCTION__); } diff --git a/ODIN_II/SRC/GenericWriter.cpp b/ODIN_II/SRC/GenericWriter.cpp index a84508be76f..0ca7ff5a0fa 100644 --- a/ODIN_II/SRC/GenericWriter.cpp +++ b/ODIN_II/SRC/GenericWriter.cpp @@ -37,6 +37,7 @@ GenericWriter::GenericWriter() : GenericIO() { this->output_file = NULL; this->blif_writer = NULL; + this->verilog_writer = NULL; } GenericWriter::~GenericWriter() { @@ -44,6 +45,8 @@ GenericWriter::~GenericWriter() { fclose(this->output_file); if (this->blif_writer) delete this->blif_writer; + if (this->verilog_writer) + delete this->verilog_writer; } inline void GenericWriter::_write(const netlist_t* netlist) { @@ -52,12 +55,12 @@ inline void GenericWriter::_write(const netlist_t* netlist) { this->write_blif(netlist); break; } + case (file_type_e::_VERILOG): { + this->write_verilog(netlist); + break; + } /** * [TODO] - * case (file_type_e::_VERILOG): { - * netlist = this->write_verilog(); - * break; - * } * case (file_type_e::_EBLIF): { * netlist = this->write_verilog(); * break; @@ -79,22 +82,30 @@ inline void GenericWriter::write_blif(const netlist_t* netlist) { this->blif_writer->_write(netlist); } -inline void GenericWriter::_create_file(const file_type_e file_type) { +inline void GenericWriter::write_verilog(const netlist_t* netlist) { + oassert(this->verilog_writer); + this->verilog_writer->_write(netlist); +} + +inline void GenericWriter::_create_file(const char* file_name, const file_type_e file_type) { + // validate the file_name pointer + oassert(file_name); + switch (file_type) { case (file_type_e::_BLIF): { if (!this->blif_writer) { this->blif_writer = new BLIF::Writer(); - this->blif_writer->_create_file(file_type); + this->blif_writer->_create_file(file_name, file_type); } break; } + case (file_type_e::_VERILOG): { + this->verilog_writer = new Verilog::Writer(); + this->verilog_writer->_create_file(file_name, file_type); + break; + } /** * [TODO] - * case (file_type_e::_VERILOG): { - * this->verilog_writer = new VERILOG::Writer(); - * this->verilog_writer->_create_file(); - * break; - * } * case (file_type_e::_EBLIF): { * this->eblif_writer = new EBLIF::Writer(); * this->eblif_writer->_create_file(); diff --git a/ODIN_II/SRC/VerilogWriter.cpp b/ODIN_II/SRC/VerilogWriter.cpp new file mode 100644 index 00000000000..0e70972cec1 --- /dev/null +++ b/ODIN_II/SRC/VerilogWriter.cpp @@ -0,0 +1,214 @@ +/** + * Copyright (c) 2021 Seyed Alireza Damghani (sdamghann@gmail.com) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * @file: includes the definition of VERILOG Writer class to write a + * given netlist in a Verilog file. In addition to the netlist, the + * target architecture hardblocks(DSPs) can be outputed as a blackbox. + * With that said, only the DSPs' declaration are printed. + */ + +#include //std::stringstream + +#include "Verilog.hpp" +#include "odin_globals.h" +#include "hard_blocks.h" +#include "vtr_util.h" + +Verilog::Writer::Writer() + : GenericWriter() { + this->models_declaration = sc_new_string_cache(); +} + +Verilog::Writer::~Writer() { + if (this->models_declaration) + sc_free_string_cache(this->models_declaration); +} + +inline void Verilog::Writer::_create_file(const char* file_name, const file_type_e file_type) { + // validate the file_name pointer + oassert(file_name); + // validate the file type + if (file_type != _VERILOG) + error_message(UTIL, unknown_location, + "Verilog back-end entity cannot create file types(%d) other than Verilog", file_type); + // create the Verilog file and set it as the output file + this->output_file = create_verilog(file_name); +} + +void Verilog::Writer::_write(const netlist_t* netlist) { + // to write the top module and netlist components + if (netlist) { + /* [TODO] */ + } + + // print out the rest od models, including DSPs in the target architecture + t_model* model = Arch.models; + + while (model) { + int sc_spot; + if ((sc_spot = sc_lookup_string(this->models_declaration, model->name)) != -1) { + fprintf(this->output_file, "%s", (char*)this->models_declaration->data[sc_spot]); + fflush(this->output_file); + } + model = model->next; + } +} + +/** + *------------------------------------------------------------------------------------------- + * (function: create_verilog) + * + * @brief initiate a new output file stream + * + * @param file_name the path to the verilog file + * + * @return an output stream to the verilog file + *------------------------------------------------------------------------------------------- + */ +FILE* Verilog::Writer::create_verilog(const char* file_name) { + FILE* out = NULL; + + /* open the file for output */ + out = fopen(file_name, "w"); + + if (out == NULL) { + error_message(UTIL, unknown_location, "Could not open output file %s\n", file_name); + } + return (out); +} + +/** + *------------------------------------------------------------------------------------------- + * (function: declare_blackbox) + * + * @brief find the corresponding blackbox with the given + * name in the given target arhitecture, then add its + * Verilog declartion to this->models_declaration string cache. + * + * @param bb_name the blackbox(DSP) name + * + * @return a long value, which is representing the index of + * the declartion in models string cache. Will return -1 if + * a DSP with the given name does not exist in the architecture. + *------------------------------------------------------------------------------------------- + */ +long Verilog::Writer::declare_blackbox(const char* bb_name) { + /* to validate the blackbox name */ + oassert(bb_name); + + t_model* bb = find_hard_block(bb_name); + if (bb == NULL) { + error_message(UTIL, unknown_location, + "Odin-II failed to find DSP module \"%s\" in the target device.", bb_name); + } + + std::stringstream bb_declaration; + + // need to specify "(* blackbox *)" tag if Yosys + // is going to elaborate the Verilog file + if (elaborator_e::_YOSYS) { + bb_declaration << BLACKBOX_ATTR << NEWLINE; + } + + bb_declaration << MODULE << TAB << bb_name << OPEN_PARENTHESIS << std::endl; + bb_declaration << declare_ports(bb) << std::endl; + bb_declaration << CLOSE_PARENTHESIS << SEMICOLON << std::endl; + bb_declaration << HARD_BLOCK_COMMENT << std::endl; + bb_declaration << END_MODULE << NEWLINE << std::endl; + + int sc_spot; + if ((sc_spot = sc_add_string(this->models_declaration, bb->name)) != -1) { + this->models_declaration->data[sc_spot] = (void*)vtr::strdup(bb_declaration.str().c_str()); + return (sc_spot); + } + + return (-1); +} + +/** + *------------------------------------------------------------------------------------------- + * (function: declare_ports) + * + * @brief generate a string that includes the declaration + * of input/output ports of a given t_model + * + * @param model the DSP t_model pointer + * + * @return a string value including the declaration of all + * input/output ports related to the given DSP model + *------------------------------------------------------------------------------------------- + */ +std::string Verilog::Writer::declare_ports(t_model* model) { + /* to validate the model pointer */ + oassert(model); + + std::stringstream input_stream; + t_model_ports* input_port = model->inputs; + while (input_port) { + input_stream << TAB + << INPUT_PORT << TAB + << OPEN_SQUARE_BRACKET + << input_port->size << COLON << "0" + << CLOSE_SQUARE_BRACKET + << TAB << input_port->name + << COMMA << std::endl; + + // move forward until the end of input ports' list + input_port = input_port->next; + } + + std::stringstream output_stream; + t_model_ports* output_port = model->outputs; + while (output_port) { + output_stream << TAB + << OUTPUT_PORT << TAB + << OPEN_SQUARE_BRACKET + << output_port->size << COLON << "0" + << CLOSE_SQUARE_BRACKET + << TAB << output_port->name + << COMMA << std::endl; + + // move forward until the end of output ports' list + output_port = output_port->next; + } + + std::string input_str = input_stream.str(); + std::string output_str = output_stream.str(); + + // check the value of input/output ports declaration + // to trim extra last semicolon if required + std::stringstream ports_declaration; + if (!input_stream.str().empty() && output_stream.str().empty()) { + input_str[input_str.find_last_not_of(COMMA) - 1] = '\0'; + ports_declaration << input_str; + } else if (!output_stream.str().empty()) { + if (!input_stream.str().empty()) + ports_declaration << input_str; + + ports_declaration << output_str.substr(0, output_str.find_last_not_of(COMMA) - 1); + } + + // return the string value + return (ports_declaration.str()); +} diff --git a/ODIN_II/SRC/YYosys.cpp b/ODIN_II/SRC/YYosys.cpp index 1475a0d7944..55bbac6d36f 100644 --- a/ODIN_II/SRC/YYosys.cpp +++ b/ODIN_II/SRC/YYosys.cpp @@ -42,9 +42,11 @@ #include // wait #include "YYosys.hpp" -#include "config_t.h" // configuration -#include "odin_util.h" // get_directory -#include "odin_error.h" // error_message +#include "Verilog.hpp" +#include "config_t.h" // configuration +#include "odin_util.h" // get_directory +#include "odin_error.h" // error_message +#include "hard_blocks.h" // hard_block_names #ifdef ODIN_USE_YOSYS # include "kernel/yosys.h" // Yosys @@ -122,6 +124,8 @@ void YYosys::perform_elaboration() { if (this->yosys_pid == 0) { /* initalize Yosys */ this->init_yosys(); + /* generate and load DSP declarations */ + this->load_target_dsp_blocks(); /* perform elaboration using Yosys API */ this->elaborate(); @@ -144,6 +148,35 @@ void YYosys::perform_elaboration() { #endif } +/** + * --------------------------------------------------------------------------------------------- + * (function: load_target_dsp_blocks) + * + * @brief this routine generates a Verilog file, including the + * declaration of all DSP blocks available in the targer architecture. + * Then, the Verilog fle is read by Yosys to make it aware of them + * -------------------------------------------------------------------------------------------*/ +void YYosys::load_target_dsp_blocks() { +#ifndef ODIN_USE_YOSYS + error_message(PARSE_ARGS, unknown_location, "%s", YOSYS_INSTALLATION_ERROR); +#else + Verilog::Writer vw = Verilog::Writer(); + vw._create_file(configuration.dsp_verilog.c_str()); + + t_model* hb = Arch.models; + while (hb) { + // declare hardblocks in a verilog file + if (strcmp(hb->name, SINGLE_PORT_RAM_string) && strcmp(hb->name, DUAL_PORT_RAM_string) && strcmp(hb->name, "multiply") && strcmp(hb->name, "adder")) + vw.declare_blackbox(hb->name); + + hb = hb->next; + } + + vw._write(NULL); + run_pass(std::string("read_verilog -nomem2reg " + configuration.dsp_verilog)); +#endif +} + /** * --------------------------------------------------------------------------------------------- * (function: init_yosys) @@ -220,7 +253,7 @@ void YYosys::execute() { run_pass(std::string("read_verilog -nomem2reg -nolatches " + verilog_circuit)); // Check whether cells match libraries and find top module - run_pass(std::string("hierarchy -check -auto-top")); + run_pass(std::string("hierarchy -check -auto-top -purge_lib")); // Use a readable name convention run_pass(std::string("autoname")); @@ -307,7 +340,7 @@ void YYosys::output_blif() { // "-param" is to print non-standard cells parameters // "-impltf" is to not show the definition of primary netlist ports, i.e., VCC, GND and PAD, in the output. - run_pass(std::string("write_blif -param -impltf " + this->coarse_grain_blif)); + run_pass(std::string("write_blif -blackbox -param -impltf " + this->coarse_grain_blif)); #endif } diff --git a/ODIN_II/SRC/hard_blocks.cpp b/ODIN_II/SRC/hard_blocks.cpp index 9e097b83712..b9d08b66ed5 100644 --- a/ODIN_II/SRC/hard_blocks.cpp +++ b/ODIN_II/SRC/hard_blocks.cpp @@ -59,7 +59,8 @@ void cache_hard_block_names() { hard_blocks = Arch.models; hard_block_names = sc_new_string_cache(); while (hard_blocks) { - sc_add_string(hard_block_names, hard_blocks->name); + int sc_spot = sc_add_string(hard_block_names, hard_blocks->name); + hard_block_names->data[sc_spot] = (void*)hard_blocks; hard_blocks = hard_blocks->next; } } diff --git a/ODIN_II/SRC/include/BLIF.hpp b/ODIN_II/SRC/include/BLIF.hpp index 82d8f35a335..80952f89351 100644 --- a/ODIN_II/SRC/include/BLIF.hpp +++ b/ODIN_II/SRC/include/BLIF.hpp @@ -608,7 +608,7 @@ class BLIF { } void _write(const netlist_t* netlist); - void _create_file(const file_type_e file_type); + void _create_file(const char* file_name, const file_type_e file_type = _BLIF); protected: /** diff --git a/ODIN_II/SRC/include/GenericIO.hpp b/ODIN_II/SRC/include/GenericIO.hpp index de4006d1638..91341cc81bf 100644 --- a/ODIN_II/SRC/include/GenericIO.hpp +++ b/ODIN_II/SRC/include/GenericIO.hpp @@ -50,7 +50,7 @@ class GenericIO { virtual void _write(const netlist_t* netlist); /* to create the output file */ - virtual void _create_file(const file_type_e file_type); + virtual void _create_file(const char* file_name, const file_type_e file_type = _UNDEFINED); }; #endif // __GENERIC_IO_H__ diff --git a/ODIN_II/SRC/include/GenericWriter.hpp b/ODIN_II/SRC/include/GenericWriter.hpp index e313186fc01..87e43043750 100644 --- a/ODIN_II/SRC/include/GenericWriter.hpp +++ b/ODIN_II/SRC/include/GenericWriter.hpp @@ -54,24 +54,24 @@ class GenericWriter : public GenericIO { void _write(const netlist_t* netlist); void write_blif(const netlist_t* netlist); + void write_verilog(const netlist_t* netlist); /** * [TODO] - * void write_verilog(const netlist_t* netlist, FILE* output_file); * void write_systemverilog(const netlist_t* netlist, FILE* output_file); * void write_ilang(const netlist_t* netlist, FILE* output_file); */ /* to create the output file */ - void _create_file(const file_type_e file_type); + void _create_file(const char* file_name, const file_type_e file_type = _UNDEFINED); protected: FILE* output_file; private: GenericWriter* blif_writer; + GenericWriter* verilog_writer; /** * [TODO] - * GenericWriter* verilog_writer; * GenericWriter* systemverilog_writer; * GenericWriter* ilang_writer; */ diff --git a/ODIN_II/SRC/include/Verilog.hpp b/ODIN_II/SRC/include/Verilog.hpp index 821b871b51f..b82b97baa8d 100644 --- a/ODIN_II/SRC/include/Verilog.hpp +++ b/ODIN_II/SRC/include/Verilog.hpp @@ -35,6 +35,29 @@ #include "ast_util.h" +/* Yosys models attributes to be printed in a Verilog file */ +#define BLACKBOX_ATTR "(* blackbox *)" +#define KEEP_HIERARCHY_ATTR "(* keep_hierarchy *)" +/* useful aliases and fixed comment messages */ +#define TAB "\t" +#define NEWLINE "\n" +#define HARD_BLOCK_COMMENT "/* the body of the hardblock model is empty since it should be seen as a blackbox */" +/* some fix keywords in the Verilog standard */ +#define MODULE "module" +#define OPEN_PARENTHESIS "(" +#define CLOSE_PARENTHESIS ")" +#define OPEN_SQUARE_BRACKET "[" +#define CLOSE_SQUARE_BRACKET "]" +#define SEMICOLON ";" +#define COLON ":" +#define COMMA "," +#define SPACE " " +#define INPUT_PORT "input" +#define OUTPUT_PORT "output" +#define WIRE_PORT "wire" +#define REG_PORT "reg" +#define END_MODULE "endmodule" + /** * @brief A class to provide the general object of an input Verilog file reader */ @@ -95,9 +118,54 @@ class Verilog { } void _write(const netlist_t* netlist); - void _create_file(const file_type_e file_type); + void _create_file(const char* file_name, const file_type_e file_type = _VERILOG); + + /** + *------------------------------------------------------------------------------------------- + * (function: declare_blackbox) + * + * @brief find the corresponding blackbox with the given + * name in the given target arhitecture, then add its + * Verilog declartion to this->models string cache. + * + * @param bb_name the blackbox(DSP) name + * + * @return a long value, which is representing the index of + * the declartion in models string cache. Will return -1 if + * a DSP with the given name does not exist in the architecture. + *------------------------------------------------------------------------------------------- + */ + long declare_blackbox(const char* bb_name); protected: + STRING_CACHE* models_declaration; + + /** + *------------------------------------------------------------------------------------------- + * (function: create_verilog) + * + * @brief initiate a new output file stream + * + * @param file_name the path to the verilog file + * + * @return a FILE pointer to the verilog file + *------------------------------------------------------------------------------------------- + */ + FILE* create_verilog(const char* file_name); + /** + *------------------------------------------------------------------------------------------- + * (function: declare_ports) + * + * @brief generate a string that includes the declaration + * of input/output ports of a given t_model + * + * @param model the DSP t_model pointer + * + * @return a string value including the declaration of all + * input/output ports related to the given DSP model + *------------------------------------------------------------------------------------------- + */ + std::string declare_ports(t_model* model); }; }; diff --git a/ODIN_II/SRC/include/YYosys.hpp b/ODIN_II/SRC/include/YYosys.hpp index 05b83ca3c48..b7f451ae223 100644 --- a/ODIN_II/SRC/include/YYosys.hpp +++ b/ODIN_II/SRC/include/YYosys.hpp @@ -87,6 +87,15 @@ class YYosys { std::string vtr_primitives_file; // the path of VTR primitives Verilog file std::vector verilog_circuits; // Odin-II input Verilog files + /** + * --------------------------------------------------------------------------------------------- + * (function: load_target_dsp_blocks) + * + * @brief this routine generates a Verilog file, including the + * declaration of all DSP blocks available in the targer architecture. + * Then, the Verilog fle is read by Yosys to make the modules reachable. + * -------------------------------------------------------------------------------------------*/ + void load_target_dsp_blocks(); /** * --------------------------------------------------------------------------------------------- * (function: set_default_variables) diff --git a/ODIN_II/SRC/include/config_t.h b/ODIN_II/SRC/include/config_t.h index 5af66daa6de..5c1df57758b 100644 --- a/ODIN_II/SRC/include/config_t.h +++ b/ODIN_II/SRC/include/config_t.h @@ -10,6 +10,7 @@ struct config_t { std::vector list_of_file_names; std::string debug_output_path; // path for where to output the debug outputs + std::string dsp_verilog; // path for the output Verilog file including target DSPs' declaration enum file_type_e input_file_type; enum file_type_e output_file_type; enum elaborator_e elaborator_type; diff --git a/ODIN_II/SRC/include/odin_util.h b/ODIN_II/SRC/include/odin_util.h index 0a8a1287cec..b5ab3be15b0 100644 --- a/ODIN_II/SRC/include/odin_util.h +++ b/ODIN_II/SRC/include/odin_util.h @@ -59,6 +59,7 @@ char* get_pin_name(char* name); char* get_port_name(char* name); char* get_hard_block_node_name(char* name); char* get_stripped_name(const char* subcircuit_name); +char* retrieve_node_type_from_subckt_name(const char* subcircuit_name); int get_pin_number(char* name); short get_bit(char in); short get_bit(short in); diff --git a/ODIN_II/SRC/odin_ii.cpp b/ODIN_II/SRC/odin_ii.cpp index 5a90588dd3c..f8d8b17b6a8 100644 --- a/ODIN_II/SRC/odin_ii.cpp +++ b/ODIN_II/SRC/odin_ii.cpp @@ -203,7 +203,7 @@ static void techmap() { static void output() { /* creating the output file */ - generic_writer._create_file(configuration.output_file_type); + generic_writer._create_file(global_args.output_file.value().c_str(), configuration.output_file_type); if (syn_netlist) { /** @@ -817,6 +817,7 @@ void set_default_config() { configuration.print_parse_tokens = 0; configuration.output_preproc_source = 0; // TODO: unused configuration.debug_output_path = std::string(DEFAULT_OUTPUT); + configuration.dsp_verilog = "arch_dsp.v"; configuration.arch_file = ""; configuration.fixed_hard_multiplier = 0; diff --git a/ODIN_II/SRC/odin_util.cpp b/ODIN_II/SRC/odin_util.cpp index 2d7ce8b8bd2..e2c5f024c72 100644 --- a/ODIN_II/SRC/odin_util.cpp +++ b/ODIN_II/SRC/odin_util.cpp @@ -669,9 +669,40 @@ char* get_stripped_name(const char* subcircuit_name) { subcircuit_stripped_name[5] = '\0'; } + if (subcircuit_stripped_name == NULL) + return (vtr::strdup(subcircuit_name)); + return (subcircuit_stripped_name); } +/** + *--------------------------------------------------------------------------------------------- + * (function: retrieve_node_type_from_subckt_name) + * + * @brief to retrieve the actual node type from the subcircuit name + * in cases where yosys generates a weird name, which includes port + * widths and additional information in a subcircuit name + * + * @param stripped_name subcircuit irregular name + * + * @return the actual subcircuit name if it was successfully + * retrieved, otherwise NULL pointer + * ------------------------------------------------------------------------------------------- + */ +char* retrieve_node_type_from_subckt_name(const char* subcircuit_name) { + /* validation */ + oassert(subcircuit_name); + + /* looking for Yosys style generated RTLIL module name */ + if (true) { + for (auto pair : yosys_subckt_strmap) + if (std::string(subcircuit_name).find(pair.first, 0) != std::string::npos) + return vtr::strdup(pair.first.c_str()); + } + + return (NULL); +} + /* * Gets the pin number (the number after the ~) * from the given name. diff --git a/ODIN_II/regression_test/benchmark/task/yosys+odin/koios/synthesis_result.json b/ODIN_II/regression_test/benchmark/task/yosys+odin/koios/synthesis_result.json index 59617477ba2..0645e8d7078 100644 --- a/ODIN_II/regression_test/benchmark/task/yosys+odin/koios/synthesis_result.json +++ b/ODIN_II/regression_test/benchmark/task/yosys+odin/koios/synthesis_result.json @@ -4688,11 +4688,11 @@ "[NETLIST] requesting a shift left that will overflow the maximum size of 255 [63]" ], "max_rss(MiB)": 2372.7, - "exec_time(ms)": 18585.2, + "exec_time(ms)": 4802463.9, "elaboration_time(ms)": 12798.1, "optimization_time(ms)": 37.9, - "techmap_time(ms)": 3862, - "synthesis_time(ms)": 16698, + "techmap_time(ms)": 4773374.4, + "synthesis_time(ms)": 4797356.4, "Latch Drivers": 1, "Pi": 790, "Po": 2283, @@ -4726,7 +4726,7 @@ "Multiplier": 7, "Memory": 14, "generic logic size": 4, - "Longest Path": 113, + "Longest Path": 111, "Average Path": 2, "Estimated LUTs": 3548, "Total Node": 4927 @@ -4750,7 +4750,7 @@ "Multiplier": 224, "Memory": 96, "generic logic size": 4, - "Longest Path": 239, + "Longest Path": 235, "Average Path": 4, "Estimated LUTs": 53037, "Total Node": 154766 @@ -5687,7 +5687,7 @@ "exec_time(ms)": 8816.9, "elaboration_time(ms)": 7419.6, "optimization_time(ms)": 11.9, - "techmap_time(ms)": 956.9, + "techmap_time(ms)": 275436.4, "synthesis_time(ms)": 8388.5, "Latch Drivers": 1, "Pi": 1, diff --git a/ODIN_II/regression_test/benchmark/task/yosys+odin/large/synthesis_result.json b/ODIN_II/regression_test/benchmark/task/yosys+odin/large/synthesis_result.json index d132d012868..cdc8df6c636 100644 --- a/ODIN_II/regression_test/benchmark/task/yosys+odin/large/synthesis_result.json +++ b/ODIN_II/regression_test/benchmark/task/yosys+odin/large/synthesis_result.json @@ -137,11 +137,11 @@ "architecture": "k6_frac_N10_frac_chain_mem32K_40nm.xml", "verilog": "LargeRam.v", "max_rss(MiB)": 6326.8, - "exec_time(ms)": 24197.5, + "exec_time(ms)": 9226014.3, "elaboration_time(ms)": 35, - "optimization_time(ms)": 10133, + "optimization_time(ms)": 9177403.5, "techmap_time(ms)": 6358.1, - "synthesis_time(ms)": 16526.1, + "synthesis_time(ms)": 9203921.3, "Pi": 37, "Po": 2, "logic element": 2883573, diff --git a/ODIN_II/regression_test/tools/synth.tcl b/ODIN_II/regression_test/tools/synth.tcl index 2daebc73872..543e06f7658 100644 --- a/ODIN_II/regression_test/tools/synth.tcl +++ b/ODIN_II/regression_test/tools/synth.tcl @@ -6,7 +6,7 @@ yosys -import # Read the hardware decription Verilog read_verilog -nomem2reg -nolatches $env(TCL_CIRCUIT); # Check that cells match libraries and find top module -hierarchy -check -auto-top; +hierarchy -check -auto-top -purge_lib; # Make name convention more readable autoname; diff --git a/vtr_flow/arch/COFFE_22nm/k6FracN10LB_mem20K_complexDSP_customSB_22nm.xml b/vtr_flow/arch/COFFE_22nm/k6FracN10LB_mem20K_complexDSP_customSB_22nm.xml index efc3a169b00..51e19e73195 100644 --- a/vtr_flow/arch/COFFE_22nm/k6FracN10LB_mem20K_complexDSP_customSB_22nm.xml +++ b/vtr_flow/arch/COFFE_22nm/k6FracN10LB_mem20K_complexDSP_customSB_22nm.xml @@ -423,7 +423,6 @@ -