diff --git a/.gitignore b/.gitignore index 2ed34f461fb..fa8ce3cd0e1 100644 --- a/.gitignore +++ b/.gitignore @@ -105,6 +105,11 @@ ODIN_II/usefull_tools/**/track_completed # Yosys +# +#ArchFPGA exec dir +# +ArchFPGA + # #Python # diff --git a/doc/src/yosys+odin/dev_guide/contributing.rst b/doc/src/yosys+odin/dev_guide/contributing.rst index 51609a73291..cc0db069af0 100644 --- a/doc/src/yosys+odin/dev_guide/contributing.rst +++ b/doc/src/yosys+odin/dev_guide/contributing.rst @@ -156,6 +156,10 @@ If no architecture is passed in, Odin-II will create the soft logic and use LUTs However, if an architecture is passed, Odin-II will map accordingly to the available hard blocks and LUTs. It uses a combination of soft logic and hard logic. +.. note:: + + Please visit the Yosys's `Developers Guide `_ for more information about how Yosys deals with the complex blocks defined in the VTR architecture file. + With the integration of Yosys+Odin-II, the Odin-II partial mapping features such as hard/soft logic trade-offs become available for a Yosys elaborated circuit. For instance, using optimization command arguments, a user can force the partial mapper to infer at least a user-defined percentage of multipliers in soft logic. diff --git a/doc/src/yosys/dev_guide.rst b/doc/src/yosys/dev_guide.rst index bd301432f49..bbbb061083c 100644 --- a/doc/src/yosys/dev_guide.rst +++ b/doc/src/yosys/dev_guide.rst @@ -28,8 +28,8 @@ Changes applied to the VTB files are outlined as follows: The LUT size is considered the one defined in the architecture file as the same as the regular VTR flow -How to add new changes? ------------------------ +Working with Complex Blocks and How to Instantiate them? +------------------------------------------------------- The Yosys synthesis commands, including the generic synthesis and additional VTR specific configurations, are provided in `synthesis.tcl `_. To make changes in the overall Yosys synthesis flow, the `synthesis.tcl `_ @@ -42,10 +42,31 @@ the `yosys_models.v `_ and `dual_port_ram.v `_ Verilog files that perform the depth splitting process, the other files are defined as black-box, i.e., their declarations are required while no definition is needed. To add new black-box -components, developers should first provide the corresponding Verilog files similar to the `adder.v `_. Then, a new `read_verilog -lib TTT/NEW_BB.v` +components manually, developers should first provide the corresponding Verilog files similar to the `adder.v `_. Then, a new `read_verilog -lib TTT/NEW_BB.v` command should be added to the Yosys synthesis script. If there is an implicit inference of the new black-box component, the `yosys_models.v `_ Verilog file must also be modified, as mentioned earlier. +It is worth noting that the VTR flow scripts for running Yosys standalone as the VTR frontend are designed to automatically provide the black box declaration of complex blocks defined in the architecture XML file for Yosys. +Technically, by running the ``run_vtr_flow.py`` script with the Yosys frontend, the ``write_arch_bb`` routine, defined in the ``libarchfpga``, is executed initially to extract the information of complex blocks defined in the architecture file. +Then, the routine generates a file, including the black box declaration of the complex blocks in the Verilog format. +The output file is named ``arch_dsps.v`` by default, found in the project destination directory. + +Instantiation of complex blocks is similar to the explicit instantiation of VTR primitives in HDL format. +The ``write_arch_bb`` generates a Verilog module with the same name as the complex block model. +Module ports are also defined according to the port declaration provided in the architecture file. +For instance, the HDL instantiation of the ``multiply_fp_clk`` complex block defined in the ``COFFE_22nm/k6FracN10LB_mem20K_complexDSP_customSB_22nm.xml`` architecture file is as follows: + +.. code-block:: verilog + ... + multiply_fp_clk instance_name( + .b(i_b), // input [31:0] b + .a(i_a), // input [31:0] a + .clk(i_clk), // input [0:0] clk + .out(i_out) // output [31:0] out + ); + ... + +**Algorithm 1** - Custom Complex Blocks HDL Instantiation Yosys Synthesis Script File --------------------------- @@ -135,4 +156,4 @@ Yosys Synthesis Script File # ZZZ will be replaced by run_vtr_flow.pl write_blif -true + vcc -false + gnd -undef + unconn -blackbox ZZZ -**Algorithm 1** - The Yosys Tcl Script File \ No newline at end of file +**Algorithm 2** - The Yosys Tcl Script File \ No newline at end of file diff --git a/libs/EXTERNAL/libyosys/CMakeLists.txt b/libs/EXTERNAL/libyosys/CMakeLists.txt index 97251a453eb..50d9ae3fba5 100644 --- a/libs/EXTERNAL/libyosys/CMakeLists.txt +++ b/libs/EXTERNAL/libyosys/CMakeLists.txt @@ -39,7 +39,10 @@ add_custom_target(yosys ALL DEPENDS ${LIB_FILE} ${BINARY_LIB_FILE}) # create an library target out of the library compilation result add_library(libyosys SHARED IMPORTED GLOBAL) -add_dependencies(libyosys yosys) + +# adding dependency to libarchfpga, as it is required +# by VTR scripts for Yosys standalone frontend +add_dependencies(libyosys yosys libarchfpga) # specify where the library is and where to find the headers set_target_properties(libyosys diff --git a/libs/libarchfpga/CMakeLists.txt b/libs/libarchfpga/CMakeLists.txt index 30b3c628ae9..e2a5ddadbb0 100644 --- a/libs/libarchfpga/CMakeLists.txt +++ b/libs/libarchfpga/CMakeLists.txt @@ -2,13 +2,14 @@ cmake_minimum_required(VERSION 3.9) project("libarchfpga") -file(GLOB_RECURSE EXEC_SOURCES src/main.cpp) +file(GLOB_RECURSE READ_ARCH_EXEC_SRC src/main.cpp) +file(GLOB_RECURSE WRITE_ARCH_BB_EXEC_SRC src/write_arch_bb.cpp) file(GLOB_RECURSE LIB_SOURCES src/*.cpp) file(GLOB_RECURSE LIB_HEADERS src/*.h) files_to_dirs(LIB_HEADERS LIB_INCLUDE_DIRS) #Remove test executable from library -list(REMOVE_ITEM LIB_SOURCES ${EXEC_SOURCES}) +list(REMOVE_ITEM LIB_SOURCES ${READ_ARCH_EXEC_SRC} ${WRITE_ARCH_BB_EXEC_SRC}) #Create the library add_library(libarchfpga STATIC @@ -31,16 +32,40 @@ target_link_libraries(libarchfpga target_compile_definitions(libarchfpga PUBLIC ${INTERCHANGE_SCHEMA_HEADERS}) #Create the test executable -add_executable(read_arch ${EXEC_SOURCES}) +add_executable(read_arch ${READ_ARCH_EXEC_SRC}) +add_executable(write_arch_bb ${WRITE_ARCH_BB_EXEC_SRC}) target_link_libraries(read_arch libarchfpga) +target_link_libraries(write_arch_bb libarchfpga) #Supress IPO link warnings if IPO is enabled get_target_property(READ_ARCH_USES_IPO read_arch INTERPROCEDURAL_OPTIMIZATION) +get_target_property(WRITE_ARCH_BB_USES_IPO write_arch_bb INTERPROCEDURAL_OPTIMIZATION) if (READ_ARCH_USES_IPO) set_property(TARGET read_arch APPEND PROPERTY LINK_FLAGS ${IPO_LINK_WARN_SUPRESS_FLAGS}) endif() +if (WRITE_ARCH_BB_USES_IPO) + set_property(TARGET write_arch_bb APPEND PROPERTY LINK_FLAGS ${IPO_LINK_WARN_SUPRESS_FLAGS}) +endif() + +install(TARGETS libarchfpga read_arch write_arch_bb DESTINATION bin) -install(TARGETS libarchfpga read_arch DESTINATION bin) +# +# install executables in the VTR source root directory +# to utilize them for scripts running VTR flow +# +set(ARCHFPGA_DIR ${VTR_SOURCE_DIR}/ArchFPGA) +# making a new custom target out of libarchfpga to automatically perform +# the house keeping for end users by deleting the ArchFPGA dir in the +# VTR root dir if it exists and holds expired execs +add_custom_target(archfpga-execs ALL + DEPENDS read_arch write_arch_bb + COMMAND ${CMAKE_COMMAND} -E + remove_directory ${ARCHFPGA_DIR} + COMMAND ${CMAKE_COMMAND} -E + make_directory ${ARCHFPGA_DIR} + COMMAND ${CMAKE_COMMAND} -E + copy_directory ${CMAKE_CURRENT_BINARY_DIR} ${ARCHFPGA_DIR} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) # # Unit Tests diff --git a/libs/libarchfpga/src/main.cpp b/libs/libarchfpga/src/main.cpp index 676c3f7562f..6a9e3f354d1 100644 --- a/libs/libarchfpga/src/main.cpp +++ b/libs/libarchfpga/src/main.cpp @@ -12,6 +12,7 @@ #include "vtr_error.h" #include "vtr_memory.h" +#include "arch_util.h" #include "read_xml_arch_file.h" #include "echo_arch.h" @@ -19,7 +20,7 @@ void print_help(); int main(int argc, char** argv) { try { - t_arch* arch = (t_arch*)vtr::calloc(1, sizeof(t_arch)); + t_arch arch; std::vector physical_tile_types; std::vector logical_block_types; @@ -43,12 +44,17 @@ int main(int argc, char** argv) { printf("Reading in architecture\n"); /* function declarations */ - XmlReadArch(argv[1], atoi(argv[2]), arch, physical_tile_types, logical_block_types); + XmlReadArch(argv[1], atoi(argv[2]), &arch, physical_tile_types, logical_block_types); printf("Printing Results\n"); - EchoArch(argv[3], physical_tile_types, logical_block_types, arch); - free(arch); + EchoArch(argv[3], physical_tile_types, logical_block_types, &arch); + + // CLEAN UP + free_arch(&arch); + free_type_descriptors(physical_tile_types); + free_type_descriptors(logical_block_types); + } catch (vtr::VtrError& vtr_error) { printf("Failed to process architecture %s: %s\n", argv[1], vtr_error.what()); return 1; diff --git a/libs/libarchfpga/src/write_arch_bb.cpp b/libs/libarchfpga/src/write_arch_bb.cpp new file mode 100644 index 00000000000..454bd134791 --- /dev/null +++ b/libs/libarchfpga/src/write_arch_bb.cpp @@ -0,0 +1,80 @@ +/** + * Reading an architecture and output the Verilog black box + * declaration of complex blocks in a file + * + * Date: July, 2022 + * Author: Seyed Alireza Damghani + */ + +#include +#include +#include + +#include "vtr_error.h" +#include "vtr_memory.h" + +#include "arch_util.h" +#include "read_xml_arch_file.h" +#include "write_models_bb.h" + +void print_help(); + +int main(int argc, char** argv) { + try { + t_arch arch; + std::vector physical_tile_types; + std::vector logical_block_types; + + if (argc - 1 != 2) { + printf("Error: Unexpected # of arguments. Expected 2 found %d arguments\n", + argc); + print_help(); + return 1; + } + + printf("-------------------------------------------------------------------------------------------------------\n"); + printf("- Read architecture file and generate a Verilog file including the declaration of models as black boxes\n"); + printf("-------------------------------------------------------------------------------------------------------\n\n"); + + printf( + "Inputs: \n" + "architecture %s\n" + "output file %s\n", + argv[1], argv[2]); + printf("Reading in architecture ...\n"); + + /* function declarations */ + XmlReadArch(argv[1], false, &arch, physical_tile_types, logical_block_types); + + printf("Printing Results ...\n"); + + WriteModels_bb(argv[1], argv[2], &arch); + + // CLEAN UP + free_arch(&arch); + free_type_descriptors(physical_tile_types); + free_type_descriptors(logical_block_types); + + } catch (vtr::VtrError& vtr_error) { + printf("Failed to process architecture %s: %s\n", argv[1], vtr_error.what()); + return 1; + } catch (std::exception& error) { + printf("Failed to process architecture %s: %s\n", argv[1], error.what()); + return 1; + } + + printf("Done\n"); + + return 0; +} + +void print_help() { + printf("\n-----------------------------------------------------------------------------------------------------------------------\n"); + printf("write_arch_bb - Read a VPR architecture file and output a Verilog file including the declaration of models as black boxes\n"); + printf("\n"); + printf("Usage: write_arch_bb \n"); + printf("\n"); + printf(" ex: write_arch_bb k4_n10.xml dsp_bb.v\n"); + printf(" Read timing-driven architecture k4_n10.xml and output the results to arch_data.out\n"); + printf("\n-----------------------------------------------------------------------------------------------------------------------\n"); +} diff --git a/libs/libarchfpga/src/write_models_bb.cpp b/libs/libarchfpga/src/write_models_bb.cpp new file mode 100644 index 00000000000..24de3938c96 --- /dev/null +++ b/libs/libarchfpga/src/write_models_bb.cpp @@ -0,0 +1,119 @@ +#include // std::all_of + +#include "vtr_util.h" // vtr::fopen +#include "vtr_assert.h" // VTR ASSERT + +#include "write_models_bb.h" + +using vtr::t_linked_vptr; + +/* the output file description */ +#define OUTPUT_HEADER_COMMENT(Echo, ArchFile) \ + { \ + fprintf(Echo, \ + "/*********************************************************************************************************/\n"); \ + fprintf(Echo, "/* %-100s*/\n", ""); \ + fprintf(Echo, "/* %-100s*/\n", \ + "This is a machine-generated Verilog code, including the black box declaration of"); \ + fprintf(Echo, "/* %-100s*/\n", \ + "complex blocks defined in the following architecture file:"); \ + fprintf(Echo, "/* %-100s*/\n", ""); \ + fprintf(Echo, "/* %-90s*/\n", strrchr(ArchFile, '/') + 1); \ + fprintf(Echo, "/* %-100s*/\n", ""); \ + fprintf(Echo, \ + "/*********************************************************************************************************/\n\n"); \ + } + +/* a comment for the body of black box modules */ +const char* HARD_BLOCK_COMMENT = "/* the body of the complex block module is empty since it should be seen as a black box */"; +/* list of vtr primitives blocks */ +static constexpr short num_vtr_primitives = 8; +static constexpr const char* vtr_primitives[num_vtr_primitives] = { + "LUT_K", + "DFF", + "fpga_interconnect", + "mux", + "adder", + "multiply", + "single_port_ram", + "dual_port_ram"}; + +/* declarations */ +void DeclareModel_bb(FILE* Echo, const t_model* model); + +/** + * (function: WriteModels_bb) + * + * @brief Output the black box declaration of + * complex blocks in the Verilog format + * + * @param ArchFile path to the architecture file + * @param VEchoFile path to the architecture file + * @param arch pointer to the arch data structure + */ +void WriteModels_bb(const char* ArchFile, + const char* VEchoFile, + const t_arch* arch) { + // validate the arch + VTR_ASSERT(arch); + + FILE* Echo = vtr::fopen(VEchoFile, "w"); + t_model* cur_model = arch->models; + + /* the output file description */ + OUTPUT_HEADER_COMMENT(Echo, ArchFile) + + // iterate over models + while (cur_model) { + // avoid printing vtr primitives + if (std::all_of(vtr_primitives, + vtr_primitives + num_vtr_primitives, + [&](const auto& e) { return strcmp(e, cur_model->name); })) + DeclareModel_bb(Echo, cur_model); + + // moving forward with the next complex block + cur_model = cur_model->next; + } + + // CLEAN UP + fclose(Echo); +} + +/** + * (function: DeclareModel_bb) + * + * @brief prints the declaration of the given + * complex block model into the Echo file + * + * @param Echo pointer output file + * @param model pointer to the complex block t_model + */ +void DeclareModel_bb(FILE* Echo, const t_model* model) { + // validate the blackbox name + VTR_ASSERT(model); + + // module + fprintf(Echo, "module %s(\n", model->name); + + // input/output ports + t_model_ports* input_port = model->inputs; + while (input_port) { + fprintf(Echo, "\tinput\t[%d:0]\t%s,\n", input_port->size - 1, input_port->name); + // move forward until the end of input ports' list + input_port = input_port->next; + } + + t_model_ports* output_port = model->outputs; + while (output_port) { + fprintf(Echo, "\toutput\t[%d:0]\t%s,\n", output_port->size - 1, output_port->name); + // move forward until the end of output ports' list + output_port = output_port->next; + } + fprintf(Echo, ");\n"); + + // body + fprintf(Echo, "%s\n", HARD_BLOCK_COMMENT); + + // endmodule + fprintf(Echo, "endmodule\n\n"); +} \ No newline at end of file diff --git a/libs/libarchfpga/src/write_models_bb.h b/libs/libarchfpga/src/write_models_bb.h new file mode 100644 index 00000000000..251ebf51aad --- /dev/null +++ b/libs/libarchfpga/src/write_models_bb.h @@ -0,0 +1,10 @@ +#ifndef WRITE_MODELS_BB_H +#define WRITE_MODELS_BB_H + +#include "arch_types.h" + +void WriteModels_bb(const char* ArchFile, + const char* VEchoFile, + const t_arch* arch); + +#endif diff --git a/vtr_flow/misc/yosyslib/synthesis.tcl b/vtr_flow/misc/yosyslib/synthesis.tcl index 0b7f7af2c09..3d344954c3c 100644 --- a/vtr_flow/misc/yosyslib/synthesis.tcl +++ b/vtr_flow/misc/yosyslib/synthesis.tcl @@ -18,6 +18,9 @@ yosys -import # XXX (input circuit) is replaced with filename by the run_vtr_flow script read_verilog -sv -nolatches XXX +# read the custom complex blocks in the architecture +read_verilog -lib CCC + # These commands follow the generic `synth' # command script inside Yosys # The -libdir argument allows Yosys to search the current @@ -64,7 +67,7 @@ opt -full techmap opt -fast -# We read the definitions for all the VTR primitives +# read the definitions for all the VTR primitives # as blackboxes read_verilog -lib TTT/adder.v read_verilog -lib TTT/multiply.v diff --git a/vtr_flow/scripts/python_libs/vtr/paths.py b/vtr_flow/scripts/python_libs/vtr/paths.py index 61a4d3c8a48..0d87fa1483a 100644 --- a/vtr_flow/scripts/python_libs/vtr/paths.py +++ b/vtr_flow/scripts/python_libs/vtr/paths.py @@ -22,6 +22,10 @@ yosys_lib_path = vtr_flow_path / "misc" / "yosyslib" yosys_script_path = yosys_lib_path / "synthesis.tcl" +# ARCHFPGA paths +archfpga_path = root_path / "ArchFPGA" +write_arch_bb_exe_path = root_path / "build/libs/libarchfpga/write_arch_bb" + # ABC paths abc_path = root_path / "abc" abc_exe_path = abc_path / "abc" diff --git a/vtr_flow/scripts/python_libs/vtr/yosys/yosys.py b/vtr_flow/scripts/python_libs/vtr/yosys/yosys.py index 0cad32a963f..3b29a34daa7 100644 --- a/vtr_flow/scripts/python_libs/vtr/yosys/yosys.py +++ b/vtr_flow/scripts/python_libs/vtr/yosys/yosys.py @@ -25,6 +25,7 @@ "DPRAM": "dual_port_ram.v", "SPRAMR": "spram_rename.v", "DPRAMR": "dpram_rename.v", + "DSPBB": "arch_dsps.v", } @@ -58,6 +59,7 @@ def init_script_file( yosys_dpram_full_path, yosys_spram_rename_full_path, yosys_dpram_rename_full_path, + architecture_dsp_full_path, circuit_list, output_netlist, memory_addr_width, @@ -81,6 +83,7 @@ def init_script_file( "DDD": yosys_dpram_full_path, "SSR": yosys_spram_rename_full_path, "DDR": yosys_dpram_rename_full_path, + "CCC": architecture_dsp_full_path, "TTT": str(vtr.paths.yosys_lib_path), "ZZZ": output_netlist, }, @@ -99,7 +102,7 @@ def init_script_file( vtr.file_replace(yosys_dpram_rename_full_path, {"PPP": memory_addr_width}) -# pylint: disable=too-many-arguments, too-many-locals +# pylint: disable=too-many-arguments, too-many-locals, too-many-statements def run( architecture_file, circuit_file, @@ -202,6 +205,21 @@ def run( shutil.copyfile(yosys_base_spram_rename, yosys_spram_rename_full_path) shutil.copyfile(yosys_base_dpram_rename, yosys_dpram_rename_full_path) + write_arch_bb_exec = str(vtr.paths.write_arch_bb_exe_path) + architecture_dsp_full_path = str(vtr.paths.scripts_path / temp_dir / YOSYS_LIB_FILES["DSPBB"]) + + # executing write_arch_bb to extract the black box definitions of the given arch file + command_runner.run_system_command( + [ + write_arch_bb_exec, + str(vtr.paths.scripts_path / architecture_file), + architecture_dsp_full_path, + ], + temp_dir=temp_dir, + log_filename="write_arch_bb.log", + indent_depth=1, + ) + # Create a list showing all (.v) and (.vh) files circuit_list = create_circuits_list(circuit_file, include_files) @@ -212,6 +230,7 @@ def run( yosys_dpram_full_path, yosys_spram_rename_full_path, yosys_dpram_rename_full_path, + architecture_dsp_full_path, circuit_list, output_netlist.name, vtr.determine_memory_addr_width(str(architecture_file)), @@ -236,4 +255,4 @@ def run( ) -# pylint: enable=too-many-arguments, too-many-locals +# pylint: enable=too-many-arguments, too-many-locals, too-many-statements