From 092e10afda7c2e2496b638220684bbc2422489db Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 28 Feb 2020 11:14:50 -0700 Subject: [PATCH] bring pnr sdc generator online and fixed minor bugs in bitstream writing --- openfpga/src/base/openfpga_bitstream.cpp | 8 ++ openfpga/src/base/openfpga_sdc.cpp | 80 +++++++++++++++++++ openfpga/src/base/openfpga_sdc.h | 23 ++++++ openfpga/src/base/openfpga_sdc_command.cpp | 79 ++++++++++++++++++ openfpga/src/base/openfpga_sdc_command.h | 21 +++++ openfpga/src/fpga_sdc/pnr_sdc_grid_writer.cpp | 2 +- .../src/fpga_sdc/pnr_sdc_routing_writer.cpp | 8 +- openfpga/src/fpga_sdc/pnr_sdc_writer.cpp | 10 +-- openfpga/src/main.cpp | 4 + openfpga/test_script/s298_k6_frac.openfpga | 13 ++- 10 files changed, 236 insertions(+), 12 deletions(-) create mode 100644 openfpga/src/base/openfpga_sdc.cpp create mode 100644 openfpga/src/base/openfpga_sdc.h create mode 100644 openfpga/src/base/openfpga_sdc_command.cpp create mode 100644 openfpga/src/base/openfpga_sdc_command.h diff --git a/openfpga/src/base/openfpga_bitstream.cpp b/openfpga/src/base/openfpga_bitstream.cpp index 08fa7bf16..e732dee92 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 openfpgautil library */ +#include "openfpga_digest.h" + #include "build_device_bitstream.h" #include "bitstream_writer.h" #include "build_fabric_bitstream.h" @@ -30,6 +33,11 @@ void fpga_bitstream(OpenfpgaContext& openfpga_ctx, cmd_context.option_enable(cmd, opt_verbose)); if (true == cmd_context.option_enable(cmd, opt_file)) { + 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()); + 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 new file mode 100644 index 000000000..4fce8d552 --- /dev/null +++ b/openfpga/src/base/openfpga_sdc.cpp @@ -0,0 +1,80 @@ +/******************************************************************** + * This file includes functions to compress the hierachy of routing architecture + *******************************************************************/ +/* Headers from vtrutil library */ +#include "vtr_time.h" +#include "vtr_log.h" + +/* Headers from openfpgautil library */ +#include "openfpga_digest.h" + +#include "circuit_library_utils.h" +#include "pnr_sdc_writer.h" +#include "openfpga_sdc.h" + +/* Include global variables of VPR */ +#include "globals.h" + +/* begin namespace openfpga */ +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) { + + CommandOptionId opt_output_dir = cmd.option("file"); + CommandOptionId opt_constrain_global_port = cmd.option("constrain_global_port"); + CommandOptionId opt_constrain_grid = cmd.option("constrain_grid"); + CommandOptionId opt_constrain_sb = cmd.option("constrain_sb"); + CommandOptionId opt_constrain_cb = cmd.option("constrain_cb"); + CommandOptionId opt_constrain_configurable_memory_outputs = cmd.option("constrain_configurable_memory_outputs"); + CommandOptionId opt_constrain_routing_multiplexer_outputs = cmd.option("constrain_routing_multiplexer_outputs"); + CommandOptionId opt_constrain_switch_block_outputs = cmd.option("constrain_switch_block_outputs"); + + /* This is an intermediate data structure which is designed to modularize the FPGA-SDC + * Keep it independent from any other outside data structures + */ + 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()); + + PnrSdcOption options(sdc_dir_path); + + options.set_constrain_global_port(cmd_context.option_enable(cmd, opt_constrain_global_port)); + options.set_constrain_grid(cmd_context.option_enable(cmd, opt_constrain_grid)); + options.set_constrain_sb(cmd_context.option_enable(cmd, opt_constrain_sb)); + options.set_constrain_cb(cmd_context.option_enable(cmd, opt_constrain_cb)); + options.set_constrain_configurable_memory_outputs(cmd_context.option_enable(cmd, opt_constrain_configurable_memory_outputs)); + options.set_constrain_routing_multiplexer_outputs(cmd_context.option_enable(cmd, opt_constrain_routing_multiplexer_outputs)); + options.set_constrain_switch_block_outputs(cmd_context.option_enable(cmd, opt_constrain_switch_block_outputs)); + + /* We first turn on default sdc option and then disable part of them by following users' options */ + if (false == options.generate_sdc_pnr()) { + options.set_generate_sdc_pnr(true); + } + + /* Collect global ports from the circuit library: + * TODO: should we place this in the OpenFPGA context? + */ + std::vector global_ports = find_circuit_library_global_ports(openfpga_ctx.arch().circuit_lib); + + /* Execute only when sdc is enabled */ + if (true == options.generate_sdc_pnr()) { + print_pnr_sdc(options, + 0, /* TODO: add critical path stats to OpenFPGA context */ + //openfpga_ctx.vpr_timing_annotation().critical_path_delay(); + g_vpr_ctx.device(), + openfpga_ctx.vpr_device_annotation(), + openfpga_ctx.device_rr_gsb(), + openfpga_ctx.module_graph(), + openfpga_ctx.mux_lib(), + openfpga_ctx.arch().circuit_lib, + global_ports, + openfpga_ctx.flow_manager().compress_routing()); + } +} + +} /* end namespace openfpga */ diff --git a/openfpga/src/base/openfpga_sdc.h b/openfpga/src/base/openfpga_sdc.h new file mode 100644 index 000000000..4e48964f3 --- /dev/null +++ b/openfpga/src/base/openfpga_sdc.h @@ -0,0 +1,23 @@ +#ifndef OPENFPGA_SDC_H +#define OPENFPGA_SDC_H + +/******************************************************************** + * Include header files that are required by function declaration + *******************************************************************/ +#include "command.h" +#include "command_context.h" +#include "openfpga_context.h" + +/******************************************************************** + * Function declaration + *******************************************************************/ + +/* begin namespace openfpga */ +namespace openfpga { + +void write_pnr_sdc(OpenfpgaContext& openfpga_ctx, + const Command& cmd, const CommandContext& cmd_context); + +} /* end namespace openfpga */ + +#endif diff --git a/openfpga/src/base/openfpga_sdc_command.cpp b/openfpga/src/base/openfpga_sdc_command.cpp new file mode 100644 index 000000000..cf31d73b0 --- /dev/null +++ b/openfpga/src/base/openfpga_sdc_command.cpp @@ -0,0 +1,79 @@ +/******************************************************************** + * Add commands to the OpenFPGA shell interface, + * in purpose of generate SDC files + * - write_pnr_sdc : generate SDC to constrain the back-end flow for FPGA fabric + * - write_analysis_sdc: TODO: generate SDC based on users' implementations + *******************************************************************/ +#include "openfpga_sdc.h" +#include "openfpga_sdc_command.h" + +/* begin namespace openfpga */ +namespace openfpga { + +/******************************************************************** + * - Add a command to Shell environment: generate PnR SDC + * - Add associated options + * - Add command dependency + *******************************************************************/ +static +void add_openfpga_write_pnr_sdc_command(openfpga::Shell& shell, + const ShellCommandClassId& cmd_class_id, + const ShellCommandId& shell_cmd_build_fabric_id) { + Command shell_cmd("write_pnr_sdc"); + + /* Add an option '--file' in short '-f'*/ + CommandOptionId output_opt = shell_cmd.add_option("file", true, "Specify the output directory for SDC files"); + shell_cmd.set_option_short_name(output_opt, "f"); + shell_cmd.set_option_require_value(output_opt, openfpga::OPT_STRING); + + /* Add an option '--constrain_global_port' */ + shell_cmd.add_option("constrain_global_port", false, "Constrain all the global ports of FPGA fabric"); + + /* Add an option '--constrain_grid' */ + shell_cmd.add_option("constrain_grid", false, "Constrain all the grids of FPGA fabric"); + + /* Add an option '--constrain_sb' */ + shell_cmd.add_option("constrain_sb", false, "Constrain all the switch blocks of FPGA fabric"); + + /* Add an option '--constrain_cb' */ + shell_cmd.add_option("constrain_cb", false, "Constrain all the connection blocks of FPGA fabric"); + + /* Add an option '--constrain_configurable_memory_outputs' */ + shell_cmd.add_option("constrain_configurable_memory_outputs", false, "Constrain all the outputs of configurable memories of FPGA fabric"); + + /* Add an option '--constrain_routing_multiplexer_outputs' */ + shell_cmd.add_option("constrain_routing_multiplexer_outputs", false, "Constrain all the outputs of routing multiplexer of FPGA fabric"); + + /* Add an option '--constrain_switch_block_outputs' */ + shell_cmd.add_option("constrain_switch_block_outputs", false, "Constrain all the outputs of switch blocks of FPGA fabric"); + + /* Add an option '--verbose' */ + shell_cmd.add_option("verbose", false, "Enable verbose output"); + + /* Add command 'write_fabric_verilog' to the Shell */ + ShellCommandId shell_cmd_id = shell.add_command(shell_cmd, "generate SDC files to constrain the backend flow for FPGA fabric"); + shell.set_command_class(shell_cmd_id, cmd_class_id); + shell.set_command_execute_function(shell_cmd_id, write_pnr_sdc); + + /* The 'build_fabric' command should NOT be executed before 'link_openfpga_arch' */ + std::vector cmd_dependency; + cmd_dependency.push_back(shell_cmd_build_fabric_id); + shell.set_command_dependency(shell_cmd_id, cmd_dependency); +} + +void add_openfpga_sdc_commands(openfpga::Shell& shell) { + /* Get the unique id of 'build_fabric' command which is to be used in creating the dependency graph */ + const ShellCommandId& shell_cmd_build_fabric_id = shell.command(std::string("build_fabric")); + + /* Add a new class of commands */ + ShellCommandClassId openfpga_sdc_cmd_class = shell.add_command_class("FPGA-SDC"); + + /******************************** + * Command 'write_fabric_verilog' + */ + add_openfpga_write_pnr_sdc_command(shell, + openfpga_sdc_cmd_class, + shell_cmd_build_fabric_id); +} + +} /* end namespace openfpga */ diff --git a/openfpga/src/base/openfpga_sdc_command.h b/openfpga/src/base/openfpga_sdc_command.h new file mode 100644 index 000000000..9fbeb42a5 --- /dev/null +++ b/openfpga/src/base/openfpga_sdc_command.h @@ -0,0 +1,21 @@ +#ifndef OPENFPGA_SDC_COMMAND_H +#define OPENFPGA_SDC_COMMAND_H + +/******************************************************************** + * Include header files that are required by function declaration + *******************************************************************/ +#include "shell.h" +#include "openfpga_context.h" + +/******************************************************************** + * Function declaration + *******************************************************************/ + +/* begin namespace openfpga */ +namespace openfpga { + +void add_openfpga_sdc_commands(openfpga::Shell& shell); + +} /* end namespace openfpga */ + +#endif diff --git a/openfpga/src/fpga_sdc/pnr_sdc_grid_writer.cpp b/openfpga/src/fpga_sdc/pnr_sdc_grid_writer.cpp index ea7702a12..f8ce1c703 100644 --- a/openfpga/src/fpga_sdc/pnr_sdc_grid_writer.cpp +++ b/openfpga/src/fpga_sdc/pnr_sdc_grid_writer.cpp @@ -323,7 +323,7 @@ void print_pnr_sdc_constrain_grid_timing(const std::string& sdc_dir, const ModuleManager& module_manager) { /* Start time count */ - vtr::ScopedStartFinishTimer timer("Generating SDC for constraining grid timing for P&R flow"); + vtr::ScopedStartFinishTimer timer("Write SDC for constraining grid timing for P&R flow"); for (const t_physical_tile_type& physical_tile : device_ctx.physical_tile_types) { /* Bypass empty type or nullptr */ diff --git a/openfpga/src/fpga_sdc/pnr_sdc_routing_writer.cpp b/openfpga/src/fpga_sdc/pnr_sdc_routing_writer.cpp index 348ee3dac..dcb5b6849 100644 --- a/openfpga/src/fpga_sdc/pnr_sdc_routing_writer.cpp +++ b/openfpga/src/fpga_sdc/pnr_sdc_routing_writer.cpp @@ -166,7 +166,7 @@ void print_pnr_sdc_flatten_routing_constrain_sb_timing(const std::string& sdc_di const DeviceRRGSB& device_rr_gsb) { /* Start time count */ - vtr::ScopedStartFinishTimer timer("Generating SDC for constrain Switch Block timing for P&R flow"); + vtr::ScopedStartFinishTimer timer("Write SDC for constrain Switch Block timing for P&R flow"); /* Get the range of SB array */ vtr::Point sb_range = device_rr_gsb.get_gsb_range(); @@ -195,7 +195,7 @@ void print_pnr_sdc_compact_routing_constrain_sb_timing(const std::string& sdc_di const DeviceRRGSB& device_rr_gsb) { /* Start time count */ - vtr::ScopedStartFinishTimer timer("Generating SDC for constrain Switch Block timing for P&R flow"); + vtr::ScopedStartFinishTimer timer("Write SDC for constrain Switch Block timing for P&R flow"); for (size_t isb = 0; isb < device_rr_gsb.get_num_sb_unique_module(); ++isb) { const RRGSB& rr_gsb = device_rr_gsb.get_sb_unique_module(isb); @@ -362,7 +362,7 @@ void print_pnr_sdc_flatten_routing_constrain_cb_timing(const std::string& sdc_di const DeviceRRGSB& device_rr_gsb) { /* Start time count */ - vtr::ScopedStartFinishTimer timer("Generating SDC for constrain Connection Block timing for P&R flow"); + vtr::ScopedStartFinishTimer timer("Write SDC for constrain Connection Block timing for P&R flow"); print_pnr_sdc_flatten_routing_constrain_cb_timing(sdc_dir, module_manager, rr_graph, @@ -385,7 +385,7 @@ void print_pnr_sdc_compact_routing_constrain_cb_timing(const std::string& sdc_di const DeviceRRGSB& device_rr_gsb) { /* Start time count */ - vtr::ScopedStartFinishTimer timer("Generating SDC for constrain Connection Block timing for P&R flow"); + vtr::ScopedStartFinishTimer timer("Write SDC for constrain Connection Block timing for P&R flow"); /* Print SDC for unique X-direction connection block modules */ for (size_t icb = 0; icb < device_rr_gsb.get_num_cb_unique_module(CHANX); ++icb) { diff --git a/openfpga/src/fpga_sdc/pnr_sdc_writer.cpp b/openfpga/src/fpga_sdc/pnr_sdc_writer.cpp index e418bc620..aa1895014 100644 --- a/openfpga/src/fpga_sdc/pnr_sdc_writer.cpp +++ b/openfpga/src/fpga_sdc/pnr_sdc_writer.cpp @@ -58,7 +58,7 @@ void print_pnr_sdc_global_ports(const std::string& sdc_dir, std::string sdc_fname(sdc_dir + std::string(SDC_GLOBAL_PORTS_FILE_NAME)); /* Start time count */ - std::string timer_message = std::string("Generating SDC for constraining clocks for P&R flow '") + sdc_fname + std::string("'"); + std::string timer_message = std::string("Write SDC for constraining clocks for P&R flow '") + sdc_fname + std::string("'"); vtr::ScopedStartFinishTimer timer(timer_message); /* Create the file stream */ @@ -153,7 +153,7 @@ void print_pnr_sdc_constrain_configurable_memory_outputs(const std::string& sdc_ std::string sdc_fname(sdc_dir + std::string(SDC_DISABLE_CONFIG_MEM_OUTPUTS_FILE_NAME)); /* Start time count */ - std::string timer_message = std::string("Generating SDC to disable configurable memory outputs for P&R flow '") + sdc_fname + std::string("'"); + std::string timer_message = std::string("Write SDC to disable configurable memory outputs for P&R flow '") + sdc_fname + std::string("'"); vtr::ScopedStartFinishTimer timer(timer_message); /* Create the file stream */ @@ -187,7 +187,7 @@ void print_sdc_disable_routing_multiplexer_outputs(const std::string& sdc_dir, std::string sdc_fname(sdc_dir + std::string(SDC_DISABLE_MUX_OUTPUTS_FILE_NAME)); /* Start time count */ - std::string timer_message = std::string("Generating SDC to disable routing multiplexer outputs for P&R flow '") + sdc_fname + std::string("'"); + std::string timer_message = std::string("Write SDC to disable routing multiplexer outputs for P&R flow '") + sdc_fname + std::string("'"); vtr::ScopedStartFinishTimer timer(timer_message); /* Create the file stream */ @@ -242,7 +242,7 @@ void print_pnr_sdc_flatten_routing_disable_switch_block_outputs(const std::strin std::string sdc_fname(sdc_dir + std::string(SDC_DISABLE_SB_OUTPUTS_FILE_NAME)); /* Start time count */ - std::string timer_message = std::string("Generating SDC to disable switch block outputs for P&R flow '") + sdc_fname + std::string("'"); + std::string timer_message = std::string("Write SDC to disable switch block outputs for P&R flow '") + sdc_fname + std::string("'"); vtr::ScopedStartFinishTimer timer(timer_message); /* Create the file stream */ @@ -298,7 +298,7 @@ void print_pnr_sdc_compact_routing_disable_switch_block_outputs(const std::strin std::string sdc_fname(sdc_dir + std::string(SDC_DISABLE_SB_OUTPUTS_FILE_NAME)); /* Start time count */ - std::string timer_message = std::string("Generating SDC to disable switch block outputs for P&R flow '") + sdc_fname + std::string("'"); + std::string timer_message = std::string("Write SDC to disable switch block outputs for P&R flow '") + sdc_fname + std::string("'"); vtr::ScopedStartFinishTimer timer(timer_message); /* Create the file stream */ diff --git a/openfpga/src/main.cpp b/openfpga/src/main.cpp index c018db4bf..b2c9d2e6c 100644 --- a/openfpga/src/main.cpp +++ b/openfpga/src/main.cpp @@ -14,6 +14,7 @@ #include "openfpga_setup_command.h" #include "openfpga_verilog_command.h" #include "openfpga_bitstream_command.h" +#include "openfpga_sdc_command.h" #include "basic_command.h" #include "openfpga_title.h" @@ -60,6 +61,9 @@ int main(int argc, char** argv) { /* Add openfpga bitstream commands */ openfpga::add_openfpga_bitstream_commands(shell); + /* Add openfpga sdc commands */ + openfpga::add_openfpga_sdc_commands(shell); + /* Add basic commands: exit, help, etc. * Note: * This MUST be the last command group to be added! diff --git a/openfpga/test_script/s298_k6_frac.openfpga b/openfpga/test_script/s298_k6_frac.openfpga index d79fc3b9b..a5c2c3669 100644 --- a/openfpga/test_script/s298_k6_frac.openfpga +++ b/openfpga/test_script/s298_k6_frac.openfpga @@ -35,10 +35,19 @@ fpga_bitstream --verbose --file /var/tmp/xtang/openfpga_test_src/fabric_indepene # 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 --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 -write_verilog_testbench --file /var/tmp/xtang/openfpga_test_src --reference_benchmark_file_path /var/tmp/xtang/s298.v --print_top_testbench --print_preconfig_top_testbench --print_simulation_ini /var/tmp/xtang/openfpga_test_src/simulation_deck.ini +# - We suggest the use of same output directory as fabric Verilog netlists +# - Must specify the reference benchmark file if you want to output any testbenches +# - 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/s298.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 +write_pnr_sdc --file /var/tmp/xtang/openfpga_test_src/SDC # Finish and exit OpenFPGA exit