From 1fb37f4c719a494af835feeda7911304471bc358 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 8 Apr 2020 12:55:09 -0600 Subject: [PATCH 1/5] improve directory creator to support same functionality as 'mkdir -p' --- .../libopenfpgautil/src/openfpga_digest.cpp | 137 ++++++++++++++---- .../libopenfpgautil/src/openfpga_digest.h | 2 +- .../annotation/write_xml_device_rr_gsb.cpp | 2 +- openfpga/src/base/openfpga_bitstream.cpp | 2 +- openfpga/src/base/openfpga_sdc.cpp | 4 +- openfpga/src/fpga_verilog/verilog_api.cpp | 10 +- 6 files changed, 121 insertions(+), 36 deletions(-) diff --git a/libopenfpga/libopenfpgautil/src/openfpga_digest.cpp b/libopenfpga/libopenfpgautil/src/openfpga_digest.cpp index 4714700e4..3ae2083df 100644 --- a/libopenfpga/libopenfpgautil/src/openfpga_digest.cpp +++ b/libopenfpga/libopenfpgautil/src/openfpga_digest.cpp @@ -3,6 +3,7 @@ * in OpenFPGA framework *******************************************************************/ #include +#include #include /* Headers from vtrutil library */ @@ -117,37 +118,121 @@ std::string find_path_dir_name(const std::string& file_name) { /******************************************************************** * Create a directory with a given path ********************************************************************/ -bool create_dir_path(const char* dir_path) { - /* Give up if the path is empty */ - if (nullptr == dir_path) { - VTR_LOG_ERROR("dir_path is empty and nothing is created.\n"); - return false; - } +static +bool create_dir_path(const std::string& dir_path, + const bool& verbose) { + /* Give up if the path is empty */ + if (true == dir_path.empty()) { + VTR_LOG_ERROR("Directory path is empty and nothing will be created.\n"); + return false; + } - /* Try to create a directory */ - int ret = mkdir(dir_path, S_IRWXU|S_IRWXG|S_IROTH|S_IXOTH); + /* Try to create a directory */ + int ret = mkdir(dir_path.c_str(), S_IRWXU|S_IRWXG|S_IROTH|S_IXOTH); - /* Analyze the return flag and output status */ - switch (ret) { - case 0: - VTR_LOG("Succeed to create directory '%s'\n", - dir_path); - return true; - case -1: - if (EEXIST == errno) { - VTR_LOG_WARN("Directory '%s' already exists. Will overwrite contents\n", - dir_path); - return true; - } - break; - default: - VTR_LOG_ERROR("Create directory '%s'...Failed!\n", - dir_path); - exit(1); - return false; + /* Analyze the return flag and output status */ + switch (ret) { + case 0: + VTR_LOGV(verbose, + "Succeed to create directory '%s'\n", + dir_path.c_str()); + return true; + case -1: + if (EEXIST == errno) { + VTR_LOGV_WARN(verbose, + "Directory '%s' already exists. Will overwrite contents\n", + dir_path.c_str()); + return true; + } + VTR_LOG_ERROR("Create directory '%s'...Failed!\n", + dir_path.c_str()); + exit(1); + break; + default: + VTR_LOG_ERROR("Create directory '%s'...Failed!\n", + dir_path.c_str()); + exit(1); + return false; } return false; } +/******************************************************************** + * Recursively create a directory with a given path + * The create_dir_path() function will only try to create a directory + * in the last level. If any parent directory is not created, it will + * always fail. + * This function will try to create all the parent directory before + * creating the last level. + ********************************************************************/ +static +bool rec_create_dir_path(const std::string& dir_path) { + /* Give up if the path is empty */ + if (true == dir_path.empty()) { + VTR_LOG_ERROR("Directory path is empty and nothing will be created.\n"); + return false; + } + + /* Try to find the positions of all the slashes + * which are the splitter between directories + */ + char back_slash = '/'; + +#ifdef _WIN32 +/* For windows OS, replace any '/' with '\' */ + char back_slash = '\\'; +#endif + + std::vector slash_pos; + + /* Keep searching until we reach the end of the string */ + for (size_t pos = 0; pos < dir_path.size(); ++pos) { + /* Skip the pos = 0, we should avoid creating any root directory */ + if ( (back_slash == dir_path.at(pos)) + && (0 != pos)) { + slash_pos.push_back(pos); + } + } + + /* Create directory by following the position of back slash + * For each back slash, create a sub string from the beginning + * and try to create directory + */ + for (const size_t& pos : slash_pos) { + std::string sub_dir = dir_path.substr(0, pos); + + /* Turn on verbose output only for the last position: the leaf directory */ + if (false == create_dir_path(sub_dir, &pos == &slash_pos.back())) { + return false; + } + } + + return true; +} + +/******************************************************************** + * Top function to create a directory with a given path + * Allow users to select if use the recursive way or not + * + * Strongly recommend to use the recursive way, as it can maximum + * guarantee the success in creation of directories + ********************************************************************/ +void create_directory(const std::string& dir_path, const bool& recursive) { + std::string formatted_dir_path = format_dir_path(dir_path); + bool status = false; + + if (true == recursive) { + status = rec_create_dir_path(formatted_dir_path); + } else { + status = create_dir_path(formatted_dir_path, true); + } + + if (false == status) { + VTR_LOG_ERROR("Fail to create directory '%s'\n", + formatted_dir_path.c_str()); + exit(1); + } +} + } /* namespace openfpga ends */ diff --git a/libopenfpga/libopenfpgautil/src/openfpga_digest.h b/libopenfpga/libopenfpgautil/src/openfpga_digest.h index 90af3dc4e..0e1cd5d76 100644 --- a/libopenfpga/libopenfpgautil/src/openfpga_digest.h +++ b/libopenfpga/libopenfpgautil/src/openfpga_digest.h @@ -23,7 +23,7 @@ std::string find_path_file_name(const std::string& file_name); std::string find_path_dir_name(const std::string& file_name); -bool create_dir_path(const char* dir_path); +void create_directory(const std::string& dir_path, const bool& recursive = true); } /* namespace openfpga ends */ diff --git a/openfpga/src/annotation/write_xml_device_rr_gsb.cpp b/openfpga/src/annotation/write_xml_device_rr_gsb.cpp index 906c71d70..63c5454a7 100644 --- a/openfpga/src/annotation/write_xml_device_rr_gsb.cpp +++ b/openfpga/src/annotation/write_xml_device_rr_gsb.cpp @@ -182,7 +182,7 @@ void write_device_rr_gsb_to_xml(const char* sb_xml_dir, std::string xml_dir_name = format_dir_path(std::string(sb_xml_dir)); /* Create directories */ - create_dir_path(xml_dir_name.c_str()); + create_directory(xml_dir_name); vtr::Point sb_range = device_rr_gsb.get_gsb_range(); diff --git a/openfpga/src/base/openfpga_bitstream.cpp b/openfpga/src/base/openfpga_bitstream.cpp index e732dee92..e472e7618 100644 --- a/openfpga/src/base/openfpga_bitstream.cpp +++ b/openfpga/src/base/openfpga_bitstream.cpp @@ -36,7 +36,7 @@ void fpga_bitstream(OpenfpgaContext& openfpga_ctx, std::string src_dir_path = find_path_dir_name(cmd_context.option_value(cmd, opt_file)); /* Create directories */ - create_dir_path(src_dir_path.c_str()); + create_directory(src_dir_path); write_arch_independent_bitstream_to_xml_file(openfpga_ctx.bitstream_manager(), cmd_context.option_value(cmd, opt_file)); diff --git a/openfpga/src/base/openfpga_sdc.cpp b/openfpga/src/base/openfpga_sdc.cpp index cb2e1bf72..06b594e73 100644 --- a/openfpga/src/base/openfpga_sdc.cpp +++ b/openfpga/src/base/openfpga_sdc.cpp @@ -42,7 +42,7 @@ void write_pnr_sdc(OpenfpgaContext& openfpga_ctx, std::string sdc_dir_path = format_dir_path(cmd_context.option_value(cmd, opt_output_dir)); /* Create directories */ - create_dir_path(sdc_dir_path.c_str()); + create_directory(sdc_dir_path); PnrSdcOption options(sdc_dir_path); @@ -96,7 +96,7 @@ void write_analysis_sdc(OpenfpgaContext& openfpga_ctx, std::string sdc_dir_path = format_dir_path(cmd_context.option_value(cmd, opt_output_dir)); /* Create directories */ - create_dir_path(sdc_dir_path.c_str()); + create_directory(sdc_dir_path); AnalysisSdcOption options(sdc_dir_path); options.set_generate_sdc_analysis(true); diff --git a/openfpga/src/fpga_verilog/verilog_api.cpp b/openfpga/src/fpga_verilog/verilog_api.cpp index dc332db58..c37b68888 100644 --- a/openfpga/src/fpga_verilog/verilog_api.cpp +++ b/openfpga/src/fpga_verilog/verilog_api.cpp @@ -63,19 +63,19 @@ void fpga_fabric_verilog(ModuleManager& module_manager, std::string src_dir_path = format_dir_path(options.output_directory()); /* Create directories */ - create_dir_path(src_dir_path.c_str()); + create_directory(src_dir_path); /* Sub directory under SRC directory to contain all the primitive block netlists */ std::string submodule_dir_path = src_dir_path + std::string(DEFAULT_SUBMODULE_DIR_NAME); - create_dir_path(submodule_dir_path.c_str()); + create_directory(submodule_dir_path); /* Sub directory under SRC directory to contain all the logic block netlists */ std::string lb_dir_path = src_dir_path + std::string(DEFAULT_LB_DIR_NAME); - create_dir_path(lb_dir_path.c_str()); + create_directory(lb_dir_path); /* Sub directory under SRC directory to contain all the routing block netlists */ std::string rr_dir_path = src_dir_path + std::string(DEFAULT_RR_DIR_NAME); - create_dir_path(rr_dir_path.c_str()); + create_directory(rr_dir_path); /* Print Verilog files containing preprocessing flags */ print_verilog_preprocessing_flags_netlist(std::string(src_dir_path), @@ -153,7 +153,7 @@ void fpga_verilog_testbench(const ModuleManager& module_manager, std::string netlist_name = atom_ctx.nlist.netlist_name(); /* Create directories */ - create_dir_path(src_dir_path.c_str()); + create_directory(src_dir_path); /* TODO: check if this works here. This function was in fabric generator */ print_verilog_simulation_preprocessing_flags(std::string(src_dir_path), From b9ade3fcb6d4421afc4aca80d4b7ebc4e27ff811 Mon Sep 17 00:00:00 2001 From: Xifan Tang Date: Wed, 8 Apr 2020 14:13:28 -0600 Subject: [PATCH 2/5] documentation update to introduce new features in script mode of OpenFPGA shell --- .../openfpga_shell/launch_openfpga_shell.rst | 2 + .../openfpga_shell/openfpga_commands.rst | 2 +- .../source/openfpga_shell/openfpga_script.rst | 39 +++++++++++++++---- 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/docs/source/openfpga_shell/launch_openfpga_shell.rst b/docs/source/openfpga_shell/launch_openfpga_shell.rst index 3ef6e9fb5..8ef7e3858 100644 --- a/docs/source/openfpga_shell/launch_openfpga_shell.rst +++ b/docs/source/openfpga_shell/launch_openfpga_shell.rst @@ -11,6 +11,8 @@ To launch OpenFPGA shell, users can choose two modes. Launch OpenFPGA in interactive mode where users type-in command by command and get runtime results + .. warning:: Currently OpenFPGA does not support continued lines and comments + .. option:: --file or -f Launch OpenFPGA in script mode where users write commands in scripts and FPGA will execute them diff --git a/docs/source/openfpga_shell/openfpga_commands.rst b/docs/source/openfpga_shell/openfpga_commands.rst index 8f71cdb54..3712cea0d 100644 --- a/docs/source/openfpga_shell/openfpga_commands.rst +++ b/docs/source/openfpga_shell/openfpga_commands.rst @@ -194,7 +194,7 @@ FPGA-SDC - ``--constrain_zero_delay_paths`` Constrain all the zero-delay paths in FPGA fabric - .. note:: Zero-delay path may cause errors in some PnR tools as it is considered illegal + .. note:: Zero-delay path may cause errors in some PnR tools as it is considered illegal - ``--verbose`` Enable verbose output diff --git a/docs/source/openfpga_shell/openfpga_script.rst b/docs/source/openfpga_shell/openfpga_script.rst index dde33a044..7c9bd5548 100644 --- a/docs/source/openfpga_shell/openfpga_script.rst +++ b/docs/source/openfpga_shell/openfpga_script.rst @@ -4,8 +4,20 @@ OpenFPGA Script Format ---------------------- OpenFPGA accepts a simplified tcl-like script format. -Commented lines are started with `#`. -Note that comments can be added inline or as a new line. + +.. option:: Comments + + Any content after a ``#`` will be treated as comments. + Comments will not be executed. + + .. note:: comments can be added inline or as a new line. See the example below + +.. option:: Continued line + + Lines to be continued should be finished with ``\``. + Continued lines will be conjuncted and executed as one line + + .. note:: please ensure necessary spaces. Otherwise it may cause command parser fail. The following is an example. @@ -21,7 +33,8 @@ The following is an example. #write_openfpga_arch -f ./arch_echo.xml # Annotate the OpenFPGA architecture to VPR data base - link_openfpga_arch --activity_file ./test_blif/and.act --sort_gsb_chan_node_in_edges #--verbose + link_openfpga_arch --activity_file ./test_blif/and.act \ + --sort_gsb_chan_node_in_edges #--verbose # Check and correct any naming conflicts in the BLIF netlist check_netlist_naming_conflict --fix --report ./netlist_renaming.xml @@ -35,7 +48,8 @@ The following is an example. # Build the module graph # - Enabled compression on routing architecture modules # - Enable pin duplication on grid modules - build_fabric --compress_routing --duplicate_grid_pin #--verbose + build_fabric --compress_routing \ + --duplicate_grid_pin #--verbose # Repack the netlist to physical pbs # This must be done before bitstream generator and testbench generation @@ -44,14 +58,21 @@ The following is an example. # Build the bitstream # - Output the fabric-independent bitstream to a file - build_architecture_bitstream --verbose --file /var/tmp/xtang/openfpga_test_src/fabric_indepenent_bitstream.xml + build_architecture_bitstream --verbose \ + --file /var/tmp/xtang/openfpga_test_src/fabric_indepenent_bitstream.xml # Build fabric-dependent bitstream build_fabric_bitstream --verbose # Write the Verilog netlist for FPGA fabric # - Enable the use of explicit port mapping in Verilog netlist - write_fabric_verilog --file /var/tmp/xtang/openfpga_test_src/SRC --explicit_port_mapping --include_timing --include_signal_init --support_icarus_simulator --print_user_defined_template --verbose + write_fabric_verilog --file /var/tmp/xtang/openfpga_test_src/SRC \ + --explicit_port_mapping \ + --include_timing \ + --include_signal_init \ + --support_icarus_simulator \ + --print_user_defined_template \ + --verbose # Write the Verilog testbench for FPGA fabric # - We suggest the use of same output directory as fabric Verilog netlists @@ -59,7 +80,11 @@ The following is an example. # - Enable top-level testbench which is a full verification including programming circuit and core logic of FPGA # - Enable pre-configured top-level testbench which is a fast verification skipping programming phase # - Simulation ini file is optional and is needed only when you need to interface different HDL simulators using openfpga flow-run scripts - write_verilog_testbench --file /var/tmp/xtang/openfpga_test_src/SRC --reference_benchmark_file_path /var/tmp/xtang/and.v --print_top_testbench --print_preconfig_top_testbench --print_simulation_ini /var/tmp/xtang/openfpga_test_src/simulation_deck.ini + write_verilog_testbench --file /var/tmp/xtang/openfpga_test_src/SRC \ + --reference_benchmark_file_path /var/tmp/xtang/and.v \ + --print_top_testbench \ + --print_preconfig_top_testbench \ + --print_simulation_ini /var/tmp/xtang/openfpga_test_src/simulation_deck.ini # Write the SDC files for PnR backend # - Turn on every options here From b9dab2baaf760d7ba5bb440e8467758349f4b2b1 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 8 Apr 2020 16:18:05 -0600 Subject: [PATCH 3/5] add exit codes to command execution in shell context --- .../libopenfpgashell/src/command_exit_codes.h | 27 +++++ libopenfpga/libopenfpgashell/src/shell.h | 55 ++++++++--- libopenfpga/libopenfpgashell/src/shell.tpp | 98 ++++++++++++++----- .../libopenfpgashell/test/test_shell.cpp | 10 +- .../check_netlist_naming_conflict.cpp | 20 +++- .../check_netlist_naming_conflict.h | 4 +- openfpga/src/base/openfpga_bitstream.cpp | 17 +++- openfpga/src/base/openfpga_bitstream.h | 8 +- openfpga/src/base/openfpga_build_fabric.cpp | 10 +- openfpga/src/base/openfpga_build_fabric.h | 4 +- openfpga/src/base/openfpga_link_arch.cpp | 12 ++- openfpga/src/base/openfpga_link_arch.h | 4 +- .../base/openfpga_lut_truth_table_fixup.cpp | 11 ++- .../src/base/openfpga_lut_truth_table_fixup.h | 4 +- openfpga/src/base/openfpga_pb_pin_fixup.cpp | 10 +- openfpga/src/base/openfpga_pb_pin_fixup.h | 4 +- openfpga/src/base/openfpga_read_arch.cpp | 17 +++- openfpga/src/base/openfpga_read_arch.h | 8 +- openfpga/src/base/openfpga_repack.cpp | 10 +- openfpga/src/base/openfpga_repack.h | 4 +- openfpga/src/base/openfpga_sdc.cpp | 17 +++- openfpga/src/base/openfpga_sdc.h | 8 +- openfpga/src/base/openfpga_verilog.cpp | 17 +++- openfpga/src/base/openfpga_verilog.h | 8 +- openfpga/src/base/openfpga_write_gsb.cpp | 10 +- openfpga/src/base/openfpga_write_gsb.h | 4 +- 26 files changed, 293 insertions(+), 108 deletions(-) create mode 100644 libopenfpga/libopenfpgashell/src/command_exit_codes.h diff --git a/libopenfpga/libopenfpgashell/src/command_exit_codes.h b/libopenfpga/libopenfpgashell/src/command_exit_codes.h new file mode 100644 index 000000000..f1490e533 --- /dev/null +++ b/libopenfpga/libopenfpgashell/src/command_exit_codes.h @@ -0,0 +1,27 @@ +#ifndef COMMAND_EXIT_CODES_H +#define COMMAND_EXIT_CODES_H + +/* Begin namespace openfpga */ +namespace openfpga { + +/********************************************************************* + * Exit codes to signal success/failure status of command execution + * Depend on the exit code, OpenFPGA shell will decide to continue or abort + ********************************************************************/ + +/* Never been executed */ +constexpr int CMD_EXEC_NONE = -1; + +/* Everything OK */ +constexpr int CMD_EXEC_SUCCESS = 0; + +/* Fatal error occurred, we have to abort and do not execute the rest of commands */ +constexpr int CMD_EXEC_FATAL_ERROR = 1; + +/* See minor errors but it will not impact the downsteam. We can continue to execute the rest of commands */ +constexpr int CMD_EXEC_MINOR_ERROR = 2; + + +} /* End namespace openfpga */ + +#endif diff --git a/libopenfpga/libopenfpgashell/src/shell.h b/libopenfpga/libopenfpgashell/src/shell.h index 427580010..1a49b313c 100644 --- a/libopenfpga/libopenfpgashell/src/shell.h +++ b/libopenfpga/libopenfpgashell/src/shell.h @@ -10,6 +10,7 @@ #include "vtr_range.h" #include "command.h" #include "command_context.h" +#include "command_exit_codes.h" #include "shell_fwd.h" /* Begin namespace openfpga */ @@ -88,25 +89,49 @@ class Shell { ShellCommandId add_command(const Command& cmd, const char* descr); void set_command_class(const ShellCommandId& cmd_id, const ShellCommandClassId& cmd_class_id); /* Link the execute function to a command - * We support here three types of functions to be executed in the shell - * 1. Standard function, including the data exchange and commands - * 2. Short function, including only the data exchange - * 3. Built-in function, including only the shell envoriment variables - * 4. Marco function, which directly call a macro function without command parsing + * We support here different types of functions to be executed in the shell * Users just need to specify the function object and its type will be automatically inferred + * + * Note that all the function should return exit codes complying to the shell_exit_code.h + * execept the internal functions + */ + + /* Standard function, including the data exchange and commands + * This function requires the data exchange to be constant + * This is designed for outputting functions requiring external data than the */ void set_command_const_execute_function(const ShellCommandId& cmd_id, - std::function exec_func); + std::function exec_func); + + /* Standard function, including the data exchange and commands + * This function allows modification to the data exchange + * This is designed for implementing functions requiring external data than the + */ void set_command_execute_function(const ShellCommandId& cmd_id, - std::function exec_func); + std::function exec_func); + + /* Short function, including only the data exchange + * This function requires the data exchange to be constant + * This is designed for outputting functions without external data than the + */ void set_command_const_execute_function(const ShellCommandId& cmd_id, - std::function exec_func); + std::function exec_func); + + /* Short function, including only the data exchange + * This function allows modification to the data exchange + * This is designed for internal implementing functions without external data than the + */ void set_command_execute_function(const ShellCommandId& cmd_id, - std::function exec_func); + std::function exec_func); + + /* Built-in function, including only the shell envoriment variables */ void set_command_execute_function(const ShellCommandId& cmd_id, std::function exec_func); + + /* Marco function, which directly call a macro function without command parsing */ void set_command_execute_function(const ShellCommandId& cmd_id, std::function exec_func); + void set_command_dependency(const ShellCommandId& cmd_id, const std::vector& cmd_dependency); ShellCommandClassId add_command_class(const char* name); @@ -126,7 +151,7 @@ class Shell { /* Execute a command, the command line is the user's input to launch a command * The common_context is the data structure to exchange data between commands */ - void execute_command(const char* cmd_line, T& common_context); + int execute_command(const char* cmd_line, T& common_context); private: /* Internal data */ /* Name of the shell, this will appear in the interactive mode */ std::string name_; @@ -162,10 +187,10 @@ class Shell { * 3. Built-in function, including only the shell envoriment variables * 4. Marco function, which directly call a macro function without command parsing */ - vtr::vector> command_const_execute_functions_; - vtr::vector> command_standard_execute_functions_; - vtr::vector> command_short_const_execute_functions_; - vtr::vector> command_short_execute_functions_; + vtr::vector> command_const_execute_functions_; + vtr::vector> command_standard_execute_functions_; + vtr::vector> command_short_const_execute_functions_; + vtr::vector> command_short_execute_functions_; vtr::vector> command_builtin_execute_functions_; vtr::vector> command_macro_execute_functions_; @@ -175,7 +200,7 @@ class Shell { vtr::vector command_execute_function_types_; /* A flag to indicate if the command has been executed */ - vtr::vector command_status_; + vtr::vector command_status_; /* Dependency graph for different commands, * This helps the shell interface to check if a command need other commands to be run before its execution diff --git a/libopenfpga/libopenfpgashell/src/shell.tpp b/libopenfpga/libopenfpgashell/src/shell.tpp index 5fe043f8e..69ec89ab9 100644 --- a/libopenfpga/libopenfpgashell/src/shell.tpp +++ b/libopenfpga/libopenfpgashell/src/shell.tpp @@ -131,7 +131,7 @@ ShellCommandId Shell::add_command(const Command& cmd, const char* descr) { command_short_execute_functions_.emplace_back(); command_builtin_execute_functions_.emplace_back(); command_macro_execute_functions_.emplace_back(); - command_status_.push_back(false); /* By default, the command should be marked as never executed */ + command_status_.push_back(CMD_EXEC_NONE); /* By default, the command should be marked as fatal error as it has been never executed */ command_dependencies_.emplace_back(); /* Register the name in the name2id map */ @@ -155,7 +155,7 @@ void Shell::set_command_class(const ShellCommandId& cmd_id, const ShellComman template void Shell::set_command_const_execute_function(const ShellCommandId& cmd_id, - std::function exec_func) { + std::function exec_func) { VTR_ASSERT(true == valid_command_id(cmd_id)); command_execute_function_types_[cmd_id] = CONST_STANDARD; command_const_execute_functions_[cmd_id] = exec_func; @@ -163,7 +163,7 @@ void Shell::set_command_const_execute_function(const ShellCommandId& cmd_id, template void Shell::set_command_execute_function(const ShellCommandId& cmd_id, - std::function exec_func) { + std::function exec_func) { VTR_ASSERT(true == valid_command_id(cmd_id)); command_execute_function_types_[cmd_id] = STANDARD; command_standard_execute_functions_[cmd_id] = exec_func; @@ -171,7 +171,7 @@ void Shell::set_command_execute_function(const ShellCommandId& cmd_id, template void Shell::set_command_const_execute_function(const ShellCommandId& cmd_id, - std::function exec_func) { + std::function exec_func) { VTR_ASSERT(true == valid_command_id(cmd_id)); command_execute_function_types_[cmd_id] = CONST_SHORT; command_short_const_execute_functions_[cmd_id] = exec_func; @@ -179,7 +179,7 @@ void Shell::set_command_const_execute_function(const ShellCommandId& cmd_id, template void Shell::set_command_execute_function(const ShellCommandId& cmd_id, - std::function exec_func) { + std::function exec_func) { VTR_ASSERT(true == valid_command_id(cmd_id)); command_execute_function_types_[cmd_id] = SHORT; command_short_execute_functions_[cmd_id] = exec_func; @@ -341,9 +341,15 @@ void Shell::run_script_mode(const char* script_file_name, T& context) { /* Process the command only when the full command line in ended */ if (!cmd_line.empty()) { VTR_LOG("\nCommand line to execute: %s\n", cmd_line.c_str()); - execute_command(cmd_line.c_str(), context); + int status = execute_command(cmd_line.c_str(), context); /* Empty the line ready to start a new line */ cmd_line.clear(); + + /* Check the execution status of the command, if fatal error happened, we should abort immediately */ + if (CMD_EXEC_FATAL_ERROR == status) { + VTR_LOG("Fatal error occurred!\nAbort and enter interactive mode\n"); + break; + } } } fp.close(); @@ -376,16 +382,49 @@ void Shell::print_commands() const { template void Shell::exit() const { + /* Check all the command status, if we see fatal errors or minor errors, we drop an error code */ + int exit_code = 0; + for (const int& status : command_status_) { + if ( (status == CMD_EXEC_FATAL_ERROR) + || (status == CMD_EXEC_MINOR_ERROR) ) { + exit_code = 1; + break; + } + } + + /* Show error message if we detect any errors */ + int num_err = 0; + if (0 != exit_code) { + VTR_LOG("\n"); + for (const ShellCommandId& cmd : commands()) { + if (command_status_[cmd] == CMD_EXEC_FATAL_ERROR) { + VTR_LOG_ERROR("Command '%s' execution has fatal errors\n", + commands_[cmd].name().c_str()); + num_err++; + } + + if (command_status_[cmd] == CMD_EXEC_MINOR_ERROR) { + VTR_LOG_ERROR("Command '%s' execution has minor errors\n", + commands_[cmd].name().c_str()); + num_err++; + } + } + } + + VTR_LOG("\nFinish execution with %d errors\n", + num_err); + VTR_LOG("\nThank you for using %s!\n", name().c_str()); - std::exit(0); + + std::exit(exit_code); } /************************************************************************ * Private executors ***********************************************************************/ template -void Shell::execute_command(const char* cmd_line, +int Shell::execute_command(const char* cmd_line, T& common_context) { /* Tokenize the line */ openfpga::StringToken tokenizer(cmd_line); @@ -396,17 +435,18 @@ void Shell::execute_command(const char* cmd_line, if (ShellCommandId::INVALID() == cmd_id) { VTR_LOG("Try to call a command '%s' which is not defined!\n", tokens[0].c_str()); - return; + return CMD_EXEC_FATAL_ERROR; } /* Check the dependency graph to see if all the prequistics have been met */ for (const ShellCommandId& dep_cmd : command_dependencies_[cmd_id]) { - if (false == command_status_[dep_cmd]) { + if ( (CMD_EXEC_NONE == command_status_[dep_cmd]) + || (CMD_EXEC_FATAL_ERROR == command_status_[dep_cmd]) ) { VTR_LOG("Command '%s' is required to be executed before command '%s'!\n", commands_[dep_cmd].name().c_str(), commands_[cmd_id].name().c_str()); /* Echo the command help desk */ print_command_options(commands_[cmd_id]); - return; + return CMD_EXEC_FATAL_ERROR; } } @@ -421,25 +461,22 @@ void Shell::execute_command(const char* cmd_line, argv[itok] = (char*)malloc((tokens[itok].length() + 1) * sizeof(char)); strcpy(argv[itok], tokens[itok].c_str()); } - /* Execute the marco function */ - command_macro_execute_functions_[cmd_id](tokens.size(), argv); + /* Execute the marco function and record the execution status */ + command_status_[cmd_id] = command_macro_execute_functions_[cmd_id](tokens.size(), argv); /* Free the argv */ for (size_t itok = 0; itok < tokens.size(); ++itok) { free(argv[itok]); } free(argv); - /* Change the status of the command */ - command_status_[cmd_id] = true; - /* Finish for macro command, return */ - return; + return command_status_[cmd_id]; } if (false == parse_command(tokens, commands_[cmd_id], command_contexts_[cmd_id])) { /* Echo the command */ print_command_options(commands_[cmd_id]); - return; + return CMD_EXEC_FATAL_ERROR; } /* Parse succeed. Let user to confirm selected options */ @@ -448,31 +485,38 @@ void Shell::execute_command(const char* cmd_line, /* Execute the command depending on the type of function ! */ switch (command_execute_function_types_[cmd_id]) { case CONST_STANDARD: - command_const_execute_functions_[cmd_id](common_context, commands_[cmd_id], command_contexts_[cmd_id]); + command_status_[cmd_id] = command_const_execute_functions_[cmd_id](common_context, commands_[cmd_id], command_contexts_[cmd_id]); break; case STANDARD: - command_standard_execute_functions_[cmd_id](common_context, commands_[cmd_id], command_contexts_[cmd_id]); + command_status_[cmd_id] = command_standard_execute_functions_[cmd_id](common_context, commands_[cmd_id], command_contexts_[cmd_id]); break; case CONST_SHORT: - command_short_const_execute_functions_[cmd_id](common_context); + command_status_[cmd_id] = command_short_const_execute_functions_[cmd_id](common_context); break; case SHORT: - command_short_execute_functions_[cmd_id](common_context); + command_status_[cmd_id] = command_short_execute_functions_[cmd_id](common_context); break; case BUILTIN: command_builtin_execute_functions_[cmd_id](); + /* Built-in execution is always correct */ + command_status_[cmd_id] = CMD_EXEC_SUCCESS; break; /* MACRO should be executed eariler in this function. It should not appear here */ default: /* This is not allowed! Error out */ - VTR_LOG("Invalid type of execute function for command '%s'!\n", - commands_[cmd_id].name().c_str()); + VTR_LOG_ERROR("Invalid type of execute function for command '%s'!\n", + commands_[cmd_id].name().c_str()); /* Exit the shell using the exit() function inside this class! */ - exit(); + return CMD_EXEC_FATAL_ERROR; } - /* Change the status of the command */ - command_status_[cmd_id] = true; + /* Forbid users to return the status CMD_EXEC_NONE */ + if (CMD_EXEC_NONE == command_status_[cmd_id]) { + VTR_LOG_ERROR("It is illegal to return never-executed status for an executed command!\n"); + return CMD_EXEC_FATAL_ERROR; + } + + return command_status_[cmd_id]; } /************************************************************************ diff --git a/libopenfpga/libopenfpgashell/test/test_shell.cpp b/libopenfpga/libopenfpgashell/test/test_shell.cpp index 649859d85..0edc257dd 100644 --- a/libopenfpga/libopenfpgashell/test/test_shell.cpp +++ b/libopenfpga/libopenfpgashell/test/test_shell.cpp @@ -15,16 +15,20 @@ class ShellContext { }; static -void shell_execute_set(ShellContext& context, +int shell_execute_set(ShellContext& context, const Command& cmd, const CommandContext& cmd_context) { CommandOptionId opt_id = cmd.option("value"); /* Get the value of a in the command context */ context.a = std::atoi(cmd_context.option_value(cmd, opt_id).c_str()); + + return CMD_EXEC_SUCCESS; } static -void shell_execute_print(ShellContext& context) { +int shell_execute_print(ShellContext& context) { VTR_LOG("a=%d\n", context.a); + + return CMD_EXEC_SUCCESS; } static @@ -35,7 +39,7 @@ int shell_execute_print_macro(int argc, char** argv) { VTR_LOG("\t[%d]: %s\n", iarg, argv[iarg]); } - return 0; + return CMD_EXEC_SUCCESS; } int main(int argc, char** argv) { diff --git a/openfpga/src/annotation/check_netlist_naming_conflict.cpp b/openfpga/src/annotation/check_netlist_naming_conflict.cpp index 3470c9f0a..a8ab94384 100644 --- a/openfpga/src/annotation/check_netlist_naming_conflict.cpp +++ b/openfpga/src/annotation/check_netlist_naming_conflict.cpp @@ -11,6 +11,9 @@ #include "vtr_assert.h" #include "vtr_log.h" +/* Headers from openfpgashell library */ +#include "command_exit_codes.h" + /* Headers from archopenfpga library */ #include "write_xml_utils.h" @@ -213,8 +216,8 @@ void print_netlist_naming_fix_report(const std::string& fname, * in the users' BLIF netlist that violates the syntax of OpenFPGA * fabric generator, i.e., Verilog generator and SPICE generator *******************************************************************/ -void check_netlist_naming_conflict(OpenfpgaContext& openfpga_context, - const Command& cmd, const CommandContext& cmd_context) { +int check_netlist_naming_conflict(OpenfpgaContext& openfpga_context, + const Command& cmd, const CommandContext& cmd_context) { vtr::ScopedStartFinishTimer timer("Check naming violations of netlist blocks and nets"); /* By default, we replace all the illegal characters with '_' */ @@ -231,7 +234,15 @@ void check_netlist_naming_conflict(OpenfpgaContext& openfpga_context, num_conflicts); VTR_LOGV(0 == num_conflicts, "Check naming conflicts in the netlist passed.\n"); - return; + + /* If we see conflicts, report minor error */ + if (0 < num_conflicts) { + return CMD_EXEC_MINOR_ERROR; + } + + /* Otherwise, we should see zero conflicts */ + VTR_ASSERT(0 == num_conflicts); + return CMD_EXEC_SUCCESS; } /* If the auto correction is enabled, we apply a fix */ @@ -248,6 +259,9 @@ void check_netlist_naming_conflict(OpenfpgaContext& openfpga_context, cmd_context.option_value(cmd, opt_report).c_str()); } } + + /* TODO: should identify the error code from internal function execution */ + return CMD_EXEC_SUCCESS; } } /* end namespace openfpga */ diff --git a/openfpga/src/annotation/check_netlist_naming_conflict.h b/openfpga/src/annotation/check_netlist_naming_conflict.h index 54d86bca4..cad6c3963 100644 --- a/openfpga/src/annotation/check_netlist_naming_conflict.h +++ b/openfpga/src/annotation/check_netlist_naming_conflict.h @@ -15,8 +15,8 @@ /* begin namespace openfpga */ namespace openfpga { -void check_netlist_naming_conflict(OpenfpgaContext& openfpga_context, - const Command& cmd, const CommandContext& cmd_context); +int check_netlist_naming_conflict(OpenfpgaContext& openfpga_context, + const Command& cmd, const CommandContext& cmd_context); } /* end namespace openfpga */ diff --git a/openfpga/src/base/openfpga_bitstream.cpp b/openfpga/src/base/openfpga_bitstream.cpp index e472e7618..7e2a19fc4 100644 --- a/openfpga/src/base/openfpga_bitstream.cpp +++ b/openfpga/src/base/openfpga_bitstream.cpp @@ -5,6 +5,9 @@ #include "vtr_time.h" #include "vtr_log.h" +/* Headers from openfpgashell library */ +#include "command_exit_codes.h" + /* Headers from openfpgautil library */ #include "openfpga_digest.h" @@ -22,8 +25,8 @@ namespace openfpga { /******************************************************************** * A wrapper function to call the build_device_bitstream() in FPGA bitstream *******************************************************************/ -void fpga_bitstream(OpenfpgaContext& openfpga_ctx, - const Command& cmd, const CommandContext& cmd_context) { +int fpga_bitstream(OpenfpgaContext& openfpga_ctx, + const Command& cmd, const CommandContext& cmd_context) { CommandOptionId opt_verbose = cmd.option("verbose"); CommandOptionId opt_file = cmd.option("file"); @@ -41,19 +44,25 @@ void fpga_bitstream(OpenfpgaContext& openfpga_ctx, write_arch_independent_bitstream_to_xml_file(openfpga_ctx.bitstream_manager(), cmd_context.option_value(cmd, opt_file)); } + + /* TODO: should identify the error code from internal function execution */ + return CMD_EXEC_SUCCESS; } /******************************************************************** * A wrapper function to call the build_fabric_bitstream() in FPGA bitstream *******************************************************************/ -void build_fabric_bitstream(OpenfpgaContext& openfpga_ctx, - const Command& cmd, const CommandContext& cmd_context) { +int build_fabric_bitstream(OpenfpgaContext& openfpga_ctx, + const Command& cmd, const CommandContext& cmd_context) { CommandOptionId opt_verbose = cmd.option("verbose"); openfpga_ctx.mutable_fabric_bitstream() = build_fabric_dependent_bitstream(openfpga_ctx.bitstream_manager(), openfpga_ctx.module_graph(), cmd_context.option_enable(cmd, opt_verbose)); + + /* TODO: should identify the error code from internal function execution */ + return CMD_EXEC_SUCCESS; } } /* end namespace openfpga */ diff --git a/openfpga/src/base/openfpga_bitstream.h b/openfpga/src/base/openfpga_bitstream.h index 9dc2ad471..58f1c7e86 100644 --- a/openfpga/src/base/openfpga_bitstream.h +++ b/openfpga/src/base/openfpga_bitstream.h @@ -15,11 +15,11 @@ /* begin namespace openfpga */ namespace openfpga { -void fpga_bitstream(OpenfpgaContext& openfpga_ctx, - const Command& cmd, const CommandContext& cmd_context); +int fpga_bitstream(OpenfpgaContext& openfpga_ctx, + const Command& cmd, const CommandContext& cmd_context); -void build_fabric_bitstream(OpenfpgaContext& openfpga_ctx, - const Command& cmd, const CommandContext& cmd_context); +int build_fabric_bitstream(OpenfpgaContext& openfpga_ctx, + const Command& cmd, const CommandContext& cmd_context); } /* end namespace openfpga */ diff --git a/openfpga/src/base/openfpga_build_fabric.cpp b/openfpga/src/base/openfpga_build_fabric.cpp index 4e8b44916..67203216a 100644 --- a/openfpga/src/base/openfpga_build_fabric.cpp +++ b/openfpga/src/base/openfpga_build_fabric.cpp @@ -5,6 +5,9 @@ #include "vtr_time.h" #include "vtr_log.h" +/* Headers from openfpgashell library */ +#include "command_exit_codes.h" + #include "device_rr_gsb.h" #include "device_rr_gsb_utils.h" #include "build_device_module.h" @@ -56,8 +59,8 @@ void compress_routing_hierarchy(OpenfpgaContext& openfpga_ctx, /******************************************************************** * Build the module graph for FPGA device *******************************************************************/ -void build_fabric(OpenfpgaContext& openfpga_ctx, - const Command& cmd, const CommandContext& cmd_context) { +int build_fabric(OpenfpgaContext& openfpga_ctx, + const Command& cmd, const CommandContext& cmd_context) { CommandOptionId opt_compress_routing = cmd.option("compress_routing"); CommandOptionId opt_duplicate_grid_pin = cmd.option("duplicate_grid_pin"); @@ -77,6 +80,9 @@ void build_fabric(OpenfpgaContext& openfpga_ctx, cmd_context.option_enable(cmd, opt_compress_routing), cmd_context.option_enable(cmd, opt_duplicate_grid_pin), cmd_context.option_enable(cmd, opt_verbose)); + + /* TODO: should identify the error code from internal function execution */ + return CMD_EXEC_SUCCESS; } } /* end namespace openfpga */ diff --git a/openfpga/src/base/openfpga_build_fabric.h b/openfpga/src/base/openfpga_build_fabric.h index 824ed63a1..3b63c7ab2 100644 --- a/openfpga/src/base/openfpga_build_fabric.h +++ b/openfpga/src/base/openfpga_build_fabric.h @@ -15,8 +15,8 @@ /* begin namespace openfpga */ namespace openfpga { -void build_fabric(OpenfpgaContext& openfpga_ctx, - const Command& cmd, const CommandContext& cmd_context); +int build_fabric(OpenfpgaContext& openfpga_ctx, + const Command& cmd, const CommandContext& cmd_context); } /* end namespace openfpga */ diff --git a/openfpga/src/base/openfpga_link_arch.cpp b/openfpga/src/base/openfpga_link_arch.cpp index 34c98ee8d..65aef7cf8 100644 --- a/openfpga/src/base/openfpga_link_arch.cpp +++ b/openfpga/src/base/openfpga_link_arch.cpp @@ -8,6 +8,9 @@ #include "vtr_assert.h" #include "vtr_log.h" +/* Headers from openfpgashell library */ +#include "command_exit_codes.h" + /* Headers from vpr library */ #include "read_activity.h" @@ -59,8 +62,8 @@ bool is_vpr_rr_graph_supported(const RRGraph& rr_graph) { * - physical pb_graph nodes and pb_graph pins * - circuit models for global routing architecture *******************************************************************/ -void link_arch(OpenfpgaContext& openfpga_ctx, - const Command& cmd, const CommandContext& cmd_context) { +int link_arch(OpenfpgaContext& openfpga_ctx, + const Command& cmd, const CommandContext& cmd_context) { vtr::ScopedStartFinishTimer timer("Link OpenFPGA architecture to VPR architecture"); @@ -105,7 +108,7 @@ void link_arch(OpenfpgaContext& openfpga_ctx, * - DeviceRRGSB */ if (false == is_vpr_rr_graph_supported(g_vpr_ctx.device().rr_graph)) { - return; + return CMD_EXEC_FATAL_ERROR; } annotate_device_rr_gsb(g_vpr_ctx.device(), @@ -147,6 +150,9 @@ void link_arch(OpenfpgaContext& openfpga_ctx, annotate_simulation_setting(g_vpr_ctx.atom(), openfpga_ctx.net_activity(), openfpga_ctx.mutable_arch().sim_setting); + + /* TODO: should identify the error code from internal function execution */ + return CMD_EXEC_SUCCESS; } } /* end namespace openfpga */ diff --git a/openfpga/src/base/openfpga_link_arch.h b/openfpga/src/base/openfpga_link_arch.h index 742c29541..8eba64386 100644 --- a/openfpga/src/base/openfpga_link_arch.h +++ b/openfpga/src/base/openfpga_link_arch.h @@ -15,8 +15,8 @@ /* begin namespace openfpga */ namespace openfpga { -void link_arch(OpenfpgaContext& openfpga_context, - const Command& cmd, const CommandContext& cmd_context); +int link_arch(OpenfpgaContext& openfpga_context, + const Command& cmd, const CommandContext& cmd_context); } /* end namespace openfpga */ diff --git a/openfpga/src/base/openfpga_lut_truth_table_fixup.cpp b/openfpga/src/base/openfpga_lut_truth_table_fixup.cpp index 45ecbca31..396842dcd 100644 --- a/openfpga/src/base/openfpga_lut_truth_table_fixup.cpp +++ b/openfpga/src/base/openfpga_lut_truth_table_fixup.cpp @@ -7,6 +7,9 @@ #include "vtr_assert.h" #include "vtr_log.h" +/* Headers from openfpgashell library */ +#include "command_exit_codes.h" + /* Headers from vpr library */ #include "vpr_utils.h" @@ -182,7 +185,6 @@ void update_lut_tt_with_post_packing_results(const AtomContext& atom_ctx, } } - /******************************************************************** * Top-level function to fix up the lut truth table results after packing is done * The problem comes from a mismatch between the packing results and @@ -194,8 +196,8 @@ void update_lut_tt_with_post_packing_results(const AtomContext& atom_ctx, * This function aims to fix the mess after packing so that the truth table * can be synchronized *******************************************************************/ -void lut_truth_table_fixup(OpenfpgaContext& openfpga_context, - const Command& cmd, const CommandContext& cmd_context) { +int lut_truth_table_fixup(OpenfpgaContext& openfpga_context, + const Command& cmd, const CommandContext& cmd_context) { vtr::ScopedStartFinishTimer timer("Fix up LUT truth tables after packing optimization"); @@ -206,6 +208,9 @@ void lut_truth_table_fixup(OpenfpgaContext& openfpga_context, g_vpr_ctx.clustering(), openfpga_context.mutable_vpr_clustering_annotation(), cmd_context.option_enable(cmd, opt_verbose)); + + /* TODO: should identify the error code from internal function execution */ + return CMD_EXEC_SUCCESS; } } /* end namespace openfpga */ diff --git a/openfpga/src/base/openfpga_lut_truth_table_fixup.h b/openfpga/src/base/openfpga_lut_truth_table_fixup.h index f11abc7fb..d685a4b44 100644 --- a/openfpga/src/base/openfpga_lut_truth_table_fixup.h +++ b/openfpga/src/base/openfpga_lut_truth_table_fixup.h @@ -15,8 +15,8 @@ /* begin namespace openfpga */ namespace openfpga { -void lut_truth_table_fixup(OpenfpgaContext& openfpga_context, - const Command& cmd, const CommandContext& cmd_context); +int lut_truth_table_fixup(OpenfpgaContext& openfpga_context, + const Command& cmd, const CommandContext& cmd_context); } /* end namespace openfpga */ diff --git a/openfpga/src/base/openfpga_pb_pin_fixup.cpp b/openfpga/src/base/openfpga_pb_pin_fixup.cpp index cc91bdebe..2a8686190 100644 --- a/openfpga/src/base/openfpga_pb_pin_fixup.cpp +++ b/openfpga/src/base/openfpga_pb_pin_fixup.cpp @@ -7,6 +7,9 @@ #include "vtr_assert.h" #include "vtr_log.h" +/* Headers from openfpgashell library */ +#include "command_exit_codes.h" + /* Headers from vpr library */ #include "vpr_utils.h" @@ -254,8 +257,8 @@ void update_pb_pin_with_post_routing_results(const DeviceContext& device_ctx, * This function aims to fix the mess after routing so that the net mapping * can be synchronized *******************************************************************/ -void pb_pin_fixup(OpenfpgaContext& openfpga_context, - const Command& cmd, const CommandContext& cmd_context) { +int pb_pin_fixup(OpenfpgaContext& openfpga_context, + const Command& cmd, const CommandContext& cmd_context) { vtr::ScopedStartFinishTimer timer("Fix up pb pin mapping results after routing optimization"); @@ -268,6 +271,9 @@ void pb_pin_fixup(OpenfpgaContext& openfpga_context, openfpga_context.vpr_routing_annotation(), openfpga_context.mutable_vpr_clustering_annotation(), cmd_context.option_enable(cmd, opt_verbose)); + + /* TODO: should identify the error code from internal function execution */ + return CMD_EXEC_SUCCESS; } } /* end namespace openfpga */ diff --git a/openfpga/src/base/openfpga_pb_pin_fixup.h b/openfpga/src/base/openfpga_pb_pin_fixup.h index e924c6067..bab4e9565 100644 --- a/openfpga/src/base/openfpga_pb_pin_fixup.h +++ b/openfpga/src/base/openfpga_pb_pin_fixup.h @@ -15,8 +15,8 @@ /* begin namespace openfpga */ namespace openfpga { -void pb_pin_fixup(OpenfpgaContext& openfpga_context, - const Command& cmd, const CommandContext& cmd_context); +int pb_pin_fixup(OpenfpgaContext& openfpga_context, + const Command& cmd, const CommandContext& cmd_context); } /* end namespace openfpga */ diff --git a/openfpga/src/base/openfpga_read_arch.cpp b/openfpga/src/base/openfpga_read_arch.cpp index 1a36e85a3..214af1612 100644 --- a/openfpga/src/base/openfpga_read_arch.cpp +++ b/openfpga/src/base/openfpga_read_arch.cpp @@ -5,6 +5,9 @@ /* Headers from vtrutil library */ #include "vtr_log.h" +/* Headers from openfpgashell library */ +#include "command_exit_codes.h" + /* Headers from archopenfpga library */ #include "read_xml_openfpga_arch.h" #include "check_circuit_library.h" @@ -22,8 +25,8 @@ namespace openfpga { * The command will accept an option '--file' which is the architecture * file provided by users *******************************************************************/ -void read_arch(OpenfpgaContext& openfpga_context, - const Command& cmd, const CommandContext& cmd_context) { +int read_arch(OpenfpgaContext& openfpga_context, + const Command& cmd, const CommandContext& cmd_context) { /* Check the option '--file' is enabled or not * Actually, it must be enabled as the shell interface will check * before reaching this fuction @@ -44,6 +47,9 @@ void read_arch(OpenfpgaContext& openfpga_context, * 3. Simulation settings (TODO) */ check_circuit_library(openfpga_context.arch().circuit_lib); + + /* TODO: should identify the error code from internal function execution */ + return CMD_EXEC_SUCCESS; } /******************************************************************** @@ -53,8 +59,8 @@ void read_arch(OpenfpgaContext& openfpga_context, * The command will accept an option '--file' which is the architecture * file provided by users *******************************************************************/ -void write_arch(const OpenfpgaContext& openfpga_context, - const Command& cmd, const CommandContext& cmd_context) { +int write_arch(const OpenfpgaContext& openfpga_context, + const Command& cmd, const CommandContext& cmd_context) { /* Check the option '--file' is enabled or not * Actually, it must be enabled as the shell interface will check * before reaching this fuction @@ -68,6 +74,9 @@ void write_arch(const OpenfpgaContext& openfpga_context, VTR_LOG("Writing XML architecture to '%s'...\n", arch_file_name.c_str()); write_xml_openfpga_arch(arch_file_name.c_str(), openfpga_context.arch()); + + /* TODO: should identify the error code from internal function execution */ + return CMD_EXEC_SUCCESS; } } /* end namespace openfpga */ diff --git a/openfpga/src/base/openfpga_read_arch.h b/openfpga/src/base/openfpga_read_arch.h index dcc04d77a..b664a7b3e 100644 --- a/openfpga/src/base/openfpga_read_arch.h +++ b/openfpga/src/base/openfpga_read_arch.h @@ -15,11 +15,11 @@ /* begin namespace openfpga */ namespace openfpga { -void read_arch(OpenfpgaContext& openfpga_context, - const Command& cmd, const CommandContext& cmd_context); +int read_arch(OpenfpgaContext& openfpga_context, + const Command& cmd, const CommandContext& cmd_context); -void write_arch(const OpenfpgaContext& openfpga_context, - const Command& cmd, const CommandContext& cmd_context); +int write_arch(const OpenfpgaContext& openfpga_context, + const Command& cmd, const CommandContext& cmd_context); } /* end namespace openfpga */ diff --git a/openfpga/src/base/openfpga_repack.cpp b/openfpga/src/base/openfpga_repack.cpp index 91c6b4798..fe0529d04 100644 --- a/openfpga/src/base/openfpga_repack.cpp +++ b/openfpga/src/base/openfpga_repack.cpp @@ -5,6 +5,9 @@ #include "vtr_time.h" #include "vtr_log.h" +/* Headers from openfpgashell library */ +#include "command_exit_codes.h" + #include "build_physical_truth_table.h" #include "repack.h" #include "openfpga_repack.h" @@ -18,8 +21,8 @@ namespace openfpga { /******************************************************************** * A wrapper function to call the fabric_verilog function of FPGA-Verilog *******************************************************************/ -void repack(OpenfpgaContext& openfpga_ctx, - const Command& cmd, const CommandContext& cmd_context) { +int repack(OpenfpgaContext& openfpga_ctx, + const Command& cmd, const CommandContext& cmd_context) { CommandOptionId opt_verbose = cmd.option("verbose"); @@ -35,6 +38,9 @@ void repack(OpenfpgaContext& openfpga_ctx, g_vpr_ctx.clustering(), openfpga_ctx.vpr_device_annotation(), openfpga_ctx.arch().circuit_lib); + + /* TODO: should identify the error code from internal function execution */ + return CMD_EXEC_SUCCESS; } } /* end namespace openfpga */ diff --git a/openfpga/src/base/openfpga_repack.h b/openfpga/src/base/openfpga_repack.h index 0fce62f78..83e4bce63 100644 --- a/openfpga/src/base/openfpga_repack.h +++ b/openfpga/src/base/openfpga_repack.h @@ -15,8 +15,8 @@ /* begin namespace openfpga */ namespace openfpga { -void repack(OpenfpgaContext& openfpga_ctx, - const Command& cmd, const CommandContext& cmd_context); +int repack(OpenfpgaContext& openfpga_ctx, + const Command& cmd, const CommandContext& cmd_context); } /* end namespace openfpga */ diff --git a/openfpga/src/base/openfpga_sdc.cpp b/openfpga/src/base/openfpga_sdc.cpp index 06b594e73..21a3ab8fb 100644 --- a/openfpga/src/base/openfpga_sdc.cpp +++ b/openfpga/src/base/openfpga_sdc.cpp @@ -5,6 +5,9 @@ #include "vtr_time.h" #include "vtr_log.h" +/* Headers from openfpgashell library */ +#include "command_exit_codes.h" + /* Headers from openfpgautil library */ #include "openfpga_digest.h" @@ -22,8 +25,8 @@ namespace openfpga { /******************************************************************** * A wrapper function to call the PnR SDC generator of FPGA-SDC *******************************************************************/ -void write_pnr_sdc(OpenfpgaContext& openfpga_ctx, - const Command& cmd, const CommandContext& cmd_context) { +int write_pnr_sdc(OpenfpgaContext& openfpga_ctx, + const Command& cmd, const CommandContext& cmd_context) { CommandOptionId opt_output_dir = cmd.option("file"); CommandOptionId opt_constrain_global_port = cmd.option("constrain_global_port"); @@ -80,13 +83,16 @@ void write_pnr_sdc(OpenfpgaContext& openfpga_ctx, global_ports, openfpga_ctx.flow_manager().compress_routing()); } + + /* TODO: should identify the error code from internal function execution */ + return CMD_EXEC_SUCCESS; } /******************************************************************** * A wrapper function to call the analysis SDC generator of FPGA-SDC *******************************************************************/ -void write_analysis_sdc(OpenfpgaContext& openfpga_ctx, - const Command& cmd, const CommandContext& cmd_context) { +int write_analysis_sdc(OpenfpgaContext& openfpga_ctx, + const Command& cmd, const CommandContext& cmd_context) { CommandOptionId opt_output_dir = cmd.option("file"); @@ -114,6 +120,9 @@ void write_analysis_sdc(OpenfpgaContext& openfpga_ctx, global_ports, openfpga_ctx.flow_manager().compress_routing()); } + + /* TODO: should identify the error code from internal function execution */ + return CMD_EXEC_SUCCESS; } } /* end namespace openfpga */ diff --git a/openfpga/src/base/openfpga_sdc.h b/openfpga/src/base/openfpga_sdc.h index 110a8cd72..99a87f899 100644 --- a/openfpga/src/base/openfpga_sdc.h +++ b/openfpga/src/base/openfpga_sdc.h @@ -15,11 +15,11 @@ /* begin namespace openfpga */ namespace openfpga { -void write_pnr_sdc(OpenfpgaContext& openfpga_ctx, - const Command& cmd, const CommandContext& cmd_context); +int write_pnr_sdc(OpenfpgaContext& openfpga_ctx, + const Command& cmd, const CommandContext& cmd_context); -void write_analysis_sdc(OpenfpgaContext& openfpga_ctx, - const Command& cmd, const CommandContext& cmd_context); +int write_analysis_sdc(OpenfpgaContext& openfpga_ctx, + const Command& cmd, const CommandContext& cmd_context); } /* end namespace openfpga */ diff --git a/openfpga/src/base/openfpga_verilog.cpp b/openfpga/src/base/openfpga_verilog.cpp index 1ce23a1d4..c79b68fc2 100644 --- a/openfpga/src/base/openfpga_verilog.cpp +++ b/openfpga/src/base/openfpga_verilog.cpp @@ -5,6 +5,9 @@ #include "vtr_time.h" #include "vtr_log.h" +/* Headers from openfpgashell library */ +#include "command_exit_codes.h" + #include "verilog_api.h" #include "openfpga_verilog.h" @@ -17,8 +20,8 @@ namespace openfpga { /******************************************************************** * A wrapper function to call the fabric Verilog generator of FPGA-Verilog *******************************************************************/ -void write_fabric_verilog(OpenfpgaContext& openfpga_ctx, - const Command& cmd, const CommandContext& cmd_context) { +int write_fabric_verilog(OpenfpgaContext& openfpga_ctx, + const Command& cmd, const CommandContext& cmd_context) { CommandOptionId opt_output_dir = cmd.option("file"); CommandOptionId opt_explicit_port_mapping = cmd.option("explicit_port_mapping"); @@ -48,13 +51,16 @@ void write_fabric_verilog(OpenfpgaContext& openfpga_ctx, openfpga_ctx.vpr_device_annotation(), openfpga_ctx.device_rr_gsb(), options); + + /* TODO: should identify the error code from internal function execution */ + return CMD_EXEC_SUCCESS; } /******************************************************************** * A wrapper function to call the Verilog testbench generator of FPGA-Verilog *******************************************************************/ -void write_verilog_testbench(OpenfpgaContext& openfpga_ctx, - const Command& cmd, const CommandContext& cmd_context) { +int write_verilog_testbench(OpenfpgaContext& openfpga_ctx, + const Command& cmd, const CommandContext& cmd_context) { CommandOptionId opt_output_dir = cmd.option("file"); CommandOptionId opt_reference_benchmark = cmd.option("reference_benchmark_file_path"); @@ -87,6 +93,9 @@ void write_verilog_testbench(OpenfpgaContext& openfpga_ctx, openfpga_ctx.arch().sim_setting, openfpga_ctx.arch().config_protocol.type(), options); + + /* TODO: should identify the error code from internal function execution */ + return CMD_EXEC_SUCCESS; } } /* end namespace openfpga */ diff --git a/openfpga/src/base/openfpga_verilog.h b/openfpga/src/base/openfpga_verilog.h index faf8cf6b0..096039aab 100644 --- a/openfpga/src/base/openfpga_verilog.h +++ b/openfpga/src/base/openfpga_verilog.h @@ -15,11 +15,11 @@ /* begin namespace openfpga */ namespace openfpga { -void write_fabric_verilog(OpenfpgaContext& openfpga_ctx, - const Command& cmd, const CommandContext& cmd_context); +int write_fabric_verilog(OpenfpgaContext& openfpga_ctx, + const Command& cmd, const CommandContext& cmd_context); -void write_verilog_testbench(OpenfpgaContext& openfpga_ctx, - const Command& cmd, const CommandContext& cmd_context); +int write_verilog_testbench(OpenfpgaContext& openfpga_ctx, + const Command& cmd, const CommandContext& cmd_context); } /* end namespace openfpga */ diff --git a/openfpga/src/base/openfpga_write_gsb.cpp b/openfpga/src/base/openfpga_write_gsb.cpp index 9c367ebfb..cdb833c75 100644 --- a/openfpga/src/base/openfpga_write_gsb.cpp +++ b/openfpga/src/base/openfpga_write_gsb.cpp @@ -5,6 +5,9 @@ #include "vtr_time.h" #include "vtr_log.h" +/* Headers from openfpgashell library */ +#include "command_exit_codes.h" + #include "write_xml_device_rr_gsb.h" #include "openfpga_write_gsb.h" @@ -19,8 +22,8 @@ namespace openfpga { * Write internal structrure of all the General Switch Blocks (GSBs) * to an XML file *******************************************************************/ -void write_gsb(const OpenfpgaContext& openfpga_ctx, - const Command& cmd, const CommandContext& cmd_context) { +int write_gsb(const OpenfpgaContext& openfpga_ctx, + const Command& cmd, const CommandContext& cmd_context) { /* Check the option '--file' is enabled or not * Actually, it must be enabled as the shell interface will check @@ -38,6 +41,9 @@ void write_gsb(const OpenfpgaContext& openfpga_ctx, g_vpr_ctx.device().rr_graph, openfpga_ctx.device_rr_gsb(), cmd_context.option_enable(cmd, opt_verbose)); + + /* TODO: should identify the error code from internal function execution */ + return CMD_EXEC_SUCCESS; } } /* end namespace openfpga */ diff --git a/openfpga/src/base/openfpga_write_gsb.h b/openfpga/src/base/openfpga_write_gsb.h index 4f7110717..206e6cd5a 100644 --- a/openfpga/src/base/openfpga_write_gsb.h +++ b/openfpga/src/base/openfpga_write_gsb.h @@ -15,8 +15,8 @@ /* begin namespace openfpga */ namespace openfpga { -void write_gsb(const OpenfpgaContext& openfpga_ctx, - const Command& cmd, const CommandContext& cmd_context); +int write_gsb(const OpenfpgaContext& openfpga_ctx, + const Command& cmd, const CommandContext& cmd_context); } /* end namespace openfpga */ From e6c896d58312d1b7f2bcf9c518681d1e46b41a78 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 8 Apr 2020 16:54:08 -0600 Subject: [PATCH 4/5] now inout must be global port and I/O port so that it will appear in the top-level module --- .../libarchopenfpga/src/check_circuit_library.cpp | 12 ++++++++++++ .../src/read_xml_circuit_library.cpp | 4 +--- openfpga/src/fabric/build_grid_modules.cpp | 15 +++++---------- openfpga/src/fpga_sdc/analysis_sdc_writer.cpp | 6 ++++++ openfpga/src/utils/module_manager_utils.cpp | 12 ++++++++---- .../test_openfpga_arch/k6_N10_40nm_openfpga.xml | 2 +- .../k6_frac_N10_40nm_openfpga.xml | 2 +- .../k6_frac_N10_adder_chain_40nm_openfpga.xml | 2 +- ..._frac_N10_adder_chain_mem16K_40nm_openfpga.xml | 2 +- ...c_N10_adder_chain_mem16K_aib_40nm_openfpga.xml | 4 ++-- ..._frac_N10_adder_column_chain_40nm_openfpga.xml | 2 +- ...rac_N10_adder_register_chain_40nm_openfpga.xml | 2 +- ...10_adder_register_scan_chain_40nm_openfpga.xml | 2 +- .../k6_frac_N10_spyio_40nm_openfpga.xml | 8 ++++---- .../k6_frac_N10_stdcell_mux_40nm_openfpga.xml | 2 +- .../k6_frac_N10_tree_mux_40nm_openfpga.xml | 2 +- 16 files changed, 47 insertions(+), 32 deletions(-) diff --git a/libopenfpga/libarchopenfpga/src/check_circuit_library.cpp b/libopenfpga/libarchopenfpga/src/check_circuit_library.cpp index 2e8c1a214..0abc16a0e 100644 --- a/libopenfpga/libarchopenfpga/src/check_circuit_library.cpp +++ b/libopenfpga/libarchopenfpga/src/check_circuit_library.cpp @@ -317,6 +317,18 @@ size_t check_circuit_library_ports(const CircuitLibrary& circuit_lib) { } } + /* Check global output ports: make sure they are all I/Os */ + for (const auto& port : circuit_lib.ports()) { + if ( (circuit_lib.port_is_global(port)) + && (CIRCUIT_MODEL_PORT_OUTPUT == circuit_lib.port_type(port)) + && (false == circuit_lib.port_is_io(port)) ) { + VTR_LOG_ERROR("Circuit port (type=%s) of model (name=%s) is defined as global output port but not an I/O!\n", + CIRCUIT_MODEL_PORT_TYPE_STRING[size_t(circuit_lib.port_type(port))], + circuit_lib.model_name(port).c_str()); + num_err++; + } + } + /* Check set/reset/config_enable ports: make sure they are all global ports */ for (const auto& port : circuit_lib.ports()) { if ( ( (circuit_lib.port_is_set(port)) diff --git a/libopenfpga/libarchopenfpga/src/read_xml_circuit_library.cpp b/libopenfpga/libarchopenfpga/src/read_xml_circuit_library.cpp index cd8ffd1c5..ba6e6af7f 100644 --- a/libopenfpga/libarchopenfpga/src/read_xml_circuit_library.cpp +++ b/libopenfpga/libarchopenfpga/src/read_xml_circuit_library.cpp @@ -489,9 +489,7 @@ void read_xml_circuit_port(pugi::xml_node& xml_port, /* Identify if the port is for io, this is only applicable to INPUT ports. * By default, it will NOT be a mode selection port */ - if (CIRCUIT_MODEL_PORT_INPUT == circuit_lib.port_type(port)) { - circuit_lib.set_port_is_io(port, get_attribute(xml_port, "io", loc_data, pugiutil::ReqOpt::OPTIONAL).as_bool(false)); - } + circuit_lib.set_port_is_io(port, get_attribute(xml_port, "is_io", loc_data, pugiutil::ReqOpt::OPTIONAL).as_bool(false)); /* Identify if the port is for mode selection, this is only applicable to SRAM ports. * By default, it will NOT be a mode selection port diff --git a/openfpga/src/fabric/build_grid_modules.cpp b/openfpga/src/fabric/build_grid_modules.cpp index 95e435f6f..0b693fcec 100644 --- a/openfpga/src/fabric/build_grid_modules.cpp +++ b/openfpga/src/fabric/build_grid_modules.cpp @@ -306,22 +306,17 @@ void build_primitive_block_module(ModuleManager& module_manager, /* Find the inout ports required by the primitive node, and add them to the module * This is mainly due to the I/O blocks, which have inout ports for the top-level fabric */ - if (CIRCUIT_MODEL_IOPAD == circuit_lib.model_type(primitive_model)) { - std::vector primitive_model_inout_ports = circuit_lib.model_ports_by_type(primitive_model, CIRCUIT_MODEL_PORT_INOUT); - for (auto port : primitive_model_inout_ports) { + for (const auto& port : circuit_lib.model_global_ports(primitive_model, false)) { + if ( (CIRCUIT_MODEL_PORT_INOUT == circuit_lib.port_type(port)) + && (true == circuit_lib.port_is_io(port)) ) { add_primitive_module_fpga_global_io_port(module_manager, primitive_module, logic_module, logic_instance_id, ModuleManager::MODULE_GPIO_PORT, circuit_lib, primitive_model, port); - } - } - - /* Find the other i/o ports required by the primitive node, and add them to the module */ - for (const auto& port : circuit_lib.model_global_ports(primitive_model, false)) { - if ( (CIRCUIT_MODEL_PORT_INPUT == circuit_lib.port_type(port)) - && (true == circuit_lib.port_is_io(port)) ) { + } else if ( (CIRCUIT_MODEL_PORT_INPUT == circuit_lib.port_type(port)) + && (true == circuit_lib.port_is_io(port)) ) { add_primitive_module_fpga_global_io_port(module_manager, primitive_module, logic_module, logic_instance_id, ModuleManager::MODULE_GPIN_PORT, diff --git a/openfpga/src/fpga_sdc/analysis_sdc_writer.cpp b/openfpga/src/fpga_sdc/analysis_sdc_writer.cpp index c188dedd8..584f6e63f 100644 --- a/openfpga/src/fpga_sdc/analysis_sdc_writer.cpp +++ b/openfpga/src/fpga_sdc/analysis_sdc_writer.cpp @@ -203,6 +203,12 @@ void print_analysis_sdc_disable_global_ports(std::fstream& fp, continue; } + /* Skip any gpio port here! */ + if ( (CIRCUIT_MODEL_PORT_INOUT == circuit_lib.port_type(global_port)) + && (true == circuit_lib.port_is_io(global_port)) ) { + continue; + } + ModulePortId module_port = module_manager.find_module_port(top_module, circuit_lib.port_prefix(global_port)); BasicPort port_to_disable = module_manager.module_port(top_module, module_port); diff --git a/openfpga/src/utils/module_manager_utils.cpp b/openfpga/src/utils/module_manager_utils.cpp index 64bef2e88..a57e97261 100644 --- a/openfpga/src/utils/module_manager_utils.cpp +++ b/openfpga/src/utils/module_manager_utils.cpp @@ -37,8 +37,9 @@ ModuleId add_circuit_model_to_module_manager(ModuleManager& module_manager, /* Add ports */ /* Find global ports and add one by one - * Global input ports will be considered as global port in the context of module manager - * Global output ports will be considered as spy port in the context of module manager + * Non-I/O Global input ports will be considered as global port to be shorted wired in the context of module manager + * I/O Global output ports will be considered as general purpose output port in the context of module manager + * I/O Global inout ports will be considered as general purpose i/o port in the context of module manager */ for (const auto& port : circuit_lib.model_global_ports(circuit_model, false)) { BasicPort port_info(circuit_lib.port_prefix(port), circuit_lib.port_size(port)); @@ -50,9 +51,12 @@ ModuleId add_circuit_model_to_module_manager(ModuleManager& module_manager, } else if ( (CIRCUIT_MODEL_PORT_INPUT == circuit_lib.port_type(port)) && (true == circuit_lib.port_is_io(port)) ) { module_manager.add_port(module, port_info, ModuleManager::MODULE_GPIN_PORT); - } else { - VTR_ASSERT(CIRCUIT_MODEL_PORT_OUTPUT == circuit_lib.port_type(port)); + } else if (CIRCUIT_MODEL_PORT_OUTPUT == circuit_lib.port_type(port)) { + VTR_ASSERT(true == circuit_lib.port_is_io(port)); module_manager.add_port(module, port_info, ModuleManager::MODULE_GPOUT_PORT); + } else if ( (CIRCUIT_MODEL_PORT_INOUT == circuit_lib.port_type(port)) + && (true == circuit_lib.port_is_io(port)) ) { + module_manager.add_port(module, port_info, ModuleManager::MODULE_GPIO_PORT); } } diff --git a/openfpga/test_openfpga_arch/k6_N10_40nm_openfpga.xml b/openfpga/test_openfpga_arch/k6_N10_40nm_openfpga.xml index 17eb8b550..de0602e1e 100644 --- a/openfpga/test_openfpga_arch/k6_N10_40nm_openfpga.xml +++ b/openfpga/test_openfpga_arch/k6_N10_40nm_openfpga.xml @@ -156,7 +156,7 @@ - + diff --git a/openfpga/test_openfpga_arch/k6_frac_N10_40nm_openfpga.xml b/openfpga/test_openfpga_arch/k6_frac_N10_40nm_openfpga.xml index c43614ae8..51e250a8a 100644 --- a/openfpga/test_openfpga_arch/k6_frac_N10_40nm_openfpga.xml +++ b/openfpga/test_openfpga_arch/k6_frac_N10_40nm_openfpga.xml @@ -173,7 +173,7 @@ - + diff --git a/openfpga/test_openfpga_arch/k6_frac_N10_adder_chain_40nm_openfpga.xml b/openfpga/test_openfpga_arch/k6_frac_N10_adder_chain_40nm_openfpga.xml index cf619cd27..ae08c8250 100644 --- a/openfpga/test_openfpga_arch/k6_frac_N10_adder_chain_40nm_openfpga.xml +++ b/openfpga/test_openfpga_arch/k6_frac_N10_adder_chain_40nm_openfpga.xml @@ -174,7 +174,7 @@ - + diff --git a/openfpga/test_openfpga_arch/k6_frac_N10_adder_chain_mem16K_40nm_openfpga.xml b/openfpga/test_openfpga_arch/k6_frac_N10_adder_chain_mem16K_40nm_openfpga.xml index 4ddf1dd0b..cb145e06d 100644 --- a/openfpga/test_openfpga_arch/k6_frac_N10_adder_chain_mem16K_40nm_openfpga.xml +++ b/openfpga/test_openfpga_arch/k6_frac_N10_adder_chain_mem16K_40nm_openfpga.xml @@ -174,7 +174,7 @@ - + diff --git a/openfpga/test_openfpga_arch/k6_frac_N10_adder_chain_mem16K_aib_40nm_openfpga.xml b/openfpga/test_openfpga_arch/k6_frac_N10_adder_chain_mem16K_aib_40nm_openfpga.xml index f0e84e167..e65851291 100644 --- a/openfpga/test_openfpga_arch/k6_frac_N10_adder_chain_mem16K_aib_40nm_openfpga.xml +++ b/openfpga/test_openfpga_arch/k6_frac_N10_adder_chain_mem16K_aib_40nm_openfpga.xml @@ -174,7 +174,7 @@ - + @@ -209,7 +209,7 @@ - + diff --git a/openfpga/test_openfpga_arch/k6_frac_N10_adder_column_chain_40nm_openfpga.xml b/openfpga/test_openfpga_arch/k6_frac_N10_adder_column_chain_40nm_openfpga.xml index d70ebcb2d..65117d199 100644 --- a/openfpga/test_openfpga_arch/k6_frac_N10_adder_column_chain_40nm_openfpga.xml +++ b/openfpga/test_openfpga_arch/k6_frac_N10_adder_column_chain_40nm_openfpga.xml @@ -174,7 +174,7 @@ - + diff --git a/openfpga/test_openfpga_arch/k6_frac_N10_adder_register_chain_40nm_openfpga.xml b/openfpga/test_openfpga_arch/k6_frac_N10_adder_register_chain_40nm_openfpga.xml index 81a9582dc..779880dea 100644 --- a/openfpga/test_openfpga_arch/k6_frac_N10_adder_register_chain_40nm_openfpga.xml +++ b/openfpga/test_openfpga_arch/k6_frac_N10_adder_register_chain_40nm_openfpga.xml @@ -174,7 +174,7 @@ - + diff --git a/openfpga/test_openfpga_arch/k6_frac_N10_adder_register_scan_chain_40nm_openfpga.xml b/openfpga/test_openfpga_arch/k6_frac_N10_adder_register_scan_chain_40nm_openfpga.xml index 840a2e3bb..621847439 100644 --- a/openfpga/test_openfpga_arch/k6_frac_N10_adder_register_scan_chain_40nm_openfpga.xml +++ b/openfpga/test_openfpga_arch/k6_frac_N10_adder_register_scan_chain_40nm_openfpga.xml @@ -179,7 +179,7 @@ - + diff --git a/openfpga/test_openfpga_arch/k6_frac_N10_spyio_40nm_openfpga.xml b/openfpga/test_openfpga_arch/k6_frac_N10_spyio_40nm_openfpga.xml index 547c742c8..159214507 100644 --- a/openfpga/test_openfpga_arch/k6_frac_N10_spyio_40nm_openfpga.xml +++ b/openfpga/test_openfpga_arch/k6_frac_N10_spyio_40nm_openfpga.xml @@ -173,11 +173,11 @@ - + - - - + + + diff --git a/openfpga/test_openfpga_arch/k6_frac_N10_stdcell_mux_40nm_openfpga.xml b/openfpga/test_openfpga_arch/k6_frac_N10_stdcell_mux_40nm_openfpga.xml index d3e3d1f6c..59f493a13 100644 --- a/openfpga/test_openfpga_arch/k6_frac_N10_stdcell_mux_40nm_openfpga.xml +++ b/openfpga/test_openfpga_arch/k6_frac_N10_stdcell_mux_40nm_openfpga.xml @@ -165,7 +165,7 @@ - + diff --git a/openfpga/test_openfpga_arch/k6_frac_N10_tree_mux_40nm_openfpga.xml b/openfpga/test_openfpga_arch/k6_frac_N10_tree_mux_40nm_openfpga.xml index 8052fb2dc..d04318510 100644 --- a/openfpga/test_openfpga_arch/k6_frac_N10_tree_mux_40nm_openfpga.xml +++ b/openfpga/test_openfpga_arch/k6_frac_N10_tree_mux_40nm_openfpga.xml @@ -164,7 +164,7 @@ - + From d99776b260ea94880573814d6279d8e4dd7436a0 Mon Sep 17 00:00:00 2001 From: Xifan Tang Date: Wed, 8 Apr 2020 18:18:53 -0600 Subject: [PATCH 5/5] update documentation on the global I/O ports --- docs/source/arch_lang/circuit_library.rst | 112 +++++++++++++++++- .../arch_lang/figures/global_inout_ports.png | Bin 0 -> 24210 bytes .../arch_lang/figures/global_input_ports.png | Bin 0 -> 24062 bytes docs/source/arch_lang/figures/gpin_ports.png | Bin 0 -> 24052 bytes docs/source/arch_lang/figures/gpio_ports.png | Bin 0 -> 24674 bytes docs/source/arch_lang/figures/gpout_ports.png | Bin 0 -> 23998 bytes 6 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 docs/source/arch_lang/figures/global_inout_ports.png create mode 100644 docs/source/arch_lang/figures/global_input_ports.png create mode 100644 docs/source/arch_lang/figures/gpin_ports.png create mode 100644 docs/source/arch_lang/figures/gpio_ports.png create mode 100644 docs/source/arch_lang/figures/gpout_ports.png diff --git a/docs/source/arch_lang/circuit_library.rst b/docs/source/arch_lang/circuit_library.rst index 2cab83abd..bf32fc113 100644 --- a/docs/source/arch_lang/circuit_library.rst +++ b/docs/source/arch_lang/circuit_library.rst @@ -272,7 +272,7 @@ A circuit model may consist of a number of ports. The port list is mandatory in - ``io="true|false"`` Specify if this port should be treated as an I/O port of an FPGA fabric. When this is enabled, this port of each circuit model instanciated in FPGA will be added as an I/O of an FPGA. - .. note:: ``io`` is only valid for ``input`` ports + .. note:: global ``output`` ports must be ``io`` ports - ``mode_select="true|false"`` Specify if this port controls the mode switching in a configurable logic block. This is due to that a configurable logic block can operate in different modes, which is controlled by SRAM bits. @@ -296,3 +296,113 @@ A circuit model may consist of a number of ports. The port list is mandatory in .. note:: Different types of ``circuit_model`` have different XML syntax, with which users can highly customize their circuit topologies. See refer to examples of :ref:``circuit_model_example`` for more details. .. note:: Note that we have a list of reserved port names, which indicate the usage of these ports when building FPGA fabrics. Please do not use ``mem_out``, ``mem_inv``, ``bl``, ``wl``, ``blb``, ``wlb``, ``ccff_head`` and ``ccff_tail``. + +FPGA I/O Port +^^^^^^^^^^^^^ + +The ``circuit_model`` support not only highly customizable circuit-level modeling but also flexible I/O connection in the FPGA fabric. +Typically, circuit ports appear in the primitive modules of a FPGA fabric. +However, it is also very common that some circuit ports should be I/O of a FPGA fabric. +Using syntax ``is_global`` and ``is_io``, users can freely define how these ports are connected as FPGA I/Os. + +In principle, when ``is_global`` is set ``true``, the port will appear as an FPGA I/O. +The syntax ``is_io`` is applicable when ``is_global`` is ``true``. +When ``is_io`` is ``true``, the port from different instances will be treated as independent I/Os. +When ``is_io`` is ``false``, the port from different instances will be treated as the same I/Os, which are short-wired. + +To beef up, the following examples will explain how to use ``is_global`` and ``is_io`` to achieve different types of connections to FPGA I/Os. + +.. option:: Global short-wired inputs + +.. code-block:: xml + + + +The global inputs are short wired across different instances. +These inputs are widely seen in FPGAs, such as clock ports, which are shared between sequential elements. + +:numref:`fig_global_input_ports` shows an example on how the global inputs are wired inside FPGA fabric. + +.. _fig_global_input_ports: + +.. figure:: ./figures/global_input_ports.png + :scale: 100% + :alt: classical inverter 1x symbol + + Short-wired global inputs as an FPGA I/O + +.. option:: Global short-wired inouts + +.. code-block:: xml + + + +The global inouts are short wired across different instances. + +:numref:`fig_global_ioput_ports` shows an example on how the global inouts are wired inside FPGA fabric. + +.. _fig_global_inout_ports: + +.. figure:: ./figures/global_inout_ports.png + :scale: 100% + :alt: classical inverter 1x symbol + + Short-wired global inouts as an FPGA I/O + +.. option:: General-purpose inputs + +.. code-block:: xml + + + +The general-purpose inputs are independent wired from different instances to separated FPGA I/Os. +For example, power-gating signals can be applied to each tile of a FPGA. + +:numref:`fig_gpin_ports` shows an example on how the general-purpose inputs are wired inside FPGA fabric. + +.. _fig_gpin_ports: + +.. figure:: ./figures/gpin_ports.png + :scale: 100% + :alt: classical inverter 1x symbol + + General-purpose inputs as separated FPGA I/Os + +.. option:: General-purpose I/O + +.. code-block:: xml + + + +The general-purpose I/O are independent wired from different instances to separated FPGA I/Os. +In practice, inout of GPIO cell is typically wired like this. + +:numref:`fig_gpin_ports` shows an example on how the general-purpose inouts are wired inside FPGA fabric. + +.. _fig_gpio_ports: + +.. figure:: ./figures/gpio_ports.png + :scale: 100% + :alt: classical inverter 1x symbol + + General-purpose inouts as separated FPGA I/Os + +.. option:: General-purpose outputs + +.. code-block:: xml + + + +The general-purpose outputs are independent wired from different instances to separated FPGA outputs. +In practice, these outputs are typically spypads to probe internal signals of a FPGA. + +:numref:`fig_gpout_ports` shows an example on how the general-purpose outputs are wired inside FPGA fabric. + +.. _fig_gpout_ports: + +.. figure:: ./figures/gpout_ports.png + :scale: 100% + :alt: classical inverter 1x symbol + + General-purpose outputs as separated FPGA I/Os + diff --git a/docs/source/arch_lang/figures/global_inout_ports.png b/docs/source/arch_lang/figures/global_inout_ports.png new file mode 100644 index 0000000000000000000000000000000000000000..9dd7d2b8966d9de5291c8fcd93fa2e81f4506ba8 GIT binary patch literal 24210 zcmd?R1yo(#vMv}bKtj*}0fGdA6Fhi;Ai*WLJ8Ycb?ruSYO9&cVg1fr}cb5>{9eVEk z|GDR!`)d_+@ z10+~*#h*}F1^k1tl@k$oR6O)@8+?g0R1q_hl6ph~J|jJP4D5@2Em|NO%IlUwOQ-TY8hF)eMCHYgt&g>njij*vgpp}gw$y<6> zdPY*-CnO{!JT?YKTyjDm{(c;Mdq-+)XZMMVfx*$yk=~Jo-pU5Tz{JVP$-v0Wz|8yx zlz3z7Y-y+K^v2Sb?5|4xQIC+Jt-g)PCp!}>OA=_kx_VajcJD|@p$+}V&tLttGco#S zOP02O4+{*C0eXjliJp<+Kk5dL@<6Y0$=H|}f|jB6^D^=LDfw^L{@Ko7xS=t%ee6j&E^5<#hzn}i!FY%x2k~6fmGPj35tY~Rs$NP^8{?q0E{FI=T1!&aP z7TV*tf4BLs*ZwZg!vLMGf0@3&*5=PuusFO=co_a;p?RMSe+~(G^oakFn9zF#Cz!od zM7LPs>uxClv<%0r&{NVzq!$?9p9JZ^U_?|bFL56z#Gb^qI|Qy$hq!#3hY1Ps@gY$` zhZCiwA`!)iM1>J3$+&AaFmRh$Fn1VZo4Ke?FCE}^Z#ro@8DKft<;K9J*QgO7#z2RG z{`SzoMyV=B_F??_hVC5-|JuopILHeL{2EZhAg9rF7PSfS!-HQNFMd9AfyA?tIOAq%1WB=uV>9l-pJ>K4I>>t_eLS}vi9ax6{HtMeFq!XkL{Ky}At52{o$Imt_31X~XO+oVm)+h@N%MZLQdnCmmpwDnlKX`w zAJaP@ScWz--7YOs#^V%UZ+DfyAmHWi97yr=wNKaN1j5Vz9LgRB*&F=TN&dD9ymq*>iQbPxg7inXBEb~1*8~yQ+4@0UkTk+Z+CQpC= z%tV|ouKS%I+cKMA6U5JjtPwSIDo#Y=y*F1qRj3++c+*E)GXKLQMyk_Gz2=kdEe4O1 zbUN<>O42<78dLMtCIJ=;RV$VPMpbm;%5;@Q@^`+aKvY5-9PeYtiv>r5^!oj}P^7El z4e)Trk$2jw$y!^8oe)G|jUuPl8O-Bi2Hr2*{rOq~tA-=(him1>n~7gkGa$HBvMq7b zW%?pDig~i$4yrPoLL@9m#u43N9}{l|FMAYHvDuV7x*~|RD@_&Ei88m8wcWAtuGB@I z(g9J<<|sH&8HbF$~#_@;5sl$5jYpmD8JV}r( zP`j)Tm*2b6a_3I#cZKQV522#_CmD);d!t!5p7;`p;*HPC_Zuj)p!hTPc^&+ttF3e_ zyOTloWQmR!h110O$|Z|GOvcP<()~X2Ct@Y|vD%*R&cwH9blVu}>5&dd5z;6ZOQMGc zvI*|!yoBuiF#h??z<=&K*ISpwkMH)d{X;l@867eV$MkALfp=JMI$!g5zAqvJwur0C z?QJDe2>~v%KWu`$h+)-CPv9uqeFj`GhMmC)g`dlo>2Iho7Sp}Oo&h| z$vWZ%Q=8DuMe{>AnqexB^Js^VH_Q8bESK0eLvf#6^=eCn1f<>6gwZP_+Dz$GgF&4oGKUL+dSdY8wy_pKcisyB6lDKY4 zU`g=iMLTi>6o`WTcOe)rhR#slEXu$(+G@+5%;#m+i6Tdbp~c zK&|e6v(u3t0Zib`?sxgz&qu6mnv%m&k_I)N5BKB}aS0?@@hllK)f2BvElDAL!ncf$ z6wEtLfoQ~Cx;b46kJ&STY{KcsrTdxt-5&QdRB=qAsOD6}OC#G3G55ojXwXj5P!!K zt;Wb}6Ma#oD&9rS_JC)EQYl61)#bECe%F0pXn(r8DYZieQ|CwLr+97Sa*>?SBbSdJ zMN`MWkYP|M^(s^~FGDDuY02xJtvhnQ-p*yB)l2R8&{F1nV$@W&&75Xrtix~J#bkLd z`~pvvk%_bPov#}{ubWe)>BQ(s1&TcBd1b5~jc@yS_h;YnZppaRN*fA;Iit}mF}B!e zxv}tQaIC6$cVEG-Wb55us896?+z^r{C)IF2n_yETLFI1XBEUvk;b*S4HW#s)DbKdw znPd$?%P=uAwyi>?)TO%%d&pNT_=SrzUt>T^n{7HRDQ9D#^G=>d;NFsgq%{V+(Ml2T zhDV;p1&-EA>5%9Ca!s;JwaZ#5=v9Kd`KjVsFq>C9C;VJb2NRC?GXl1bm`dD9^%nut z#Jr!Dy)-GxkH(f6kG=eIcne7qCEX^w6ZyK3hSEcAwoxiAPhW)fr@No4uKD&9Di*|j zeDX0NjHwQ}e2qE>E2ohyMu*TF3zY^^j~N6TVjm!tY!twTn2uV3A&MRo_DV2dnnP*P zRiXWZXm6C*ndEnltNQR3E2RcYGY6dN_`5BKz1fdcC)#W_7TblT>eZFY<-8n>a;tN6 zLnMpd_YU}JAhcd^N(oylIt))T9VU5T zgqw2%Gb&yYY5I;cJw}+P9N@{LiF;00nXT}Q#z;%nkHhZ`-&AM!y61WihTY8Rcue6b zhPMI|Bi|^c84_bq^I_Z5uIXSz0zq|(te)2%7|f>QRHvAyuWqFRkIce2Z8v3^0`#kn zRENgg3nriCSW`4|T#iv|!ghn>^*a(Lo41LXz0OymS)4Yod-ycXYzl zO&&(m-d*J8BXT)xMU*lu%*N~LzNLFi?n|8W_1nq^kyp<7$QBq~-g_k<-%8#OCcP!# zcA%3og1-prB^UT%z1F1=mY&PlptmNX#!`9lc|b2mGgcqhVzI&5$kyNIQJZB<+5Kv? zWSG0NxL5E~>E|K19%6=l zaapY0oc1#%Dk|cRT3Z~OpCYlEi1Bs?o5;cXGV*0*KsY*GYKoDLf&T=KyiJ9c5UP;0 zJqtzl6Q@g-w?zDEAtPaa3Oz1U&$+Dr~^(1bq;irJJ%_mi?z z@y}Q#DGK*k`v@O{oJL}nyo}LDZiKP!MPbT4)X|F)upXus)>2AqUd0RSLC-xmQ_OD@ zT8cn!WYNQ#ilqrtCzh;KEeP3 zw4?%iIX`n?S_wr5eqmnlGCd;&I?yUUQNkb-IiA<6y@3Ufy&@xN#bQ3CQGvpSc`<&U z?$oA@KogjHtlzcs?Yc4*jwoOztCP>u0t5V&EdF}c7mc?@zZ;d{htVLuxWU$Uu^0+k<>DXryQ_BFqn)t= zqdY+((I0R>UyqTQmAeP- z-&*kUd(qNdpJd(C5wH$%G>Uy45L@GsukSyw<8#_%NtqGSDity^T|qt8*&impzL&sq z3+&>#hdz7I@BSRMK9V7bO`|~47E3L^Ig}cj2^_|040OB8!p`PvP+lID9Rj`Tfq(#`DFD(*5`H+$$bl#N zdaJ%OZ2-Uq`z9AR0++TsoZupm@77!5c)r$_5|uRrK*X)#bmC_@7IRfW?Ba%So=l3jV?7;}I*4tD5iv{R z9flUFY<}hB$HlORnRxUg9*nxX`?;z3`lw&hUdlv)^4i)fD@lr0kIel@cwOHlY(m1j z63@F(iP%z|laFo~=-!7=M`_~DEYOLCG@aA7Yy6RLYdsCy5A&Jw#SHHoSt>r%O6C^2 z`9#eASZd!E4*TB<%eC3hV=P{0p_&DI-mVdsC5uug-2$bjA0I+>tr<@59+C+TVo{G`}SeP8x9d{;y_WkwiX?jHBAY*> z!PI49-pP$H36D<)#}mrh7+5UEO2s@hE&z3|>1z$Q^G4RPBH+omh3WT1z7k~+ z>aVhxW6bJ`kshdpNa7CF*j@wQ6K5cOh_vNkP_q`;bbTsbdLy}vIGKzl zYf{F5QZcF~W~T}IE(CyL4fRhJ*|3422;Jmo_DVm@riwSuJ3o7|PpSy#gKghX(XH|X zJ;QRLE{GIUk0MYChCukT)ZXt^%3yf<6TAW#k3M}r(&NWB>{-vPFH<9tJIz~@cTosU`$ix%1zaxy!v;Z{;nZO_KNmW`xq0-$<6NE2*Wh$WS(} z?*mk0mE!_^Yd%g4NGw)$GPxi5N)P$mY+hL6)KOOZ)4_!%Qf#lFWCCBkjk$hBfgU4dDzK)Z(|BB>mc9q?Gw2lT2 zO$4ekBm-C2Yq1Yi2j9$<-<$B@jgVVkzfpKBtAN89!EgSkd8g00NG_Zu-Rs8@Fa?{BW@BpzM@B*R8y2@@SY9|Mf~}j3|3W;-<3zTT{RopoEOsV2Yw%sYM;Lv zj|0}OS8kq05<0I!;Ks$DGC}4uU;>jE6_@cToPph9io%U9f4JCWop@t470zoNVv zX^=QsVF`eUD)kA$Ge>%{rY-9{_PGA+5w;yznDv>M1MkJ_Av`2`RYMZ64kq4s#KZ@D zsxcH&w<3%gJMjz;rt>v$uID@~CUPW4?Q}!_y6tU+!ZZ1t7;VW#*MeWH|IB3%&6c;H zpDGpwiA`0ZmQ><1{j<5oLV*$+s6@a3i74FhV-XX3nkyr+NOyPKf3h`XsM$&*_D5o{ zp!a`0tH@%z@kRSg#FK!%@f`)aPCZ>vbx>yOrdID9UrkC+-;%Is0(TVUu1OO694Jtd zex#oKH~q4Kg(Ndm{(t#yhr;~$5ezhV>kw_`1JCcz)_jzkZ|Hsd8t9TG6|?AR#c=-! z9U~YlOs2R<2YxsKACKvHuIo8UGEc2=wPn=DkJ~+xVo+a?1cC)tpzgjul~Sf&tMUG= z`*l_-H?h;zMxXtTk>{C3wCamPhH?yfn z`ZP&UfdIP@EMA=}AajP`fd{0aR$&5(oQDpF1eO0lb&^rCXrk=z=s*LDY!eN8RI#fH+jFV4#i=g^2zY1oBvU~n-q z^DX7OYpMD*)b#h%&Rj7mqT(*QJ0(&BN#qj6_^iKHHV5U!sXYI#PvXGum1h05o0+}2 z-Tm%}p#9 z@7%7u(Pda-G-R1`;C3TEmRYRgAwxb_RQ(&j_aGu_Lz&(78jMS)e z8~o&H$a?>j%|Jqi#hfLdjluY6cEk^J=i#?g^Y0A%0y;YKf`UZUD}SpNO#ZOn(bB3Z z7618d&GlRePEg~n#+4m&=e{dEP|J~U2B?-|QlQE5_s`AE-P{^-r#7bWETWdqVZ3mrW1>KWUTeNutC3=(pF3t?cdoh@1ZCc+oyIISIugF)^1N{n zdd?X+H@8qX;c+4bk0uw`pKLm=12L9M=dH22|3y}Q{cBP^J)QevyN1K3SgiQb`|BVt z2`J%CPMF#{$m6ko>BR*{@i`%(hMUQ^V(9B`Df6$xMOWpU^~L4U5xDzZ{erkx9JvZE z%bp@QENmUO!|juXYR#dqRPt=y)^O@ghS4A!Af+L_LuMUsQ&lIvd zeN$;FrBeC(dzA${A;(CK24{5XirwbzRY3^0nUjh0p2qR0Mt&`|50W32_Y$S=$~a9W z`3~|+ZoA!+YF^@Tb6GZRpZ-tG(^c8Almrsy)C;`M%ugLDK7XvrDblv0zaZi^Lcx>k zdw)-g9tWRw%YQMXs&XrCiMcqWNqsls;a{ARbpj8@59HYY5cE)c24kKZrd zA2yyuREA|xn!oBDPAe4`Zvn&ymeu-mJ^I#rfuNSO9>u+yB*HAx;~C-@~DxK05;gZ47UTK4z2iVa%8k81(v?gvz> z5>zvaec5DR6~YZ6sy5P)eLkw8B%4iD4xTxuBq^xcT@p!@Yu|)XKdSmQOPcz2`EC+s zbEMMc>@P#eKSWLvPPuiiS!c@2Gb1#e*h!AXAp^$-N%>LRD5J>8rZ6+;wKu&z*1#D) zhLv(Keq?;ST>;50)KsrG=)Lw%d|x6h%3*WOns~@ebW;UeIO`Nn(7YBbdhd?Scei3V zk@K}rI3)Jzeb(a$ae%_hIf1J%)8MPnNJm=gHdR~&0DTJEU<1lH)grW_Ly`3SysB|<|70wF6Y4{mxrt2!>bdsrlZFtmhD)*Lh$!o4G;Gs1mA z0U`IX<*vHf)c*NOpcrKMc+!;g5I5#lTJGTGIvK1kSPaSmE`>ocZkQov(YMwl*0%=7 zhsxSt=w!dHDJo+G#^ZkyisYp4k-S$Ny)_# z7NS4c}aseSBKNX1TsDE3K?AvvJSRw7fnt-S>r)lhtEOdX~?&J%F<54riro)f@52 zR{xaI?sRxCZba#g-rY5ybaI!s)zinQLgz2!F4!!?!c-gd5#udr6n`&$g|R%S{(SFp zsB;mFwX`#1JJyaymOVYh)GL3zX}~!o#4j|1gp{TovxEwhkCPu41u-;a6Fu` zF}cneln0WbAz^OxY&g`%qdo|quI6@U948APS~@JHAIT&_97WaH85AolbJr$>LyPGY zg0O_k{MVK_3Nbwn&Fpj*tuzmh!(ZNvnn8waLiwG5Ly3HFZ!f$f_l}eGr~_H6FF2Bs z1Dz%NTc$I$eOsA+!NtCCEz^AiD;JekLp=T$1a6c2ebW)IH6aNNwZfCc2;_IEZp%Kw zUgNEKvk(L45dIffU=d$97ON*2RY^*kxz};h1-8#l?$1GjV?%>i;LUE2Rz?VSh+}=% zgv$K(73-^{I-LtA_x7l?zCPNzAVH8q=R;mKAVJ+d`b-T((h8`>wtCNrx={FhY+4*_ zjI!6x72W9XCyce48h&~YXniI(9P;nS!ZsZ8JUOh6=iu-S+;~fu6~2X7pfp3g!;z`V zE)ccRv=Q$?do7_y+TA)qtJwD;QV?E40H_LbLc*azp^#}?zP;WI*6FmD_%ZBOOV?)@ znEla)!#Qw>4n&;HUv=A=nV5=b6cU;|?#3(4oReFsli6dQV7-+dp(eocrSKCYU<&Ng zbW4WI8IHAKR(;3ZS;pz-nTw3ob$7XD7K&?|LWLN%y0&$ayE#}Ez^MK{GoC@j?krDr zOvVjJz6$1uoVtobK`6eVH0mHWUT<%Py~LMt%0S-9{0YA12O{*B$g_FoGwk(tx`u@( ze#qy)7(ve3{w-CJiN0GKzD>iN&{5V~0{gVoC7u*=TR+=S z@G{@AvaGrMp##}WN{0qu|LYDRhx-{XF%FOUro3kxCW3mTu#dx^WGH5Q(me=RZs&a_ zj>!gl<#u=fV&`NZ)UN2LRAf^5@#&a4hnay) zl%rHWdGZdX>f-7o57AT{;DK-mc3=_9B%*yZyN=5DwPCU^jqA$qVVW4nDc<)V#c{DI zpkg4oLN(k{r>Ra5^1$qm?X>UmWtpxS?yl*IGw!FqVk#h5c8BBC=@{$O|I}W+TJXHP z6QN(Yej8|qE^G3g2NIdgV0t#qd^rA0@~>L+oK(j#>{cOkFavn*H^E;?pc?i2ixodr zvx%2~z>jw%bjvy8=KUcXmgzxn_J3PdDnXH_fHcsS>zZGm`~lzffR(Q)Xr54mK8M5! zKwYGxH_ab(wGVZri|>`p{(!c10H*{N5%T|_@tROC_=x&z^&%+6{omBsSAC56iKUtR z%1!f4b47ARK&+5FMG{@>h3%nfi{U?^AAHwnmx>IpW@izFTuUQ?A<6)3)HZqEsR;?A zTh}3LmK-LO0VDy2lIQwk5tQ}teklkB+imxShUO2-d=I|;|MnhfcJR!er;QeR+<42d5cFL97k{*~oDTtB@DoPul|w zRkZqgLizm;U6`Uo*j|CTPPX&Qe+8Xg%U3{N;?k73|Hw-+Fe<$igc+uP#7rG3X4$zD z(oiw$p#ZW}E+&$P4+ZYaI6yirw@oVlFjM8oKm^T4G4cccpnrcLXX-9$d(WYZX$~~$ z|Jmk#XW8t z?)0oHyn@{dHGh+uoYQrGey%^xg3pa3Z~nO|yoM-nO6hk`!_1GbPPS&+R!VfDeD)5^ zmrVF`lcday3}D`GR{kH57q%|D$yUc3eU-aSH*Nvfr;^mYU2uqx2NRCu!Y33>LcX*BLF3Wf`UY;d&>m7c|CV*?`bBA{Vumh zN(7I}JLN-CobTVzDqNN-m#i{0j%TR7MOk+seuvL(sZn314>>y^R?iM`tkpi-!A-Qu zY*<@cle8hFHZj(i?kG5{+T#_ye0Et^!+CH28!RfjG(oD}yyXMmVXztQny`C-TJabP2 ziPVKH*yYzawW-{H#da*S3pVbIJG=KrXW4Fzgg4DK;IZ%RC^z3PTQ$Avr6uHMqm$p< z|1Ph5u)qzBx-z$Y8_WKbwng+17DZ`}@@ws;IQ=dZi#dmzD6-5rdiN~De%IpK&3$Tl zw$~INgoSu!^A(5HDszg|FOJ*%6+>_cmntBu!B{~B#Eu6a^cI$Cjz)Hh$<*D2S`@)n zYHP07PG@Jx{?PTfqVKsQ@6e{NqIz}P!fy5$#%wklMC#K4r;FVHi1gGni^aSNL@kmO z)tQ2fN0UqSec^UKrwe#=Qe|nOQALO0@RHN#X7}nOC=Y{u@v;Nt%uJ6nXkN<-THEx`p=7_3)}NqfMF7MHwzvcr*I06*RM=B@Ef+O|1124<>JfXx2_lE4+>OPS{>NO<~HfPhEH+q zj7Y1IYP`V&5x8*5&n6Vbjmw#4$p6lI-hEAmB4hVT>)OxNk>uH>S|ckb7AMOq8Fp0a5o(Ul?ksI-ve`Q2M$ z=_*?mD8td(*HR<1-1H;OVRN37M}{0RQNhoJGI%J}b>aSQ=i=bOVT=N+b(4SH;S22) z-ABFqDhm~?gdcHdBWrA*PbRb$D8d!;SiA{hU_tzOfUEbbLsV$`V~#=MM?^oD#^4{fPZsK9+N0%xxGRV*;lbeH z))cl+%*O(z%sq)c*V@JBB$bQkr%d`gZo|FVS#pU`%2P zJs680lGvv@5hK&@b!;r29&oik*%+H|^rgJSZ?>g;lU%FYjL0_T6S zVaDRH+tnd-+pN-jA2F6=y*%gR4OhfdQ*EtpFtAF<9W;_7mwo>XfBD>F=T`|LnnOCr zQDfRW_IJ08av^&uDZ#RpINpVS;_V%ZT3wjSqOyMQflf9y#s^&X99}vHM{7vYy!Jcy zYjrzR{V$$=dO^i-x}IwCF)C`fvx`(%ORdyvqcltesWEBT5IU^)YHZo*u{oetXI1D z5ed{FA)whz`ENqO67S*L)iHuF1dx#_KbO-CbB2+*Pp@ZFj{k77_@!VCV za<+kNp0zjE^=75L;j8OjlY7<7hMpcrE54`OKn6D()h9&o6!JoWgGI7mOjVIODsTv6 z0WuK_4!dm+K)K?XIvH@VvC?iwlBu(uonlz9V(4v3b3 zbZ|ArJVy7s>+fb$HXnunD=_9HInMDuaBXeGkI{r|bEGB|^4x;cu7^n3^fR8JEz*ND z7Dd?2QTG%M0}+7WFqz)V65_mzm&a)=tnis zuXk*|%8YRFxMiw;D;49;t5uOBR%_E}I^p86$g^lDTWS2Wxyrb;;7M1JiZ?=Q|5M!P z-+Px%LqD3b9rh^ae&F$X-oH!t9J)t$<%x>=KD^F2?qT?olzF9N6ojW{D#SHsJx!}< zk$=ID+S%97d_+2*@3Om_i{eB-_ONICpts7PR?$|fU8B)^}&97m8B>Ul88a} zxZ3j0xIl^M-lTpUIm=`%M?sYzIR7~ON*FW#{70||mnV78{(BF#DY7BF4W`nScz~{T!8U zTE?kRVrRmK0W#BcKakjyr7)V6CjAMSlA@~tH#TFVWE6_GTI|8L(3sjVErlv-zc`?y zjIRpp{-|a`kfAqaUyDx%MQIrzqZLc-o<;j`B)e*7mx&lsxfdlnf3W_CSmQBLy@>O_Ig z^Z%uLJt4c4i^@^I$YE2u)N>bU~zW8*=bkMO70nb1TM z5qo7LB?r-|VhN+6fdR}|$0`ah`{47da(guYj~if+A0as<)X`kqYw>IHJCA#gG!ty` zp<#ei#kg_SeF2TQ*h~SCdUEGM>v|?qGxY&qrskq_mJ+(mGhv`F=991X^M)de1>*)Z zRzFt-lz&M%&1bm~n1P|;MgZiN+#|Asf!8G8V-oE=ht*R&A+MAjpi|C$7SR9O1_V>$ zD>)>R30^g*_Nn_Lya&4kz4W;vRB(hy?!b6Phh;hczFhS zL-!^@`h}SFzU4`Bo`*F5rzSe)Os$&e(Wf>Io-5OT#k&KZLEZ`h@uvjvo43rb7UIRw zGMtB744*bUpzVQddup176x4#PEV^cWpotFBJaUh~F`gr=qyUnK&M4i0_=Es)8mJ`V zKqV0&vb{8DP2@9L9*fRuP;hWPR(q+lX*9TP1O=p$b-Jk+lj+r;J>2ZlX>UsXSsq zp)QA}r_D=(8BcK~eq{^rOyFFVlr35P^Ic4HwF>x){Yb}T2h$LEQ+wM29a~x8p#4dV z!y3BdKJ>?p^SB}}&aQ?YGl$Zcr;JzE8Oj{nV_b;O^NpKdrKc0>! z;@!mj6Q{dEd9o)r_ib-3J&|Q=M=IGyG|<+2EEzmtz#yfSXaN~dkR@WCMLMHseZ_VXfLhx1Xq>2-&4f5 zgY2)Jv-P_J4EyHa+5i6C=!(c{ercL3?bLO5UGRS^UqX_{8rJ%3ZGSe$$YsIa zpa9@+kmeRqPzeAhvRyme=jTU$f!T=bv6nnly{NAf}w5nOD&CAhB3jo1z_Bctqq;h>j@ zn|!)xL#Q)aJW+u7f@Q*31<%gups_&9ldx0IuG-RG{7YSv=>%%;q!}5veUjUpg}&?Q zucgwAh3MK}^dDjI4wv>9e){d_DO&*#7BC9Gp{?2)Ges`0q=PlcPyz`AbL}L#Ig`X~-*RO6 zpaPO<)i_yu0-`bZ^S9qlHUH-+6b@DdAXh^1$^S~OMEH_OcG4HpApQi5OLyiMM$hDJ zp~g{XE>7;fIbB({-OYM0$hPJ9Fq2f}(O5h0x|_gcAWDsR6$*k;0Nuqc{QmucP;8Rs zGiPDS8`O#u&&zS@af~(R(RRaBm?7b zM+?O^8%gBi14~tVV+IwlZd^(QN<5zTTbqO2jw@}z7mWBEL5w}^kvu35!ZUEtXx~?? z3BM&|y7{VS6->oU^fgwqtRDQP?WHCj>@#h9#nkduL|lFkK?qMvZ9|tT&DOsOGk|ks zG_Q1LiZuZdz^C6H03`xo9flZ;Ax9b= zldQl(cQolsNh=gcV`Cc&d)km3htP$v=x-D~oDoA=q;W*Q>LiEhnN43!vRq{OOU&>I z&X16I$F|cOq1SVk@WyZSTwYIe&&;#n3yvq{ar!Q|p*`oURI|b_N&kvH8CCVj@C4x0~xpH|RZwPvf!u3-tBycy(>{v1ErzmM}LvatE_oqLc4W*VmmHZ|fM^GWJcn` zA}4ac{q(z)4i-Xf^lzO_>}2hn7~VpH^(Y6IG@s#rN}<9TeZTRwhjdvQR?W--(j2H* zAkXz?{MuFpHL$X1p?a9DUPBUvQe`ayEpT7u;p@wnlp*AHC9{aQ#mg#V41rsO841l8i znZGgvra8bFY;Zsf97Z)FO@H~}5w+g%-4DvZ(Z{Yf#*&K-?mJT=qI42*?~+kpE_cGf z;j__UVU6Vr_;2q_$!ONcvDh>%G$bk{?#K}sJ`T&UhkA1xcXFbom zH_`7?DI{N9tVNW((HgM+_L4C~COM0u5#jH;O+XX@zYfqe z3v$`Jy%~VSJR3e}Mnn|xVWUw$AEeh*!Q0`{ZF{CzP&{1$aT`tx@B2b#XMVAtqB483 z7BN#~lC*nrl=K$F4t5j^CQnW_kLZ2#g+uQvg`a9EGFo;%p+f>mnvn`t-QBi1XMctM z2SGZ}!PTwpdEoR~aG0b!MPSA`Z75C@GG!d9#Z)oKudO-5fKmP{>~C2S`ghoW3^RG` zH5^YVb802h1ag)N-Y%bYn;KSvQYljfFB3++7s!Xh`b=ESU@GW58<`N~^*&R;SdmI& z8d89k&gCC%XMeQ%FCl-;x=YEO6;-2-Ads)iH=F+@&~ujF9@b>GhFbA&|6fta;gxIy zKg>Oksc({8fq~eXYUj}?ejysjyY%OywZC=FDv!UVp=!Ymn0*Zv7MjakbNg8KgeA45 zP%3#pkqeu<4tKWtLUkJWr0FT|lE3=qN?(PM$oxy%(>dv(Zi!am_(#ecHTZ+;GQLyM z{ z{=bn5zxKv6HV%G|4q_x0fB4!J>O~78%GQR}fptGYCNr8nw#G*f;JIo1lzz*civdvB zmhUSsW;*^vx2$8I|`9HNZwR&9rmXy@z2TbbP=A!c4A07i9plg9gn!#R@n@^TYGOqmRpBcN!cW zbHh>l%I^)TzCr0TA1>6r9F<_Oc5J#_4NY8l8FA~};LNt`3$oGWB9QJGmRxq;#IQ~K z4VkBV-aD(qNMqPNM%d>C2NuB@P^nvNTBVmfP9tO%T*TxN^8)sXGiU-vOM%~ccdf0h zEoOgEtCW&d3q_F%gEyWKll-<@?1hQLbYjiY0dEok11E5be*QKM;VI5Q+PgX4*NJ;T zL&|_thP>b`J}WM()8XxzmYj-eh3F);3OTa92O67bd2w6Jq8@syj^;@BUVM= z9^9R&*wVf~#>J!{C(o{>aKAY>baMtTe*woHUzj79XOuLatAV3f9$?X+Z&$IHJ3sJz zsDIWLbuZGJsE$8BzlG$q9}dnh@*Z_yapYOxANTGezLGy^S0Hwv__|Q`{PDL93DuILi4th0oKY6uEH?oS(e} z@BFwpmzfB}$WZt$ha%TuK*aC9=z8!Dl7Gr4J~V$@BkzLVbboDTs#s;N8j$94_Irhh z-7+QJt&N##BJd6j!EfMjrG0GdmUXGON_NuqYFc6kDIY75bY!7WAbDM~2v9FI5LV^BVjV?;&#@Q^(A*ke4Xci(+?^XAQ& zwV4J3&U}dW&O7h4YSoJIlt&yfQkR#%Q3Ir7)P{HZGTf#8`t@Ty%5?P5p+o&7aR&KeXrrAtae^lbt(454dg>{<(gtzQ z+<*W5pe|apXmoTm3n@ST_@fQ=?+D~BA_ugky?gg^^U(Xu0PwLlQmT*A)~#C^Bj^J7 zFysE>i!XS((N1dDuDyKua8LvzZlP6E^+_^IoJ4Txd6)K?AA|3*1nu!w#BIYaHsPsNV zF+;b<(na8%NE28d`_rHPlqXLfQ+ogY{TXK%MgQ@SfAB1`PQZ=lS$SFuF9uu&6vDV8 zdH9_&5Mje3L?1K6@S%@Q7JvKO-$-jd+^=|22E!up3l}cTB|GFM^vyTlWHhH*pk%}$ z2=PXSD2zyjZ@&4)Wa#mI>#et5%089q8xHGuPNHS&06fR-TZ9!KuPcb?8XK3P>Iodz}`A;rcrl2i$j$OepMB;LA0bWs$(doDTef`p@a_rc#EbNfVbS1grrXLac&QvMQ z6a6zJ2cz-uppq?Yix)4BgK@#$C*11zP;-V_hIlGKd!0pFH|_G!cmlbL7|{%t(W6H* zS*9%3)@`1tK1#cH@4orwo3Fn5Y7#P*@i;T?RH;&hOMsIPQj^vp@=cz1-g&3FZ79z8 z_o39~_0tX#R0Hd87S2j;~# z!09mKG9#MV#$-Te;!oc*4r z{PWK^5De&2h+je()0s+}4-bh=>)%21NP=2J`!A)QjTYq;pGZFPw=L)Sq3?OjOwMLN zK@ghTmzg7TdE$5M*wI8lhvSlA#axmz6LWmn6v2nNDiZ{z4Bj7ZVv__75+TPoni&q} z;NE+}CMH$&5In}8{)4&M+2$VQ*`~=Ri2Bs2Q-@HdUB-uRGtFoAVSLOK#t0tc!#!3^LJ_e{4rmc7EOUz= ze)xg36ogXi5!vVC8VEykpRl?0-FM%SCrMs-;RTAY_X(rzk|j&ue>dXhF1nrH=z=|oLsU(_&6+HMLQ;Es?unG15 zAecBzJyFGQv;4rQVu~<9L4Est5TL}|f=b$~7&>?~e2&XDj!%cr`!Lnp0ABWVFZtn6UK+R230pK z5M{U#V9r$L=0=^go(LYN4q^R`!`$DQx5qPQ&KxRv#~pW=;#kW9^ybZ*&7~Po`t<2z zYsE8cR6uSfo*dvJ)fm=^X+B0%Mo}w$@S+Gy$^MR)VEDh5~Otnx@*cD*@4n6xMm>T-|X5onB zPDR`l6rkVmvM+4$DsEqDmZkh>_= zN69>!Pd@pit&G#*NALvlAULy1r#qzwfxDV#fyIAj=x7f}`W-uVq@gUI_hG8H0Rw{f zV{UxVM+2`0a~EzKltQ0L$dCnXX7kKJ;Xr#CguP?>6g))pkI2lb|L})D{5F;)|7X@A zX3Uu3U5X!{haP%}sg)f_ea7Sw=BYGN#wgZA%hjnxt$V(Ek1l$9dJYsNVC z0O%fP=?vWVlAcBq!-O^>a+s2^scV<)Y&7H(ZpI5%$*rf;L0YC2PM`F+S)#Pb8Sj|d zm`i#PhliaQHw1Sr(|^W9#EDIqZ5<5g%-@mj3?-(LG=bYJz+W}7O+_knGTT6ge)`&8 z`ga7*(0LnBLu`{!2zUz6&zRW&ob@ZjCleQzzbVvqlm7~2*be{rea229==Mtl~;jfyz*85EQ!$^gqtpyqi;-Y{^Z z@dS7mnS%TyGUGP$4>JXE){VJ^^U}YYfrT7c*7F!hZK{NX1iFd&fwA#p4aO`&5Fr=; zSfpkVi5U=^|7=~-Y!qt55AxP#flPCbUuI}9!x^d!t7nwKDu<2F90a#nowS~Q9FQfH zJp(^+{0EVP|Ku!cvmuPGhwNoB4I%82VSIc%W1saz|HI8PkA8_L`$~Y%IDHUqwG>rR9o=hATK>Xhl&a47w$bG`fxJ_%e<>_cvswtiM zDNhgri3s>$fM8?#cVyIEl>SF4rJKau%zhpO{|(HjP^Mhlw{K@H9fg?nC>ArAF*B8B zfh+w*q z62@l5unsA5U>(zXBA-w)?4^eTxkY>wH|vk6Ll?G}sXEMd83UGyNhMjUF$*9zEe&A` zOzZ5Ln+f8^rF8nkuB#eFm`N*ZDa0{5x*p4k#GweAc}6)>T46v5!#>28LN_7#%q7Ds zHx1gAb7gPl%$YQb{x)%_JeLgO=8}Cl21mQcV>|<4Xkw=4+vgGo88X*lXmjrEnO_D3 z2${_%?EQei#0t@cwrY0K16*nggrT`l7@M$UGXxMqP{oJ&DU&wbb~}VS(3pfcw_z+d zpG$2vG(C<~A0;!-MSbyEiqZSIJxu5y|M*8|qeA{5&`sR8bg`{G{f?|fyR|+6I(*)T zf!qcG=I=k6pQSdYv)oarI3@?S(%CO}ZoJu?eJ-`7iiq7=`qX1(o?Sz3437cR7Ub<< zU6Ik_+H0@%4r0B|ND#yXR;Jz&@VTh*I6pL)-3yF~UwP#fGi$Sj&^%;!kLG#nYjUY5-q-H3bISS4Yy zMM0FpI6|H_j(>+)qeMl;$^zR;Ha0=YC}1jS($WM%xlK{;ymO;0w&+%_Nu65UrdQ6^~hicea7}Al}#;Ff&a?1ZFn|6kUKYK;>e3LL8QExL={l zh7E3fs38^^@TAw+4`k1Y1zh@w0g-(;WREEP7EH82FAS?Xl! zO-yDmJbp$7FcariH>wXi;Z%c6nBigbYU)WF+2{9o+?+KJ%I)V-!ZL;D!l-D>8qM?; zQ(7~RG^JoXjif|t#H^H|+3bO%>mw-%3hjfy5)1b{JqR~8V|bQ9hg!@{MRx>9$^U(r z>TM8UDSo1H1F(h3V@@2N0xZsPFiB#E)uiG^LZa|cAWh+qZby?Dop{)p2XLSJzmro% zgkcoJ0=>*|f$q+YM=5-`pP78K`QoSYHi$=wpDHuJS|97+S)gkexVW{fr>DcGIP&mh zEWm(@x-tYXma#O)#+OqzQUgp3n1Gwy5qFFo4BzB~3c@7Rqg2!m9)6Ef*iU0{G%-oS zHWI`=;`q5l!ZCmvNlPZYzX2;LYqnt$@~8s^iRh7!5i<;Ptk*LrlL=jdr!yKu27=Hw zgh34*li|Y|C(UjsImNIo1=<)HGt${mqpP7inmBAH@C2H28Q|y|o0eYl0LVfRnkWSL zumNsX2Dp!np&FS4!Z6KkWHw{#=5$aElPCQ}#mssR5f}ov>v#f#Dv{X$syV+;Vu+-7 z0BF@j`qvm+J4?rHOcPBhei))cQ9a@_eKEQeZe+aEl8}X5eDLSPNR6PSgK*o~rM<(G zqx|+o=OS@~YNr3lDLqP$KmNG0T;sNOk0wuU27VM_WD+ur- ze$VY;>W^JJb1$a({+Za&RPRG#`ne5kK52F!Y`iBKOnGgFEHWc?xOHhDBOzm{QT=H$ zQj=)@@8m!bu?WvFXdee0OrY7jvUNz+f#Shaz=)A*OrH_1@agN}$q>ez$awlGiM~gA zBgv7^9ytVliELn(7vVRaAiS-3mPaZY`)SPKG zsyc$lY)xhVwy1_F5nz8212YyC(e_vYqfc2ML-9{3zWhZ%1VTW-DTTb<$XjE=%OV2{ z0_c61Z+S<{=00qSP-@bAHD`m$EC!;<5{<=>Y~CDI&kuoN!-hGZBG!b{tUdcF zML{AU0_h>(XY(vQjM9g6`FYj0$OUzyyBI!2n0fam1u?xKQXaD4b^Xx{nSc9SxJDMOY@rnKZP;@wL9v5 tqA4h|2}tl{Heuy20wN#+B5)aj{|7()-nE|+4AKAq002ovPDHLkV1nY-W2XQB literal 0 HcmV?d00001 diff --git a/docs/source/arch_lang/figures/global_input_ports.png b/docs/source/arch_lang/figures/global_input_ports.png new file mode 100644 index 0000000000000000000000000000000000000000..4c9025ab3ecfbd8c2430ede774848e38b6b27738 GIT binary patch literal 24062 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%0AKYa=E+^QJdprJ6 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 IEtk0e0qN>RwEzGB literal 0 HcmV?d00001 diff --git a/docs/source/arch_lang/figures/gpout_ports.png b/docs/source/arch_lang/figures/gpout_ports.png new file mode 100644 index 0000000000000000000000000000000000000000..e5140bd99b67d1c761ac7a8cf361b0eb3ff62df2 GIT binary patch literal 23998 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�nvK0n9$8c{i)zl`5j2Noh%U@1cUFv$3_a$NF&O|| z2#|_9WGhC*4RizP5rc@)DlcdD2mz;>3O1vV*=a+<43HTN zGIC@STCg{t+pye)@Jy{3g3fPxkeo#_GvCNq7;g-OeV&~xh!+oe^nwMQWaoRS3@ini z*$*#a4?tlo;e#~_+Y0lh*u}42e#fL8ex!^n-b9kMxXL8c%fgG`71aV{O z-23kI7S-mM&m-GXI7!5%jQCW7-3s(h*mr<7q8GwEIBWZ+Q{oa(PBBA({Va4+-Lu0C zZQ%B0_W*Lu83LYW^KvF>#VP_3BfyDSv?(spu{|NLzVddFN=~^+fCXB!>)j<$y09U4 g!MFsGQ%(^0fAm<~%N~ab#{d8T07*qoM6N<$g6reffB*mh literal 0 HcmV?d00001