diff --git a/docs/source/manual/file_formats/bitstream_setting.rst b/docs/source/manual/file_formats/bitstream_setting.rst index 764bf0c87..eb2af5ddf 100644 --- a/docs/source/manual/file_formats/bitstream_setting.rst +++ b/docs/source/manual/file_formats/bitstream_setting.rst @@ -13,6 +13,9 @@ This can define a hard-coded bitstream for a reconfigurable resource in FPGA fab + + + pb_type-related Settings @@ -39,7 +42,6 @@ The following syntax are applicable to the XML definition tagged by ``pb_type`` .. option:: content="" The content of the ``pb_type`` bitstream, which could be a keyword in a ``.eblif`` file. For example, ``content=".attr LUT"`` means that the bitstream will be extracted from the ``.attr LUT`` line which is defined under the ``.blif model`` (that is defined under the ``pb_type`` in VPR architecture file). - .. option:: is_mode_select_bitstream="" @@ -71,3 +73,45 @@ The following syntax are applicable to the XML definition tagged by ``interconne The default path can be either ``iopad.inpad`` or ``ff.Q`` which corresponds to the first input and the second input respectively. + +non_fabric-related Settings +^^^^^^^^^^^^^^^^^^^^^^^^ + +This is special syntax to extract PB defined parameter or attribute and save the data into dedicated JSON file outside of fabric bitstream + +The following syntax are applicable to the XML definition tagged by ``non_fabric`` in bitstream setting files. + +.. option:: name="" + + The ``pb_type`` top level name that the data to be extracted. For example, + + .. code-block:: xml + + name="bram" + +.. option:: file="" + + The filepath the data is saved to. For example, + + .. code-block:: xml + + file="bram.json" + +.. option:: ``pb`` child element name="" + + Together with ``pb_type`` top level name, that is the source of the ``pb_type`` bitstream + + The final ``pb_type`` name is "" + "" + + For example, + + .. code-block:: xml + + + + + The final ``pb_type`` name is "bram.bram_lr[mem_36K_tdp].mem_36K" + +.. option:: ``pb`` child element content="" + + The content of the ``pb_type`` data to be extracted. For example, ``content=".param INIT_i"`` means that the data will be extracted from the ``.param INIT_i`` line defined under the ``.blif model``. diff --git a/libs/libarchopenfpga/src/bitstream_setting.cpp b/libs/libarchopenfpga/src/bitstream_setting.cpp index c04eeba87..7d763f9d2 100644 --- a/libs/libarchopenfpga/src/bitstream_setting.cpp +++ b/libs/libarchopenfpga/src/bitstream_setting.cpp @@ -102,6 +102,10 @@ std::string BitstreamSetting::default_path( return interconnect_default_paths_[interconnect_setting_id]; } +std::vector BitstreamSetting::non_fabric() const { + return non_fabric_; +} + /************************************************************************ * Public Mutators ***********************************************************************/ @@ -154,6 +158,26 @@ BitstreamSetting::add_bitstream_interconnect_setting( return interc_setting_id; } +void BitstreamSetting::add_non_fabric(const std::string& name, + const std::string& file) { + VTR_ASSERT(name.size()); + VTR_ASSERT(file.size()); + non_fabric_.push_back(NonFabricBitstreamSetting(name, file)); +} + +void BitstreamSetting::add_non_fabric_pb(const std::string& pb, + const std::string& content) { + VTR_ASSERT(non_fabric_.size()); + VTR_ASSERT(content.find(".param ") == 0 || content.find(".attr ") == 0); + if (content.find(".param ") == 0) { + VTR_ASSERT(content.size() > 7); + non_fabric_.back().add_pb(pb, "param", content.substr(7)); + } else { + VTR_ASSERT(content.size() > 6); + non_fabric_.back().add_pb(pb, "attr", content.substr(6)); + } +} + /************************************************************************ * Public Validators ***********************************************************************/ diff --git a/libs/libarchopenfpga/src/bitstream_setting.h b/libs/libarchopenfpga/src/bitstream_setting.h index 7963942a0..1b12c8de3 100644 --- a/libs/libarchopenfpga/src/bitstream_setting.h +++ b/libs/libarchopenfpga/src/bitstream_setting.h @@ -6,6 +6,7 @@ * which are used by OpenFPGA *******************************************************************/ #include +#include #include "bitstream_setting_fwd.h" #include "vtr_vector.h" @@ -13,6 +14,29 @@ /* namespace openfpga begins */ namespace openfpga { +struct NonFabricBitstreamPBSetting { + NonFabricBitstreamPBSetting(const std::string& p = "", + const std::string& t = "", + const std::string& c = "") + : pb(p), type(t), content(c) {} + const std::string pb = ""; + const std::string type = ""; + const std::string content = ""; +}; + +struct NonFabricBitstreamSetting { + NonFabricBitstreamSetting(const std::string& n = "", + const std::string& f = "") + : name(n), file(f) {} + void add_pb(const std::string& p, const std::string& t, + const std::string& c) { + pbs.push_back(NonFabricBitstreamPBSetting(p, t, c)); + } + const std::string name = ""; + const std::string file = ""; + std::vector pbs; +}; + /******************************************************************** * A data structure to describe bitstream settings * @@ -73,6 +97,7 @@ class BitstreamSetting { const BitstreamInterconnectSettingId& interconnect_setting_id) const; std::string default_path( const BitstreamInterconnectSettingId& interconnect_setting_id) const; + std::vector non_fabric() const; public: /* Public Mutators */ BitstreamPbTypeSettingId add_bitstream_pb_type_setting( @@ -92,6 +117,9 @@ class BitstreamSetting { const std::vector& parent_mode_names, const std::string& default_path); + void add_non_fabric(const std::string& name, const std::string& file); + void add_non_fabric_pb(const std::string& pb, const std::string& content); + public: /* Public Validators */ bool valid_bitstream_pb_type_setting_id( const BitstreamPbTypeSettingId& pb_type_setting_id) const; @@ -133,6 +161,7 @@ class BitstreamSetting { interconnect_parent_mode_names_; vtr::vector interconnect_default_paths_; + std::vector non_fabric_; }; } // namespace openfpga diff --git a/libs/libarchopenfpga/src/read_xml_bitstream_setting.cpp b/libs/libarchopenfpga/src/read_xml_bitstream_setting.cpp index 7447bec2a..7f6bd1237 100644 --- a/libs/libarchopenfpga/src/read_xml_bitstream_setting.cpp +++ b/libs/libarchopenfpga/src/read_xml_bitstream_setting.cpp @@ -76,6 +76,32 @@ static void read_xml_bitstream_interconnect_setting( operating_pb_parser.modes(), default_path_attr); } +/******************************************************************** + * Parse XML description for a non_fabric annotation under a XML + *node + *******************************************************************/ +static void read_xml_non_fabric_bitstream_setting( + pugi::xml_node& xml_non_fabric, const pugiutil::loc_data& loc_data, + openfpga::BitstreamSetting& bitstream_setting) { + const std::string& name_attr = + get_attribute(xml_non_fabric, "name", loc_data).as_string(); + const std::string& file_attr = + get_attribute(xml_non_fabric, "file", loc_data).as_string(); + /* Add to non-fabric */ + bitstream_setting.add_non_fabric(name_attr, file_attr); + for (pugi::xml_node xml_child : xml_non_fabric.children()) { + if (xml_child.name() != std::string("pb")) { + bad_tag(xml_child, loc_data, xml_non_fabric, {"pb"}); + } + const std::string& pb_name_attr = + get_attribute(xml_child, "name", loc_data).as_string(); + const std::string& content_attr = + get_attribute(xml_child, "content", loc_data).as_string(); + /* Add PB to non-fabric */ + bitstream_setting.add_non_fabric_pb(pb_name_attr, content_attr); + } +} + /******************************************************************** * Parse XML codes about to an object *******************************************************************/ @@ -89,17 +115,22 @@ openfpga::BitstreamSetting read_xml_bitstream_setting( for (pugi::xml_node xml_child : Node.children()) { /* Error out if the XML child has an invalid name! */ if ((xml_child.name() != std::string("pb_type")) && - (xml_child.name() != std::string("interconnect"))) { - bad_tag(xml_child, loc_data, Node, {"pb_type | interconnect"}); + (xml_child.name() != std::string("interconnect")) && + (xml_child.name() != std::string("non_fabric"))) { + bad_tag(xml_child, loc_data, Node, + {"pb_type | interconnect | non_fabric"}); } if (xml_child.name() == std::string("pb_type")) { read_xml_bitstream_pb_type_setting(xml_child, loc_data, bitstream_setting); - } else { - VTR_ASSERT_SAFE(xml_child.name() == std::string("interconnect")); + } else if (xml_child.name() == std::string("interconnect")) { read_xml_bitstream_interconnect_setting(xml_child, loc_data, bitstream_setting); + } else { + VTR_ASSERT_SAFE(xml_child.name() == std::string("non_fabric")); + read_xml_non_fabric_bitstream_setting(xml_child, loc_data, + bitstream_setting); } } diff --git a/openfpga/src/base/openfpga_bitstream_template.h b/openfpga/src/base/openfpga_bitstream_template.h index 8821c8392..c132e907f 100644 --- a/openfpga/src/base/openfpga_bitstream_template.h +++ b/openfpga/src/base/openfpga_bitstream_template.h @@ -11,6 +11,7 @@ #include "command.h" #include "command_context.h" #include "command_exit_codes.h" +#include "extract_device_non_fabric_bitstream.h" #include "globals.h" #include "openfpga_digest.h" #include "openfpga_naming.h" @@ -59,6 +60,9 @@ int fpga_bitstream_template(T& openfpga_ctx, const Command& cmd, !cmd_context.option_enable(cmd, opt_no_time_stamp)); } + extract_device_non_fabric_bitstream( + g_vpr_ctx, openfpga_ctx, cmd_context.option_enable(cmd, opt_verbose)); + /* TODO: should identify the error code from internal function execution */ return CMD_EXEC_SUCCESS; } diff --git a/openfpga/src/fpga_bitstream/extract_device_non_fabric_bitstream.cpp b/openfpga/src/fpga_bitstream/extract_device_non_fabric_bitstream.cpp new file mode 100644 index 000000000..3793c1b3d --- /dev/null +++ b/openfpga/src/fpga_bitstream/extract_device_non_fabric_bitstream.cpp @@ -0,0 +1,283 @@ +/******************************************************************** + * This file includes functions to build bitstream from a mapped + * FPGA fabric. + * We decode the bitstream from configuration of routing multiplexers + * and Look-Up Tables (LUTs) which locate in CLBs and global routing + *architecture + *******************************************************************/ +#include +#include + +/* Headers from vtrutil library */ +#include "extract_device_non_fabric_bitstream.h" +#include "openfpga_pb_parser.h" +#include "pb_type_utils.h" +#include "vtr_assert.h" +#include "vtr_log.h" +#include "vtr_time.h" + +/* begin namespace openfpga */ +namespace openfpga { + +#define PRINT_LAYOUT_NAME "__layout__" + +/******************************************************************** + * Extract data from the targetted PB + * 1. If it is primitive + * a. If it match the targetted PB, try to get data from + * param of attr depends on what being defined in XML + * b. If it is does not match, do nothing + * 2. If it is not primitive, then we loop for the child + *******************************************************************/ +static bool extract_pb_data(std::fstream& fp, const AtomContext& atom_ctx, + const t_pb* op_pb, const t_pb_type* target_pb_type, + const NonFabricBitstreamPBSetting& setting) { + t_pb_graph_node* pb_graph_node = op_pb->pb_graph_node; + t_pb_type* pb_type = pb_graph_node->pb_type; + bool found_pb = false; + if (true == is_primitive_pb_type(pb_type)) { + if (target_pb_type == pb_type) { + AtomBlockId atom_blk = atom_ctx.nlist.find_block(op_pb->name); + VTR_ASSERT(atom_blk); + if (setting.type == "param") { + for (const auto& param_search : atom_ctx.nlist.block_params(atom_blk)) { + std::string param = param_search.first; + std::string content = param_search.second; + if (setting.content == param) { + fp << ",\n \"data\" : \"" << content.c_str() << "\""; + break; + } + } + } else { + VTR_ASSERT(setting.type == "attr"); + for (const auto& attr_search : atom_ctx.nlist.block_attrs(atom_blk)) { + std::string attr = attr_search.first; + std::string content = attr_search.second; + if (setting.content == attr) { + fp << ",\n \"data\" : \"" << content.c_str() << "\""; + break; + } + } + } + found_pb = true; + } + } else { + t_mode* mapped_mode = &(pb_graph_node->pb_type->modes[op_pb->mode]); + for (int ipb = 0; ipb < mapped_mode->num_pb_type_children && !found_pb; + ++ipb) { + /* Each child may exist multiple times in the hierarchy*/ + for (int jpb = 0; + jpb < mapped_mode->pb_type_children[ipb].num_pb && !found_pb; + ++jpb) { + if ((nullptr != op_pb->child_pbs[ipb]) && + (nullptr != op_pb->child_pbs[ipb][jpb].name)) { + found_pb = + extract_pb_data(fp, atom_ctx, &(op_pb->child_pbs[ipb][jpb]), + target_pb_type, setting); + } + } + } + } + return found_pb; +} + +/******************************************************************** + * Extract data from the targetted PB (from that particular grid) + *******************************************************************/ +static void extract_grid_non_fabric_bitstream( + std::fstream& fp, const VprContext& vpr_ctx, + const ClusterBlockId& cluster_block_id, const t_pb_type* target_pb_type, + const NonFabricBitstreamPBSetting setting) { + const ClusteringContext& clustering_ctx = vpr_ctx.clustering(); + const AtomContext& atom_ctx = vpr_ctx.atom(); + + if (ClusterBlockId::INVALID() != cluster_block_id) { + const t_pb* op_pb = clustering_ctx.clb_nlist.block_pb(cluster_block_id); + extract_pb_data(fp, atom_ctx, op_pb, target_pb_type, setting); + } else { + // Grid is valid, but this resource is not being used + } +} + +/******************************************************************** + * Extract data from the targetted PB (from the device) + *******************************************************************/ +static void extract_device_non_fabric_pb_bitstream( + std::fstream& fp, const NonFabricBitstreamPBSetting setting, + const std::string& target_parent_pb_name, const t_pb_type* target_pb_type, + const VprContext& vpr_ctx) { + const DeviceContext& device_ctx = vpr_ctx.device(); + const PlacementContext& placement_ctx = vpr_ctx.placement(); + const DeviceGrid& grids = device_ctx.grid; + const size_t& layer = 0; + + // Loop logic block one by one + if (target_parent_pb_name != PRINT_LAYOUT_NAME) { + fp << ",\n \"grid\" : ["; + } + size_t grid_count = 0; + for (size_t ix = 1; ix < grids.width() - 1; ++ix) { + for (size_t iy = 1; iy < grids.height() - 1; ++iy) { + t_physical_tile_loc phy_tile_loc(ix, iy, layer); + t_physical_tile_type_ptr grid_type = + grids.get_physical_type(phy_tile_loc); + // Bypass EMPTY grid + if (true == is_empty_type(grid_type)) { + continue; + } + + // Skip width > 1 or height > 1 tiles (mostly heterogeneous blocks) + if ((0 < grids.get_width_offset(phy_tile_loc)) || + (0 < grids.get_height_offset(phy_tile_loc))) { + continue; + } + + // Skip if this grid is not what we are looking for + if (target_parent_pb_name == PRINT_LAYOUT_NAME) { + if (grid_count) { + fp << ",\n"; + } + fp << " {\n"; + fp << " \"x\" : " << (uint32_t)(ix) << ",\n"; + fp << " \"y\" : " << (uint32_t)(iy) << ",\n"; + fp << " \"name\" : \"" << grid_type->name << "\"\n"; + fp << " }"; + grid_count++; + continue; + } + + // Skip if this grid is not what we are looking for + if (target_parent_pb_name != std::string(grid_type->name)) { + continue; + } + + // Get the mapped blocks to this grid + for (int isubtile = 0; isubtile < grid_type->capacity; ++isubtile) { + ClusterBlockId cluster_blk_id = + placement_ctx.grid_blocks.block_at_location( + {(int)ix, (int)iy, (int)isubtile, (int)layer}); + if (grid_count) { + fp << ","; + } + fp << "\n"; + fp << " {\n"; + fp << " \"x\" : " << (uint32_t)(ix) << ",\n"; + fp << " \"y\" : " << (uint32_t)(iy); + extract_grid_non_fabric_bitstream(fp, vpr_ctx, cluster_blk_id, + target_pb_type, setting); + fp << "\n }"; + grid_count++; + } + } + } + if (target_parent_pb_name == PRINT_LAYOUT_NAME) { + fp << "\n"; + } else { + fp << "\n ]"; + } +} + +/******************************************************************** + * Search the PB type based on the given name defined in XML + *******************************************************************/ +static t_pb_type* find_pb_type(const DeviceContext& device_ctx, + const std::string& parent_pb, + const std::string& pb) { + t_pb_type* pb_type = nullptr; + openfpga::PbParser pb_parser(pb); + std::vector names = pb_parser.parents(); + names.push_back(pb_parser.leaf()); + for (const t_logical_block_type& lb_type : device_ctx.logical_block_types) { + /* Bypass nullptr for pb_type head */ + if (nullptr == lb_type.pb_type) { + continue; + } + + /* Check the name of the top-level pb_type, if it does not match, we can + * bypass */ + if (parent_pb != std::string(lb_type.pb_type->name)) { + continue; + } + + /* Match the name in the top-level, we go further to search the pb_type in + * the graph */ + pb_type = try_find_pb_type_with_given_path(lb_type.pb_type, names, + pb_parser.modes()); + if (nullptr == pb_type) { + continue; + } + break; + } + return pb_type; +} + +/******************************************************************** + * A top-level function to extract data based on non-fabric bitstream setting + *******************************************************************/ +void extract_device_non_fabric_bitstream(const VprContext& vpr_ctx, + const OpenfpgaContext& openfpga_ctx, + const bool& verbose) { + std::string timer_message = + std::string("\nBuild non-fabric bitstream for implementation '") + + vpr_ctx.atom().nlist.netlist_name() + std::string("'\n"); + vtr::ScopedStartFinishTimer timer(timer_message); + const openfpga::BitstreamSetting& bitstream_setting = + openfpga_ctx.bitstream_setting(); + std::vector non_fabric_setting = + bitstream_setting.non_fabric(); + + // Only proceed if it is defined in bitstream_setting.xml + if (non_fabric_setting.size()) { + // Go through each non_fabric settting + for (auto setting : non_fabric_setting) { + std::fstream fp; + fp.open(setting.file.c_str(), std::fstream::out); + fp << "{\n"; + fp << " \"" << setting.name.c_str() << "\" : [\n"; + if (setting.name == PRINT_LAYOUT_NAME) { + extract_device_non_fabric_pb_bitstream( + fp, NonFabricBitstreamPBSetting{}, setting.name, nullptr, vpr_ctx); + } else { + int pb_count = 0; + // Extract each needed PB data + for (auto pb_setting : setting.pbs) { + std::string pb_type = setting.name + pb_setting.pb; + t_pb_type* target_pb_type = + find_pb_type(vpr_ctx.device(), setting.name, pb_type); + if (pb_count) { + fp << ",\n"; + } + fp << " {\n"; + fp << " \"pb\" : \"" << pb_type.c_str() << "\",\n"; + if (target_pb_type == nullptr) { + fp << " \"is_primitive_pb_type\" : \"invalid\",\n"; + } else { + if (is_primitive_pb_type(target_pb_type)) { + fp << " \"is_primitive_pb_type\" : \"true\",\n"; + } else { + fp << " \"is_primitive_pb_type\" : \"false\",\n"; + } + } + fp << " \"type\" : \"" << pb_setting.type.c_str() << "\",\n"; + fp << " \"content\" : \"" << pb_setting.content.c_str() << "\""; + if (target_pb_type != nullptr && + is_primitive_pb_type(target_pb_type)) { + extract_device_non_fabric_pb_bitstream(fp, pb_setting, setting.name, + target_pb_type, vpr_ctx); + } + fp << "\n }"; + pb_count++; + } + if (pb_count) { + fp << "\n"; + } + } + fp << " ]\n"; + fp << "}\n"; + fp.close(); + } + } + VTR_LOGV(verbose, "Done\n"); +} + +} /* end namespace openfpga */ diff --git a/openfpga/src/fpga_bitstream/extract_device_non_fabric_bitstream.h b/openfpga/src/fpga_bitstream/extract_device_non_fabric_bitstream.h new file mode 100644 index 000000000..658c40b96 --- /dev/null +++ b/openfpga/src/fpga_bitstream/extract_device_non_fabric_bitstream.h @@ -0,0 +1,25 @@ +#ifndef EXTRACT_DEVICE_NON_FABRIC_BITSTREAM_H +#define EXTRACT_DEVICE_NON_FABRIC_BITSTREAM_H + +/******************************************************************** + * Include header files that are required by function declaration + *******************************************************************/ +#include + +#include "openfpga_context.h" +#include "vpr_context.h" + +/******************************************************************** + * Function declaration + *******************************************************************/ + +/* begin namespace openfpga */ +namespace openfpga { + +void extract_device_non_fabric_bitstream(const VprContext& vpr_ctx, + const OpenfpgaContext& openfpga_ctx, + const bool& verbose); + +} /* end namespace openfpga */ + +#endif diff --git a/openfpga_flow/regression_test_scripts/fpga_bitstream_reg_test.sh b/openfpga_flow/regression_test_scripts/fpga_bitstream_reg_test.sh index 184eceee9..8d46be27f 100755 --- a/openfpga_flow/regression_test_scripts/fpga_bitstream_reg_test.sh +++ b/openfpga_flow/regression_test_scripts/fpga_bitstream_reg_test.sh @@ -52,3 +52,6 @@ run-task fpga_bitstream/filter_value0 $@ run-task fpga_bitstream/filter_value1 $@ run-task fpga_bitstream/path_only $@ run-task fpga_bitstream/value_only $@ + +echo -e "Testing extracting mode bits for DSP blocks when generating bitstream"; +run-task fpga_bitstream/extract_dsp_mode_bit $@ diff --git a/openfpga_flow/tasks/fpga_bitstream/extract_dsp_mode_bit/config/bitstream_annotation.xml b/openfpga_flow/tasks/fpga_bitstream/extract_dsp_mode_bit/config/bitstream_annotation.xml new file mode 100644 index 000000000..7c835ad7e --- /dev/null +++ b/openfpga_flow/tasks/fpga_bitstream/extract_dsp_mode_bit/config/bitstream_annotation.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/openfpga_flow/tasks/fpga_bitstream/extract_dsp_mode_bit/config/task.conf b/openfpga_flow/tasks/fpga_bitstream/extract_dsp_mode_bit/config/task.conf new file mode 100644 index 000000000..908678571 --- /dev/null +++ b/openfpga_flow/tasks/fpga_bitstream/extract_dsp_mode_bit/config/task.conf @@ -0,0 +1,44 @@ +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# Configuration file for running experiments +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs +# Each job execute fpga_flow script on combination of architecture & benchmark +# timeout_each_job is timeout for each job +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = + +[GENERAL] +run_engine=openfpga_shell +power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml +power_analysis = false +spice_output=false +verilog_output=true +timeout_each_job = 20*60 +fpga_flow=yosys_vpr + +[OpenFPGA_SHELL] +openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/bitstream_setting_example_script.openfpga +openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_frac_dsp16_40nm_cc_openfpga.xml +openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/fixed_sim_openfpga.xml +openfpga_bitstream_setting_file=${PATH:TASK_DIR}/config/bitstream_annotation.xml +# VPR parameter +openfpga_vpr_circuit_format=eblif + +[ARCHITECTURES] +arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_frac_dsp16_40nm.xml + +[BENCHMARKS] +bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/mult/mult8/mult8.v + +[SYNTHESIS_PARAM] +# Yosys script parameters +bench_yosys_cell_sim_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k4_N4_tileable_frac_dsp16_40nm_cell_sim.v +bench_yosys_dsp_map_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k4_N4_tileable_frac_dsp16_40nm_dsp_map.v +bench_yosys_dsp_map_parameters_common=-D DSP_A_MAXWIDTH=8 -D DSP_B_MAXWIDTH=8 -D DSP_A_MINWIDTH=2 -D DSP_B_MINWIDTH=2 -D DSP_NAME=mult_8x8 +bench_read_verilog_options_common = -nolatches +bench_yosys_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_dsp_flow.ys +bench_yosys_rewrite_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_dsp_flow_with_rewrite.ys;${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_rewrite_flow.ys +bench0_top = mult8 + +[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH] +end_flow_with_test= +vpr_fpga_verilog_formal_verification_top_netlist=